kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
UnauthorizedModal: convert to TSX
rodzic
31486b1320
commit
2a9f1ccb91
|
@ -20,7 +20,7 @@ interface IModal {
|
||||||
/** Whether the confirmation button is disabled. */
|
/** Whether the confirmation button is disabled. */
|
||||||
confirmationDisabled?: boolean,
|
confirmationDisabled?: boolean,
|
||||||
/** Confirmation button text. */
|
/** Confirmation button text. */
|
||||||
confirmationText?: string,
|
confirmationText?: React.ReactNode,
|
||||||
/** Confirmation button theme. */
|
/** Confirmation button theme. */
|
||||||
confirmationTheme?: 'danger',
|
confirmationTheme?: 'danger',
|
||||||
/** Callback when the modal is closed. */
|
/** Callback when the modal is closed. */
|
||||||
|
@ -28,7 +28,7 @@ interface IModal {
|
||||||
/** Callback when the secondary action is chosen. */
|
/** Callback when the secondary action is chosen. */
|
||||||
secondaryAction?: () => void,
|
secondaryAction?: () => void,
|
||||||
/** Secondary button text. */
|
/** Secondary button text. */
|
||||||
secondaryText?: string,
|
secondaryText?: React.ReactNode,
|
||||||
/** Don't focus the "confirm" button on mount. */
|
/** Don't focus the "confirm" button on mount. */
|
||||||
skipFocus?: boolean,
|
skipFocus?: boolean,
|
||||||
/** Title text for the modal. */
|
/** Title text for the modal. */
|
||||||
|
|
|
@ -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('/signup');
|
|
||||||
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;
|
Ładowanie…
Reference in New Issue