Merge remote-tracking branch 'origin/develop' into use-instance
This commit is contained in:
commit
42aff1ca29
21 changed files with 120 additions and 70 deletions
|
@ -38,6 +38,7 @@ const messages = defineMessages({
|
||||||
developers: { id: 'navigation.developers', defaultMessage: 'Developers' },
|
developers: { id: 'navigation.developers', defaultMessage: 'Developers' },
|
||||||
addAccount: { id: 'profile_dropdown.add_account', defaultMessage: 'Add an existing account' },
|
addAccount: { id: 'profile_dropdown.add_account', defaultMessage: 'Add an existing account' },
|
||||||
followRequests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
followRequests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
||||||
|
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||||
});
|
});
|
||||||
|
|
||||||
interface ISidebarLink {
|
interface ISidebarLink {
|
||||||
|
@ -148,7 +149,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
title='close'
|
title={intl.formatMessage(messages.close)}
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
src={require('@tabler/icons/x.svg')}
|
src={require('@tabler/icons/x.svg')}
|
||||||
ref={closeButtonRef}
|
ref={closeButtonRef}
|
||||||
|
|
|
@ -67,6 +67,7 @@ const messages = defineMessages({
|
||||||
userEndorsed: { id: 'account.endorse.success', defaultMessage: 'You are now featuring @{acct} on your profile' },
|
userEndorsed: { id: 'account.endorse.success', defaultMessage: 'You are now featuring @{acct} on your profile' },
|
||||||
userUnendorsed: { id: 'account.unendorse.success', defaultMessage: 'You are no longer featuring @{acct}' },
|
userUnendorsed: { id: 'account.unendorse.success', defaultMessage: 'You are no longer featuring @{acct}' },
|
||||||
profileExternal: { id: 'account.profile_external', defaultMessage: 'View profile on {domain}' },
|
profileExternal: { id: 'account.profile_external', defaultMessage: 'View profile on {domain}' },
|
||||||
|
header: { id: 'account.header.alt', defaultMessage: 'Profile header' },
|
||||||
});
|
});
|
||||||
|
|
||||||
interface IHeader {
|
interface IHeader {
|
||||||
|
@ -556,7 +557,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
||||||
<a href={account.header} onClick={handleHeaderClick} target='_blank'>
|
<a href={account.header} onClick={handleHeaderClick} target='_blank'>
|
||||||
<StillImage
|
<StillImage
|
||||||
src={account.header}
|
src={account.header}
|
||||||
alt='Profile Header'
|
alt={intl.formatMessage(messages.header)}
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -11,6 +11,7 @@ const token = new URLSearchParams(window.location.search).get('reset_password_to
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
resetPasswordFail: { id: 'reset_password.fail', defaultMessage: 'Expired token, please try again.' },
|
resetPasswordFail: { id: 'reset_password.fail', defaultMessage: 'Expired token, please try again.' },
|
||||||
|
passwordPlaceholder: { id: 'reset_password.password.placeholder', defaultMessage: 'Placeholder' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const Statuses = {
|
const Statuses = {
|
||||||
|
@ -66,11 +67,11 @@ const PasswordResetConfirm = () => {
|
||||||
|
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormGroup labelText='Password' errors={renderErrors()}>
|
<FormGroup labelText={<FormattedMessage id='reset_password.password.label' defaultMessage='Password' />} errors={renderErrors()}>
|
||||||
<Input
|
<Input
|
||||||
type='password'
|
type='password'
|
||||||
name='password'
|
name='password'
|
||||||
placeholder='Password'
|
placeholder={intl.formatMessage(messages.passwordPlaceholder)}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -18,6 +19,10 @@ import ChatBox from './chat-box';
|
||||||
|
|
||||||
import type { Account as AccountEntity } from 'soapbox/types/entities';
|
import type { Account as AccountEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
close: { id: 'chat_window.close', defaultMessage: 'Close chat' },
|
||||||
|
});
|
||||||
|
|
||||||
type WindowState = 'open' | 'minimized';
|
type WindowState = 'open' | 'minimized';
|
||||||
|
|
||||||
const getChat = makeGetChat();
|
const getChat = makeGetChat();
|
||||||
|
@ -33,6 +38,7 @@ interface IChatWindow {
|
||||||
|
|
||||||
/** Floating desktop chat window. */
|
/** Floating desktop chat window. */
|
||||||
const ChatWindow: React.FC<IChatWindow> = ({ idx, chatId, windowState }) => {
|
const ChatWindow: React.FC<IChatWindow> = ({ idx, chatId, windowState }) => {
|
||||||
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const displayFqn = useAppSelector(getDisplayFqn);
|
const displayFqn = useAppSelector(getDisplayFqn);
|
||||||
|
@ -98,7 +104,7 @@ const ChatWindow: React.FC<IChatWindow> = ({ idx, chatId, windowState }) => {
|
||||||
@{getAcct(account, displayFqn)}
|
@{getAcct(account, displayFqn)}
|
||||||
</button>
|
</button>
|
||||||
<div className='pane__close'>
|
<div className='pane__close'>
|
||||||
<IconButton src={require('@tabler/icons/x.svg')} title='Close chat' onClick={handleChatClose(chat.id)} />
|
<IconButton src={require('@tabler/icons/x.svg')} title={intl.formatMessage(messages.close)} onClick={handleChatClose(chat.id)} />
|
||||||
</div>
|
</div>
|
||||||
</HStack>
|
</HStack>
|
||||||
<div className='pane__content'>
|
<div className='pane__content'>
|
||||||
|
|
|
@ -33,9 +33,9 @@ const Chat: React.FC<IChat> = ({ chatId, onClick }) => {
|
||||||
return (
|
return (
|
||||||
<div className='account'>
|
<div className='account'>
|
||||||
<button className='floating-link' onClick={() => onClick(chat)} />
|
<button className='floating-link' onClick={() => onClick(chat)} />
|
||||||
<HStack key={account.id} space={3} className='relative'>
|
<HStack key={account.id} space={3} className='relative overflow-hidden'>
|
||||||
<Avatar src={account.avatar} size={36} />
|
<Avatar className='flex-none' src={account.avatar} size={36} />
|
||||||
<Stack>
|
<Stack className='overflow-hidden'>
|
||||||
<DisplayName account={account} withSuffix={false} />
|
<DisplayName account={account} withSuffix={false} />
|
||||||
{attachment && (
|
{attachment && (
|
||||||
<Icon
|
<Icon
|
||||||
|
@ -49,6 +49,7 @@ const Chat: React.FC<IChat> = ({ chatId, onClick }) => {
|
||||||
size='sm'
|
size='sm'
|
||||||
className='chat__last-message'
|
className='chat__last-message'
|
||||||
dangerouslySetInnerHTML={{ __html: parsedContent }}
|
dangerouslySetInnerHTML={{ __html: parsedContent }}
|
||||||
|
truncate
|
||||||
/>
|
/>
|
||||||
) : attachment && (
|
) : attachment && (
|
||||||
<span
|
<span
|
||||||
|
|
|
@ -29,6 +29,7 @@ const isJSONValid = (text: any): boolean => {
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
heading: { id: 'column.settings_store', defaultMessage: 'Settings store' },
|
heading: { id: 'column.settings_store', defaultMessage: 'Settings store' },
|
||||||
|
advanced: { id: 'developers.settings_store.advanced', defaultMessage: 'Advanced settings' },
|
||||||
hint: { id: 'developers.settings_store.hint', defaultMessage: 'It is possible to directly edit your user settings here. BE CAREFUL! Editing this section can break your account, and you will only be able to recover through the API.' },
|
hint: { id: 'developers.settings_store.hint', defaultMessage: 'It is possible to directly edit your user settings here. BE CAREFUL! Editing this section can break your account, and you will only be able to recover through the API.' },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -98,7 +99,7 @@ const SettingsStore: React.FC = () => {
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle title='Advanced settings' />
|
<CardTitle title={intl.formatMessage(messages.advanced)} />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
<List>
|
<List>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import classNames from 'clsx';
|
import classNames from 'clsx';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { defineMessages, FormattedMessage } from 'react-intl';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
import { patchMe } from 'soapbox/actions/me';
|
import { patchMe } from 'soapbox/actions/me';
|
||||||
|
@ -11,6 +11,10 @@ import resizeImage from 'soapbox/utils/resize-image';
|
||||||
|
|
||||||
import type { AxiosError } from 'axios';
|
import type { AxiosError } from 'axios';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
error: { id: 'onboarding.error', defaultMessage: 'An unexpected error occurred. Please try again or skip this step.' },
|
||||||
|
});
|
||||||
|
|
||||||
/** Default avatar filenames from various backends */
|
/** Default avatar filenames from various backends */
|
||||||
const DEFAULT_AVATARS = [
|
const DEFAULT_AVATARS = [
|
||||||
'/avatars/original/missing.png', // Mastodon
|
'/avatars/original/missing.png', // Mastodon
|
||||||
|
@ -64,7 +68,7 @@ const AvatarSelectionStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
if (error.response?.status === 422) {
|
if (error.response?.status === 422) {
|
||||||
dispatch(snackbar.error((error.response.data as any).error.replace('Validation failed: ', '')));
|
dispatch(snackbar.error((error.response.data as any).error.replace('Validation failed: ', '')));
|
||||||
} else {
|
} else {
|
||||||
dispatch(snackbar.error('An unexpected error occurred. Please try again or skip this step.'));
|
dispatch(snackbar.error(messages.error));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).catch(console.error);
|
}).catch(console.error);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
import { patchMe } from 'soapbox/actions/me';
|
import { patchMe } from 'soapbox/actions/me';
|
||||||
|
@ -9,7 +9,13 @@ import { useOwnAccount } from 'soapbox/hooks';
|
||||||
|
|
||||||
import type { AxiosError } from 'axios';
|
import type { AxiosError } from 'axios';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
bioPlaceholder: { id: 'onboarding.bio.placeholder', defaultMessage: 'Tell the world a little about yourself…' },
|
||||||
|
error: { id: 'onboarding.error', defaultMessage: 'An unexpected error occurred. Please try again or skip this step.' },
|
||||||
|
});
|
||||||
|
|
||||||
const BioStep = ({ onNext }: { onNext: () => void }) => {
|
const BioStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
|
const intl = useIntl();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const account = useOwnAccount();
|
const account = useOwnAccount();
|
||||||
|
@ -32,7 +38,7 @@ const BioStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
if (error.response?.status === 422) {
|
if (error.response?.status === 422) {
|
||||||
setErrors([(error.response.data as any).error.replace('Validation failed: ', '')]);
|
setErrors([(error.response.data as any).error.replace('Validation failed: ', '')]);
|
||||||
} else {
|
} else {
|
||||||
dispatch(snackbar.error('An unexpected error occurred. Please try again or skip this step.'));
|
dispatch(snackbar.error(messages.error));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -56,13 +62,13 @@ const BioStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
<Stack space={5}>
|
<Stack space={5}>
|
||||||
<div className='sm:pt-10 sm:w-2/3 mx-auto'>
|
<div className='sm:pt-10 sm:w-2/3 mx-auto'>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
hintText='Max 500 characters'
|
hintText={<FormattedMessage id='onboarding.bio.hint' defaultMessage='Max 500 characters' />}
|
||||||
labelText='Bio'
|
labelText={<FormattedMessage id='edit_profile.fields.bio_label' defaultMessage='Bio' />}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
>
|
>
|
||||||
<Textarea
|
<Textarea
|
||||||
onChange={(event) => setValue(event.target.value)}
|
onChange={(event) => setValue(event.target.value)}
|
||||||
placeholder='Tell the world a little about yourself…'
|
placeholder={intl.formatMessage(messages.bioPlaceholder)}
|
||||||
value={value}
|
value={value}
|
||||||
maxLength={500}
|
maxLength={500}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import classNames from 'clsx';
|
import classNames from 'clsx';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
import { patchMe } from 'soapbox/actions/me';
|
import { patchMe } from 'soapbox/actions/me';
|
||||||
|
@ -12,6 +12,11 @@ import resizeImage from 'soapbox/utils/resize-image';
|
||||||
|
|
||||||
import type { AxiosError } from 'axios';
|
import type { AxiosError } from 'axios';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
header: { id: 'account.header.alt', defaultMessage: 'Profile header' },
|
||||||
|
error: { id: 'onboarding.error', defaultMessage: 'An unexpected error occurred. Please try again or skip this step.' },
|
||||||
|
});
|
||||||
|
|
||||||
/** Default header filenames from various backends */
|
/** Default header filenames from various backends */
|
||||||
const DEFAULT_HEADERS = [
|
const DEFAULT_HEADERS = [
|
||||||
'/headers/original/missing.png', // Mastodon
|
'/headers/original/missing.png', // Mastodon
|
||||||
|
@ -24,6 +29,7 @@ const isDefaultHeader = (url: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const CoverPhotoSelectionStep = ({ onNext }: { onNext: () => void }) => {
|
const CoverPhotoSelectionStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
|
const intl = useIntl();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const account = useOwnAccount();
|
const account = useOwnAccount();
|
||||||
|
|
||||||
|
@ -65,7 +71,7 @@ const CoverPhotoSelectionStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
if (error.response?.status === 422) {
|
if (error.response?.status === 422) {
|
||||||
dispatch(snackbar.error((error.response.data as any).error.replace('Validation failed: ', '')));
|
dispatch(snackbar.error((error.response.data as any).error.replace('Validation failed: ', '')));
|
||||||
} else {
|
} else {
|
||||||
dispatch(snackbar.error('An unexpected error occurred. Please try again or skip this step.'));
|
dispatch(snackbar.error(messages.error));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).catch(console.error);
|
}).catch(console.error);
|
||||||
|
@ -90,7 +96,6 @@ const CoverPhotoSelectionStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||||
<Stack space={10}>
|
<Stack space={10}>
|
||||||
<div className='border border-solid border-gray-200 dark:border-gray-800 rounded-lg'>
|
<div className='border border-solid border-gray-200 dark:border-gray-800 rounded-lg'>
|
||||||
{/* eslint-disable-next-line jsx-a11y/interactive-supports-focus */}
|
|
||||||
<div
|
<div
|
||||||
role='button'
|
role='button'
|
||||||
className='relative h-24 bg-gray-200 dark:bg-gray-800 rounded-t-md flex items-center justify-center'
|
className='relative h-24 bg-gray-200 dark:bg-gray-800 rounded-t-md flex items-center justify-center'
|
||||||
|
@ -98,7 +103,7 @@ const CoverPhotoSelectionStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
{selectedFile || account?.header && (
|
{selectedFile || account?.header && (
|
||||||
<StillImage
|
<StillImage
|
||||||
src={selectedFile || account.header}
|
src={selectedFile || account.header}
|
||||||
alt='Profile Header'
|
alt={intl.formatMessage(messages.header)}
|
||||||
className='absolute inset-0 object-cover rounded-t-md'
|
className='absolute inset-0 object-cover rounded-t-md'
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -138,7 +143,11 @@ const CoverPhotoSelectionStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
|
|
||||||
<Stack justifyContent='center' space={2}>
|
<Stack justifyContent='center' space={2}>
|
||||||
<Button block theme='primary' type='button' onClick={onNext} disabled={isDefault && isDisabled || isSubmitting}>
|
<Button block theme='primary' type='button' onClick={onNext} disabled={isDefault && isDisabled || isSubmitting}>
|
||||||
{isSubmitting ? 'Saving…' : 'Next'}
|
{isSubmitting ? (
|
||||||
|
<FormattedMessage id='onboarding.saving' defaultMessage='Saving…' />
|
||||||
|
) : (
|
||||||
|
<FormattedMessage id='onboarding.next' defaultMessage='Next' />
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{isDisabled && (
|
{isDisabled && (
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
import { patchMe } from 'soapbox/actions/me';
|
import { patchMe } from 'soapbox/actions/me';
|
||||||
|
@ -9,7 +9,13 @@ import { useOwnAccount } from 'soapbox/hooks';
|
||||||
|
|
||||||
import type { AxiosError } from 'axios';
|
import type { AxiosError } from 'axios';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
usernamePlaceholder: { id: 'onboarding.display_name.placeholder', defaultMessage: 'Eg. John Smith' },
|
||||||
|
error: { id: 'onboarding.error', defaultMessage: 'An unexpected error occurred. Please try again or skip this step.' },
|
||||||
|
});
|
||||||
|
|
||||||
const DisplayNameStep = ({ onNext }: { onNext: () => void }) => {
|
const DisplayNameStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
|
const intl = useIntl();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const account = useOwnAccount();
|
const account = useOwnAccount();
|
||||||
|
@ -43,7 +49,7 @@ const DisplayNameStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
if (error.response?.status === 422) {
|
if (error.response?.status === 422) {
|
||||||
setErrors([(error.response.data as any).error.replace('Validation failed: ', '')]);
|
setErrors([(error.response.data as any).error.replace('Validation failed: ', '')]);
|
||||||
} else {
|
} else {
|
||||||
dispatch(snackbar.error('An unexpected error occurred. Please try again or skip this step.'));
|
dispatch(snackbar.error(messages.error));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -68,12 +74,12 @@ const DisplayNameStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
<Stack space={5}>
|
<Stack space={5}>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
hintText={hintText}
|
hintText={hintText}
|
||||||
labelText='Display name'
|
labelText={<FormattedMessage id='onboarding.display_name.label' defaultMessage='Display name' />}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
onChange={(event) => setValue(event.target.value)}
|
onChange={(event) => setValue(event.target.value)}
|
||||||
placeholder='Eg. John Smith'
|
placeholder={intl.formatMessage(messages.usernamePlaceholder)}
|
||||||
type='text'
|
type='text'
|
||||||
value={value}
|
value={value}
|
||||||
maxLength={30}
|
maxLength={30}
|
||||||
|
@ -88,7 +94,11 @@ const DisplayNameStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
disabled={isDisabled || isSubmitting}
|
disabled={isDisabled || isSubmitting}
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
>
|
>
|
||||||
{isSubmitting ? 'Saving…' : 'Next'}
|
{isSubmitting ? (
|
||||||
|
<FormattedMessage id='onboarding.saving' defaultMessage='Saving…' />
|
||||||
|
) : (
|
||||||
|
<FormattedMessage id='onboarding.next' defaultMessage='Next' />
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button block theme='tertiary' type='button' onClick={onNext}>
|
<Button block theme='tertiary' type='button' onClick={onNext}>
|
||||||
|
|
|
@ -15,6 +15,7 @@ import Sonar from './sonar';
|
||||||
import type { AxiosError } from 'axios';
|
import type { AxiosError } from 'axios';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
menu: { id: 'header.menu.title', defaultMessage: 'Open menu' },
|
||||||
home: { id: 'header.home.label', defaultMessage: 'Home' },
|
home: { id: 'header.home.label', defaultMessage: 'Home' },
|
||||||
login: { id: 'header.login.label', defaultMessage: 'Log in' },
|
login: { id: 'header.login.label', defaultMessage: 'Log in' },
|
||||||
register: { id: 'header.register.label', defaultMessage: 'Register' },
|
register: { id: 'header.register.label', defaultMessage: 'Register' },
|
||||||
|
@ -79,7 +80,7 @@ const Header = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
title='Open Menu'
|
title={intl.formatMessage(messages.menu)}
|
||||||
src={require('@tabler/icons/menu-2.svg')}
|
src={require('@tabler/icons/menu-2.svg')}
|
||||||
onClick={open}
|
onClick={open}
|
||||||
className='md:hidden mr-4 bg-transparent text-gray-700 dark:text-gray-600 hover:text-gray-600'
|
className='md:hidden mr-4 bg-transparent text-gray-700 dark:text-gray-600 hover:text-gray-600'
|
||||||
|
|
|
@ -30,7 +30,7 @@ const BoostModal: React.FC<IBoostModal> = ({ status, onReblog, onClose }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title='Repost?'
|
title={<FormattedMessage id='boost_modal.title' defaultMessage='Repost?' />}
|
||||||
confirmationAction={handleReblog}
|
confirmationAction={handleReblog}
|
||||||
confirmationText={intl.formatMessage(buttonText)}
|
confirmationText={intl.formatMessage(buttonText)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -150,7 +150,7 @@ const VerifySmsModal: React.FC<IVerifySmsModal> = ({ onClose }) => {
|
||||||
);
|
);
|
||||||
case Statuses.READY:
|
case Statuses.READY:
|
||||||
return (
|
return (
|
||||||
<FormGroup labelText='Phone Number'>
|
<FormGroup labelText={<FormattedMessage id='sms_verification.phone.label' defaultMessage='Phone number' />}>
|
||||||
<PhoneInput
|
<PhoneInput
|
||||||
value={phone}
|
value={phone}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
|
|
@ -16,22 +16,12 @@ import PasswordIndicator from './components/password-indicator';
|
||||||
import type { AxiosError } from 'axios';
|
import type { AxiosError } from 'axios';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
success: {
|
success: { id: 'registrations.success', defaultMessage: 'Welcome to {siteTitle}!' },
|
||||||
id: 'registrations.success',
|
usernameLabel: { id: 'registrations.username.label', defaultMessage: 'Your username' },
|
||||||
defaultMessage: 'Welcome to {siteTitle}!',
|
usernameHint: { id: 'registrations.username.hint', defaultMessage: 'May only contain A-Z, 0-9, and underscores' },
|
||||||
},
|
usernameTaken: { id: 'registrations.unprocessable_entity', defaultMessage: 'This username has already been taken.' },
|
||||||
usernameHint: {
|
passwordLabel: { id: 'registrations.password.label', defaultMessage: 'Password' },
|
||||||
id: 'registrations.username.hint',
|
error: { id: 'registrations.error', defaultMessage: 'Failed to register your account.' },
|
||||||
defaultMessage: 'May only contain A-Z, 0-9, and underscores',
|
|
||||||
},
|
|
||||||
usernameTaken: {
|
|
||||||
id: 'registrations.unprocessable_entity',
|
|
||||||
defaultMessage: 'This username has already been taken.',
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
id: 'registrations.error',
|
|
||||||
defaultMessage: 'Failed to register your account.',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
|
@ -108,7 +98,7 @@ const Registration = () => {
|
||||||
|
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto space-y-4'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto space-y-4'>
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormGroup labelText='Your username' hintText={intl.formatMessage(messages.usernameHint)}>
|
<FormGroup labelText={intl.formatMessage(messages.usernameLabel)} hintText={intl.formatMessage(messages.usernameHint)}>
|
||||||
<Input
|
<Input
|
||||||
name='username'
|
name='username'
|
||||||
type='text'
|
type='text'
|
||||||
|
@ -120,7 +110,7 @@ const Registration = () => {
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup labelText='Password'>
|
<FormGroup labelText={intl.formatMessage(messages.passwordLabel)}>
|
||||||
<Input
|
<Input
|
||||||
name='password'
|
name='password'
|
||||||
type='password'
|
type='password'
|
||||||
|
@ -140,7 +130,7 @@ const Registration = () => {
|
||||||
type='submit'
|
type='submit'
|
||||||
disabled={isLoading || !hasValidPassword}
|
disabled={isLoading || !hasValidPassword}
|
||||||
>
|
>
|
||||||
Register
|
<FormattedMessage id='header.register.label' defaultMessage='Register' />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{(links.get('termsOfService') && links.get('privacyPolicy')) ? (
|
{(links.get('termsOfService') && links.get('privacyPolicy')) ? (
|
||||||
|
|
|
@ -23,7 +23,7 @@ describe('<EmailVerification />', () => {
|
||||||
it('successfully submits', async() => {
|
it('successfully submits', async() => {
|
||||||
render(<EmailVerification />);
|
render(<EmailVerification />);
|
||||||
|
|
||||||
await userEvent.type(screen.getByLabelText('Email Address'), 'foo@bar.com{enter}');
|
await userEvent.type(screen.getByLabelText('E-mail address'), 'foo@bar.com{enter}');
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
fireEvent.submit(
|
fireEvent.submit(
|
||||||
|
@ -50,7 +50,7 @@ describe('<EmailVerification />', () => {
|
||||||
it('renders errors', async() => {
|
it('renders errors', async() => {
|
||||||
render(<EmailVerification />);
|
render(<EmailVerification />);
|
||||||
|
|
||||||
await userEvent.type(screen.getByLabelText('Email Address'), 'foo@bar.com{enter}');
|
await userEvent.type(screen.getByLabelText('E-mail address'), 'foo@bar.com{enter}');
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
fireEvent.submit(
|
fireEvent.submit(
|
||||||
|
|
|
@ -26,7 +26,7 @@ describe('<SmsVerification />', () => {
|
||||||
|
|
||||||
render(<SmsVerification />);
|
render(<SmsVerification />);
|
||||||
|
|
||||||
await userEvent.type(screen.getByLabelText('Phone Number'), '+1 (555) 555-5555');
|
await userEvent.type(screen.getByLabelText('Phone number'), '+1 (555) 555-5555');
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
fireEvent.submit(
|
fireEvent.submit(
|
||||||
screen.getByRole('button', { name: 'Next' }), {
|
screen.getByRole('button', { name: 'Next' }), {
|
||||||
|
@ -53,7 +53,7 @@ describe('<SmsVerification />', () => {
|
||||||
|
|
||||||
render(<SmsVerification />);
|
render(<SmsVerification />);
|
||||||
|
|
||||||
await userEvent.type(screen.getByLabelText('Phone Number'), '+1 (555) 555-5555');
|
await userEvent.type(screen.getByLabelText('Phone number'), '+1 (555) 555-5555');
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
fireEvent.submit(
|
fireEvent.submit(
|
||||||
screen.getByRole('button', { name: 'Next' }), {
|
screen.getByRole('button', { name: 'Next' }), {
|
||||||
|
@ -87,7 +87,7 @@ describe('<SmsVerification />', () => {
|
||||||
it('renders errors', async() => {
|
it('renders errors', async() => {
|
||||||
render(<SmsVerification />);
|
render(<SmsVerification />);
|
||||||
|
|
||||||
await userEvent.type(screen.getByLabelText('Phone Number'), '+1 (555) 555-5555');
|
await userEvent.type(screen.getByLabelText('Phone number'), '+1 (555) 555-5555');
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
fireEvent.submit(
|
fireEvent.submit(
|
||||||
screen.getByRole('button', { name: 'Next' }), {
|
screen.getByRole('button', { name: 'Next' }), {
|
||||||
|
|
|
@ -61,13 +61,21 @@ const AgeVerification = () => {
|
||||||
<Datepicker onChange={onChange} />
|
<Datepicker onChange={onChange} />
|
||||||
|
|
||||||
<Text theme='muted' size='sm'>
|
<Text theme='muted' size='sm'>
|
||||||
{instance.title} requires users to be at least {ageMinimum} years old to
|
<FormattedMessage
|
||||||
access its platform. Anyone under the age of {ageMinimum} years old
|
id='age_verification.body'
|
||||||
cannot access this platform.
|
defaultMessage='{siteTitle} requires users to be at least {ageMinimum} years old to access its platform. Anyone under the age of {ageMinimum} years old cannot access this platform.'
|
||||||
|
values={{
|
||||||
|
siteTitle: instance.title,
|
||||||
|
ageMinimum,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<div className='text-center'>
|
<div className='text-center'>
|
||||||
<Button block theme='primary' type='submit' disabled={isLoading || !isValid}>Next</Button>
|
<Button block theme='primary' type='submit' disabled={isLoading || !isValid}>
|
||||||
|
<FormattedMessage id='onboarding.next' defaultMessage='Next' />
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,6 +13,7 @@ const messages = defineMessages({
|
||||||
verificationFail: { id: 'email_verification.fail', defaultMessage: 'Failed to request email verification.' },
|
verificationFail: { id: 'email_verification.fail', defaultMessage: 'Failed to request email verification.' },
|
||||||
verificationFailTakenAlert: { id: 'email_verifilcation.exists', defaultMessage: 'This email has already been taken.' },
|
verificationFailTakenAlert: { id: 'email_verifilcation.exists', defaultMessage: 'This email has already been taken.' },
|
||||||
verificationFailTaken: { id: 'email_verification.taken', defaultMessage: 'is taken' },
|
verificationFailTaken: { id: 'email_verification.taken', defaultMessage: 'is taken' },
|
||||||
|
emailLabel: { id: 'email_verification.email.label', defaultMessage: 'E-mail address' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const Statuses = {
|
const Statuses = {
|
||||||
|
@ -122,7 +123,7 @@ const EmailVerification = () => {
|
||||||
|
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormGroup labelText='Email Address' errors={errors}>
|
<FormGroup labelText={intl.formatMessage(messages.emailLabel)} errors={errors}>
|
||||||
<Input
|
<Input
|
||||||
type='email'
|
type='email'
|
||||||
value={email}
|
value={email}
|
||||||
|
@ -134,7 +135,9 @@ const EmailVerification = () => {
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<div className='text-center'>
|
<div className='text-center'>
|
||||||
<Button block theme='primary' type='submit' disabled={isLoading || !isValid}>Next</Button>
|
<Button block theme='primary' type='submit' disabled={isLoading || !isValid}>
|
||||||
|
<FormattedMessage id='onboarding.next' defaultMessage='Next' />
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,6 +13,7 @@ const messages = defineMessages({
|
||||||
verificationSuccess: { id: 'sms_verification.success', defaultMessage: 'A verification code has been sent to your phone number.' },
|
verificationSuccess: { id: 'sms_verification.success', defaultMessage: 'A verification code has been sent to your phone number.' },
|
||||||
verificationFail: { id: 'sms_verification.fail', defaultMessage: 'Failed to send SMS message to your phone number.' },
|
verificationFail: { id: 'sms_verification.fail', defaultMessage: 'Failed to send SMS message to your phone number.' },
|
||||||
verificationExpired: { id: 'sms_verification.expired', defaultMessage: 'Your SMS token has expired.' },
|
verificationExpired: { id: 'sms_verification.expired', defaultMessage: 'Your SMS token has expired.' },
|
||||||
|
phoneLabel: { id: 'sms_verification.phone.label', defaultMessage: 'Phone number' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const Statuses = {
|
const Statuses = {
|
||||||
|
@ -98,7 +99,7 @@ const SmsVerification = () => {
|
||||||
|
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto space-y-4'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto space-y-4'>
|
||||||
<Text theme='muted' size='sm' align='center'>
|
<Text theme='muted' size='sm' align='center'>
|
||||||
We sent you a 6-digit code via SMS. Enter it below.
|
<FormattedMessage id='sms_verification.sent.body' defaultMessage='We sent you a 6-digit code via SMS. Enter it below.' />
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<OtpInput
|
<OtpInput
|
||||||
|
@ -120,7 +121,7 @@ const SmsVerification = () => {
|
||||||
onClick={resendVerificationCode}
|
onClick={resendVerificationCode}
|
||||||
disabled={requestedAnother}
|
disabled={requestedAnother}
|
||||||
>
|
>
|
||||||
Resend verification code?
|
<FormattedMessage id='sms_verification.sent.actions.resend' defaultMessage='Resend verification code?' />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -138,7 +139,7 @@ const SmsVerification = () => {
|
||||||
|
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormGroup labelText='Phone Number'>
|
<FormGroup labelText={intl.formatMessage(messages.phoneLabel)}>
|
||||||
<PhoneInput
|
<PhoneInput
|
||||||
value={phone}
|
value={phone}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
@ -147,7 +148,9 @@ const SmsVerification = () => {
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<div className='text-center'>
|
<div className='text-center'>
|
||||||
<Button block theme='primary' type='submit' disabled={isLoading || !isValid}>Next</Button>
|
<Button block theme='primary' type='submit' disabled={isLoading || !isValid}>
|
||||||
|
<FormattedMessage id='onboarding.next' defaultMessage='Next' />
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ const WaitlistPage = () => {
|
||||||
|
|
||||||
<div className='absolute inset-y-0 right-0 flex items-center pr-2'>
|
<div className='absolute inset-y-0 right-0 flex items-center pr-2'>
|
||||||
<Button onClick={onClickLogOut} theme='primary' to='/logout'>
|
<Button onClick={onClickLogOut} theme='primary' to='/logout'>
|
||||||
Sign out
|
<FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -55,13 +56,17 @@ const WaitlistPage = () => {
|
||||||
|
|
||||||
<Stack space={2}>
|
<Stack space={2}>
|
||||||
<Text size='lg' theme='muted' align='center' weight='medium'>
|
<Text size='lg' theme='muted' align='center' weight='medium'>
|
||||||
Welcome back to {instance.title}! You were previously placed on our
|
<FormattedMessage
|
||||||
waitlist. Please verify your phone number to receive
|
id='waitlist.body'
|
||||||
immediate access to your account!
|
defaultMessage='Welcome back to {title}! You were previously placed on our waitlist. Please verify your phone number to receive immediate access to your account!'
|
||||||
|
values={{ title: instance.title }}
|
||||||
|
/>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<div className='text-center'>
|
<div className='text-center'>
|
||||||
<Button onClick={openVerifySmsModal} theme='primary'>Verify phone number</Button>
|
<Button onClick={openVerifySmsModal} theme='primary'>
|
||||||
|
<FormattedMessage id='waitlist.actions.verify_number' defaultMessage='Verify phone number' />
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
|
@ -432,7 +432,7 @@
|
||||||
"emoji_button.objects": "Objects",
|
"emoji_button.objects": "Objects",
|
||||||
"emoji_button.people": "People",
|
"emoji_button.people": "People",
|
||||||
"emoji_button.recent": "Frequently used",
|
"emoji_button.recent": "Frequently used",
|
||||||
"emoji_button.search": "Search...",
|
"emoji_button.search": "Search…",
|
||||||
"emoji_button.search_results": "Search results",
|
"emoji_button.search_results": "Search results",
|
||||||
"emoji_button.symbols": "Symbols",
|
"emoji_button.symbols": "Symbols",
|
||||||
"emoji_button.travel": "Travel & Places",
|
"emoji_button.travel": "Travel & Places",
|
||||||
|
@ -1071,7 +1071,7 @@
|
||||||
"upload_form.description": "Describe for the visually impaired",
|
"upload_form.description": "Describe for the visually impaired",
|
||||||
"upload_form.preview": "Preview",
|
"upload_form.preview": "Preview",
|
||||||
"upload_form.undo": "Delete",
|
"upload_form.undo": "Delete",
|
||||||
"upload_progress.label": "Uploading...",
|
"upload_progress.label": "Uploading…",
|
||||||
"video.close": "Close video",
|
"video.close": "Close video",
|
||||||
"video.download": "Download file",
|
"video.download": "Download file",
|
||||||
"video.exit_fullscreen": "Exit full screen",
|
"video.exit_fullscreen": "Exit full screen",
|
||||||
|
|
Loading…
Reference in a new issue