Browse Source

feat: error and loading screens for passkeys flow

httpjamesm 1 year ago
parent
commit
0e130c0e7d
1 changed files with 85 additions and 6 deletions
  1. 85 6
      apps/accounts/src/pages/passkeys/flow/index.tsx

+ 85 - 6
apps/accounts/src/pages/passkeys/flow/index.tsx

@@ -1,9 +1,12 @@
-import { CenteredFlex } from '@ente/shared/components/Container';
+import {
+    CenteredFlex,
+    VerticallyCentered,
+} from '@ente/shared/components/Container';
 import FormPaper from '@ente/shared/components/Form/FormPaper';
 import { Box, Typography } from '@mui/material';
 import InfoIcon from '@mui/icons-material/Info';
 import Image from 'next/image';
-import { useEffect } from 'react';
+import { useEffect, useState } from 'react';
 import {
     BeginPasskeyAuthenticationResponse,
     beginPasskeyAuthentication,
@@ -11,31 +14,58 @@ import {
 } from 'services/passkeysService';
 import { logError } from '@ente/shared/sentry';
 import _sodium from 'libsodium-wrappers';
+import EnteButton from '@ente/shared/components/EnteButton';
+import EnteSpinner from '@ente/shared/components/EnteSpinner';
 
 const PasskeysFlow = () => {
+    const [errored, setErrored] = useState(false);
+
+    const [loading, setLoading] = useState(true);
+
     const init = async () => {
         // get passkeySessionID from the query params
         const searchParams = new URLSearchParams(window.location.search);
         const passkeySessionID = searchParams.get('passkeySessionID');
 
+        setLoading(true);
+
         let beginData: BeginPasskeyAuthenticationResponse;
 
         try {
             beginData = await beginAuthentication(passkeySessionID);
         } catch (e) {
             logError(e, "Couldn't begin passkey authentication");
+            setErrored(true);
             return;
+        } finally {
+            setLoading(false);
         }
 
         let credential: Credential;
 
-        try {
-            credential = await getCredential(beginData.options.publicKey);
-        } catch (e) {
-            logError(e, "Couldn't get credential");
+        let tries = 0;
+        const maxTries = 3;
+
+        while (tries < maxTries) {
+            try {
+                credential = await getCredential(beginData.options.publicKey);
+            } catch (e) {
+                logError(e, "Couldn't get credential");
+                continue;
+            } finally {
+                tries++;
+            }
+
+            break;
+        }
+
+        if (!credential) {
+            setErrored(true);
             return;
         }
 
+        setLoading(true);
+
         let finishData;
 
         try {
@@ -46,6 +76,8 @@ const PasskeysFlow = () => {
             );
         } catch (e) {
             logError(e, "Couldn't finish passkey authentication");
+            setErrored(true);
+            setLoading(false);
             return;
         }
 
@@ -98,6 +130,53 @@ const PasskeysFlow = () => {
         init();
     }, []);
 
+    if (loading) {
+        return (
+            <VerticallyCentered>
+                <EnteSpinner />
+            </VerticallyCentered>
+        );
+    }
+
+    if (errored) {
+        return (
+            <Box
+                display="flex"
+                justifyContent="center"
+                alignItems="center"
+                height="100%">
+                <Box maxWidth="30rem">
+                    <FormPaper
+                        style={{
+                            padding: '1rem',
+                        }}>
+                        <InfoIcon />
+                        <Typography fontWeight="bold" variant="h4">
+                            Passkey Login Failed
+                        </Typography>
+                        <Typography marginTop="1rem">
+                            An error occurred while logging in with passkey.
+                        </Typography>
+                        <EnteButton
+                            onClick={() => {
+                                setErrored(false);
+                                init();
+                            }}
+                            fullWidth
+                            style={{
+                                marginTop: '1rem',
+                            }}
+                            color="accent"
+                            type="button"
+                            variant="contained">
+                            Try Again
+                        </EnteButton>
+                    </FormPaper>
+                </Box>
+            </Box>
+        );
+    }
+
     return (
         <>
             <Box