Skip to content

Commit 73d6c90

Browse files
Merge pull request #14 from auth0-samples/release-4
Release 4
2 parents 9602069 + 1eb7dc3 commit 73d6c90

File tree

17 files changed

+985
-12
lines changed

17 files changed

+985
-12
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"preview": "vite preview"
1111
},
1212
"dependencies": {
13-
"@auth0/auth0-acul-js": "^0.1.0-beta.2",
13+
"@auth0/auth0-acul-js": "^0.1.0-beta.3",
1414
"react": "^18.3.1",
1515
"react-dom": "^18.3.1",
1616
"react-error-boundary": "^4.1.2"

src/App.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ const MfaEmailListScreen = React.lazy(() => import("./screens/mfa-email-list"));
2424
const MfaPushChallengePushScreen = React.lazy(() => import("./screens/mfa-push-challenge-push"));
2525
const MfaEnrollResultScreen = React.lazy(() => import("./screens/mfa-enroll-result"));
2626
const MfaPushListScreen = React.lazy(() => import("./screens/mfa-push-list"));
27+
const MfaOtpChallengeScreen = React.lazy(() => import("./screens/mfa-otp-challenge"));
28+
const MfaOtpEnrollmentQrScreen = React.lazy(() => import("./screens/mfa-otp-enrollment-qr"));
29+
const MfaOtpEnrollmentCodeScreen = React.lazy(() => import("./screens/mfa-otp-enrollment-code"));
30+
const ResetPasswordMfaEmailChallengeScreen = React.lazy(() => import("./screens/reset-password-mfa-email-challenge"));
31+
const ResetPasswordMfaPushChallengePushScreen = React.lazy(() => import("./screens/reset-password-mfa-push-challenge-push"));
32+
const ResetPasswordMfaSmsChallengeScreen = React.lazy(() => import("./screens/reset-password-mfa-sms-challenge"));
33+
const ResetPasswordMfaOtpChallengeScreen = React.lazy(() => import("./screens/reset-password-mfa-otp-challenge"));
34+
const OrganizationSelectionScreen = React.lazy(() => import("./screens/organization-selection"));
35+
const OrganizationPickerScreen = React.lazy(() => import("./screens/organization-picker"));
36+
const AcceptInvitationScreen = React.lazy(() => import("./screens/accept-invitation"));
37+
// const CustomizedConsentScreen = React.lazy(() => import("./screens/customized-consent"));
2738

2839

2940
const App: React.FC = () => {
@@ -81,6 +92,28 @@ const App: React.FC = () => {
8192
return <MfaEnrollResultScreen />;
8293
case "mfa-push-list":
8394
return <MfaPushListScreen />;
95+
case "mfa-otp-challenge":
96+
return <MfaOtpChallengeScreen />;
97+
case "mfa-otp-enrollment-qr":
98+
return <MfaOtpEnrollmentQrScreen />;
99+
case "mfa-otp-enrollment-code":
100+
return <MfaOtpEnrollmentCodeScreen />;
101+
case "reset-password-mfa-email-challenge":
102+
return <ResetPasswordMfaEmailChallengeScreen />;
103+
case "reset-password-mfa-push-challenge-push":
104+
return <ResetPasswordMfaPushChallengePushScreen />;
105+
case "reset-password-mfa-sms-challenge":
106+
return <ResetPasswordMfaSmsChallengeScreen />;
107+
case "reset-password-mfa-otp-challenge":
108+
return <ResetPasswordMfaOtpChallengeScreen />;
109+
case "organization-selection":
110+
return <OrganizationSelectionScreen />;
111+
case "organization-picker":
112+
return <OrganizationPickerScreen />;
113+
case "accept-invitation":
114+
return <AcceptInvitationScreen />;
115+
// case "customized-consent":
116+
// return <CustomizedConsentScreen />;
84117
default:
85118
return <>No screen rendered</>;
86119
}

src/screens/ResetPasswordSuccess/hooks/useResetPasswordSuccessManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState } from 'react';
2-
import ResetPasswordSuccess from "@auth0/auth0-acul-js/reset-password-error";
2+
import ResetPasswordSuccess from "@auth0/auth0-acul-js/reset-password-success";
33
import { withWindowDebug } from "../../../utils";
44

55
export const useResetPasswordSuccessManager = () => {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from 'react';
2+
import AcceptInvitation from '@auth0/auth0-acul-js/accept-invitation';
3+
4+
const AcceptInvitationScreen: React.FC = () => {
5+
const acceptInvitationManager = new AcceptInvitation();
6+
const { screen, transaction } = acceptInvitationManager;
7+
8+
const handleAcceptInvitation = async () => {
9+
await acceptInvitationManager.acceptInvitation();
10+
};
11+
12+
return (
13+
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-100">
14+
<div className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
15+
<h2 className="text-2xl font-bold mb-4"> {screen?.texts?.title ?? "You've Been Invited!"} </h2>
16+
<p className="mb-4">
17+
{screen?.texts?.description ?? 'XXXXXX has invited you (XXXXXXX) to join Second XXXXXX on XXXXXX.'}
18+
</p>
19+
<p className="mb-4">
20+
Inviter: {screen.data?.inviter}
21+
</p>
22+
<p className="mb-4">
23+
Email: {screen.data?.email}
24+
</p>
25+
<button
26+
className="block mx-auto bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
27+
type="button"
28+
onClick={handleAcceptInvitation}
29+
>
30+
Accept Invitation
31+
</button>
32+
33+
{transaction?.errors?.length && (
34+
<div className="mt-2 mb-4">
35+
{transaction?.errors.map((err, index) => (
36+
<p key={index} className="text-red-500">
37+
{err.message}
38+
</p>
39+
))}
40+
</div>
41+
)}
42+
</div>
43+
</div>
44+
);
45+
};
46+
47+
export default AcceptInvitationScreen;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import React from 'react';
2+
import CustomizedConsent from '@auth0/auth0-acul-js/customized-consent';
3+
4+
const CustomizedConsentScreen: React.FC = () => {
5+
const customizedConsentManager = new CustomizedConsent();
6+
const { screen } = customizedConsentManager;
7+
8+
const handleAccept = async () => {
9+
try {
10+
await customizedConsentManager.accept();
11+
} catch (error) {
12+
console.error('Failed to accept consent:', error);
13+
}
14+
};
15+
16+
const handleDeny = async () => {
17+
try {
18+
await customizedConsentManager.deny();
19+
} catch (error) {
20+
console.error('Failed to deny consent:', error);
21+
}
22+
};
23+
24+
return (
25+
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-100">
26+
<div className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
27+
<h2 className="text-2xl font-bold mb-4">Consent to the following scopes:</h2>
28+
{
29+
screen.data?.scopes && Object.entries(screen.data.scopes as Record<string, string[]>).map(([scope, description]) => (
30+
<div key={scope} className="mb-4">
31+
<h3 className="text-xl font-semibold">{scope}</h3>
32+
<ul>
33+
{description.map((desc: string, index: number) => (
34+
<li key={index} className="text-gray-700">{desc}</li>
35+
))}
36+
</ul>
37+
</div>
38+
))
39+
}
40+
<div className="flex justify-between">
41+
<button
42+
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
43+
type="button"
44+
onClick={handleDeny}
45+
>
46+
Decline
47+
</button>
48+
<button
49+
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
50+
type="button"
51+
onClick={handleAccept}
52+
>
53+
Accept
54+
</button>
55+
</div>
56+
</div>
57+
</div>
58+
);
59+
};
60+
61+
export default CustomizedConsentScreen;

src/screens/mfa-email-list/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import MfaEmailList from '@auth0/auth0-acul-js/mfa-email-list';
2+
import MfaEmailList from '@auth0/auth0-acul-js/mfa-email-list'
33

44
const MfaEmailListScreen: React.FC = () => {
55
const mfaEmailList = new MfaEmailList();
@@ -30,10 +30,10 @@ const MfaEmailListScreen: React.FC = () => {
3030
{
3131
user.enrolledEmails ? (
3232
<ul className="mb-4">
33-
{user.enrolledEmails.map((email, index) => (
34-
<li key={index} className="py-2">
33+
{user.enrolledEmails.map(({email, id}) => (
34+
<li key={id} className="py-2">
3535
<button
36-
onClick={() => handleSelectEmail(index)}
36+
onClick={() => handleSelectEmail(id)}
3737
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
3838
>
3939
{email}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import React, { useState } from 'react';
2+
import MfaOtpChallenge from '@auth0/auth0-acul-js/mfa-otp-challenge';
3+
4+
const MfaOtpChallengeScreen: React.FC = () => {
5+
const [code, setCode] = useState('');
6+
const [rememberBrowser, setRememberBrowser] = useState(false);
7+
const [error, setError] = useState('');
8+
9+
const mfaOtpChallenge = new MfaOtpChallenge();
10+
const { screen: { texts }, transaction } = mfaOtpChallenge;
11+
12+
const handleSubmit = async (e: React.FormEvent) => {
13+
e.preventDefault();
14+
setError('');
15+
16+
try {
17+
await mfaOtpChallenge.continue({
18+
code,
19+
rememberBrowser,
20+
});
21+
} catch (err) {
22+
setError('Failed to verify code. Please try again.');
23+
console.error(err);
24+
}
25+
};
26+
27+
const handleTryAnotherMethod = async () => {
28+
try {
29+
await mfaOtpChallenge.tryAnotherMethod();
30+
} catch (err) {
31+
setError('Failed to try another method. Please try again.');
32+
console.error(err);
33+
}
34+
};
35+
36+
return (
37+
<div className="min-h-screen bg-gray-100 flex flex-col py-12 sm:px-6 lg:px-8">
38+
<div className="sm:mx-auto sm:w-full sm:max-w-md">
39+
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
40+
{texts?.title ?? 'Verify Your Identity'}
41+
</h2>
42+
<p className="mt-2 text-center text-sm text-gray-600">
43+
{texts?.description ?? 'Check your preferred one-time password application for a code.'}
44+
</p>
45+
</div>
46+
47+
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
48+
<div className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
49+
<form className="space-y-6" onSubmit={handleSubmit}>
50+
<div>
51+
<label htmlFor="code" className="block text-sm font-medium text-gray-700">
52+
{texts?.codePlaceholder ?? 'Enter your one-time code'}
53+
</label>
54+
<div className="mt-1">
55+
<input
56+
id="code"
57+
name="code"
58+
type="text"
59+
placeholder={texts?.codePlaceholder ?? 'Enter your one-time code'}
60+
required
61+
value={code}
62+
onChange={(e) => setCode(e.target.value)}
63+
className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500"
64+
/>
65+
</div>
66+
</div>
67+
68+
{transaction?.errors?.length && (
69+
<div className="text-red-600 text-sm mt-2">
70+
{transaction.errors.map((err, index) => (
71+
<p key={index}>{err.message}</p>
72+
))}
73+
</div>
74+
)}
75+
76+
<div className="flex items-center">
77+
<input
78+
id="rememberBrowser"
79+
name="rememberBrowser"
80+
type="checkbox"
81+
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
82+
checked={rememberBrowser}
83+
onChange={(e) => setRememberBrowser(e.target.checked)}
84+
/>
85+
<label htmlFor="rememberBrowser" className="ml-2 block text-sm text-gray-900">
86+
{texts?.rememberMeText ?? 'Remember this browser for 30 days'}
87+
</label>
88+
</div>
89+
90+
{error && (
91+
<div className="text-red-600 text-sm">
92+
{error}
93+
</div>
94+
)}
95+
96+
<div>
97+
<button
98+
type="submit"
99+
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
100+
>
101+
Verify Code
102+
</button>
103+
</div>
104+
</form>
105+
106+
<div className="mt-6">
107+
<div className="flex justify-between">
108+
<button
109+
onClick={handleTryAnotherMethod}
110+
className="text-sm text-blue-600 hover:text-blue-500"
111+
>
112+
{texts?.pickAuthenticatorText ?? 'Try Another Method'}
113+
</button>
114+
</div>
115+
</div>
116+
</div>
117+
</div>
118+
</div>
119+
);
120+
};
121+
122+
export default MfaOtpChallengeScreen;

0 commit comments

Comments
 (0)