1
+ import React , { useState , useMemo , useCallback , useEffect } from 'react' ;
2
+ import ResetPasswordMfaWebAuthnPlatformChallenge , {
3
+ type ContinueWithPasskeyOptions ,
4
+ type TryAnotherMethodOptions ,
5
+ } from '@auth0/auth0-acul-js/reset-password-mfa-webauthn-platform-challenge' ;
6
+
7
+ const ResetPasswordMfaWebAuthnPlatformChallengeComponent : React . FC = ( ) => {
8
+ const sdk = useMemo ( ( ) => new ResetPasswordMfaWebAuthnPlatformChallenge ( ) , [ ] ) ;
9
+ const { screen, transaction, client } = sdk ;
10
+ const texts = screen . texts ?? { } ;
11
+ const { publicKey : publicKeyChallengeOptions , showRememberDevice } = screen ;
12
+
13
+ const [ rememberDevice , setRememberDevice ] = useState ( false ) ;
14
+
15
+ const handleVerify = useCallback ( ( ) => {
16
+ const opts : ContinueWithPasskeyOptions = { } ;
17
+ if ( showRememberDevice ) {
18
+ opts . rememberDevice = rememberDevice ;
19
+ }
20
+ sdk . continueWithPasskey ( opts ) ;
21
+ } , [ sdk , rememberDevice , showRememberDevice ] ) ;
22
+
23
+ const handleTryAnotherMethod = useCallback ( ( ) => {
24
+ const opts : TryAnotherMethodOptions = { } ; // Add custom options if needed
25
+ sdk . tryAnotherMethod ( opts ) ;
26
+ } , [ sdk ] ) ;
27
+
28
+ // Effect to automatically trigger verification if publicKeyChallengeOptions are available.
29
+ // This provides a more seamless UX, prompting the user immediately.
30
+ useEffect ( ( ) => {
31
+ if ( publicKeyChallengeOptions ) { // Check !isLoading to prevent re-triggering if already in process
32
+ console . log ( "WebAuthn platform challenge options available. Automatically attempting verification." ) ;
33
+ handleVerify ( ) ;
34
+ }
35
+ } , [ handleVerify , publicKeyChallengeOptions ] ) ;
36
+
37
+ return (
38
+ < div className = "flex flex-col items-center justify-center min-h-screen bg-gray-100 p-4 antialiased" >
39
+ < div className = "w-full max-w-md bg-white rounded-lg shadow-xl p-8 space-y-6" >
40
+ { client . logoUrl && (
41
+ < img src = { client . logoUrl } alt = { client . name ?? 'Client Logo' } className = "mx-auto h-12 mb-6" />
42
+ ) }
43
+ < div className = "text-center" >
44
+ < h1 className = "text-2xl font-bold text-gray-800" >
45
+ { texts . title ?? 'Verify Your Identity' }
46
+ </ h1 >
47
+ < p className = "mt-2 text-gray-600" >
48
+ { texts . description ?? 'Please use your device\'s screen lock (fingerprint, face, PIN) or a connected security key to continue resetting your password.' }
49
+ </ p >
50
+ </ div >
51
+
52
+ { transaction . errors && transaction . errors . length > 0 && (
53
+ < div className = "bg-red-50 border-l-4 border-red-400 text-red-700 p-4 rounded-md" role = "alert" >
54
+ < p className = "font-bold" > { texts . alertListTitle ?? 'Errors:' } </ p >
55
+ { transaction . errors . map ( ( err , index ) => (
56
+ < p key = { `tx-err-${ index } ` } > { err . message } </ p >
57
+ ) ) }
58
+ </ div >
59
+ ) }
60
+
61
+ { showRememberDevice && (
62
+ < div className = "flex items-center justify-center mt-4" >
63
+ < input
64
+ id = "rememberDevice"
65
+ name = "rememberDevice"
66
+ type = "checkbox"
67
+ checked = { rememberDevice }
68
+ onChange = { ( e ) => setRememberDevice ( e . target . checked ) }
69
+ className = "h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded"
70
+ />
71
+ < label htmlFor = "rememberDevice" className = "ml-2 block text-sm text-gray-900" >
72
+ { texts . rememberMeText ?? 'Remember this device for 30 days' }
73
+ </ label >
74
+ </ div >
75
+ ) }
76
+
77
+ < div className = "space-y-4 mt-6" >
78
+ { /* Button to manually trigger verification if auto-trigger fails or as a retry option */ }
79
+ { /* This might only be shown if publicKeyChallengeOptions exist but initial auto-verify failed */ }
80
+ { publicKeyChallengeOptions && (
81
+ < button
82
+ onClick = { handleVerify }
83
+ disabled = { ! publicKeyChallengeOptions }
84
+ className = "w-full flex justify-center items-center px-4 py-2.5 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-60 disabled:cursor-not-allowed"
85
+ >
86
+ { ( texts . retryButtonText ?? 'Retry Verification' ) }
87
+ </ button >
88
+ ) }
89
+
90
+ < button
91
+ onClick = { handleTryAnotherMethod }
92
+ className = "w-full flex justify-center px-4 py-2.5 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-60 disabled:cursor-not-allowed"
93
+ >
94
+ { texts . pickAuthenticatorText ?? 'Try Another Method' }
95
+ </ button >
96
+ </ div >
97
+ </ div >
98
+ </ div >
99
+ ) ;
100
+ } ;
101
+
102
+ export default ResetPasswordMfaWebAuthnPlatformChallengeComponent ;
0 commit comments