import QRCode from 'qrcode'; import * as React from 'react'; import { Logger } from 'aws-amplify'; import { authenticatorTextUtil, getTotpCodeURL } from '@aws-amplify/ui'; import { Flex } from '../../../primitives/Flex'; import { Heading } from '../../../primitives/Heading'; import { useAuthenticator } from '@aws-amplify/ui-react-core'; import { useCustomComponents } from '../hooks/useCustomComponents'; import { useFormHandlers } from '../hooks/useFormHandlers'; import { ConfirmSignInFooter } from '../shared/ConfirmSignInFooter'; import { RemoteErrorMessage } from '../shared/RemoteErrorMessage'; import { FormFields } from '../shared/FormFields'; import { RouteContainer, RouteProps } from '../RouteContainer'; const logger = new Logger('SetupTOTP-logger'); type LegacyQRFields = { totpIssuer?: string; totpUsername?: string }; const { getSetupTOTPText, getCopiedText, getLoadingText } = authenticatorTextUtil; export const SetupTOTP = ({ className, variation, }: RouteProps): JSX.Element => { const { totpSecretCode, isPending, user, QRFields } = useAuthenticator( (context) => [context.isPending, context.totpSecretCode] ); const { handleChange, handleSubmit } = useFormHandlers(); const { components: { // @ts-ignore SetupTOTP: { Header = SetupTOTP.Header, Footer = SetupTOTP.Footer }, }, } = useCustomComponents(); const [isLoading, setIsLoading] = React.useState(true); const [qrCode, setQrCode] = React.useState(); const [copyTextLabel, setCopyTextLabel] = React.useState('COPY'); const { totpIssuer = 'AWSCognito', totpUsername = user?.username } = (QRFields as LegacyQRFields) ?? {}; const generateQRCode = React.useCallback(async (): Promise => { try { const totpCode = getTotpCodeURL( totpIssuer, totpUsername!, totpSecretCode! ); const qrCodeImageSource = await QRCode.toDataURL(totpCode); setQrCode(qrCodeImageSource); } catch (error) { logger.error(error); } finally { setIsLoading(false); } }, [totpIssuer, totpUsername, totpSecretCode]); React.useEffect(() => { if (!qrCode) { generateQRCode(); } }, [generateQRCode, qrCode]); const copyText = (): void => { navigator.clipboard.writeText(totpSecretCode!); setCopyTextLabel(getCopiedText()); }; return (
{/* TODO: Add spinner here instead of loading text... */} {isLoading ? (

{getLoadingText()}…

) : ( qr code )}
{totpSecretCode}
{copyTextLabel}