From 54ef361bcc354ee26dac7d234dc975b83bb7abcc Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 18 May 2022 14:08:08 -0400 Subject: [PATCH] Allow waitlisted users to verify their SMS --- app/soapbox/actions/verification.js | 30 +++ app/soapbox/components/ui/modal/modal.tsx | 7 +- app/soapbox/containers/soapbox.tsx | 12 +- .../notifications/components/notification.tsx | 17 +- .../features/ui/components/modal_root.js | 2 + .../ui/components/modals/verify-sms-modal.tsx | 233 ++++++++++++++++++ .../features/ui/util/async-components.ts | 4 + .../verification/steps/sms-verification.js | 4 +- .../features/verification/waitlist_page.js | 31 ++- app/soapbox/normalizers/notification.ts | 3 +- 10 files changed, 324 insertions(+), 19 deletions(-) create mode 100644 app/soapbox/features/ui/components/modals/verify-sms-modal.tsx diff --git a/app/soapbox/actions/verification.js b/app/soapbox/actions/verification.js index 23b895afa..f90a5637a 100644 --- a/app/soapbox/actions/verification.js +++ b/app/soapbox/actions/verification.js @@ -323,6 +323,20 @@ function requestPhoneVerification(phone) { }; } +/** + * Send the user's phone number to Pepe to re-request confirmation + * @param {string} phone + * @returns {promise} + */ +function reRequestPhoneVerification(phone) { + return (dispatch, getState) => { + dispatch({ type: SET_LOADING }); + + return api(getState).post('/api/v1/pepe/reverify_sms/request', { phone }) + .finally(() => dispatch({ type: SET_LOADING, value: false })); + }; +} + /** * Confirm the user's phone number with Pepe * @param {string} code @@ -345,6 +359,20 @@ function confirmPhoneVerification(code) { }; } +/** + * Re-Confirm the user's phone number with Pepe + * @param {string} code + * @returns {promise} + */ +function reConfirmPhoneVerification(code) { + return (dispatch, getState) => { + dispatch({ type: SET_LOADING }); + + return api(getState).post('/api/v1/pepe/reverify_sms/confirm', { code }) + .finally(() => dispatch({ type: SET_LOADING, value: false })); + }; +} + /** * Confirm the user's age with Pepe * @param {date} birthday @@ -404,6 +432,8 @@ export { requestEmailVerification, checkEmailVerification, postEmailVerification, + reConfirmPhoneVerification, requestPhoneVerification, + reRequestPhoneVerification, verifyAge, }; diff --git a/app/soapbox/components/ui/modal/modal.tsx b/app/soapbox/components/ui/modal/modal.tsx index 5c01c513a..1cd8f7fd5 100644 --- a/app/soapbox/components/ui/modal/modal.tsx +++ b/app/soapbox/components/ui/modal/modal.tsx @@ -33,7 +33,7 @@ interface IModal { /** Position of the close button. */ closePosition?: 'left' | 'right', /** Callback when the modal is confirmed. */ - confirmationAction?: () => void, + confirmationAction?: (event?: React.MouseEvent) => void, /** Whether the confirmation button is disabled. */ confirmationDisabled?: boolean, /** Confirmation button text. */ @@ -43,9 +43,10 @@ interface IModal { /** Callback when the modal is closed. */ onClose?: () => void, /** Callback when the secondary action is chosen. */ - secondaryAction?: () => void, + secondaryAction?: (event?: React.MouseEvent) => void, /** Secondary button text. */ secondaryText?: React.ReactNode, + secondaryDisabled?: boolean, /** Don't focus the "confirm" button on mount. */ skipFocus?: boolean, /** Title text for the modal. */ @@ -66,6 +67,7 @@ const Modal: React.FC = ({ confirmationTheme, onClose, secondaryAction, + secondaryDisabled = false, secondaryText, skipFocus = false, title, @@ -128,6 +130,7 @@ const Modal: React.FC = ({ diff --git a/app/soapbox/containers/soapbox.tsx b/app/soapbox/containers/soapbox.tsx index c7f2f3c87..cde450e65 100644 --- a/app/soapbox/containers/soapbox.tsx +++ b/app/soapbox/containers/soapbox.tsx @@ -18,6 +18,7 @@ import AuthLayout from 'soapbox/features/auth_layout'; import OnboardingWizard from 'soapbox/features/onboarding/onboarding-wizard'; import PublicLayout from 'soapbox/features/public_layout'; import NotificationsContainer from 'soapbox/features/ui/containers/notifications_container'; +import { ModalContainer } from 'soapbox/features/ui/util/async-components'; import WaitlistPage from 'soapbox/features/verification/waitlist_page'; import { createGlobals } from 'soapbox/globals'; import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures, useSoapboxConfig, useSettings, useSystemTheme } from 'soapbox/hooks'; @@ -29,6 +30,7 @@ import { checkOnboardingStatus } from '../actions/onboarding'; import { preload } from '../actions/preload'; import ErrorBoundary from '../components/error_boundary'; import UI from '../features/ui'; +import BundleContainer from '../features/ui/containers/bundle_container'; import { store } from '../store'; /** Ensure the given locale exists in our codebase */ @@ -96,7 +98,7 @@ const SoapboxMount = () => { MESSAGES[locale]().then(messages => { setMessages(messages); setLocaleLoading(false); - }).catch(() => {}); + }).catch(() => { }); }, [locale]); // Load initial data from the API @@ -172,7 +174,13 @@ const SoapboxMount = () => { )} {waitlisted && ( - } /> + <> + } /> + + + {Component => } + + )} {!me && (singleUserMode diff --git a/app/soapbox/features/notifications/components/notification.tsx b/app/soapbox/features/notifications/components/notification.tsx index c4bd4add6..9dd8a8bd0 100644 --- a/app/soapbox/features/notifications/components/notification.tsx +++ b/app/soapbox/features/notifications/components/notification.tsx @@ -3,6 +3,8 @@ import { HotKeys } from 'react-hotkeys'; import { FormattedMessage, useIntl } from 'react-intl'; import { useHistory } from 'react-router-dom'; +import { useAppSelector } from 'soapbox/hooks'; + import Icon from '../../../components/icon'; import Permalink from '../../../components/permalink'; import { HStack, Text, Emoji } from '../../../components/ui'; @@ -50,6 +52,7 @@ const icons: Record = { move: require('@tabler/icons/icons/briefcase.svg'), 'pleroma:chat_mention': require('@tabler/icons/icons/messages.svg'), 'pleroma:emoji_reaction': require('@tabler/icons/icons/mood-happy.svg'), + user_approved: require('@tabler/icons/icons/user-plus.svg'), }; const messages: Record = { @@ -93,16 +96,20 @@ const messages: Record id: 'notification.pleroma:emoji_reaction', defaultMessage: '{name} reacted to your post', }, + user_approved: { + id: 'notification.user_approved', + defaultMessage: 'Welcome to {instance}!', + }, }; -const buildMessage = (type: NotificationType, account: Account, targetName?: string): JSX.Element => { +const buildMessage = (type: NotificationType, account: Account, targetName: string, instanceTitle: string): JSX.Element => { const link = buildLink(account); return ( ); }; @@ -128,6 +135,7 @@ const Notification: React.FC = (props) => { const history = useHistory(); const intl = useIntl(); + const instance = useAppSelector((state) => state.instance); const type = notification.type; const { account, status } = notification; @@ -216,6 +224,7 @@ const Notification: React.FC = (props) => { switch (type) { case 'follow': case 'follow_request': + case 'user_approved': return account && typeof account === 'object' ? ( = (props) => { case 'pleroma:emoji_reaction': return status && typeof status === 'object' ? (