@umituz/web-dashboard 5.0.1 → 6.1.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 (120) hide show
  1. package/package.json +19 -17
  2. package/src/domains/onboarding/calc/calc.test.ts +181 -0
  3. package/src/domains/onboarding/calc/card-stack-motion-curve.ts +33 -0
  4. package/src/domains/onboarding/calc/count-with-locale.ts +16 -0
  5. package/src/domains/onboarding/calc/duration-equal-split.ts +24 -0
  6. package/src/domains/onboarding/calc/elapsed-millis.ts +12 -0
  7. package/src/domains/onboarding/calc/index.ts +36 -0
  8. package/src/domains/onboarding/calc/progress-percentage.ts +37 -0
  9. package/src/domains/onboarding/calc/slider-value-bounds.ts +44 -0
  10. package/src/domains/onboarding/calc/step-index-clamp.ts +28 -0
  11. package/src/domains/onboarding/calc/swipe-gesture-curve.ts +67 -0
  12. package/src/domains/onboarding/components/OnboardingFlow.test.tsx +481 -0
  13. package/src/domains/onboarding/components/OnboardingFlow.tsx +361 -0
  14. package/src/domains/onboarding/components/OnboardingIntl.tsx +108 -0
  15. package/src/domains/onboarding/components/hooks/index.ts +7 -0
  16. package/src/domains/onboarding/components/hooks/useOnboardingAnalytics.test.tsx +74 -0
  17. package/src/domains/onboarding/components/hooks/useOnboardingAnalytics.ts +62 -0
  18. package/src/domains/onboarding/components/hooks/useOnboardingProgress.test.tsx +150 -0
  19. package/src/domains/onboarding/components/hooks/useOnboardingProgress.ts +260 -0
  20. package/src/domains/onboarding/components/hooks/usePermissionPriming.ts +52 -0
  21. package/src/domains/onboarding/components/hooks/useReducedMotion.ts +24 -0
  22. package/src/domains/onboarding/components/screens/AccountGateScreen.tsx +89 -0
  23. package/src/domains/onboarding/components/screens/AppDemoScreen.tsx +39 -0
  24. package/src/domains/onboarding/components/screens/ComparisonScreen.tsx +59 -0
  25. package/src/domains/onboarding/components/screens/GoalQuestionScreen.tsx +56 -0
  26. package/src/domains/onboarding/components/screens/PainPointsScreen.tsx +65 -0
  27. package/src/domains/onboarding/components/screens/PaywallScreen.tsx +138 -0
  28. package/src/domains/onboarding/components/screens/PermissionPrimingScreen.tsx +113 -0
  29. package/src/domains/onboarding/components/screens/PersonalizedSolutionScreen.tsx +53 -0
  30. package/src/domains/onboarding/components/screens/PreferencesScreen.tsx +194 -0
  31. package/src/domains/onboarding/components/screens/ProcessingScreen.tsx +79 -0
  32. package/src/domains/onboarding/components/screens/SocialProofScreen.tsx +116 -0
  33. package/src/domains/onboarding/components/screens/TinderCardsScreen.tsx +108 -0
  34. package/src/domains/onboarding/components/screens/ValueDeliveryScreen.tsx +85 -0
  35. package/src/domains/onboarding/components/screens/WelcomeScreen.tsx +52 -0
  36. package/src/domains/onboarding/components/screens/index.ts +28 -0
  37. package/src/domains/onboarding/components/shared/AnimationWrapper.tsx +73 -0
  38. package/src/domains/onboarding/components/shared/OnboardingErrorBoundary.tsx +81 -0
  39. package/src/domains/onboarding/components/shared/OptionCard.tsx +73 -0
  40. package/src/domains/onboarding/components/shared/PrimaryButton.tsx +58 -0
  41. package/src/domains/onboarding/components/shared/ProgressBar.tsx +51 -0
  42. package/src/domains/onboarding/components/shared/QuestionWrapper.tsx +36 -0
  43. package/src/domains/onboarding/components/shared/ScreenContainer.tsx +29 -0
  44. package/src/domains/onboarding/components/shared/SwipeCard.test.tsx +51 -0
  45. package/src/domains/onboarding/components/shared/SwipeCard.tsx +106 -0
  46. package/src/domains/onboarding/components/shared/index.ts +16 -0
  47. package/src/domains/onboarding/components/shared/renderBundledIcon.tsx +20 -0
  48. package/src/domains/onboarding/index.ts +182 -0
  49. package/src/domains/onboarding/onboarding.css +1 -0
  50. package/src/domains/onboarding/predicates/has-handler.ts +25 -0
  51. package/src/domains/onboarding/predicates/icon-name-resolves.ts +113 -0
  52. package/src/domains/onboarding/predicates/index.ts +26 -0
  53. package/src/domains/onboarding/predicates/permission-granted.ts +26 -0
  54. package/src/domains/onboarding/predicates/permission-supports.ts +66 -0
  55. package/src/domains/onboarding/predicates/predicates.test.ts +202 -0
  56. package/src/domains/onboarding/predicates/screen-emits-data.ts +17 -0
  57. package/src/domains/onboarding/predicates/storage-available.ts +22 -0
  58. package/src/domains/onboarding/templates/TemplateDemoFallback.tsx +112 -0
  59. package/src/domains/onboarding/templates/art-onboarding.ts +81 -0
  60. package/src/domains/onboarding/templates/health-onboarding.ts +97 -0
  61. package/src/domains/onboarding/templates/index.ts +6 -0
  62. package/src/domains/onboarding/templates/platform-onboarding.ts +210 -0
  63. package/src/domains/onboarding/templates/video-onboarding.ts +100 -0
  64. package/src/domains/onboarding/test/setup.ts +30 -0
  65. package/src/domains/onboarding/theme/cn.ts +10 -0
  66. package/src/domains/onboarding/theme/index.css +131 -0
  67. package/src/domains/onboarding/theme/index.ts +12 -0
  68. package/src/domains/onboarding/theme/tokens.ts +122 -0
  69. package/src/domains/onboarding/types/config.ts +68 -0
  70. package/src/domains/onboarding/types/index.ts +10 -0
  71. package/src/domains/onboarding/types/labels.ts +83 -0
  72. package/src/domains/onboarding/types/screens.ts +193 -0
  73. package/src/domains/onboarding/utils/analytics-dispatch.test.ts +93 -0
  74. package/src/domains/onboarding/utils/analytics-dispatch.ts +92 -0
  75. package/src/domains/onboarding/utils/default-storage-key.ts +2 -0
  76. package/src/domains/onboarding/utils/index.ts +13 -0
  77. package/src/domains/onboarding/utils/local-storage-bridge.test.ts +93 -0
  78. package/src/domains/onboarding/utils/local-storage-bridge.ts +104 -0
  79. package/src/domains/onboarding/utils/permission-bridge.test.ts +64 -0
  80. package/src/domains/onboarding/utils/permission-bridge.ts +95 -0
  81. package/src/domains/onboarding/validation/flow-structure-check.ts +28 -0
  82. package/src/domains/onboarding/validation/index.ts +9 -0
  83. package/src/domains/onboarding/validation/permission-status-check.ts +23 -0
  84. package/src/domains/onboarding/validation/screen-config-check.ts +105 -0
  85. package/src/domains/onboarding/validation/stored-progress-check.ts +68 -0
  86. package/src/domains/onboarding/validation/validation.test.ts +175 -0
  87. package/src/index.ts +0 -10
  88. package/src/styles/dashboard.contract.test.ts +1 -0
  89. package/src/styles/dashboard.css +0 -460
  90. package/src/domains/auth/components/AuthLayout.tsx +0 -99
  91. package/src/domains/auth/components/ForgotPasswordForm.tsx +0 -167
  92. package/src/domains/auth/components/LoginForm.tsx +0 -222
  93. package/src/domains/auth/components/RegisterForm.tsx +0 -281
  94. package/src/domains/auth/components/ResetPasswordForm.tsx +0 -173
  95. package/src/domains/auth/components/index.ts +0 -11
  96. package/src/domains/auth/components/shared/AuthErrorBanner.tsx +0 -25
  97. package/src/domains/auth/components/shared/EmailInput.tsx +0 -73
  98. package/src/domains/auth/components/shared/PasswordInput.tsx +0 -100
  99. package/src/domains/auth/components/shared/PasswordStrengthIndicator.tsx +0 -63
  100. package/src/domains/auth/components/shared/SocialLoginButtons.tsx +0 -44
  101. package/src/domains/auth/components/shared/SocialProviderIcons.tsx +0 -48
  102. package/src/domains/auth/components/shared/index.ts +0 -20
  103. package/src/domains/auth/hooks/index.ts +0 -8
  104. package/src/domains/auth/hooks/useAuth.ts +0 -230
  105. package/src/domains/auth/index.ts +0 -62
  106. package/src/domains/auth/types/auth.ts +0 -302
  107. package/src/domains/auth/types/index.ts +0 -25
  108. package/src/domains/auth/utils/auth.test.ts +0 -188
  109. package/src/domains/auth/utils/auth.ts +0 -221
  110. package/src/domains/auth/utils/i18nKeys.ts +0 -109
  111. package/src/domains/auth/utils/index.ts +0 -29
  112. package/src/domains/auth/utils/secureToken.ts +0 -33
  113. package/src/domains/auth/utils/validationKeys.ts +0 -23
  114. package/src/domains/session/DemoLogin.tsx +0 -42
  115. package/src/domains/session/OrgSwitcher.tsx +0 -102
  116. package/src/domains/session/SessionContext.tsx +0 -150
  117. package/src/domains/session/inMemoryAuthAdapter.ts +0 -53
  118. package/src/domains/session/index.ts +0 -18
  119. package/src/domains/session/types.ts +0 -47
  120. package/src/domains/session/utils/i18nKeys.ts +0 -12
