Merge branch 'thread-cta' into 'develop'
Display a CTA in threads to log in See merge request soapbox-pub/soapbox-fe!1353
This commit is contained in:
commit
938665f157
|
@ -47,7 +47,10 @@ interface ICardHeader {
|
|||
onBackClick?: (event: React.MouseEvent) => void
|
||||
}
|
||||
|
||||
/** Typically holds a CardTitle. */
|
||||
/**
|
||||
* Card header container with back button.
|
||||
* Typically holds a CardTitle.
|
||||
*/
|
||||
const CardHeader: React.FC<ICardHeader> = ({ children, backHref, onBackClick }): JSX.Element => {
|
||||
const intl = useIntl();
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ interface IModal {
|
|||
/** Whether the confirmation button is disabled. */
|
||||
confirmationDisabled?: boolean,
|
||||
/** Confirmation button text. */
|
||||
confirmationText?: string,
|
||||
confirmationText?: React.ReactNode,
|
||||
/** Confirmation button theme. */
|
||||
confirmationTheme?: 'danger',
|
||||
/** Callback when the modal is closed. */
|
||||
|
@ -28,7 +28,7 @@ interface IModal {
|
|||
/** Callback when the secondary action is chosen. */
|
||||
secondaryAction?: () => void,
|
||||
/** Secondary button text. */
|
||||
secondaryText?: string,
|
||||
secondaryText?: React.ReactNode,
|
||||
/** Don't focus the "confirm" button on mount. */
|
||||
skipFocus?: boolean,
|
||||
/** Title text for the modal. */
|
||||
|
|
|
@ -85,6 +85,7 @@ const SoapboxMount = () => {
|
|||
const systemTheme = useSystemTheme();
|
||||
const userTheme = settings.get('themeMode');
|
||||
const darkMode = userTheme === 'dark' || (userTheme === 'system' && systemTheme === 'dark');
|
||||
const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true;
|
||||
|
||||
const themeCss = generateThemeCss(soapboxConfig);
|
||||
|
||||
|
@ -160,20 +161,38 @@ const SoapboxMount = () => {
|
|||
<Switch>
|
||||
<Redirect from='/v1/verify_email/:token' to='/verify/email/:token' />
|
||||
|
||||
{waitlisted && <Route render={(props) => <WaitlistPage {...props} account={account} />} />}
|
||||
{/* Redirect signup route depending on Pepe enablement. */}
|
||||
{/* We should prefer using /signup in components. */}
|
||||
{pepeEnabled ? (
|
||||
<Redirect from='/signup' to='/verify' />
|
||||
) : (
|
||||
<Redirect from='/verify' to='/signup' />
|
||||
)}
|
||||
|
||||
{waitlisted && (
|
||||
<Route render={(props) => <WaitlistPage {...props} account={account} />} />
|
||||
)}
|
||||
|
||||
{!me && (singleUserMode
|
||||
? <Redirect exact from='/' to={`/${singleUserMode}`} />
|
||||
: <Route exact path='/' component={PublicLayout} />)}
|
||||
|
||||
{!me && <Route exact path='/' component={PublicLayout} />}
|
||||
{!me && (
|
||||
<Route exact path='/' component={PublicLayout} />
|
||||
)}
|
||||
|
||||
<Route exact path='/about/:slug?' component={PublicLayout} />
|
||||
<Route exact path='/mobile/:slug?' component={PublicLayout} />
|
||||
<Route path='/login' component={AuthLayout} />
|
||||
|
||||
{(features.accountCreation && instance.registrations) && (
|
||||
<Route exact path='/signup' component={AuthLayout} />
|
||||
)}
|
||||
|
||||
{pepeEnabled && (
|
||||
<Route path='/verify' component={AuthLayout} />
|
||||
)}
|
||||
|
||||
<Route path='/reset-password' component={AuthLayout} />
|
||||
<Route path='/edit-password' component={AuthLayout} />
|
||||
<Route path='/invite/:token' component={AuthLayout} />
|
||||
|
|
|
@ -112,7 +112,7 @@ const Header = () => {
|
|||
|
||||
{(isOpen || pepeEnabled && pepeOpen) && (
|
||||
<Button
|
||||
to={pepeEnabled ? '/verify' : '/signup'}
|
||||
to='/signup'
|
||||
theme='primary'
|
||||
>
|
||||
{intl.formatMessage(messages.register)}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Card, CardTitle, Text, Stack, Button } from 'soapbox/components/ui';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
/** Prompts logged-out users to log in when viewing a thread. */
|
||||
const ThreadLoginCta: React.FC = () => {
|
||||
const siteTitle = useAppSelector(state => state.instance.title);
|
||||
|
||||
return (
|
||||
<Card className='px-6 py-12 space-y-6 text-center' variant='rounded'>
|
||||
<Stack>
|
||||
<CardTitle title={<FormattedMessage id='thread_login.title' defaultMessage='Continue the conversation' />} />
|
||||
<Text>
|
||||
<FormattedMessage
|
||||
id='thread_login.message'
|
||||
defaultMessage='Join {siteTitle} to get the full story and details.'
|
||||
values={{ siteTitle }}
|
||||
/>
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
<Stack space={4} className='max-w-xs mx-auto'>
|
||||
<Button theme='secondary' to='/login' block>
|
||||
<FormattedMessage id='thread_login.login' defaultMessage='Log in' />
|
||||
</Button>
|
||||
<Button to='/signup' block>
|
||||
<FormattedMessage id='thread_login.signup' defaultMessage='Sign up' />
|
||||
</Button>
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThreadLoginCta;
|
|
@ -19,7 +19,7 @@ import { getSettings } from 'soapbox/actions/settings';
|
|||
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
|
||||
import ScrollableList from 'soapbox/components/scrollable_list';
|
||||
import SubNavigation from 'soapbox/components/sub_navigation';
|
||||
import { Column } from 'soapbox/components/ui';
|
||||
import { Column, Stack } from 'soapbox/components/ui';
|
||||
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder_status';
|
||||
import PendingStatus from 'soapbox/features/ui/components/pending_status';
|
||||
|
||||
|
@ -60,6 +60,7 @@ import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from
|
|||
|
||||
import ActionBar from './components/action-bar';
|
||||
import DetailedStatus from './components/detailed-status';
|
||||
import ThreadLoginCta from './components/thread-login-cta';
|
||||
import ThreadStatus from './components/thread-status';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
|
@ -72,6 +73,7 @@ import type {
|
|||
Attachment as AttachmentEntity,
|
||||
Status as StatusEntity,
|
||||
} from 'soapbox/types/entities';
|
||||
import type { Me } from 'soapbox/types/soapbox';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'status.title', defaultMessage: '@{username}\'s Post' },
|
||||
|
@ -181,6 +183,7 @@ interface IStatus extends RouteComponentProps, IntlComponentProps {
|
|||
allowedEmoji: ImmutableList<string>,
|
||||
onOpenMedia: (media: ImmutableList<AttachmentEntity>, index: number) => void,
|
||||
onOpenVideo: (video: AttachmentEntity, time: number) => void,
|
||||
me: Me,
|
||||
}
|
||||
|
||||
interface IStatusState {
|
||||
|
@ -669,7 +672,7 @@ class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { status, ancestorsIds, descendantsIds, intl } = this.props;
|
||||
const { me, status, ancestorsIds, descendantsIds, intl } = this.props;
|
||||
|
||||
const hasAncestors = ancestorsIds && ancestorsIds.size > 0;
|
||||
const hasDescendants = descendantsIds && descendantsIds.size > 0;
|
||||
|
@ -782,6 +785,7 @@ class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
|||
<SubNavigation message={intl.formatMessage(titleMessage, { username })} />
|
||||
</div>
|
||||
|
||||
<Stack space={2}>
|
||||
<div ref={this.setRef} className='thread'>
|
||||
<ScrollableList
|
||||
onRefresh={this.handleRefresh}
|
||||
|
@ -792,6 +796,9 @@ class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
|||
{children}
|
||||
</ScrollableList>
|
||||
</div>
|
||||
|
||||
{!me && <ThreadLoginCta />}
|
||||
</Stack>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ const LandingPageModal: React.FC<ILandingPageModal> = ({ onClose }) => {
|
|||
</Button>
|
||||
|
||||
{(isOpen || pepeEnabled && pepeOpen) && (
|
||||
<Button to={pepeEnabled ? '/verify' : '/signup'} theme='primary' block>
|
||||
<Button to='/signup' theme='primary' block>
|
||||
{intl.formatMessage(messages.register)}
|
||||
</Button>
|
||||
)}
|
||||
|
|
|
@ -70,7 +70,7 @@ const Navbar = () => {
|
|||
</Button>
|
||||
|
||||
{!singleUserMode && (
|
||||
<Button theme='primary' to='/' size='sm'>
|
||||
<Button theme='primary' to='/signup' size='sm'>
|
||||
<FormattedMessage id='account.register' defaultMessage='Sign up' />
|
||||
</Button>
|
||||
)}
|
||||
|
|
|
@ -23,7 +23,7 @@ const SignUpPanel = () => {
|
|||
</Text>
|
||||
</Stack>
|
||||
|
||||
<Button theme='primary' block to='/'>
|
||||
<Button theme='primary' block to='/signup'>
|
||||
<FormattedMessage id='account.register' defaultMessage='Sign up' />
|
||||
</Button>
|
||||
</Stack>
|
||||
|
|
|
@ -1,196 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import { remoteInteraction } from 'soapbox/actions/interactions';
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
|
||||
import { Button, Modal, Stack, Text } from 'soapbox/components/ui';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
const messages = defineMessages({
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
accountPlaceholder: { id: 'remote_interaction.account_placeholder', defaultMessage: 'Enter your username@domain you want to act from' },
|
||||
userNotFoundError: { id: 'remote_interaction.user_not_found_error', defaultMessage: 'Couldn\'t find given user' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const instance = state.get('instance');
|
||||
const features = getFeatures(instance);
|
||||
const soapboxConfig = getSoapboxConfig(state);
|
||||
|
||||
if (props.action !== 'FOLLOW') {
|
||||
return {
|
||||
features,
|
||||
siteTitle: state.getIn(['instance', 'title']),
|
||||
remoteInteractionsAPI: features.remoteInteractionsAPI,
|
||||
singleUserMode: soapboxConfig.get('singleUserMode'),
|
||||
};
|
||||
}
|
||||
|
||||
const userName = state.getIn(['accounts', props.account, 'display_name']);
|
||||
|
||||
return {
|
||||
features,
|
||||
siteTitle: state.getIn(['instance', 'title']),
|
||||
userName,
|
||||
remoteInteractionsAPI: features.remoteInteractionsAPI,
|
||||
singleUserMode: soapboxConfig.get('singleUserMode'),
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
dispatch,
|
||||
onRemoteInteraction(ap_id, account) {
|
||||
return dispatch(remoteInteraction(ap_id, account));
|
||||
},
|
||||
});
|
||||
|
||||
@withRouter
|
||||
class UnauthorizedModal extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
features: PropTypes.object.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onRemoteInteraction: PropTypes.func.isRequired,
|
||||
userName: PropTypes.string,
|
||||
history: PropTypes.object.isRequired,
|
||||
singleUserMode: PropTypes.bool,
|
||||
};
|
||||
|
||||
state = {
|
||||
account: '',
|
||||
};
|
||||
|
||||
onAccountChange = e => {
|
||||
this.setState({ account: e.target.value });
|
||||
}
|
||||
|
||||
onClickClose = () => {
|
||||
this.props.onClose('UNAUTHORIZED');
|
||||
};
|
||||
|
||||
onClickProceed = e => {
|
||||
e.preventDefault();
|
||||
|
||||
const { intl, ap_id, dispatch, onClose, onRemoteInteraction } = this.props;
|
||||
const { account } = this.state;
|
||||
|
||||
onRemoteInteraction(ap_id, account)
|
||||
.then(url => {
|
||||
window.open(url, '_new', 'noopener,noreferrer');
|
||||
onClose('UNAUTHORIZED');
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.message === 'Couldn\'t find user') {
|
||||
dispatch(snackbar.error(intl.formatMessage(messages.userNotFoundError)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onLogin = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
this.props.history.push('/login');
|
||||
this.onClickClose();
|
||||
}
|
||||
|
||||
onRegister = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
this.props.history.push('/');
|
||||
this.onClickClose();
|
||||
}
|
||||
|
||||
renderRemoteInteractions() {
|
||||
const { intl, siteTitle, userName, action, singleUserMode } = this.props;
|
||||
const { account } = this.state;
|
||||
|
||||
let header;
|
||||
let button;
|
||||
|
||||
if (action === 'FOLLOW') {
|
||||
header = <FormattedMessage id='remote_interaction.follow_title' defaultMessage='Follow {user} remotely' values={{ user: userName }} />;
|
||||
button = <FormattedMessage id='remote_interaction.follow' defaultMessage='Proceed to follow' />;
|
||||
} else if (action === 'REPLY') {
|
||||
header = <FormattedMessage id='remote_interaction.reply_title' defaultMessage='Reply to a post remotely' />;
|
||||
button = <FormattedMessage id='remote_interaction.reply' defaultMessage='Proceed to reply' />;
|
||||
} else if (action === 'REBLOG') {
|
||||
header = <FormattedMessage id='remote_interaction.reblog_title' defaultMessage='Reblog a post remotely' />;
|
||||
button = <FormattedMessage id='remote_interaction.reblog' defaultMessage='Proceed to repost' />;
|
||||
} else if (action === 'FAVOURITE') {
|
||||
header = <FormattedMessage id='remote_interaction.favourite_title' defaultMessage='Like a post remotely' />;
|
||||
button = <FormattedMessage id='remote_interaction.favourite' defaultMessage='Proceed to like' />;
|
||||
} else if (action === 'POLL_VOTE') {
|
||||
header = <FormattedMessage id='remote_interaction.poll_vote_title' defaultMessage='Vote in a poll remotely' />;
|
||||
button = <FormattedMessage id='remote_interaction.poll_vote' defaultMessage='Proceed to vote' />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={header}
|
||||
onClose={this.onClickClose}
|
||||
confirmationAction={!singleUserMode && this.onLogin}
|
||||
confirmationText={<FormattedMessage id='account.login' defaultMessage='Log in' />}
|
||||
secondaryAction={this.onRegister}
|
||||
secondaryText={<FormattedMessage id='account.register' defaultMessage='Sign up' />}
|
||||
>
|
||||
<div className='remote-interaction-modal__content'>
|
||||
<form className='simple_form remote-interaction-modal__fields'>
|
||||
<input
|
||||
type='text'
|
||||
placeholder={intl.formatMessage(messages.accountPlaceholder)}
|
||||
name='remote_follow[acct]'
|
||||
value={account}
|
||||
autoCorrect='off'
|
||||
autoCapitalize='off'
|
||||
onChange={this.onAccountChange}
|
||||
required
|
||||
/>
|
||||
<Button theme='primary' onClick={this.onClickProceed}>{button}</Button>
|
||||
</form>
|
||||
<div className='remote-interaction-modal__divider'>
|
||||
<Text align='center'>
|
||||
<FormattedMessage id='remote_interaction.divider' defaultMessage='or' />
|
||||
</Text>
|
||||
</div>
|
||||
{!singleUserMode && (
|
||||
<Text size='lg' weight='medium'>
|
||||
<FormattedMessage id='unauthorized_modal.title' defaultMessage='Sign up for {site_title}' values={{ site_title: siteTitle }} />
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { features, siteTitle, action } = this.props;
|
||||
|
||||
if (action && features.remoteInteractionsAPI && features.federating) return this.renderRemoteInteractions();
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={<FormattedMessage id='unauthorized_modal.title' defaultMessage='Sign up for {site_title}' values={{ site_title: siteTitle }} />}
|
||||
onClose={this.onClickClose}
|
||||
confirmationAction={this.onLogin}
|
||||
confirmationText={<FormattedMessage id='account.login' defaultMessage='Log in' />}
|
||||
secondaryAction={this.onRegister}
|
||||
secondaryText={<FormattedMessage id='account.register' defaultMessage='Sign up' />}
|
||||
>
|
||||
<Stack>
|
||||
<Text>
|
||||
<FormattedMessage id='unauthorized_modal.text' defaultMessage='You need to be logged in to do that.' />
|
||||
</Text>
|
||||
</Stack>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(UnauthorizedModal));
|
|
@ -0,0 +1,154 @@
|
|||
import React, { useState } from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { remoteInteraction } from 'soapbox/actions/interactions';
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import { Button, Modal, Stack, Text } from 'soapbox/components/ui';
|
||||
import { useAppSelector, useAppDispatch, useFeatures, useSoapboxConfig } from 'soapbox/hooks';
|
||||
|
||||
const messages = defineMessages({
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
accountPlaceholder: { id: 'remote_interaction.account_placeholder', defaultMessage: 'Enter your username@domain you want to act from' },
|
||||
userNotFoundError: { id: 'remote_interaction.user_not_found_error', defaultMessage: 'Couldn\'t find given user' },
|
||||
});
|
||||
|
||||
interface IUnauthorizedModal {
|
||||
/** Unauthorized action type. */
|
||||
action: 'FOLLOW' | 'REPLY' | 'REBLOG' | 'FAVOURITE' | 'POLL_VOTE',
|
||||
/** Close event handler. */
|
||||
onClose: (modalType: string) => void,
|
||||
/** ActivityPub ID of the account OR status being acted upon. */
|
||||
ap_id?: string,
|
||||
/** Account ID of the account being acted upon. */
|
||||
account?: string,
|
||||
}
|
||||
|
||||
/** Modal to display when a logged-out user tries to do something that requires login. */
|
||||
const UnauthorizedModal: React.FC<IUnauthorizedModal> = ({ action, onClose, account: accountId, ap_id: apId }) => {
|
||||
const intl = useIntl();
|
||||
const history = useHistory();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { singleUserMode } = useSoapboxConfig();
|
||||
const siteTitle = useAppSelector(state => state.instance.title);
|
||||
const username = useAppSelector(state => state.accounts.get(accountId)?.display_name);
|
||||
const features = useFeatures();
|
||||
|
||||
const [account, setAccount] = useState('');
|
||||
|
||||
const onAccountChange: React.ChangeEventHandler<HTMLInputElement> = e => {
|
||||
setAccount(e.target.value);
|
||||
};
|
||||
|
||||
const onClickClose = () => {
|
||||
onClose('UNAUTHORIZED');
|
||||
};
|
||||
|
||||
const onClickProceed: React.MouseEventHandler = e => {
|
||||
e.preventDefault();
|
||||
|
||||
dispatch(remoteInteraction(apId, account))
|
||||
.then(url => {
|
||||
window.open(url, '_new', 'noopener,noreferrer');
|
||||
onClose('UNAUTHORIZED');
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.message === 'Couldn\'t find user') {
|
||||
dispatch(snackbar.error(intl.formatMessage(messages.userNotFoundError)));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onLogin = () => {
|
||||
history.push('/login');
|
||||
onClickClose();
|
||||
};
|
||||
|
||||
const onRegister = () => {
|
||||
history.push('/signup');
|
||||
onClickClose();
|
||||
};
|
||||
|
||||
const renderRemoteInteractions = () => {
|
||||
let header;
|
||||
let button;
|
||||
|
||||
if (action === 'FOLLOW') {
|
||||
header = <FormattedMessage id='remote_interaction.follow_title' defaultMessage='Follow {user} remotely' values={{ user: username }} />;
|
||||
button = <FormattedMessage id='remote_interaction.follow' defaultMessage='Proceed to follow' />;
|
||||
} else if (action === 'REPLY') {
|
||||
header = <FormattedMessage id='remote_interaction.reply_title' defaultMessage='Reply to a post remotely' />;
|
||||
button = <FormattedMessage id='remote_interaction.reply' defaultMessage='Proceed to reply' />;
|
||||
} else if (action === 'REBLOG') {
|
||||
header = <FormattedMessage id='remote_interaction.reblog_title' defaultMessage='Reblog a post remotely' />;
|
||||
button = <FormattedMessage id='remote_interaction.reblog' defaultMessage='Proceed to repost' />;
|
||||
} else if (action === 'FAVOURITE') {
|
||||
header = <FormattedMessage id='remote_interaction.favourite_title' defaultMessage='Like a post remotely' />;
|
||||
button = <FormattedMessage id='remote_interaction.favourite' defaultMessage='Proceed to like' />;
|
||||
} else if (action === 'POLL_VOTE') {
|
||||
header = <FormattedMessage id='remote_interaction.poll_vote_title' defaultMessage='Vote in a poll remotely' />;
|
||||
button = <FormattedMessage id='remote_interaction.poll_vote' defaultMessage='Proceed to vote' />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={header}
|
||||
onClose={onClickClose}
|
||||
confirmationAction={!singleUserMode ? onLogin : undefined}
|
||||
confirmationText={<FormattedMessage id='account.login' defaultMessage='Log in' />}
|
||||
secondaryAction={onRegister}
|
||||
secondaryText={<FormattedMessage id='account.register' defaultMessage='Sign up' />}
|
||||
>
|
||||
<div className='remote-interaction-modal__content'>
|
||||
<form className='simple_form remote-interaction-modal__fields'>
|
||||
<input
|
||||
type='text'
|
||||
placeholder={intl.formatMessage(messages.accountPlaceholder)}
|
||||
name='remote_follow[acct]'
|
||||
value={account}
|
||||
autoCorrect='off'
|
||||
autoCapitalize='off'
|
||||
onChange={onAccountChange}
|
||||
required
|
||||
/>
|
||||
<Button theme='primary' onClick={onClickProceed}>{button}</Button>
|
||||
</form>
|
||||
<div className='remote-interaction-modal__divider'>
|
||||
<Text align='center'>
|
||||
<FormattedMessage id='remote_interaction.divider' defaultMessage='or' />
|
||||
</Text>
|
||||
</div>
|
||||
{!singleUserMode && (
|
||||
<Text size='lg' weight='medium'>
|
||||
<FormattedMessage id='unauthorized_modal.title' defaultMessage='Sign up for {site_title}' values={{ site_title: siteTitle }} />
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
if (action && features.remoteInteractionsAPI && features.federating) {
|
||||
return renderRemoteInteractions();
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={<FormattedMessage id='unauthorized_modal.title' defaultMessage='Sign up for {site_title}' values={{ site_title: siteTitle }} />}
|
||||
onClose={onClickClose}
|
||||
confirmationAction={onLogin}
|
||||
confirmationText={<FormattedMessage id='account.login' defaultMessage='Log in' />}
|
||||
secondaryAction={onRegister}
|
||||
secondaryText={<FormattedMessage id='account.register' defaultMessage='Sign up' />}
|
||||
>
|
||||
<Stack>
|
||||
<Text>
|
||||
<FormattedMessage id='unauthorized_modal.text' defaultMessage='You need to be logged in to do that.' />
|
||||
</Text>
|
||||
</Stack>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default UnauthorizedModal;
|
Loading…
Reference in New Issue