@massimo.mazzoleni/cognito-max 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +2410 -0
  2. package/dist/chunk-AD7T42HJ.js +3 -0
  3. package/dist/chunk-AD7T42HJ.js.map +1 -0
  4. package/dist/chunk-DKPFVGTY.js +683 -0
  5. package/dist/chunk-DKPFVGTY.js.map +1 -0
  6. package/dist/chunk-N4OQLBV6.js +135 -0
  7. package/dist/chunk-N4OQLBV6.js.map +1 -0
  8. package/dist/client-63FraVdm.d.ts +69 -0
  9. package/dist/client-BAoL8h4E.d.cts +69 -0
  10. package/dist/core/index.cjs +696 -0
  11. package/dist/core/index.cjs.map +1 -0
  12. package/dist/core/index.d.cts +3 -0
  13. package/dist/core/index.d.ts +3 -0
  14. package/dist/core/index.js +4 -0
  15. package/dist/core/index.js.map +1 -0
  16. package/dist/errors-BkUDHleb.d.cts +22 -0
  17. package/dist/errors-BkUDHleb.d.ts +22 -0
  18. package/dist/index.cjs +696 -0
  19. package/dist/index.cjs.map +1 -0
  20. package/dist/index.d.cts +3 -0
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.js +4 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/react/index.cjs +844 -0
  25. package/dist/react/index.cjs.map +1 -0
  26. package/dist/react/index.d.cts +104 -0
  27. package/dist/react/index.d.ts +104 -0
  28. package/dist/react/index.js +64 -0
  29. package/dist/react/index.js.map +1 -0
  30. package/dist/types-bxA1vonL.d.cts +113 -0
  31. package/dist/types-bxA1vonL.d.ts +113 -0
  32. package/dist/ui/index.cjs +1183 -0
  33. package/dist/ui/index.cjs.map +1 -0
  34. package/dist/ui/index.d.cts +241 -0
  35. package/dist/ui/index.d.ts +241 -0
  36. package/dist/ui/index.js +1109 -0
  37. package/dist/ui/index.js.map +1 -0
  38. package/package.json +81 -0
  39. package/src/core/client.ts +604 -0
  40. package/src/core/errors.ts +91 -0
  41. package/src/core/event-bus.ts +41 -0
  42. package/src/core/index.ts +5 -0
  43. package/src/core/internal/converters.ts +32 -0
  44. package/src/core/storage.ts +79 -0
  45. package/src/core/types.ts +87 -0
  46. package/src/index.ts +1 -0
  47. package/src/react/components/ProtectedRoute.tsx +56 -0
  48. package/src/react/context.tsx +126 -0
  49. package/src/react/hooks/useAuth.ts +75 -0
  50. package/src/react/hooks/useMfa.ts +19 -0
  51. package/src/react/hooks/useSession.ts +16 -0
  52. package/src/react/hooks/useUser.ts +24 -0
  53. package/src/react/index.ts +10 -0
  54. package/src/ui/components/ChangePasswordForm.tsx +105 -0
  55. package/src/ui/components/ForgotPasswordForm.tsx +159 -0
  56. package/src/ui/components/MfaSetupWizard.tsx +136 -0
  57. package/src/ui/components/RegisterForm.tsx +159 -0
  58. package/src/ui/components/SignInForm.tsx +296 -0
  59. package/src/ui/hooks/useChangePasswordForm.ts +81 -0
  60. package/src/ui/hooks/useForgotPasswordForm.ts +109 -0
  61. package/src/ui/hooks/useMfaSetup.ts +93 -0
  62. package/src/ui/hooks/useRegisterForm.ts +120 -0
  63. package/src/ui/hooks/useSignInForm.ts +245 -0
  64. package/src/ui/index.ts +31 -0
