123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- import {Fragment, useState} from 'react';
- import type {ModalRenderProps} from 'sentry/actionCreators/modal';
- import {Alert} from 'sentry/components/alert';
- import {Button} from 'sentry/components/button';
- import LoadingError from 'sentry/components/loadingError';
- import LoadingIndicator from 'sentry/components/loadingIndicator';
- import {t} from 'sentry/locale';
- import {space} from 'sentry/styles/space';
- import type {Authenticator} from 'sentry/types';
- import {useApiQuery} from 'sentry/utils/queryClient';
- import TextBlock from 'sentry/views/settings/components/text/textBlock';
- type Props = ModalRenderProps & {
- authenticatorName: string;
- };
- function RecoveryOptionsModal({
- authenticatorName,
- closeModal,
- Body,
- Header,
- Footer,
- }: Props) {
- const {
- isLoading,
- isError,
- refetch: refetchAuthenticators,
- data: authenticators = [],
- } = useApiQuery<Authenticator[]>(['/users/me/authenticators/'], {
- staleTime: 5000, // expire after 5 seconds
- });
- const [skipSms, setSkipSms] = useState<boolean>(false);
- const {recovery, sms} = authenticators.reduce<{[key: string]: Authenticator}>(
- (obj, item) => {
- obj[item.id] = item;
- return obj;
- },
- {}
- );
- const recoveryEnrolled = recovery?.isEnrolled;
- const displaySmsPrompt =
- sms && !sms.isEnrolled && !skipSms && !sms.disallowNewEnrollment;
- const handleSkipSms = () => {
- setSkipSms(true);
- };
- if (isLoading) return <LoadingIndicator />;
- if (isError) {
- return (
- <LoadingError
- message={t('There was an error loading authenticators.')}
- onRetry={refetchAuthenticators}
- />
- );
- }
- return (
- <Fragment>
- <Header closeButton>{t('Two-Factor Authentication Enabled')}</Header>
- <Body>
- <TextBlock>
- {t('Two-factor authentication via %s has been enabled.', authenticatorName)}
- </TextBlock>
- <TextBlock>
- {t('You should now set up recovery options to secure your account.')}
- </TextBlock>
- {displaySmsPrompt ? (
- // set up backup phone number
- <Alert type="warning">
- {t('We recommend adding a phone number as a backup 2FA method.')}
- </Alert>
- ) : (
- // get recovery codes
- <Alert type="warning">
- {t(
- `Recovery codes are the only way to access your account if you lose
- your device and cannot receive two-factor authentication codes.`
- )}
- </Alert>
- )}
- </Body>
- {displaySmsPrompt ? (
- // set up backup phone number
- <Footer>
- <Button onClick={handleSkipSms} name="skipStep" autoFocus>
- {t('Skip this step')}
- </Button>
- <Button
- priority="primary"
- onClick={closeModal}
- to={`/settings/account/security/mfa/${sms.id}/enroll/`}
- name="addPhone"
- css={{marginLeft: space(1)}}
- autoFocus
- >
- {t('Add a Phone Number')}
- </Button>
- </Footer>
- ) : (
- // get recovery codes
- <Footer>
- <Button
- priority="primary"
- onClick={closeModal}
- to={
- recoveryEnrolled
- ? `/settings/account/security/mfa/${recovery.authId}/`
- : '/settings/account/security/'
- }
- name="getCodes"
- autoFocus
- >
- {t('Get Recovery Codes')}
- </Button>
- </Footer>
- )}
- </Fragment>
- );
- }
- export default RecoveryOptionsModal;
|