From 2a9f1ccb91eba3d426ce09856e6af923fb8d299f Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 11 May 2022 15:26:37 -0500 Subject: [PATCH] UnauthorizedModal: convert to TSX --- app/soapbox/components/ui/modal/modal.tsx | 4 +- .../ui/components/unauthorized_modal.js | 196 ------------------ .../ui/components/unauthorized_modal.tsx | 154 ++++++++++++++ 3 files changed, 156 insertions(+), 198 deletions(-) delete mode 100644 app/soapbox/features/ui/components/unauthorized_modal.js create mode 100644 app/soapbox/features/ui/components/unauthorized_modal.tsx diff --git a/app/soapbox/components/ui/modal/modal.tsx b/app/soapbox/components/ui/modal/modal.tsx index ab714b93c..d633897e1 100644 --- a/app/soapbox/components/ui/modal/modal.tsx +++ b/app/soapbox/components/ui/modal/modal.tsx @@ -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. */ diff --git a/app/soapbox/features/ui/components/unauthorized_modal.js b/app/soapbox/features/ui/components/unauthorized_modal.js deleted file mode 100644 index ea32abca6..000000000 --- a/app/soapbox/features/ui/components/unauthorized_modal.js +++ /dev/null @@ -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 = ; - button = ; - } else if (action === 'REPLY') { - header = ; - button = ; - } else if (action === 'REBLOG') { - header = ; - button = ; - } else if (action === 'FAVOURITE') { - header = ; - button = ; - } else if (action === 'POLL_VOTE') { - header = ; - button = ; - } - - return ( - } - secondaryAction={this.onRegister} - secondaryText={} - > -
-
- - -
-
- - - -
- {!singleUserMode && ( - - - - )} -
-
- ); - } - - render() { - const { features, siteTitle, action } = this.props; - - if (action && features.remoteInteractionsAPI && features.federating) return this.renderRemoteInteractions(); - - return ( - } - onClose={this.onClickClose} - confirmationAction={this.onLogin} - confirmationText={} - secondaryAction={this.onRegister} - secondaryText={} - > - - - - - - - ); - } - -} - -export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(UnauthorizedModal)); diff --git a/app/soapbox/features/ui/components/unauthorized_modal.tsx b/app/soapbox/features/ui/components/unauthorized_modal.tsx new file mode 100644 index 000000000..41faf7c1a --- /dev/null +++ b/app/soapbox/features/ui/components/unauthorized_modal.tsx @@ -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 = ({ 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 = 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 = ; + button = ; + } else if (action === 'REPLY') { + header = ; + button = ; + } else if (action === 'REBLOG') { + header = ; + button = ; + } else if (action === 'FAVOURITE') { + header = ; + button = ; + } else if (action === 'POLL_VOTE') { + header = ; + button = ; + } + + return ( + } + secondaryAction={onRegister} + secondaryText={} + > +
+
+ + +
+
+ + + +
+ {!singleUserMode && ( + + + + )} +
+
+ ); + }; + + if (action && features.remoteInteractionsAPI && features.federating) { + return renderRemoteInteractions(); + } + + return ( + } + onClose={onClickClose} + confirmationAction={onLogin} + confirmationText={} + secondaryAction={onRegister} + secondaryText={} + > + + + + + + + ); +}; + +export default UnauthorizedModal;