Add telegram auth to frontend
This commit is contained in:
@@ -95,7 +95,16 @@ export interface Tree {
|
||||
info: PostInfo;
|
||||
}
|
||||
|
||||
export type OAuthProvider = 'facebook' | 'twitter' | 'google' | 'yandex' | 'github' | 'microsoft' | 'patreon' | 'dev';
|
||||
export type OAuthProvider =
|
||||
| 'facebook'
|
||||
| 'twitter'
|
||||
| 'google'
|
||||
| 'yandex'
|
||||
| 'github'
|
||||
| 'microsoft'
|
||||
| 'patreon'
|
||||
| 'telegram'
|
||||
| 'dev';
|
||||
export type FormProvider = 'email' | 'anonymous';
|
||||
export type Provider = OAuthProvider | FormProvider;
|
||||
|
||||
@@ -158,3 +167,8 @@ export interface ApiError {
|
||||
/** in-depth explanation */
|
||||
error: string;
|
||||
}
|
||||
|
||||
export interface TelegramParams {
|
||||
bot: string;
|
||||
token: string;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import type { User } from 'common/types';
|
||||
import type { User, TelegramParams } from 'common/types';
|
||||
|
||||
import { authFetcher } from 'common/fetcher';
|
||||
import { siteId } from 'common/settings';
|
||||
|
||||
const EMAIL_SIGNIN_ENDPOINT = '/email/login';
|
||||
const TELEGRAM_SIGNIN_ENDPOINT = '/telegram/login';
|
||||
|
||||
export function anonymousSignin(user: string): Promise<User> {
|
||||
return authFetcher.get<User>('/anonymous/login', { user, aud: siteId });
|
||||
@@ -23,6 +24,20 @@ export function verifyEmailSignin(token: string): Promise<User> {
|
||||
return authFetcher.get(EMAIL_SIGNIN_ENDPOINT, { token });
|
||||
}
|
||||
|
||||
/**
|
||||
* First step of two of `telegram` authorization
|
||||
*/
|
||||
export function getTelegramSigninParams(): Promise<TelegramParams> {
|
||||
return authFetcher.get(TELEGRAM_SIGNIN_ENDPOINT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Second step of two of `telegram` authorization
|
||||
*/
|
||||
export function verifyTelegramSignin(token: string): Promise<User> {
|
||||
return authFetcher.get(TELEGRAM_SIGNIN_ENDPOINT, { token });
|
||||
}
|
||||
|
||||
export function logout(): Promise<void> {
|
||||
return authFetcher.get('/logout');
|
||||
}
|
||||
|
||||
@@ -33,7 +33,13 @@ export function useDropdown(disableClosing?: boolean) {
|
||||
}
|
||||
|
||||
function handleClickOutside(evt: MouseEvent) {
|
||||
if (disableClosing || dropdownElement?.contains(evt.target as HTMLDivElement)) {
|
||||
if (
|
||||
disableClosing ||
|
||||
dropdownElement?.contains(evt.target as HTMLDivElement) ||
|
||||
(evt.target as Element).classList?.contains('telegram-auth')
|
||||
// telegram button is gone from dropdown render by the time of this check
|
||||
// without that condition click on telegram button considered as outside click
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,30 @@ export const messages = defineMessages({
|
||||
id: 'auth.submit',
|
||||
defaultMessage: 'Submit',
|
||||
},
|
||||
telegramLink: {
|
||||
id: 'auth.telegram-link',
|
||||
defaultMessage: 'by the link',
|
||||
},
|
||||
telegramCheck: {
|
||||
id: 'auth.telegram-check',
|
||||
defaultMessage: 'Check',
|
||||
},
|
||||
telegramMessage1: {
|
||||
id: 'auth.telegram-message-1',
|
||||
defaultMessage: 'Open the Telegram',
|
||||
},
|
||||
telegramOptionalQR: {
|
||||
id: 'auth.telegram-optional-qr',
|
||||
defaultMessage: 'or by scanning the QR code',
|
||||
},
|
||||
telegramMessage2: {
|
||||
id: 'auth.telegram-message-2',
|
||||
defaultMessage: 'and click “Start” there.',
|
||||
},
|
||||
telegramMessage3: {
|
||||
id: 'auth.telegram-message-3',
|
||||
defaultMessage: 'Afterwards, click “Check” below.',
|
||||
},
|
||||
openProfile: {
|
||||
id: 'auth.open-profile',
|
||||
defaultMessage: 'Open My Profile',
|
||||
|
||||
@@ -195,3 +195,8 @@
|
||||
color: var(--error-color);
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.qr {
|
||||
display: block;
|
||||
margin: 0 auto 1.5rem auto;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@ import clsx from 'clsx';
|
||||
import { h, Fragment } from 'preact';
|
||||
import { useState } from 'preact/hooks';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import QRCode from 'qrcode.react';
|
||||
|
||||
import { setUser } from 'store/user/actions';
|
||||
import { setTelegramParams, setUser } from 'store/user/actions';
|
||||
import { Input } from 'components/input';
|
||||
import { CrossIcon } from 'components/icons/cross';
|
||||
import { TextareaAutosize } from 'components/textarea-autosize';
|
||||
@@ -16,19 +17,22 @@ import { OAuth } from './components/oauth';
|
||||
import { messages } from './auth.messsages';
|
||||
import { useDropdown } from './auth.hooks';
|
||||
import { getProviders, getTokenInvalidReason } from './auth.utils';
|
||||
import { emailSignin, verifyEmailSignin, anonymousSignin } from './auth.api';
|
||||
import { emailSignin, verifyEmailSignin, anonymousSignin, verifyTelegramSignin } from './auth.api';
|
||||
import { StoreState } from 'store';
|
||||
|
||||
import styles from './auth.module.css';
|
||||
|
||||
export function Auth() {
|
||||
const intl = useIntl();
|
||||
const dispatch = useDispatch();
|
||||
const telegramParams = useSelector((s: StoreState) => s.telegramParams);
|
||||
const [oauthProviders, formProviders] = getProviders();
|
||||
|
||||
// UI State
|
||||
const [isLoading, setLoading] = useState(false);
|
||||
const [view, setView] = useState<typeof formProviders[number] | 'token'>(formProviders[0]);
|
||||
const [ref, isDropdownShown, toggleDropdownState] = useDropdown(view === 'token');
|
||||
const [isTelegramShown, toggleTelegram] = useState(false);
|
||||
const [ref, isDropdownShown, toggleDropdownState] = useDropdown(view === 'token' || isTelegramShown);
|
||||
|
||||
// Errors
|
||||
const [invalidReason, setInvalidReason] = useState<keyof typeof messages | null>(null);
|
||||
@@ -42,6 +46,7 @@ export function Auth() {
|
||||
evt.preventDefault();
|
||||
setView(formProviders[0]);
|
||||
toggleDropdownState();
|
||||
toggleTelegram(false);
|
||||
}
|
||||
|
||||
function handleProviderChange(evt: Event) {
|
||||
@@ -96,6 +101,23 @@ export function Auth() {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
async function handleTelegramSubmit(evt: Event) {
|
||||
evt.preventDefault();
|
||||
setLoading(true);
|
||||
setInvalidReason(null);
|
||||
if (telegramParams) {
|
||||
try {
|
||||
const user = await verifyTelegramSignin(telegramParams.token);
|
||||
dispath(setUser(user));
|
||||
toggleTelegram(false);
|
||||
dispath(setTelegramParams(null));
|
||||
} catch (e) {
|
||||
setInvalidReason(e.message || e.error);
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
function handleShowEmailStep(evt: Event) {
|
||||
evt.preventDefault();
|
||||
setView('email');
|
||||
@@ -122,7 +144,68 @@ export function Auth() {
|
||||
{isDropdownShown && (
|
||||
<div className={clsx('auth-dropdown', styles.dropdown)} ref={ref}>
|
||||
<form className={clsx('auth-form', styles.form)} onSubmit={handleSubmit}>
|
||||
{isTokenView ? (
|
||||
{isTelegramShown && telegramParams ? (
|
||||
<>
|
||||
<div className={clsx('auth-row', styles.row)}>
|
||||
<div className={styles.backButton}>
|
||||
<Button
|
||||
className="auth-back-button"
|
||||
size="xs"
|
||||
kind="transparent"
|
||||
onClick={() => toggleTelegram(false)}
|
||||
>
|
||||
<svg
|
||||
className={styles.backButtonArrow}
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 14 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8.75 3L5 7.25L9 11"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
{intl.formatMessage(messages.back)}
|
||||
</Button>
|
||||
</div>
|
||||
<button
|
||||
className={clsx('auth-close-button', styles.closeButton)}
|
||||
title="Close sign-in dropdown"
|
||||
onClick={handleDropdownClose}
|
||||
>
|
||||
<CrossIcon />
|
||||
</button>
|
||||
</div>
|
||||
<p>
|
||||
{intl.formatMessage(messages.telegramMessage1)}{' '}
|
||||
<a
|
||||
href={`https://t.me/${telegramParams.bot}/?start=${telegramParams.token}`}
|
||||
className="comment-form__markdown-link"
|
||||
>
|
||||
{intl.formatMessage(messages.telegramLink)}
|
||||
</a>
|
||||
{window.screen.width >= 768 && ` ${intl.formatMessage(messages.telegramOptionalQR)}`}{' '}
|
||||
{intl.formatMessage(messages.telegramMessage2)}
|
||||
<br />
|
||||
{intl.formatMessage(messages.telegramMessage3)}
|
||||
</p>
|
||||
{window.screen.width >= 768 && (
|
||||
<QRCode
|
||||
value={`https://t.me/${telegramParams.bot}/?start=${telegramParams.token}`}
|
||||
className={clsx('qr', styles.qr)}
|
||||
/>
|
||||
)}
|
||||
<Button key="submit" className="auth-submit" type="submit" onClick={handleTelegramSubmit}>
|
||||
{intl.formatMessage(messages.telegramCheck)}
|
||||
</Button>
|
||||
{errorMessage && <div className={clsx('auth-error', styles.error)}>{errorMessage}</div>}
|
||||
</>
|
||||
) : isTokenView ? (
|
||||
<>
|
||||
<div className={clsx('auth-row', styles.row)}>
|
||||
<div className={styles.backButton}>
|
||||
@@ -171,7 +254,7 @@ export function Auth() {
|
||||
<h5 className={clsx('auth-form-title', styles.title)}>
|
||||
{intl.formatMessage(messages.oauthSource)}
|
||||
</h5>
|
||||
<OAuth providers={oauthProviders} />
|
||||
<OAuth providers={oauthProviders} toggleTelegram={toggleTelegram} />
|
||||
</>
|
||||
)}
|
||||
{hasOAuthProviders && hasFormProviders && (
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240"><defs><linearGradient id="a" x1=".667" x2=".417" y1=".167" y2=".75"><stop offset="0" stop-color="#37aee2"/><stop offset="1" stop-color="#1e96c8"/></linearGradient><linearGradient id="b" x1=".66" x2=".851" y1=".437" y2=".802"><stop offset="0" stop-color="#eff7fc"/><stop offset="1" stop-color="#fff"/></linearGradient></defs><circle cx="120" cy="120" r="120" fill="url(#a)"/><path fill="#c8daea" d="M98 175c-3.888 0-3.227-1.468-4.568-5.17L82 132.207 170 80"/><path fill="#a9c9dd" d="M98 175c3 0 4.325-1.372 6-3l16-15.558-19.958-12.035"/><path fill="url(#b)" d="M100.04 144.41l48.36 35.729c5.519 3.045 9.501 1.468 10.876-5.123l19.685-92.763c2.015-8.08-3.08-11.746-8.36-9.349l-115.59 44.571c-7.89 3.165-7.843 7.567-1.438 9.528l29.663 9.259 68.673-43.325c3.242-1.966 6.218-.91 3.776 1.258"/></svg>
|
||||
|
After Width: | Height: | Size: 855 B |
@@ -13,6 +13,7 @@ export const OAUTH_DATA = {
|
||||
dark: require('./assets/github-dark.svg').default as string,
|
||||
},
|
||||
},
|
||||
telegram: require('./assets/telegram.svg').default as string,
|
||||
} as const;
|
||||
|
||||
export const OAUTH_PROVIDERS = Object.keys(OAUTH_DATA);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { h, JSX } from 'preact';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import clsx from 'clsx';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import type { OAuthProvider } from 'common/types';
|
||||
import { siteId } from 'common/settings';
|
||||
import { useTheme } from 'hooks/useTheme';
|
||||
import { setUser } from 'store/user/actions';
|
||||
import { setUser, setTelegramParams } from 'store/user/actions';
|
||||
import { StoreState } from 'store';
|
||||
|
||||
import { messages } from 'components/auth/auth.messsages';
|
||||
|
||||
@@ -14,16 +15,19 @@ import { oauthSignin } from './oauth.api';
|
||||
import { BASE_URL } from 'common/constants.config';
|
||||
import { getButtonVariant, getProviderData } from './oauth.utils';
|
||||
import styles from './oauth.module.css';
|
||||
import { getTelegramSigninParams } from '../auth.api';
|
||||
|
||||
const location = encodeURIComponent(`${window.location.origin}${window.location.pathname}?selfClose`);
|
||||
|
||||
type Props = {
|
||||
providers: OAuthProvider[];
|
||||
toggleTelegram?: (showTelegram: boolean) => void;
|
||||
};
|
||||
|
||||
export function OAuth({ providers }: Props) {
|
||||
export function OAuth({ providers, toggleTelegram }: Props) {
|
||||
const intl = useIntl();
|
||||
const dispatch = useDispatch();
|
||||
const telegramParams = useSelector((s: StoreState) => s.telegramParams);
|
||||
const theme = useTheme();
|
||||
const buttonVariant = getButtonVariant(providers.length);
|
||||
const handleOauthClick: JSX.GenericEventHandler<HTMLAnchorElement> = async (evt) => {
|
||||
@@ -39,6 +43,18 @@ export function OAuth({ providers }: Props) {
|
||||
dispatch(setUser(user));
|
||||
};
|
||||
|
||||
const handleTelegramClick: JSX.EventHandler<JSX.TargetedMouseEvent<HTMLButtonElement>> = async (evt) => {
|
||||
evt.preventDefault();
|
||||
if (!telegramParams) {
|
||||
const params = await getTelegramSigninParams();
|
||||
if (params === null) {
|
||||
return;
|
||||
}
|
||||
dispath(setTelegramParams(params));
|
||||
}
|
||||
toggleTelegram && toggleTelegram(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<ul className={clsx('oauth', styles.root)}>
|
||||
{providers.map((p) => {
|
||||
@@ -46,17 +62,28 @@ export function OAuth({ providers }: Props) {
|
||||
|
||||
return (
|
||||
<li key={name} className={clsx('oauth-item', styles.item)}>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={`${BASE_URL}/auth/${p}/login?from=${location}&site=${siteId}`}
|
||||
onClick={handleOauthClick}
|
||||
className={clsx('oauth-button', styles.button, styles[buttonVariant], styles[p])}
|
||||
data-provider-name={name}
|
||||
title={intl.formatMessage(messages.oauthTitle, { provider: name })}
|
||||
>
|
||||
<img className="oauth-icon" src={icon} width="20" height="20" alt="" aria-hidden={true} />
|
||||
</a>
|
||||
{name === 'Telegram' ? (
|
||||
<button
|
||||
onClick={handleTelegramClick}
|
||||
className={clsx('oauth-button telegram-auth', styles.button, styles[buttonVariant], styles[p])}
|
||||
data-provider-name={name}
|
||||
title={intl.formatMessage(messages.oauthTitle, { provider: name })}
|
||||
>
|
||||
<img className="oauth-icon telegram-auth" src={icon} width="20" height="20" alt="" aria-hidden={true} />
|
||||
</button>
|
||||
) : (
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={`${BASE_URL}/auth/${p}/login?from=${location}&site=${siteId}`}
|
||||
onClick={handleOauthClick}
|
||||
className={clsx('oauth-button', styles.button, styles[buttonVariant], styles[p])}
|
||||
data-provider-name={name}
|
||||
title={intl.formatMessage(messages.oauthTitle, { provider: name })}
|
||||
>
|
||||
<img className="oauth-icon" src={icon} width="20" height="20" alt="" aria-hidden={true} />
|
||||
</a>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "Выйсці?",
|
||||
"auth.submit": "Адправіць",
|
||||
"auth.symbols-restriction": "імя карыстальніка мусіць пачынацца з літары і ўтрымоўваць толькі лацінскія літары, лічбы, знакі падкрэслівання і прабелы(?)",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "Карыстальнік не знойдзены",
|
||||
"auth.username": "Імя карыстальніка",
|
||||
"authPanel.disable-comments": "Адключыць каментары",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "Изход",
|
||||
"auth.submit": "Изпрати",
|
||||
"auth.symbols-restriction": "Потребителското име трябва да започва с буква и да бъде само от латински букви, цифри, подчертавки или разтояния",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "Не бе намерен потребител",
|
||||
"auth.username": "Потребителско име",
|
||||
"authPanel.disable-comments": "Забрани коментарите",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "Fazer logout",
|
||||
"auth.submit": "Enviar",
|
||||
"auth.symbols-restriction": "O nome de usuário deve conter apenas letras, números, sublinhados ou espaços",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "Nenhum usuário encontrado",
|
||||
"auth.username": "Nome do usuário",
|
||||
"authPanel.disable-comments": "Desabilitar comentários",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "Abmelden",
|
||||
"auth.submit": "Absenden",
|
||||
"auth.symbols-restriction": "Der Benutzername darf nur Buchstaben, Zahlen, Unterstriche oder Leerzeichen enthalten",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "Benutzer konnte nicht gefunden werden",
|
||||
"auth.username": "Benutzername",
|
||||
"authPanel.disable-comments": "Kommentarfunktion deaktivieren",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "Sign Out",
|
||||
"auth.submit": "Submit",
|
||||
"auth.symbols-restriction": "Username must contain only letters, numbers, underscores or spaces",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "by the link",
|
||||
"auth.telegram-message-1": "Open the Telegram",
|
||||
"auth.telegram-message-2": "and click “Start” there.",
|
||||
"auth.telegram-message-3": "Afterwards, click “Check” below.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "No user was found",
|
||||
"auth.username": "Username",
|
||||
"authPanel.disable-comments": "Disable comments",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "¿Salir?",
|
||||
"auth.submit": "Enviar",
|
||||
"auth.symbols-restriction": "El nombre de usuario debe comenzar con una letra y contener solamente letras latinas, números, guión bajo o espacio",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "No se encontró el usuario",
|
||||
"auth.username": "Nombre de usuario",
|
||||
"authPanel.disable-comments": "Deshabilitar comentarios",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "Kirjaudu ulos",
|
||||
"auth.submit": "Lähetä",
|
||||
"auth.symbols-restriction": "Käyttäjätunnuksen tulee alkaa kirjaimella ja sisältää vain latinalaisia kirjaimia, numeroita, alaviivoja ja välilyöntejä",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "Käyttäjää ei löytynyt",
|
||||
"auth.username": "Käyttäjätunnus",
|
||||
"authPanel.disable-comments": "Poista kommentit käytöstä",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "Se déconnecter",
|
||||
"auth.submit": "Valider",
|
||||
"auth.symbols-restriction": "Le nom d'utilisateur ne doit contenir que des lettres, nombres, tirets bas et espaces.",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "Aucun utilisateur n'a été trouvé",
|
||||
"auth.username": "Nom d'utilisateur",
|
||||
"authPanel.disable-comments": "Désactiver les commentaires",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "Esci",
|
||||
"auth.submit": "Invia",
|
||||
"auth.symbols-restriction": "L'username deve contenere solo lettere, numberi, trattini bassi o spazi",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "Nessun utente trovato",
|
||||
"auth.username": "Username",
|
||||
"authPanel.disable-comments": "Disabilita commenti",
|
||||
@@ -157,8 +163,8 @@
|
||||
"toolbar.ordered-list": "Aggiungi lista numerata",
|
||||
"toolbar.quote": "Inserisci citazione",
|
||||
"toolbar.unordered-list": "Aggiungi lista a pallini",
|
||||
"user.my-comments": "My comments",
|
||||
"user.comments": "Comments",
|
||||
"user.my-comments": "My comments",
|
||||
"vote.anonymous": "Gli utenti anonimi non possono votare",
|
||||
"vote.deleted": "Non puoi votare per un commento eliminato",
|
||||
"vote.guest": "Accedi per votare",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "ログアウトしますか",
|
||||
"auth.submit": "送信",
|
||||
"auth.symbols-restriction": "ユーザー名には英数字、アンダースコア、またはスペースのみを指定してください",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "ユーザーが見つかりませんでした",
|
||||
"auth.username": "ユーザー名",
|
||||
"authPanel.disable-comments": "コメントの無効化",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "로그아웃하시겠어요",
|
||||
"auth.submit": "확인",
|
||||
"auth.symbols-restriction": "사용자 이름에는 문자, 숫자, 밑줄 또는 공백만 포함되어야 합니다",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "사용자를 찾을 수 없습니다",
|
||||
"auth.username": "사용자 이름",
|
||||
"authPanel.disable-comments": "댓글 비활성화",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "Wyloguj",
|
||||
"auth.submit": "Potwierdź",
|
||||
"auth.symbols-restriction": "Nazwa użytkownika powinna składać się z liter, numerów, podkreślinków lub spacji",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "Żaden użytkownik nie został znaleziony",
|
||||
"auth.username": "Nazwa użytkownika",
|
||||
"authPanel.disable-comments": "Wyłącz komentarze",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "Выйти",
|
||||
"auth.submit": "Отправить",
|
||||
"auth.symbols-restriction": "Имя пользователя должно начинаться с буквы и содержать только латинские буквы, цифры, знаки подчеркивания и пробелы",
|
||||
"auth.telegram-check": "Проверить",
|
||||
"auth.telegram-link": "по ссылке",
|
||||
"auth.telegram-message-1": "Откройте Телеграм",
|
||||
"auth.telegram-message-2": "и нажмите там кнопку “Start”/“Начать”.",
|
||||
"auth.telegram-message-3": "Затем нажмите кнопку “Проверить”.",
|
||||
"auth.telegram-optional-qr": "или по QR-коду",
|
||||
"auth.user-not-found": "Пользователь не найден",
|
||||
"auth.username": "Имя пользователя",
|
||||
"authPanel.disable-comments": "Отключить комментарии",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "Çıkış yap",
|
||||
"auth.submit": "Gönder",
|
||||
"auth.symbols-restriction": "Kullanıcı adı harf ile başlayıp; yalnızca harf, rakam, alt çizgi veya boşluk içerebilir",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "Kullanıcı bulunamadı",
|
||||
"auth.username": "Kullanıcı adı",
|
||||
"authPanel.disable-comments": "Yorumları devre dışı bırak",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "Вийти",
|
||||
"auth.submit": "Відправити",
|
||||
"auth.symbols-restriction": "Ім’я користувача повинно починатися з літери та містити тільки символи латинського алфавіту, цифри, знаки підкреслення або пробіли",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "Користувач не знайдений",
|
||||
"auth.username": "Ім’я користувача",
|
||||
"authPanel.disable-comments": "Вимкнути коментарі",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "Thoát",
|
||||
"auth.submit": "Gửi đi",
|
||||
"auth.symbols-restriction": "Tên người dùng chỉ được chứa các chữ cái, số, dấu gạch dưới hoặc dấu cách",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "Không tìm thấy người dùng nào",
|
||||
"auth.username": "Tên người dùng",
|
||||
"authPanel.disable-comments": "Tắt bình luận",
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"auth.signout": "登出",
|
||||
"auth.submit": "提交",
|
||||
"auth.symbols-restriction": "用户名只能包含字母、数字、下划线或空格",
|
||||
"auth.telegram-check": "Check",
|
||||
"auth.telegram-link": "Telegram bot",
|
||||
"auth.telegram-message-1": "You need to authorize your account in the",
|
||||
"auth.telegram-message-2": "by clicking “Start” there.",
|
||||
"auth.telegram-message-3": "Click “Check” below after authorization in the Telegram bot.",
|
||||
"auth.telegram-optional-qr": "or by scanning the QR code",
|
||||
"auth.user-not-found": "未找到用户",
|
||||
"auth.username": "用户名",
|
||||
"authPanel.disable-comments": "禁用评论",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as api from 'common/api';
|
||||
import { logout } from 'components/auth/auth.api';
|
||||
import { User, BlockedUser, BlockTTL } from 'common/types';
|
||||
import { User, BlockedUser, BlockTTL, TelegramParams } from 'common/types';
|
||||
import { ttlToTime } from 'utils/ttl-to-time';
|
||||
import { getHiddenUsers } from 'utils/get-hidden-users';
|
||||
import { LS_EMAIL_KEY, LS_HIDDEN_USERS_KEY } from 'common/constants';
|
||||
@@ -17,6 +17,8 @@ import {
|
||||
USER_UNHIDE,
|
||||
USER_SUBSCRIPTION_SET,
|
||||
USER_SET_ACTION,
|
||||
TELEGRAM_PARAMS_SET,
|
||||
TELEGRAM_PARAMS_SET_ACTION,
|
||||
} from './types';
|
||||
import { fetchComments, unsetCommentMode } from '../comments/actions';
|
||||
import { COMMENTS_PATCH } from '../comments/types';
|
||||
@@ -28,6 +30,13 @@ export function setUser(user: User | null = null): USER_SET_ACTION {
|
||||
};
|
||||
}
|
||||
|
||||
export function setTelegramParams(telegramParams: TelegramParams | null = null): TELEGRAM_PARAMS_SET_ACTION {
|
||||
return {
|
||||
type: TELEGRAM_PARAMS_SET,
|
||||
telegramParams,
|
||||
};
|
||||
}
|
||||
|
||||
export function signout(cleanSession = true): StoreAction<Promise<void>> {
|
||||
return async (dispatch) => {
|
||||
if (cleanSession) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { User, BlockedUser } from 'common/types';
|
||||
import type { User, BlockedUser, TelegramParams } from 'common/types';
|
||||
|
||||
import {
|
||||
USER_SET,
|
||||
@@ -10,6 +10,8 @@ import {
|
||||
USER_HIDE,
|
||||
USER_UNHIDE,
|
||||
USER_SUBSCRIPTION_SET,
|
||||
TELEGRAM_PARAMS_SET,
|
||||
TELEGRAM_PARAMS_SET_ACTION,
|
||||
} from './types';
|
||||
|
||||
export const user = (state: User | null = null, action: USER_ACTIONS): User | null => {
|
||||
@@ -73,3 +75,16 @@ export const hiddenUsers = (state: { [id: string]: User } = {}, action: USER_ACT
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export const telegramParams = (
|
||||
state: TelegramParams | null = null,
|
||||
action: TELEGRAM_PARAMS_SET_ACTION
|
||||
): TelegramParams | null => {
|
||||
switch (action.type) {
|
||||
case TELEGRAM_PARAMS_SET: {
|
||||
return action.telegramParams;
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { User, BlockedUser } from 'common/types';
|
||||
import { User, BlockedUser, TelegramParams } from 'common/types';
|
||||
|
||||
export const USER_SET = 'USER/SET';
|
||||
|
||||
export const TELEGRAM_PARAMS_SET = 'TELEGRAM_PARAMS/SET';
|
||||
|
||||
export interface USER_SET_ACTION {
|
||||
type: typeof USER_SET;
|
||||
user: User | null;
|
||||
}
|
||||
|
||||
export interface TELEGRAM_PARAMS_SET_ACTION {
|
||||
type: typeof TELEGRAM_PARAMS_SET;
|
||||
telegramParams: TelegramParams | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set list of banned users
|
||||
*/
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
"lodash-es": "^4.17.21",
|
||||
"node-emoji": "^1.10.0",
|
||||
"preact": "^10.5.13",
|
||||
"qrcode.react": "^1.0.1",
|
||||
"react-intl": "^5.17.4",
|
||||
"react-redux": "^7.2.4",
|
||||
"redux": "^4.1.0",
|
||||
@@ -55,6 +56,7 @@
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/lodash-es": "^4.17.4",
|
||||
"@types/node-emoji": "^1.8.1",
|
||||
"@types/qrcode.react": "^1.0.2",
|
||||
"@types/react-redux": "^7.1.16",
|
||||
"@types/redux-mock-store": "^1.0.2",
|
||||
"@types/webpack-env": "^1.16.0",
|
||||
|
||||
Reference in New Issue
Block a user