@@ -1,99 +0,0 @@
1
- import { BrandLogo } from "../../layouts/components";
2
- import { cn } from "@umituz/web-design-system/utils/cn";
3
- import { AUTH_KEYS } from "../utils/i18nKeys";
4
- import type { AuthLayoutProps, Translate } from "../types/auth";
5
-
6
- const DEFAULT_STRINGS: Record<string, string> = {
7
- [AUTH_KEYS.layout.backToHome]: "Back to home",
8
- [AUTH_KEYS.layout.orContinueWith]: "Or continue with",
9
- [AUTH_KEYS.layout.allRightsReserved]: "All rights reserved.",
10
- };
11
-
12
- export const AuthLayout = ({
13
- config,
14
- translate,
15
- onSocialLogin,
16
- children,
17
- }: AuthLayoutProps) => {
18
- const t: Translate = translate ?? ((key) => DEFAULT_STRINGS[key] ?? key);
19
- const homeRoute = config.homeRoute ?? config.afterLoginRoute;
20
- const footerLinks = config.footerLinks ?? [];
21
-
22
- return (
23
- <div className="udb-root udb-auth">
24
- <header className="udb-auth__header">
25
- <div className="udb-auth__brand">
26
- <BrandLogo size={32} />
27
- <span className="udb-auth__brand-name">{config.brandName}</span>
28
- </div>
29
-
30
- {homeRoute && (
31
- <a href={homeRoute} className="udb-auth__home-link">
32
- {t(AUTH_KEYS.layout.backToHome)}
33
- </a>
34
- )}
35
- </header>
36
-
37
- <main className="udb-auth__main">
38
- <div className="udb-auth__column">
39
- <div className="udb-auth__card">
40
- {config.brandTagline && (
41
- <p className="udb-auth__tagline">
42
- {config.brandTagline}
43
- </p>
44
- )}
45
-
46
- {children}
47
- </div>
48
-
49
- {config.showSocialLogin && config.socialProviders && config.socialProviders.length > 0 && (
50
- <div className="udb-auth__social">
51
- <div className="udb-divider-row">
52
- <span className="udb-divider-row__label">
53
- {t(AUTH_KEYS.layout.orContinueWith)}
54
- </span>
55
- </div>
56
-
57
- <div className="udb-social-grid">
58
- {config.socialProviders.map((provider) => (
59
- <button
60
- key={provider.id}
61
- type="button"
62
- className={cn("udb-social-btn")}
63
- onClick={() => onSocialLogin?.(provider.id)}
64
- >
65
- <span className="udb-social-btn__icon">{provider.icon}</span>
66
- <span>{provider.name}</span>
67
- </button>
68
- ))}
69
- </div>
70
- </div>
71
- )}
72
- </div>
73
- </main>
74
-
75
- <footer className="udb-auth__footer">
76
- <div className="udb-auth__footer-inner">
77
- <p>
78
- © {new Date().getFullYear()} {config.brandName}. {t(AUTH_KEYS.layout.allRightsReserved)}
79
- </p>
80
- {footerLinks.length > 0 && (
81
- <div className="udb-auth__footer-links">
82
- {footerLinks.map((link) => (
83
- <a
84
- key={link.href}
85
- href={link.href}
86
- className="udb-auth__footer-link"
87
- >
88
- {link.label}
89
- </a>
90
- ))}
91
- </div>
92
- )}
93
- </div>
94
- </footer>
95
- </div>
96
- );
97
- };
98
-
99
- export default AuthLayout;
@@ -1,167 +0,0 @@
1
- import { useState } from "react";
2
- import { useNavigate } from "react-router-dom";
3
- import { useT } from "@umituz/web-localization/react";
4
- import { ArrowLeft, Loader2, CheckCircle2, Check } from "lucide-react";
5
- import { Button } from "@umituz/web-design-system/atoms";
6
- import type { ForgotPasswordFormProps, Translate } from "../types/auth";
7
- import { validateForgotPassword } from "../utils/auth";
8
- import { AUTH_KEYS } from "../utils/i18nKeys";
9
- import { AUTH_VALIDATION_KEYS } from "../utils/validationKeys";
10
- import { AuthErrorBanner, EmailInput } from "./shared";
11
-
12
- const KEYS = {
13
- title: 'auth.forgotPassword.title',
14
- description: 'auth.forgotPassword.description',
15
- emailLabel: AUTH_KEYS.fields.email,
16
- emailPlaceholder: AUTH_KEYS.placeholders.emailExample,
17
- submitting: 'auth.forgotPassword.submitting',
18
- submit: 'auth.forgotPassword.submit',
19
- backToSignIn: 'auth.forgotPassword.backToSignIn',
20
- successTitle: 'auth.forgotPassword.successTitle',
21
- successMessage: 'auth.forgotPassword.successMessage',
22
- sentTo: 'auth.forgotPassword.sentTo',
23
- step1: 'auth.forgotPassword.steps.step1',
24
- step2: 'auth.forgotPassword.steps.step2',
25
- step3: 'auth.forgotPassword.steps.step3',
26
- invalidEmail: AUTH_VALIDATION_KEYS.emailInvalid,
27
- sendResetFailed: 'auth.errors.sendResetFailed',
28
- } as const;
29
-
30
- export const ForgotPasswordForm = ({
31
- config,
32
- onSuccess,
33
- onError,
34
- showBackLink = true,
35
- }: ForgotPasswordFormProps) => {
36
- const navigate = useNavigate();
37
- const t = useT();
38
- const translate: Translate = t;
39
-
40
- const [email, setEmail] = useState("");
41
- const [isLoading, setIsLoading] = useState(false);
42
- const [error, setError] = useState<string | null>(null);
43
- const [success, setSuccess] = useState(false);
44
-
45
- const handleSubmit = async (e: React.FormEvent) => {
46
- e.preventDefault();
47
- setError(null);
48
-
49
- const validation = validateForgotPassword({ email });
50
- if (!validation.valid) {
51
- const message = validation.error ?? KEYS.invalidEmail;
52
- setError(message);
53
- onError?.(message);
54
- return;
55
- }
56
-
57
- setIsLoading(true);
58
- try {
59
- await onSuccess?.({ email });
60
- setSuccess(true);
61
- } catch (err) {
62
- const message = err instanceof Error ? err.message : KEYS.sendResetFailed;
63
- setError(message);
64
- onError?.(message);
65
- } finally {
66
- setIsLoading(false);
67
- }
68
- };
69
-
70
- if (success) {
71
- return (
72
- <div className="udb-form" role="status" aria-live="polite">
73
- <div className="udb-form__header">
74
- <div className="udb-success-badge">
75
- <CheckCircle2 className="udb-success-badge__icon" aria-hidden="true" />
76
- </div>
77
- <h1 className="udb-form__title">
78
- {translate(KEYS.successTitle)}
79
- </h1>
80
- <p className="udb-form__subtitle">
81
- {translate(KEYS.sentTo)}{' '}
82
- <span className="udb-form__subtitle-strong">{email}</span>
83
- </p>
84
- </div>
85
-
86
- <ol className="udb-steps-list">
87
- <li className="udb-steps-list__item">
88
- <Check className="udb-steps-list__icon" aria-hidden="true" />
89
- {translate(KEYS.step1)}
90
- </li>
91
- <li className="udb-steps-list__item">
92
- <Check className="udb-steps-list__icon" aria-hidden="true" />
93
- {translate(KEYS.step2)}
94
- </li>
95
- <li className="udb-steps-list__item">
96
- <Check className="udb-steps-list__icon" aria-hidden="true" />
97
- {translate(KEYS.step3)}
98
- </li>
99
- </ol>
100
-
101
- {showBackLink && config.loginRoute && (
102
- <Button
103
- type="button"
104
- variant="ghost"
105
- onClick={() => navigate(config.loginRoute)}
106
- className="udb-submit-btn"
107
- >
108
- <ArrowLeft className="udb-btn__spinner" aria-hidden="true" />
109
- {translate(KEYS.backToSignIn)}
110
- </Button>
111
- )}
112
- </div>
113
- );
114
- }
115
-
116
- return (
117
- <form onSubmit={handleSubmit} className="udb-form" noValidate>
118
- <div className="udb-form__header">
119
- <h1 className="udb-form__title udb-form__title--lg">
120
- {translate(KEYS.title)}
121
- </h1>
122
- <p className="udb-form__subtitle">{translate(KEYS.description)}</p>
123
- </div>
124
-
125
- <AuthErrorBanner message={error} translate={translate} />
126
-
127
- <EmailInput
128
- id="forgot-email"
129
- labelKey={KEYS.emailLabel}
130
- placeholderKey={KEYS.emailPlaceholder}
131
- value={email}
132
- onChange={setEmail}
133
- translate={translate}
134
- disabled={isLoading}
135
- required
136
- />
137
-
138
- <Button
139
- type="submit"
140
- className="udb-submit-btn udb-submit-btn--pill"
141
- disabled={isLoading}
142
- >
143
- {isLoading ? (
144
- <>
145
- <Loader2 className="udb-btn__spinner" aria-hidden="true" />
146
- {translate(KEYS.submitting)}
147
- </>
148
- ) : (
149
- translate(KEYS.submit)
150
- )}
151
- </Button>
152
-
153
- {showBackLink && config.loginRoute && (
154
- <button
155
- type="button"
156
- onClick={() => navigate(config.loginRoute)}
157
- className="udb-back-link"
158
- >
159
- <ArrowLeft className="udb-back-link__icon" aria-hidden="true" />
160
- {translate(KEYS.backToSignIn)}
161
- </button>
162
- )}
163
- </form>
164
- );
165
- };
166
-
167
- export default ForgotPasswordForm;
@@ -1,222 +0,0 @@
1
- import { useState, useCallback } from "react";
2
- import { useNavigate } from "react-router-dom";
3
- import { useT } from "@umituz/web-localization/react";
4
- import { Button, Checkbox } from "@umituz/web-design-system/atoms";
5
- import { Loader2 } from "lucide-react";
6
- import { validateLogin } from "../utils/auth";
7
- import type {
8
- LoginFormProps,
9
- LoginCredentials,
10
- User,
11
- Translate,
12
- } from "../types/auth";
13
- import {
14
- AuthErrorBanner,
15
- EmailInput,
16
- PasswordInput,
17
- SocialLoginButtons,
18
- } from "./shared";
19
-
20
- const KEYS = {
21
- welcomeBack: 'auth.login.welcomeBack',
22
- signInTo: 'auth.login.signInTo',
23
- emailLabel: 'auth.fields.email',
24
- emailPlaceholder: 'auth.placeholders.emailExample',
25
- passwordLabel: 'auth.fields.password',
26
- passwordPlaceholder: 'auth.placeholders.password',
27
- rememberMe: 'auth.login.rememberMe',
28
- forgotPassword: 'auth.login.forgotPassword',
29
- submit: 'auth.login.submit',
30
- submitting: 'auth.login.submitting',
31
- noAccount: 'auth.login.noAccount',
32
- signUp: 'auth.login.signUp',
33
- orContinueWith: 'auth.login.orContinueWith',
34
- invalidCredentials: 'auth.errors.invalidCredentials',
35
- loginFailed: 'auth.errors.loginFailed',
36
- noAuthProvider: 'auth.errors.noAuthProvider',
37
- } as const;
38
-
39
- export const LoginForm = ({
40
- config,
41
- defaultCredentials,
42
- showRememberMe = true,
43
- showForgotPassword = true,
44
- showRegisterLink = true,
45
- showSocialLogin = true,
46
- enableMockAuth = false,
47
- onLoginAttempt,
48
- onLoginSuccess,
49
- onLoginError,
50
- onGoogleLogin,
51
- onAppleLogin,
52
- }: LoginFormProps) => {
53
- const navigate = useNavigate();
54
- const t = useT();
55
- const translate: Translate = t;
56
-
57
- const [email, setEmail] = useState<string>(defaultCredentials?.email ?? "");
58
- const [password, setPassword] = useState<string>(defaultCredentials?.password ?? "");
59
- const [remember, setRemember] = useState<boolean>(false);
60
- const [loading, setLoading] = useState<boolean>(false);
61
- const [error, setError] = useState<string | null>(null);
62
-
63
- const performLogin = useCallback(
64
- async (credentials: LoginCredentials): Promise<User> => {
65
- if (onLoginAttempt) {
66
- return onLoginAttempt(credentials);
67
- }
68
- if (!enableMockAuth) {
69
- throw new Error(KEYS.noAuthProvider);
70
- }
71
- await new Promise((resolve) => setTimeout(resolve, 1000));
72
- return {
73
- id: "1",
74
- email: credentials.email,
75
- name: credentials.email.split("@")[0],
76
- };
77
- },
78
- [onLoginAttempt, enableMockAuth],
79
- );
80
-
81
- const handleSubmit = useCallback(
82
- async (e: React.FormEvent) => {
83
- e.preventDefault();
84
- setError(null);
85
-
86
- const validation = validateLogin({ email, password });
87
- if (!validation.valid) {
88
- const message = validation.error ?? KEYS.invalidCredentials;
89
- setError(message);
90
- onLoginError?.(message);
91
- return;
92
- }
93
-
94
- setLoading(true);
95
- try {
96
- const user = await performLogin({ email, password });
97
- await onLoginSuccess?.(user);
98
- navigate(config.afterLoginRoute);
99
- } catch (err) {
100
- const message = err instanceof Error ? err.message : KEYS.loginFailed;
101
- setError(message);
102
- onLoginError?.(message);
103
- } finally {
104
- setLoading(false);
105
- }
106
- },
107
- [email, password, performLogin, navigate, config.afterLoginRoute, onLoginSuccess, onLoginError],
108
- );
109
-
110
- const handleSocial = useCallback(
111
- (provider: 'google' | 'apple') => {
112
- if (provider === 'google') onGoogleLogin?.();
113
- if (provider === 'apple') onAppleLogin?.();
114
- },
115
- [onGoogleLogin, onAppleLogin],
116
- );
117
-
118
- return (
119
- <form onSubmit={handleSubmit} className="udb-form" noValidate>
120
- <div className="udb-form__header">
121
- <h1 className="udb-form__title">
122
- {translate(KEYS.welcomeBack)}
123
- </h1>
124
- <p className="udb-form__subtitle">
125
- {translate(KEYS.signInTo, { brand: config.brandName })}
126
- </p>
127
- </div>
128
-
129
- <AuthErrorBanner message={error} translate={translate} />
130
-
131
- <EmailInput
132
- id="login-email"
133
- labelKey={KEYS.emailLabel}
134
- placeholderKey={KEYS.emailPlaceholder}
135
- value={email}
136
- onChange={setEmail}
137
- translate={translate}
138
- disabled={loading}
139
- required
140
- />
141
-
142
- <PasswordInput
143
- id="login-password"
144
- labelKey={KEYS.passwordLabel}
145
- placeholderKey={KEYS.passwordPlaceholder}
146
- value={password}
147
- onChange={setPassword}
148
- translate={translate}
149
- autoComplete="current-password"
150
- disabled={loading}
151
- required
152
- />
153
-
154
- {(showRememberMe || showForgotPassword) && (
155
- <div className="udb-form__row">
156
- {showRememberMe && (
157
- <label className="udb-check-label">
158
- <Checkbox
159
- checked={remember}
160
- onCheckedChange={(checked) => setRemember(Boolean(checked))}
161
- disabled={loading}
162
- />
163
- {translate(KEYS.rememberMe)}
164
- </label>
165
- )}
166
- {showForgotPassword && (
167
- <button
168
- type="button"
169
- onClick={() => navigate(config.forgotPasswordRoute ?? '/forgot-password')}
170
- className="udb-link-btn"
171
- disabled={loading}
172
- >
173
- {translate(KEYS.forgotPassword)}
174
- </button>
175
- )}
176
- </div>
177
- )}
178
-
179
- <Button type="submit" disabled={loading} className="udb-submit-btn">
180
- {loading ? (
181
- <>
182
- <Loader2 className="udb-btn__spinner" aria-hidden="true" />
183
- {translate(KEYS.submitting)}
184
- </>
185
- ) : (
186
- translate(KEYS.submit)
187
- )}
188
- </Button>
189
-
190
- {showRegisterLink && (
191
- <p className="udb-form__footer-text">
192
- {translate(KEYS.noAccount)}{' '}
193
- <button
194
- type="button"
195
- onClick={() => navigate(config.registerRoute)}
196
- className="udb-link-btn udb-link-btn--strong"
197
- disabled={loading}
198
- >
199
- {translate(KEYS.signUp)}
200
- </button>
201
- </p>
202
- )}
203
-
204
- {showSocialLogin && (
205
- <>
206
- <div className="udb-divider-row">
207
- <span className="udb-divider-row__label">
208
- {translate(KEYS.orContinueWith)}
209
- </span>
210
- </div>
211
- <SocialLoginButtons
212
- onProvider={handleSocial}
213
- translate={translate}
214
- disabled={loading}
215
- />
216
- </>
217
- )}
218
- </form>
219
- );
220
- };
221
-
222
- export default LoginForm;