@@ -0,0 +1,1183 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ require('amazon-cognito-identity-js');
5
+ require('@aws-sdk/client-cognito-identity-provider');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ // src/ui/hooks/useSignInForm.ts
9
+ var AuthContext = react.createContext(null);
10
+ function useAuthContext() {
11
+ const ctx = react.useContext(AuthContext);
12
+ if (!ctx) {
13
+ throw new Error("useAuthContext must be used inside <AuthProvider>");
14
+ }
15
+ return ctx;
16
+ }
17
+
18
+ // src/react/hooks/useAuth.ts
19
+ function useAuth() {
20
+ const { client, state, user, isLoading, isAuthenticated } = useAuthContext();
21
+ const actions = react.useMemo(
22
+ () => ({
23
+ signIn: (email, password) => client.signIn(email, password),
24
+ signOut: (global) => client.signOut(global),
25
+ signUp: (email, password, attributes) => client.signUp(email, password, attributes),
26
+ confirmSignUp: (email, code) => client.confirmSignUp(email, code),
27
+ resendConfirmationCode: (email) => client.resendConfirmationCode(email),
28
+ forgotPassword: (email) => client.forgotPassword(email),
29
+ confirmForgotPassword: (email, code, newPassword) => client.confirmForgotPassword(email, code, newPassword),
30
+ changePassword: (current, next) => client.changePassword(current, next),
31
+ respondToMfaChallenge: (challengeSession, code, mfaType) => client.respondToMfaChallenge(challengeSession, code, mfaType),
32
+ respondToNewPasswordChallenge: (challengeSession, newPassword, userAttributes) => client.respondToNewPasswordChallenge(challengeSession, newPassword, userAttributes),
33
+ setupTotpChallenge: (challengeSession) => client.setupTotpChallenge(challengeSession),
34
+ verifyTotpChallenge: (challengeSession, code) => client.verifyTotpChallenge(challengeSession, code)
35
+ }),
36
+ [client]
37
+ );
38
+ return {
39
+ // Stato
40
+ user,
41
+ state,
42
+ isLoading,
43
+ isAuthenticated,
44
+ // Azioni
45
+ ...actions,
46
+ // Client raw per casi avanzati
47
+ client
48
+ };
49
+ }
50
+
51
+ // src/ui/hooks/useSignInForm.ts
52
+ function useSignInForm(options = {}) {
53
+ const {
54
+ signIn,
55
+ respondToMfaChallenge,
56
+ respondToNewPasswordChallenge,
57
+ setupTotpChallenge,
58
+ verifyTotpChallenge
59
+ } = useAuth();
60
+ const [step, setStep] = react.useState("credentials");
61
+ const [isLoading, setLoading] = react.useState(false);
62
+ const [error, setError] = react.useState(null);
63
+ const [email, setEmail] = react.useState("");
64
+ const [password, setPassword] = react.useState("");
65
+ const [mfaType, setMfaType] = react.useState(null);
66
+ const [challengeSession, setChallengeSession] = react.useState(null);
67
+ const [mfaCode, setMfaCode] = react.useState("");
68
+ const [newPwd, setNewPwd] = react.useState("");
69
+ const [confirmPwd, setConfirmPwd] = react.useState("");
70
+ const [requiredAttributes, setRequiredAttributes] = react.useState([]);
71
+ const [mfaSetupQrCodeUri, setMfaSetupQrCodeUri] = react.useState(null);
72
+ const [mfaSetupSecretCode, setMfaSetupSecretCode] = react.useState(null);
73
+ const [mfaSetupTotpCode, setMfaSetupTotpCode] = react.useState("");
74
+ const handleSignInResult = react.useCallback(
75
+ (result) => {
76
+ if (result.status === "SUCCESS") {
77
+ options.onSuccess?.(result);
78
+ } else if (result.status === "MFA_REQUIRED") {
79
+ setMfaType(result.mfaType);
80
+ setChallengeSession(result.challengeSession);
81
+ setStep("mfa");
82
+ } else if (result.status === "NEW_PASSWORD_REQUIRED") {
83
+ setChallengeSession(result.challengeSession);
84
+ setRequiredAttributes(result.requiredAttributes);
85
+ setStep("new_password");
86
+ } else if (result.status === "MFA_SETUP_REQUIRED") {
87
+ setChallengeSession(result.challengeSession);
88
+ setStep("mfa_setup");
89
+ }
90
+ },
91
+ [options]
92
+ );
93
+ const handleCredentialsSubmit = react.useCallback(
94
+ async (e) => {
95
+ e.preventDefault();
96
+ setError(null);
97
+ setLoading(true);
98
+ try {
99
+ const result = await signIn(email, password);
100
+ handleSignInResult(result);
101
+ } catch (err) {
102
+ const authErr = err;
103
+ setError(authErr);
104
+ options.onError?.(authErr);
105
+ } finally {
106
+ setLoading(false);
107
+ }
108
+ },
109
+ [email, password, signIn, handleSignInResult, options]
110
+ );
111
+ const handleMfaSubmit = react.useCallback(
112
+ async (e) => {
113
+ e.preventDefault();
114
+ if (!challengeSession || !mfaType) return;
115
+ setError(null);
116
+ setLoading(true);
117
+ try {
118
+ const result = await respondToMfaChallenge(challengeSession, mfaCode, mfaType);
119
+ handleSignInResult(result);
120
+ } catch (err) {
121
+ const authErr = err;
122
+ setError(authErr);
123
+ options.onError?.(authErr);
124
+ } finally {
125
+ setLoading(false);
126
+ }
127
+ },
128
+ [challengeSession, mfaType, mfaCode, respondToMfaChallenge, handleSignInResult, options]
129
+ );
130
+ const handleNewPasswordSubmit = react.useCallback(
131
+ async (e) => {
132
+ e.preventDefault();
133
+ if (!challengeSession) return;
134
+ if (newPwd !== confirmPwd) {
135
+ setError({ message: "Le password non coincidono", code: "INVALID_PASSWORD" });
136
+ return;
137
+ }
138
+ setError(null);
139
+ setLoading(true);
140
+ try {
141
+ const result = await respondToNewPasswordChallenge(challengeSession, newPwd);
142
+ handleSignInResult(result);
143
+ } catch (err) {
144
+ const authErr = err;
145
+ setError(authErr);
146
+ options.onError?.(authErr);
147
+ } finally {
148
+ setLoading(false);
149
+ }
150
+ },
151
+ [challengeSession, newPwd, confirmPwd, respondToNewPasswordChallenge, handleSignInResult, options]
152
+ );
153
+ const handleMfaSetupStart = react.useCallback(async () => {
154
+ if (!challengeSession) return;
155
+ setError(null);
156
+ setLoading(true);
157
+ try {
158
+ const result = await setupTotpChallenge(challengeSession);
159
+ setMfaSetupQrCodeUri(result.qrCodeUri);
160
+ setMfaSetupSecretCode(result.secretCode);
161
+ } catch (err) {
162
+ const authErr = err;
163
+ setError(authErr);
164
+ options.onError?.(authErr);
165
+ } finally {
166
+ setLoading(false);
167
+ }
168
+ }, [challengeSession, setupTotpChallenge, options]);
169
+ const handleMfaSetupVerify = react.useCallback(
170
+ async (e) => {
171
+ e.preventDefault();
172
+ if (!challengeSession) return;
173
+ setError(null);
174
+ setLoading(true);
175
+ try {
176
+ const result = await verifyTotpChallenge(challengeSession, mfaSetupTotpCode);
177
+ handleSignInResult(result);
178
+ } catch (err) {
179
+ const authErr = err;
180
+ setError(authErr);
181
+ options.onError?.(authErr);
182
+ } finally {
183
+ setLoading(false);
184
+ }
185
+ },
186
+ [challengeSession, mfaSetupTotpCode, verifyTotpChallenge, handleSignInResult, options]
187
+ );
188
+ const reset = react.useCallback(() => {
189
+ setStep("credentials");
190
+ setEmail("");
191
+ setPassword("");
192
+ setMfaCode("");
193
+ setNewPwd("");
194
+ setConfirmPwd("");
195
+ setError(null);
196
+ setMfaType(null);
197
+ setChallengeSession(null);
198
+ setMfaSetupQrCodeUri(null);
199
+ setMfaSetupSecretCode(null);
200
+ setMfaSetupTotpCode("");
201
+ }, []);
202
+ return {
203
+ step,
204
+ isLoading,
205
+ error,
206
+ mfaType,
207
+ credentials: { email, password, setEmail, setPassword, onSubmit: handleCredentialsSubmit },
208
+ mfa: { code: mfaCode, setCode: setMfaCode, onSubmit: handleMfaSubmit },
209
+ newPassword: {
210
+ password: newPwd,
211
+ confirmPassword: confirmPwd,
212
+ requiredAttributes,
213
+ setPassword: setNewPwd,
214
+ setConfirmPassword: setConfirmPwd,
215
+ onSubmit: handleNewPasswordSubmit
216
+ },
217
+ mfaSetup: {
218
+ qrCodeUri: mfaSetupQrCodeUri,
219
+ secretCode: mfaSetupSecretCode,
220
+ totpCode: mfaSetupTotpCode,
221
+ setTotpCode: setMfaSetupTotpCode,
222
+ start: handleMfaSetupStart,
223
+ onVerify: handleMfaSetupVerify
224
+ },
225
+ reset
226
+ };
227
+ }
228
+ function useRegisterForm(options = {}) {
229
+ const { signUp, confirmSignUp, resendConfirmationCode } = useAuth();
230
+ const [step, setStep] = react.useState("register");
231
+ const [isLoading, setLoading] = react.useState(false);
232
+ const [error, setError] = react.useState(null);
233
+ const [email, setEmail] = react.useState("");
234
+ const [password, setPassword] = react.useState("");
235
+ const [confirmPassword, setConfirmPassword] = react.useState("");
236
+ const [code, setCode] = react.useState("");
237
+ const handleRegisterSubmit = react.useCallback(
238
+ async (e) => {
239
+ e.preventDefault();
240
+ if (password !== confirmPassword) {
241
+ setError({ message: "Le password non coincidono", code: "INVALID_PASSWORD" });
242
+ return;
243
+ }
244
+ setError(null);
245
+ setLoading(true);
246
+ try {
247
+ await signUp(email, password, options.extraAttributes);
248
+ setStep("confirm");
249
+ } catch (err) {
250
+ const authErr = err;
251
+ setError(authErr);
252
+ options.onError?.(authErr);
253
+ } finally {
254
+ setLoading(false);
255
+ }
256
+ },
257
+ [email, password, confirmPassword, signUp, options]
258
+ );
259
+ const handleConfirmSubmit = react.useCallback(
260
+ async (e) => {
261
+ e.preventDefault();
262
+ setError(null);
263
+ setLoading(true);
264
+ try {
265
+ await confirmSignUp(email, code);
266
+ options.onSuccess?.();
267
+ } catch (err) {
268
+ const authErr = err;
269
+ setError(authErr);
270
+ options.onError?.(authErr);
271
+ } finally {
272
+ setLoading(false);
273
+ }
274
+ },
275
+ [email, code, confirmSignUp, options]
276
+ );
277
+ const resend = react.useCallback(async () => {
278
+ setError(null);
279
+ try {
280
+ await resendConfirmationCode(email);
281
+ } catch (err) {
282
+ setError(err);
283
+ }
284
+ }, [email, resendConfirmationCode]);
285
+ const reset = react.useCallback(() => {
286
+ setStep("register");
287
+ setEmail("");
288
+ setPassword("");
289
+ setConfirmPassword("");
290
+ setCode("");
291
+ setError(null);
292
+ }, []);
293
+ return {
294
+ step,
295
+ isLoading,
296
+ error,
297
+ register: { email, password, confirmPassword, setEmail, setPassword, setConfirmPassword, onSubmit: handleRegisterSubmit },
298
+ confirm: { email, code, setCode, onSubmit: handleConfirmSubmit, resend },
299
+ reset
300
+ };
301
+ }
302
+ function useForgotPasswordForm(options = {}) {
303
+ const { forgotPassword, confirmForgotPassword } = useAuth();
304
+ const [step, setStep] = react.useState("request");
305
+ const [isLoading, setLoading] = react.useState(false);
306
+ const [error, setError] = react.useState(null);
307
+ const [email, setEmail] = react.useState("");
308
+ const [code, setCode] = react.useState("");
309
+ const [newPassword, setNewPassword] = react.useState("");
310
+ const [confirmPassword, setConfirmPassword] = react.useState("");
311
+ const handleRequestSubmit = react.useCallback(
312
+ async (e) => {
313
+ e.preventDefault();
314
+ setError(null);
315
+ setLoading(true);
316
+ try {
317
+ await forgotPassword(email);
318
+ setStep("reset");
319
+ } catch (err) {
320
+ const authErr = err;
321
+ setError(authErr);
322
+ options.onError?.(authErr);
323
+ } finally {
324
+ setLoading(false);
325
+ }
326
+ },
327
+ [email, forgotPassword, options]
328
+ );
329
+ const handleResetSubmit = react.useCallback(
330
+ async (e) => {
331
+ e.preventDefault();
332
+ if (newPassword !== confirmPassword) {
333
+ setError({ message: "Le password non coincidono", code: "INVALID_PASSWORD" });
334
+ return;
335
+ }
336
+ setError(null);
337
+ setLoading(true);
338
+ try {
339
+ await confirmForgotPassword(email, code, newPassword);
340
+ options.onSuccess?.();
341
+ } catch (err) {
342
+ const authErr = err;
343
+ setError(authErr);
344
+ options.onError?.(authErr);
345
+ } finally {
346
+ setLoading(false);
347
+ }
348
+ },
349
+ [email, code, newPassword, confirmPassword, confirmForgotPassword, options]
350
+ );
351
+ const restart = react.useCallback(() => {
352
+ setStep("request");
353
+ setCode("");
354
+ setNewPassword("");
355
+ setConfirmPassword("");
356
+ setError(null);
357
+ }, []);
358
+ return {
359
+ step,
360
+ isLoading,
361
+ error,
362
+ request: { email, setEmail, onSubmit: handleRequestSubmit },
363
+ reset: { email, code, newPassword, confirmPassword, setCode, setNewPassword, setConfirmPassword, onSubmit: handleResetSubmit },
364
+ restart
365
+ };
366
+ }
367
+ function useChangePasswordForm(options = {}) {
368
+ const { changePassword } = useAuth();
369
+ const [isLoading, setLoading] = react.useState(false);
370
+ const [error, setError] = react.useState(null);
371
+ const [success, setSuccess] = react.useState(false);
372
+ const [currentPassword, setCurrentPassword] = react.useState("");
373
+ const [newPassword, setNewPassword] = react.useState("");
374
+ const [confirmPassword, setConfirmPassword] = react.useState("");
375
+ const handleSubmit = react.useCallback(
376
+ async (e) => {
377
+ e.preventDefault();
378
+ if (newPassword !== confirmPassword) {
379
+ setError({ message: "Le nuove password non coincidono", code: "INVALID_PASSWORD" });
380
+ return;
381
+ }
382
+ setError(null);
383
+ setLoading(true);
384
+ try {
385
+ await changePassword(currentPassword, newPassword);
386
+ setSuccess(true);
387
+ options.onSuccess?.();
388
+ } catch (err) {
389
+ const authErr = err;
390
+ setError(authErr);
391
+ options.onError?.(authErr);
392
+ } finally {
393
+ setLoading(false);
394
+ }
395
+ },
396
+ [currentPassword, newPassword, confirmPassword, changePassword, options]
397
+ );
398
+ const reset = react.useCallback(() => {
399
+ setCurrentPassword("");
400
+ setNewPassword("");
401
+ setConfirmPassword("");
402
+ setError(null);
403
+ setSuccess(false);
404
+ }, []);
405
+ return {
406
+ isLoading,
407
+ error,
408
+ success,
409
+ currentPassword,
410
+ newPassword,
411
+ confirmPassword,
412
+ setCurrentPassword,
413
+ setNewPassword,
414
+ setConfirmPassword,
415
+ onSubmit: handleSubmit,
416
+ reset
417
+ };
418
+ }
419
+
420
+ // src/react/hooks/useMfa.ts
421
+ function useMfa() {
422
+ const { client } = useAuthContext();
423
+ return {
424
+ /** Avvia il setup TOTP — restituisce secretCode e qrCodeUri per l'app authenticator */
425
+ setup: () => client.setupTotp(),
426
+ /** Conferma il codice TOTP generato dall'app per completare il setup */
427
+ verifySetup: (code) => client.verifyTotpSetup(code),
428
+ /** Legge le preferenze MFA correnti (TOTP abilitato, SMS abilitato, preferito) */
429
+ getPreference: () => client.getMfaPreference(),
430
+ /** Imposta il tipo MFA preferito ('TOTP' | 'SMS') */
431
+ setPreference: (type) => client.setMfaPreference(type),
432
+ /** Disabilita completamente il secondo fattore */
433
+ disable: () => client.disableMfa()
434
+ };
435
+ }
436
+
437
+ // src/ui/hooks/useMfaSetup.ts
438
+ function useMfaSetup(options = {}) {
439
+ const { setup, verifySetup } = useMfa();
440
+ const [step, setStep] = react.useState("idle");
441
+ const [error, setError] = react.useState(null);
442
+ const [qrCodeUri, setQrCodeUri] = react.useState(null);
443
+ const [secretCode, setSecretCode] = react.useState(null);
444
+ const [totpCode, setTotpCode] = react.useState("");
445
+ const start = react.useCallback(async () => {
446
+ setError(null);
447
+ setStep("loading");
448
+ try {
449
+ const result = await setup();
450
+ setQrCodeUri(result.qrCodeUri);
451
+ setSecretCode(result.secretCode);
452
+ setStep("scan");
453
+ } catch (err) {
454
+ const authErr = err;
455
+ setError(authErr);
456
+ setStep("idle");
457
+ options.onError?.(authErr);
458
+ }
459
+ }, [setup, options]);
460
+ const handleVerify = react.useCallback(
461
+ async (e) => {
462
+ e.preventDefault();
463
+ setError(null);
464
+ setStep("loading");
465
+ try {
466
+ await verifySetup(totpCode);
467
+ setStep("done");
468
+ options.onSuccess?.();
469
+ } catch (err) {
470
+ const authErr = err;
471
+ setError(authErr);
472
+ setStep("verify");
473
+ options.onError?.(authErr);
474
+ }
475
+ },
476
+ [totpCode, verifySetup, options]
477
+ );
478
+ const reset = react.useCallback(() => {
479
+ setStep("idle");
480
+ setError(null);
481
+ setQrCodeUri(null);
482
+ setSecretCode(null);
483
+ setTotpCode("");
484
+ }, []);
485
+ return {
486
+ step,
487
+ isLoading: step === "loading",
488
+ error,
489
+ qrCodeUri,
490
+ secretCode,
491
+ totpCode,
492
+ setTotpCode,
493
+ start,
494
+ onVerify: handleVerify,
495
+ reset
496
+ };
497
+ }
498
+ function SignInForm({
499
+ className,
500
+ labels = {},
501
+ forgotPasswordLink,
502
+ registerLink,
503
+ renderQrCode,
504
+ onSuccess,
505
+ onError
506
+ }) {
507
+ const uid = react.useId();
508
+ const form = useSignInForm({ onSuccess, onError });
509
+ const firstInputRef = react.useRef(null);
510
+ react.useEffect(() => {
511
+ firstInputRef.current?.focus();
512
+ if (form.step === "mfa_setup") {
513
+ void form.mfaSetup.start();
514
+ }
515
+ }, [form.step]);
516
+ const l = {
517
+ email: labels.email ?? "Email",
518
+ password: labels.password ?? "Password",
519
+ submit: labels.submit ?? "Accedi",
520
+ mfaCode: labels.mfaCode ?? "Codice",
521
+ mfaSubmit: labels.mfaSubmit ?? "Verifica",
522
+ newPassword: labels.newPassword ?? "Nuova password",
523
+ confirmNewPassword: labels.confirmNewPassword ?? "Conferma password",
524
+ newPasswordSubmit: labels.newPasswordSubmit ?? "Imposta password",
525
+ mfaSetupScanInstruction: labels.mfaSetupScanInstruction ?? "Scansiona il QR code con la tua app authenticator (Google Authenticator, Authy, 1Password\u2026)",
526
+ mfaSetupSecretLabel: labels.mfaSetupSecretLabel ?? "Oppure inserisci il codice manualmente",
527
+ mfaSetupCode: labels.mfaSetupCode ?? "Codice a 6 cifre",
528
+ mfaSetupSubmit: labels.mfaSetupSubmit ?? "Verifica e attiva"
529
+ };
530
+ const errorId = `${uid}-error`;
531
+ if (form.step === "mfa") {
532
+ return /* @__PURE__ */ jsxRuntime.jsxs(
533
+ "form",
534
+ {
535
+ onSubmit: form.mfa.onSubmit,
536
+ className,
537
+ "aria-label": "Verifica codice MFA",
538
+ children: [
539
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
540
+ "Inserisci il codice",
541
+ " ",
542
+ form.mfaType === "TOTP" ? "dall'app authenticator" : "ricevuto via SMS"
543
+ ] }),
544
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: form.error?.message }),
545
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
546
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-mfa-code`, children: l.mfaCode }),
547
+ /* @__PURE__ */ jsxRuntime.jsx(
548
+ "input",
549
+ {
550
+ id: `${uid}-mfa-code`,
551
+ ref: firstInputRef,
552
+ type: "text",
553
+ inputMode: "numeric",
554
+ maxLength: 6,
555
+ autoComplete: "one-time-code",
556
+ autoFocus: true,
557
+ required: true,
558
+ "aria-required": "true",
559
+ "aria-invalid": !!form.error,
560
+ "aria-describedby": form.error ? errorId : void 0,
561
+ value: form.mfa.code,
562
+ onChange: (e) => form.mfa.setCode(e.target.value)
563
+ }
564
+ )
565
+ ] }),
566
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: form.isLoading, "aria-busy": form.isLoading, children: form.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
567
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "..." }),
568
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Caricamento..." })
569
+ ] }) : l.mfaSubmit })
570
+ ]
571
+ }
572
+ );
573
+ }
574
+ if (form.step === "new_password") {
575
+ return /* @__PURE__ */ jsxRuntime.jsxs(
576
+ "form",
577
+ {
578
+ onSubmit: form.newPassword.onSubmit,
579
+ className,
580
+ "aria-label": "Imposta nuova password",
581
+ children: [
582
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Devi impostare una nuova password per continuare." }),
583
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: form.error?.message }),
584
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
585
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-new-password`, children: l.newPassword }),
586
+ /* @__PURE__ */ jsxRuntime.jsx(
587
+ "input",
588
+ {
589
+ id: `${uid}-new-password`,
590
+ ref: firstInputRef,
591
+ type: "password",
592
+ autoComplete: "new-password",
593
+ autoFocus: true,
594
+ required: true,
595
+ "aria-required": "true",
596
+ "aria-invalid": !!form.error,
597
+ "aria-describedby": form.error ? errorId : void 0,
598
+ value: form.newPassword.password,
599
+ onChange: (e) => form.newPassword.setPassword(e.target.value)
600
+ }
601
+ )
602
+ ] }),
603
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
604
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-confirm-password`, children: l.confirmNewPassword }),
605
+ /* @__PURE__ */ jsxRuntime.jsx(
606
+ "input",
607
+ {
608
+ id: `${uid}-confirm-password`,
609
+ type: "password",
610
+ autoComplete: "new-password",
611
+ required: true,
612
+ "aria-required": "true",
613
+ "aria-invalid": !!form.error,
614
+ value: form.newPassword.confirmPassword,
615
+ onChange: (e) => form.newPassword.setConfirmPassword(e.target.value)
616
+ }
617
+ )
618
+ ] }),
619
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: form.isLoading, "aria-busy": form.isLoading, children: form.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
620
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "..." }),
621
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Caricamento..." })
622
+ ] }) : l.newPasswordSubmit })
623
+ ]
624
+ }
625
+ );
626
+ }
627
+ if (form.step === "mfa_setup") {
628
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
629
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: form.error?.message }),
630
+ form.isLoading && !form.mfaSetup.qrCodeUri && /* @__PURE__ */ jsxRuntime.jsx("p", { "aria-live": "polite", "aria-atomic": "true", children: "Inizializzazione in corso..." }),
631
+ form.mfaSetup.qrCodeUri && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
632
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: l.mfaSetupScanInstruction }),
633
+ renderQrCode ? renderQrCode(form.mfaSetup.qrCodeUri) : /* @__PURE__ */ jsxRuntime.jsx("code", { style: { wordBreak: "break-all", fontSize: "0.75em" }, children: form.mfaSetup.qrCodeUri }),
634
+ form.mfaSetup.secretCode && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
635
+ l.mfaSetupSecretLabel,
636
+ ": ",
637
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: form.mfaSetup.secretCode })
638
+ ] })
639
+ ] }),
640
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: form.mfaSetup.onVerify, "aria-label": "Verifica configurazione MFA", children: [
641
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
642
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-totp-code`, children: l.mfaSetupCode }),
643
+ /* @__PURE__ */ jsxRuntime.jsx(
644
+ "input",
645
+ {
646
+ id: `${uid}-totp-code`,
647
+ ref: firstInputRef,
648
+ type: "text",
649
+ inputMode: "numeric",
650
+ maxLength: 6,
651
+ autoComplete: "one-time-code",
652
+ autoFocus: true,
653
+ required: true,
654
+ "aria-required": "true",
655
+ "aria-invalid": !!form.error,
656
+ "aria-describedby": form.error ? errorId : void 0,
657
+ disabled: form.isLoading && !form.mfaSetup.qrCodeUri,
658
+ value: form.mfaSetup.totpCode,
659
+ onChange: (e) => form.mfaSetup.setTotpCode(e.target.value)
660
+ }
661
+ )
662
+ ] }),
663
+ /* @__PURE__ */ jsxRuntime.jsx(
664
+ "button",
665
+ {
666
+ type: "submit",
667
+ disabled: form.isLoading || form.mfaSetup.totpCode.length !== 6,
668
+ "aria-busy": form.isLoading,
669
+ children: form.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
670
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "..." }),
671
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Caricamento..." })
672
+ ] }) : l.mfaSetupSubmit
673
+ }
674
+ )
675
+ ] })
676
+ ] });
677
+ }
678
+ return /* @__PURE__ */ jsxRuntime.jsxs(
679
+ "form",
680
+ {
681
+ onSubmit: form.credentials.onSubmit,
682
+ className,
683
+ "aria-label": "Accedi al tuo account",
684
+ children: [
685
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: form.error?.message }),
686
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
687
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-email`, children: l.email }),
688
+ /* @__PURE__ */ jsxRuntime.jsx(
689
+ "input",
690
+ {
691
+ id: `${uid}-email`,
692
+ ref: firstInputRef,
693
+ type: "email",
694
+ autoComplete: "email",
695
+ autoFocus: true,
696
+ required: true,
697
+ "aria-required": "true",
698
+ "aria-invalid": !!form.error,
699
+ "aria-describedby": form.error ? errorId : void 0,
700
+ value: form.credentials.email,
701
+ onChange: (e) => form.credentials.setEmail(e.target.value)
702
+ }
703
+ )
704
+ ] }),
705
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
706
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-password`, children: l.password }),
707
+ /* @__PURE__ */ jsxRuntime.jsx(
708
+ "input",
709
+ {
710
+ id: `${uid}-password`,
711
+ type: "password",
712
+ autoComplete: "current-password",
713
+ required: true,
714
+ "aria-required": "true",
715
+ "aria-invalid": !!form.error,
716
+ value: form.credentials.password,
717
+ onChange: (e) => form.credentials.setPassword(e.target.value)
718
+ }
719
+ )
720
+ ] }),
721
+ forgotPasswordLink,
722
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: form.isLoading, "aria-busy": form.isLoading, children: form.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
723
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "..." }),
724
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Caricamento..." })
725
+ ] }) : l.submit }),
726
+ registerLink
727
+ ]
728
+ }
729
+ );
730
+ }
731
+ function RegisterForm({
732
+ className,
733
+ labels = {},
734
+ signInLink,
735
+ onSuccess,
736
+ onError,
737
+ extraAttributes
738
+ }) {
739
+ const uid = react.useId();
740
+ const form = useRegisterForm({ onSuccess, onError, extraAttributes });
741
+ const firstInputRef = react.useRef(null);
742
+ react.useEffect(() => {
743
+ firstInputRef.current?.focus();
744
+ }, [form.step]);
745
+ const l = {
746
+ email: labels.email ?? "Email",
747
+ password: labels.password ?? "Password",
748
+ confirmPassword: labels.confirmPassword ?? "Conferma password",
749
+ submit: labels.submit ?? "Registrati",
750
+ code: labels.code ?? "Codice di verifica",
751
+ confirmSubmit: labels.confirmSubmit ?? "Conferma",
752
+ resend: labels.resend ?? "Invia di nuovo"
753
+ };
754
+ const errorId = `${uid}-error`;
755
+ if (form.step === "confirm") {
756
+ return /* @__PURE__ */ jsxRuntime.jsxs(
757
+ "form",
758
+ {
759
+ onSubmit: form.confirm.onSubmit,
760
+ className,
761
+ "aria-label": "Conferma registrazione",
762
+ children: [
763
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
764
+ "Controlla la tua email ",
765
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: form.confirm.email }),
766
+ " e inserisci il codice ricevuto."
767
+ ] }),
768
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: form.error?.message }),
769
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
770
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-code`, children: l.code }),
771
+ /* @__PURE__ */ jsxRuntime.jsx(
772
+ "input",
773
+ {
774
+ id: `${uid}-code`,
775
+ ref: firstInputRef,
776
+ type: "text",
777
+ inputMode: "numeric",
778
+ maxLength: 6,
779
+ autoComplete: "one-time-code",
780
+ autoFocus: true,
781
+ required: true,
782
+ "aria-required": "true",
783
+ "aria-invalid": !!form.error,
784
+ "aria-describedby": form.error ? errorId : void 0,
785
+ value: form.confirm.code,
786
+ onChange: (e) => form.confirm.setCode(e.target.value)
787
+ }
788
+ )
789
+ ] }),
790
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: form.isLoading, "aria-busy": form.isLoading, children: form.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
791
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "..." }),
792
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Caricamento..." })
793
+ ] }) : l.confirmSubmit }),
794
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: form.confirm.resend, children: l.resend })
795
+ ]
796
+ }
797
+ );
798
+ }
799
+ return /* @__PURE__ */ jsxRuntime.jsxs(
800
+ "form",
801
+ {
802
+ onSubmit: form.register.onSubmit,
803
+ className,
804
+ "aria-label": "Crea un nuovo account",
805
+ children: [
806
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: form.error?.message }),
807
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
808
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-email`, children: l.email }),
809
+ /* @__PURE__ */ jsxRuntime.jsx(
810
+ "input",
811
+ {
812
+ id: `${uid}-email`,
813
+ ref: firstInputRef,
814
+ type: "email",
815
+ autoComplete: "email",
816
+ autoFocus: true,
817
+ required: true,
818
+ "aria-required": "true",
819
+ "aria-invalid": !!form.error,
820
+ "aria-describedby": form.error ? errorId : void 0,
821
+ value: form.register.email,
822
+ onChange: (e) => form.register.setEmail(e.target.value)
823
+ }
824
+ )
825
+ ] }),
826
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
827
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-password`, children: l.password }),
828
+ /* @__PURE__ */ jsxRuntime.jsx(
829
+ "input",
830
+ {
831
+ id: `${uid}-password`,
832
+ type: "password",
833
+ autoComplete: "new-password",
834
+ required: true,
835
+ "aria-required": "true",
836
+ "aria-invalid": !!form.error,
837
+ value: form.register.password,
838
+ onChange: (e) => form.register.setPassword(e.target.value)
839
+ }
840
+ )
841
+ ] }),
842
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
843
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-confirm-password`, children: l.confirmPassword }),
844
+ /* @__PURE__ */ jsxRuntime.jsx(
845
+ "input",
846
+ {
847
+ id: `${uid}-confirm-password`,
848
+ type: "password",
849
+ autoComplete: "new-password",
850
+ required: true,
851
+ "aria-required": "true",
852
+ "aria-invalid": !!form.error,
853
+ value: form.register.confirmPassword,
854
+ onChange: (e) => form.register.setConfirmPassword(e.target.value)
855
+ }
856
+ )
857
+ ] }),
858
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: form.isLoading, "aria-busy": form.isLoading, children: form.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
859
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "..." }),
860
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Caricamento..." })
861
+ ] }) : l.submit }),
862
+ signInLink
863
+ ]
864
+ }
865
+ );
866
+ }
867
+ function ForgotPasswordForm({
868
+ className,
869
+ labels = {},
870
+ signInLink,
871
+ onSuccess,
872
+ onError
873
+ }) {
874
+ const uid = react.useId();
875
+ const form = useForgotPasswordForm({ onSuccess, onError });
876
+ const firstInputRef = react.useRef(null);
877
+ react.useEffect(() => {
878
+ firstInputRef.current?.focus();
879
+ }, [form.step]);
880
+ const l = {
881
+ email: labels.email ?? "Email",
882
+ requestSubmit: labels.requestSubmit ?? "Invia codice",
883
+ code: labels.code ?? "Codice di verifica",
884
+ newPassword: labels.newPassword ?? "Nuova password",
885
+ confirmPassword: labels.confirmPassword ?? "Conferma password",
886
+ resetSubmit: labels.resetSubmit ?? "Reimposta password"
887
+ };
888
+ const errorId = `${uid}-error`;
889
+ if (form.step === "reset") {
890
+ return /* @__PURE__ */ jsxRuntime.jsxs(
891
+ "form",
892
+ {
893
+ onSubmit: form.reset.onSubmit,
894
+ className,
895
+ "aria-label": "Reimposta password",
896
+ children: [
897
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
898
+ "Abbiamo inviato un codice a ",
899
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: form.reset.email }),
900
+ "."
901
+ ] }),
902
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: form.error?.message }),
903
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
904
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-code`, children: l.code }),
905
+ /* @__PURE__ */ jsxRuntime.jsx(
906
+ "input",
907
+ {
908
+ id: `${uid}-code`,
909
+ ref: firstInputRef,
910
+ type: "text",
911
+ inputMode: "numeric",
912
+ maxLength: 6,
913
+ autoComplete: "one-time-code",
914
+ autoFocus: true,
915
+ required: true,
916
+ "aria-required": "true",
917
+ "aria-invalid": !!form.error,
918
+ "aria-describedby": form.error ? errorId : void 0,
919
+ value: form.reset.code,
920
+ onChange: (e) => form.reset.setCode(e.target.value)
921
+ }
922
+ )
923
+ ] }),
924
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
925
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-new-password`, children: l.newPassword }),
926
+ /* @__PURE__ */ jsxRuntime.jsx(
927
+ "input",
928
+ {
929
+ id: `${uid}-new-password`,
930
+ type: "password",
931
+ autoComplete: "new-password",
932
+ required: true,
933
+ "aria-required": "true",
934
+ "aria-invalid": !!form.error,
935
+ value: form.reset.newPassword,
936
+ onChange: (e) => form.reset.setNewPassword(e.target.value)
937
+ }
938
+ )
939
+ ] }),
940
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
941
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-confirm-password`, children: l.confirmPassword }),
942
+ /* @__PURE__ */ jsxRuntime.jsx(
943
+ "input",
944
+ {
945
+ id: `${uid}-confirm-password`,
946
+ type: "password",
947
+ autoComplete: "new-password",
948
+ required: true,
949
+ "aria-required": "true",
950
+ "aria-invalid": !!form.error,
951
+ value: form.reset.confirmPassword,
952
+ onChange: (e) => form.reset.setConfirmPassword(e.target.value)
953
+ }
954
+ )
955
+ ] }),
956
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: form.isLoading, "aria-busy": form.isLoading, children: form.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
957
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "..." }),
958
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Caricamento..." })
959
+ ] }) : l.resetSubmit }),
960
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: form.restart, children: "Torna all'inizio" })
961
+ ]
962
+ }
963
+ );
964
+ }
965
+ return /* @__PURE__ */ jsxRuntime.jsxs(
966
+ "form",
967
+ {
968
+ onSubmit: form.request.onSubmit,
969
+ className,
970
+ "aria-label": "Richiedi codice di reimpostazione password",
971
+ children: [
972
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Inserisci la tua email per ricevere il codice di reimpostazione." }),
973
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: form.error?.message }),
974
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
975
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-email`, children: l.email }),
976
+ /* @__PURE__ */ jsxRuntime.jsx(
977
+ "input",
978
+ {
979
+ id: `${uid}-email`,
980
+ ref: firstInputRef,
981
+ type: "email",
982
+ autoComplete: "email",
983
+ autoFocus: true,
984
+ required: true,
985
+ "aria-required": "true",
986
+ "aria-invalid": !!form.error,
987
+ "aria-describedby": form.error ? errorId : void 0,
988
+ value: form.request.email,
989
+ onChange: (e) => form.request.setEmail(e.target.value)
990
+ }
991
+ )
992
+ ] }),
993
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: form.isLoading, "aria-busy": form.isLoading, children: form.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
994
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "..." }),
995
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Caricamento..." })
996
+ ] }) : l.requestSubmit }),
997
+ signInLink
998
+ ]
999
+ }
1000
+ );
1001
+ }
1002
+ function ChangePasswordForm({
1003
+ className,
1004
+ labels = {},
1005
+ onSuccess,
1006
+ onError
1007
+ }) {
1008
+ const uid = react.useId();
1009
+ const form = useChangePasswordForm({ onSuccess, onError });
1010
+ const firstInputRef = react.useRef(null);
1011
+ const l = {
1012
+ currentPassword: labels.currentPassword ?? "Password attuale",
1013
+ newPassword: labels.newPassword ?? "Nuova password",
1014
+ confirmPassword: labels.confirmPassword ?? "Conferma nuova password",
1015
+ submit: labels.submit ?? "Cambia password",
1016
+ successMessage: labels.successMessage ?? "Password aggiornata con successo."
1017
+ };
1018
+ const errorId = `${uid}-error`;
1019
+ if (form.success) {
1020
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", children: l.successMessage });
1021
+ }
1022
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1023
+ "form",
1024
+ {
1025
+ onSubmit: form.onSubmit,
1026
+ className,
1027
+ "aria-label": "Cambia password",
1028
+ children: [
1029
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: form.error?.message }),
1030
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1031
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-current-password`, children: l.currentPassword }),
1032
+ /* @__PURE__ */ jsxRuntime.jsx(
1033
+ "input",
1034
+ {
1035
+ id: `${uid}-current-password`,
1036
+ ref: firstInputRef,
1037
+ type: "password",
1038
+ autoComplete: "current-password",
1039
+ autoFocus: true,
1040
+ required: true,
1041
+ "aria-required": "true",
1042
+ "aria-invalid": !!form.error,
1043
+ "aria-describedby": form.error ? errorId : void 0,
1044
+ value: form.currentPassword,
1045
+ onChange: (e) => form.setCurrentPassword(e.target.value)
1046
+ }
1047
+ )
1048
+ ] }),
1049
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1050
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-new-password`, children: l.newPassword }),
1051
+ /* @__PURE__ */ jsxRuntime.jsx(
1052
+ "input",
1053
+ {
1054
+ id: `${uid}-new-password`,
1055
+ type: "password",
1056
+ autoComplete: "new-password",
1057
+ required: true,
1058
+ "aria-required": "true",
1059
+ "aria-invalid": !!form.error,
1060
+ value: form.newPassword,
1061
+ onChange: (e) => form.setNewPassword(e.target.value)
1062
+ }
1063
+ )
1064
+ ] }),
1065
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1066
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-confirm-password`, children: l.confirmPassword }),
1067
+ /* @__PURE__ */ jsxRuntime.jsx(
1068
+ "input",
1069
+ {
1070
+ id: `${uid}-confirm-password`,
1071
+ type: "password",
1072
+ autoComplete: "new-password",
1073
+ required: true,
1074
+ "aria-required": "true",
1075
+ "aria-invalid": !!form.error,
1076
+ value: form.confirmPassword,
1077
+ onChange: (e) => form.setConfirmPassword(e.target.value)
1078
+ }
1079
+ )
1080
+ ] }),
1081
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: form.isLoading, "aria-busy": form.isLoading, children: form.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1082
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "..." }),
1083
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Caricamento..." })
1084
+ ] }) : l.submit })
1085
+ ]
1086
+ }
1087
+ );
1088
+ }
1089
+ function MfaSetupWizard({
1090
+ className,
1091
+ labels = {},
1092
+ renderQrCode,
1093
+ onSuccess,
1094
+ onError
1095
+ }) {
1096
+ const uid = react.useId();
1097
+ const wizard = useMfaSetup({ onSuccess, onError });
1098
+ const firstInputRef = react.useRef(null);
1099
+ react.useEffect(() => {
1100
+ firstInputRef.current?.focus();
1101
+ }, [wizard.step]);
1102
+ const l = {
1103
+ start: labels.start ?? "Configura autenticazione a due fattori (TOTP)",
1104
+ scanInstruction: labels.scanInstruction ?? "Scansiona il QR code con la tua app authenticator (Google Authenticator, Authy, 1Password\u2026)",
1105
+ manualEntry: labels.manualEntry ?? "Oppure inserisci il codice manualmente:",
1106
+ codeLabel: labels.codeLabel ?? "Codice a 6 cifre",
1107
+ verifySubmit: labels.verifySubmit ?? "Verifica e attiva",
1108
+ successMessage: labels.successMessage ?? "Autenticazione a due fattori attivata con successo."
1109
+ };
1110
+ const errorId = `${uid}-error`;
1111
+ if (wizard.step === "done") {
1112
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", children: l.successMessage });
1113
+ }
1114
+ if (wizard.step === "idle") {
1115
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
1116
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: wizard.error?.message }),
1117
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", autoFocus: true, onClick: wizard.start, children: l.start })
1118
+ ] });
1119
+ }
1120
+ if (wizard.step === "loading") {
1121
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "aria-live": "polite", "aria-atomic": "true", children: "..." });
1122
+ }
1123
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
1124
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: wizard.error?.message }),
1125
+ wizard.qrCodeUri && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1126
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: l.scanInstruction }),
1127
+ renderQrCode ? renderQrCode(wizard.qrCodeUri) : /* @__PURE__ */ jsxRuntime.jsx("code", { style: { wordBreak: "break-all", fontSize: "0.75em" }, children: wizard.qrCodeUri }),
1128
+ wizard.secretCode && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
1129
+ l.manualEntry,
1130
+ " ",
1131
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: wizard.secretCode })
1132
+ ] })
1133
+ ] }),
1134
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: wizard.onVerify, "aria-label": "Verifica dispositivo TOTP", children: [
1135
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1136
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${uid}-totp-code`, children: l.codeLabel }),
1137
+ /* @__PURE__ */ jsxRuntime.jsx(
1138
+ "input",
1139
+ {
1140
+ id: `${uid}-totp-code`,
1141
+ ref: firstInputRef,
1142
+ type: "text",
1143
+ inputMode: "numeric",
1144
+ maxLength: 6,
1145
+ autoComplete: "one-time-code",
1146
+ autoFocus: true,
1147
+ required: true,
1148
+ "aria-required": "true",
1149
+ "aria-invalid": !!wizard.error,
1150
+ "aria-describedby": wizard.error ? errorId : void 0,
1151
+ value: wizard.totpCode,
1152
+ onChange: (e) => wizard.setTotpCode(e.target.value)
1153
+ }
1154
+ )
1155
+ ] }),
1156
+ /* @__PURE__ */ jsxRuntime.jsx(
1157
+ "button",
1158
+ {
1159
+ type: "submit",
1160
+ disabled: wizard.isLoading || wizard.totpCode.length !== 6,
1161
+ "aria-busy": wizard.isLoading,
1162
+ children: wizard.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1163
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "..." }),
1164
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Caricamento..." })
1165
+ ] }) : l.verifySubmit
1166
+ }
1167
+ )
1168
+ ] })
1169
+ ] });
1170
+ }
1171
+
1172
+ exports.ChangePasswordForm = ChangePasswordForm;
1173
+ exports.ForgotPasswordForm = ForgotPasswordForm;
1174
+ exports.MfaSetupWizard = MfaSetupWizard;
1175
+ exports.RegisterForm = RegisterForm;
1176
+ exports.SignInForm = SignInForm;
1177
+ exports.useChangePasswordForm = useChangePasswordForm;
1178
+ exports.useForgotPasswordForm = useForgotPasswordForm;
1179
+ exports.useMfaSetup = useMfaSetup;
1180
+ exports.useRegisterForm = useRegisterForm;
1181
+ exports.useSignInForm = useSignInForm;
1182
+ //# sourceMappingURL=index.cjs.map
1183
+ //# sourceMappingURL=index.cjs.map