@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,281 +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 { Loader2 } from "lucide-react";
5
- import { Button, Checkbox, Input } from "@umituz/web-design-system/atoms";
6
- import { cn } from "@umituz/web-design-system/utils/cn";
7
- import type { RegisterFormProps, RegisterData, Translate } from "../types/auth";
8
- import { validateRegister } from "../utils/auth";
9
- import { AUTH_KEYS } from "../utils/i18nKeys";
10
- import { AUTH_VALIDATION_KEYS } from "../utils/validationKeys";
11
- import {
12
- AuthErrorBanner,
13
- EmailInput,
14
- PasswordInput,
15
- PasswordStrengthIndicator,
16
- SocialLoginButtons,
17
- } from "./shared";
18
-
19
- const KEYS = {
20
- title: 'auth.register.createAccount',
21
- join: 'auth.register.join',
22
- nameLabel: 'auth.fields.name',
23
- namePlaceholder: 'auth.placeholders.fullName',
24
- emailLabel: AUTH_KEYS.fields.email,
25
- emailPlaceholder: AUTH_KEYS.placeholders.emailExample,
26
- passwordLabel: AUTH_KEYS.fields.password,
27
- passwordPlaceholder: AUTH_KEYS.placeholders.password,
28
- confirmPassword: 'auth.register.confirmPassword',
29
- submit: 'auth.register.submit',
30
- submitting: 'auth.register.submitting',
31
- acceptTerms: 'auth.register.acceptTerms',
32
- termsOfService: 'auth.register.termsOfService',
33
- privacyPolicy: 'auth.register.privacyPolicy',
34
- haveAccount: 'auth.register.haveAccount',
35
- signIn: 'auth.register.signIn',
36
- orContinueWith: 'auth.login.orContinueWith',
37
- invalidData: 'auth.errors.registrationFailed',
38
- mustAcceptTerms: 'auth.register.mustAcceptTerms',
39
- passwordsDoNotMatch: AUTH_VALIDATION_KEYS.passwordsDoNotMatch,
40
- } as const;
41
-
42
- export const RegisterForm = ({
43
- config,
44
- defaultData = {},
45
- showTerms = true,
46
- showLoginLink = true,
47
- requirePasswordConfirm = true,
48
- showSocialLogin = true,
49
- onRegisterAttempt,
50
- onRegisterSuccess,
51
- onRegisterError,
52
- onGoogleLogin,
53
- onAppleLogin,
54
- }: RegisterFormProps) => {
55
- const navigate = useNavigate();
56
- const t = useT();
57
- const translate: Translate = t;
58
-
59
- const [name, setName] = useState<string>(defaultData.name ?? '');
60
- const [email, setEmail] = useState<string>(defaultData.email ?? '');
61
- const [password, setPassword] = useState<string>(defaultData.password ?? '');
62
- const [confirmPassword, setConfirmPassword] = useState<string>('');
63
- const [agreeToTerms, setAgreeToTerms] = useState<boolean>(false);
64
- const [isLoading, setIsLoading] = useState<boolean>(false);
65
- const [error, setError] = useState<string | null>(null);
66
-
67
- const passwordsMatch = !requirePasswordConfirm || password === confirmPassword;
68
-
69
- const handleSubmit = useCallback(
70
- async (e: React.FormEvent) => {
71
- e.preventDefault();
72
- setError(null);
73
-
74
- const validation = validateRegister(
75
- { email, password, name, confirmPassword },
76
- false,
77
- requirePasswordConfirm,
78
- );
79
- if (!validation.valid) {
80
- const message = validation.error ?? KEYS.invalidData;
81
- setError(message);
82
- onRegisterError?.(message);
83
- return;
84
- }
85
-
86
- if (showTerms && !agreeToTerms) {
87
- setError(KEYS.mustAcceptTerms);
88
- onRegisterError?.(KEYS.mustAcceptTerms);
89
- return;
90
- }
91
-
92
- setIsLoading(true);
93
- try {
94
- if (!onRegisterAttempt) {
95
- throw new Error('No register handler configured');
96
- }
97
- const registerData: RegisterData = { email, password, name };
98
- const user = await onRegisterAttempt(registerData);
99
- await onRegisterSuccess?.(user);
100
- navigate(config.afterLoginRoute);
101
- } catch (err) {
102
- const message = err instanceof Error ? err.message : KEYS.invalidData;
103
- setError(message);
104
- onRegisterError?.(message);
105
- } finally {
106
- setIsLoading(false);
107
- }
108
- },
109
- [
110
- agreeToTerms,
111
- config.afterLoginRoute,
112
- confirmPassword,
113
- email,
114
- name,
115
- navigate,
116
- onRegisterAttempt,
117
- onRegisterError,
118
- onRegisterSuccess,
119
- password,
120
- requirePasswordConfirm,
121
- showTerms,
122
- ],
123
- );
124
-
125
- const handleSocial = useCallback(
126
- (provider: 'google' | 'apple') => {
127
- if (provider === 'google') onGoogleLogin?.();
128
- if (provider === 'apple') onAppleLogin?.();
129
- },
130
- [onGoogleLogin, onAppleLogin],
131
- );
132
-
133
- return (
134
- <form onSubmit={handleSubmit} className="udb-form" noValidate>
135
- <div className="udb-form__header">
136
- <h1 className="udb-form__title udb-form__title--lg">
137
- {translate(KEYS.title)}
138
- </h1>
139
- <p className="udb-form__subtitle">
140
- {translate(KEYS.join, { brand: config.brandName })}
141
- </p>
142
- </div>
143
-
144
- <AuthErrorBanner message={error} translate={translate} />
145
-
146
- <div className="udb-field">
147
- <label htmlFor="register-name" className="udb-field__label">
148
- {translate(KEYS.nameLabel)}
149
- </label>
150
- <Input
151
- id="register-name"
152
- type="text"
153
- autoComplete="name"
154
- disabled={isLoading}
155
- value={name}
156
- placeholder={translate(KEYS.namePlaceholder)}
157
- onChange={(e) => setName(e.target.value)}
158
- />
159
- </div>
160
-
161
- <EmailInput
162
- id="register-email"
163
- labelKey={KEYS.emailLabel}
164
- placeholderKey={KEYS.emailPlaceholder}
165
- value={email}
166
- onChange={setEmail}
167
- translate={translate}
168
- disabled={isLoading}
169
- required
170
- />
171
-
172
- <div className="udb-form__group">
173
- <PasswordInput
174
- id="register-password"
175
- labelKey={KEYS.passwordLabel}
176
- placeholderKey={KEYS.passwordPlaceholder}
177
- value={password}
178
- onChange={setPassword}
179
- translate={translate}
180
- autoComplete="new-password"
181
- disabled={isLoading}
182
- required
183
- />
184
- <PasswordStrengthIndicator password={password} translate={translate} />
185
- </div>
186
-
187
- {requirePasswordConfirm && (
188
- <div className="udb-field">
189
- <label htmlFor="register-confirm" className="udb-field__label">
190
- {translate(KEYS.confirmPassword)}
191
- <span className="udb-field__required" aria-hidden="true">*</span>
192
- </label>
193
- <Input
194
- id="register-confirm"
195
- type="password"
196
- autoComplete="new-password"
197
- required
198
- disabled={isLoading}
199
- value={confirmPassword}
200
- placeholder={translate(KEYS.passwordPlaceholder)}
201
- onChange={(e) => setConfirmPassword(e.target.value)}
202
- aria-invalid={Boolean(confirmPassword) && !passwordsMatch}
203
- className={cn(confirmPassword && !passwordsMatch && 'udb-input--error')}
204
- />
205
- {confirmPassword && !passwordsMatch && (
206
- <p className="udb-field__error" role="alert">
207
- {translate(KEYS.passwordsDoNotMatch)}
208
- </p>
209
- )}
210
- </div>
211
- )}
212
-
213
- {showTerms && (
214
- <label className="udb-check-label udb-check-label--multiline">
215
- <Checkbox
216
- checked={agreeToTerms}
217
- onCheckedChange={(checked) => setAgreeToTerms(Boolean(checked))}
218
- disabled={isLoading}
219
- aria-label={translate(KEYS.acceptTerms)}
220
- />
221
- <span className="udb-check-label__text">
222
- {translate(KEYS.acceptTerms)}{' '}
223
- <a href="/terms" className="udb-text-link">
224
- {translate(KEYS.termsOfService)}
225
- </a>{' '}
226
- and{' '}
227
- <a href="/privacy" className="udb-text-link">
228
- {translate(KEYS.privacyPolicy)}
229
- </a>
230
- </span>
231
- </label>
232
- )}
233
-
234
- <Button
235
- type="submit"
236
- className="udb-submit-btn udb-submit-btn--pill"
237
- disabled={isLoading || (requirePasswordConfirm && !passwordsMatch)}
238
- >
239
- {isLoading ? (
240
- <>
241
- <Loader2 className="udb-btn__spinner" aria-hidden="true" />
242
- {translate(KEYS.submitting)}
243
- </>
244
- ) : (
245
- translate(KEYS.submit)
246
- )}
247
- </Button>
248
-
249
- {showLoginLink && config.loginRoute && (
250
- <p className="udb-form__footer-text">
251
- {translate(KEYS.haveAccount)}{' '}
252
- <button
253
- type="button"
254
- onClick={() => navigate(config.loginRoute)}
255
- className="udb-link-btn udb-link-btn--strong"
256
- disabled={isLoading}
257
- >
258
- {translate(KEYS.signIn)}
259
- </button>
260
- </p>
261
- )}
262
-
263
- {showSocialLogin && config.showSocialLogin && config.socialProviders && config.socialProviders.length > 0 && (
264
- <>
265
- <div className="udb-divider-row">
266
- <span className="udb-divider-row__label">
267
- {translate(KEYS.orContinueWith)}
268
- </span>
269
- </div>
270
- <SocialLoginButtons
271
- onProvider={handleSocial}
272
- translate={translate}
273
- disabled={isLoading}
274
- />
275
- </>
276
- )}
277
- </form>
278
- );
279
- };
280
-
281
- export default RegisterForm;
@@ -1,173 +0,0 @@
1
- import { useState } from "react";
2
- import { useNavigate } from "react-router-dom";
3
- import { useT } from "@umituz/web-localization/react";
4
- import { Loader2, CheckCircle2 } from "lucide-react";
5
- import { Button, Input } from "@umituz/web-design-system/atoms";
6
- import { cn } from "@umituz/web-design-system/utils/cn";
7
- import type { ResetPasswordFormProps, Translate } from "../types/auth";
8
- import { validateResetPassword } from "../utils/auth";
9
- import { AUTH_KEYS } from "../utils/i18nKeys";
10
- import { AUTH_VALIDATION_KEYS } from "../utils/validationKeys";
11
- import {
12
- AuthErrorBanner,
13
- PasswordInput,
14
- PasswordStrengthIndicator,
15
- } from "./shared";
16
-
17
- const KEYS = {
18
- title: 'auth.resetPassword.title',
19
- description: 'auth.resetPassword.description',
20
- newPassword: 'auth.resetPassword.newPassword',
21
- confirmNewPassword: 'auth.resetPassword.confirmNewPassword',
22
- passwordsDoNotMatch: AUTH_VALIDATION_KEYS.passwordsDoNotMatch,
23
- submit: 'auth.resetPassword.submit',
24
- submitting: 'auth.resetPassword.submitting',
25
- successTitle: 'auth.resetPassword.successTitle',
26
- successMessage: 'auth.resetPassword.successMessage',
27
- goToSignIn: 'auth.resetPassword.goToSignIn',
28
- invalidResetData: AUTH_VALIDATION_KEYS.passwordTooShort,
29
- resetFailed: 'auth.errors.resetFailed',
30
- } as const;
31
-
32
- export const ResetPasswordForm = ({
33
- config,
34
- token,
35
- onSuccess,
36
- onError,
37
- }: ResetPasswordFormProps) => {
38
- const navigate = useNavigate();
39
- const t = useT();
40
- const translate: Translate = t;
41
-
42
- const [password, setPassword] = useState("");
43
- const [confirmPassword, setConfirmPassword] = useState("");
44
- const [isLoading, setIsLoading] = useState(false);
45
- const [error, setError] = useState<string | null>(null);
46
- const [success, setSuccess] = useState(false);
47
-
48
- const passwordsMatch = password === confirmPassword;
49
-
50
- const handleSubmit = async (e: React.FormEvent) => {
51
- e.preventDefault();
52
- setError(null);
53
-
54
- const validation = validateResetPassword({ token, password, confirmPassword });
55
- if (!validation.valid) {
56
- const message = validation.error ?? KEYS.invalidResetData;
57
- setError(message);
58
- onError?.(message);
59
- return;
60
- }
61
-
62
- setIsLoading(true);
63
- try {
64
- await onSuccess?.({ token, password });
65
- setPassword("");
66
- setConfirmPassword("");
67
- setSuccess(true);
68
- } catch (err) {
69
- const message = err instanceof Error ? err.message : KEYS.resetFailed;
70
- setError(message);
71
- onError?.(message);
72
- } finally {
73
- setIsLoading(false);
74
- }
75
- };
76
-
77
- if (success) {
78
- return (
79
- <div className="udb-form" role="status" aria-live="polite">
80
- <div className="udb-form__header">
81
- <div className="udb-success-badge">
82
- <CheckCircle2 className="udb-success-badge__icon" aria-hidden="true" />
83
- </div>
84
- <h1 className="udb-form__title">
85
- {translate(KEYS.successTitle)}
86
- </h1>
87
- <p className="udb-form__subtitle">
88
- {translate(KEYS.successMessage)}
89
- </p>
90
- </div>
91
-
92
- {config.loginRoute && (
93
- <Button
94
- type="button"
95
- onClick={() => navigate(config.loginRoute)}
96
- className="udb-submit-btn udb-submit-btn--pill"
97
- >
98
- {translate(KEYS.goToSignIn)}
99
- </Button>
100
- )}
101
- </div>
102
- );
103
- }
104
-
105
- return (
106
- <form onSubmit={handleSubmit} className="udb-form" noValidate>
107
- <div className="udb-form__header">
108
- <h1 className="udb-form__title udb-form__title--lg">
109
- {translate(KEYS.title)}
110
- </h1>
111
- <p className="udb-form__subtitle">{translate(KEYS.description)}</p>
112
- </div>
113
-
114
- <AuthErrorBanner message={error} translate={translate} />
115
-
116
- <div className="udb-form__group">
117
- <PasswordInput
118
- id="reset-password"
119
- labelKey={KEYS.newPassword}
120
- placeholderKey={AUTH_KEYS.placeholders.password}
121
- value={password}
122
- onChange={setPassword}
123
- translate={translate}
124
- autoComplete="new-password"
125
- disabled={isLoading}
126
- required
127
- />
128
- <PasswordStrengthIndicator password={password} translate={translate} />
129
- </div>
130
-
131
- <div className="udb-field">
132
- <label htmlFor="reset-confirm" className="udb-field__label">
133
- {translate(KEYS.confirmNewPassword)}
134
- <span className="udb-field__required" aria-hidden="true">*</span>
135
- </label>
136
- <Input
137
- id="reset-confirm"
138
- type="password"
139
- autoComplete="new-password"
140
- required
141
- disabled={isLoading}
142
- value={confirmPassword}
143
- placeholder={translate(AUTH_KEYS.placeholders.password)}
144
- onChange={(e) => setConfirmPassword(e.target.value)}
145
- aria-invalid={Boolean(confirmPassword) && !passwordsMatch}
146
- className={cn(confirmPassword && !passwordsMatch && 'udb-input--error')}
147
- />
148
- {confirmPassword && !passwordsMatch && (
149
- <p className="udb-field__error" role="alert">
150
- {translate(KEYS.passwordsDoNotMatch)}
151
- </p>
152
- )}
153
- </div>
154
-
155
- <Button
156
- type="submit"
157
- className="udb-submit-btn udb-submit-btn--pill"
158
- disabled={isLoading || !passwordsMatch}
159
- >
160
- {isLoading ? (
161
- <>
162
- <Loader2 className="udb-btn__spinner" aria-hidden="true" />
163
- {translate(KEYS.submitting)}
164
- </>
165
- ) : (
166
- translate(KEYS.submit)
167
- )}
168
- </Button>
169
- </form>
170
- );
171
- };
172
-
173
- export default ResetPasswordForm;
@@ -1,11 +0,0 @@
1
- /**
2
- * Auth Components
3
- *
4
- * Export all auth components
5
- */
6
-
7
- export { AuthLayout } from "./AuthLayout";
8
- export { LoginForm } from "./LoginForm";
9
- export { RegisterForm } from "./RegisterForm";
10
- export { ForgotPasswordForm } from "./ForgotPasswordForm";
11
- export { ResetPasswordForm } from "./ResetPasswordForm";
@@ -1,25 +0,0 @@
1
- import { AlertCircle } from "lucide-react";
2
- import { cn } from "@umituz/web-design-system/utils/cn";
3
-
4
- export interface AuthErrorBannerProps {
5
- message?: string | null;
6
- translate: (key: string) => string;
7
- className?: string;
8
- }
9
-
10
- export const AuthErrorBanner = ({ message, translate, className }: AuthErrorBannerProps) => {
11
- if (!message) return null;
12
-
13
- const resolved = message.includes('.') ? translate(message) : message;
14
-
15
- return (
16
- <div
17
- role="alert"
18
- aria-live="polite"
19
- className={cn("udb-form-alert", className)}
20
- >
21
- <AlertCircle className="udb-form-alert__icon" aria-hidden="true" />
22
- <span>{resolved}</span>
23
- </div>
24
- );
25
- };
@@ -1,73 +0,0 @@
1
- import { forwardRef } from "react";
2
- import { Input } from "@umituz/web-design-system/atoms";
3
- import { cn } from "@umituz/web-design-system/utils/cn";
4
-
5
- export interface EmailInputProps {
6
- id: string;
7
- labelKey: string;
8
- placeholderKey: string;
9
- value: string;
10
- onChange: (value: string) => void;
11
- translate: (key: string) => string;
12
- autoComplete?: string;
13
- disabled?: boolean;
14
- required?: boolean;
15
- error?: string | null;
16
- className?: string;
17
- }
18
-
19
- export const EmailInput = forwardRef<HTMLInputElement, EmailInputProps>(
20
- (
21
- {
22
- id,
23
- labelKey,
24
- placeholderKey,
25
- value,
26
- onChange,
27
- translate,
28
- autoComplete = "email",
29
- disabled = false,
30
- required = false,
31
- error = null,
32
- className,
33
- },
34
- ref,
35
- ) => {
36
- return (
37
- <div className={cn("udb-field", className)}>
38
- <label htmlFor={id} className="udb-field__label">
39
- {translate(labelKey)}
40
- {required && (
41
- <span className="udb-field__required" aria-hidden="true">
42
- *
43
- </span>
44
- )}
45
- </label>
46
- <Input
47
- ref={ref}
48
- id={id}
49
- type="email"
50
- autoComplete={autoComplete}
51
- required={required}
52
- disabled={disabled}
53
- value={value}
54
- placeholder={translate(placeholderKey)}
55
- onChange={(e) => onChange(e.target.value)}
56
- aria-invalid={Boolean(error)}
57
- aria-describedby={error ? `${id}-error` : undefined}
58
- />
59
- {error && (
60
- <p
61
- id={`${id}-error`}
62
- className="udb-field__error"
63
- role="alert"
64
- >
65
- {error}
66
- </p>
67
- )}
68
- </div>
69
- );
70
- },
71
- );
72
-
73
- EmailInput.displayName = "EmailInput";
@@ -1,100 +0,0 @@
1
- import { forwardRef, useState } from "react";
2
- import { Eye, EyeOff } from "lucide-react";
3
- import { Input } from "@umituz/web-design-system/atoms";
4
- import { Button } from "@umituz/web-design-system/atoms";
5
- import { cn } from "@umituz/web-design-system/utils/cn";
6
-
7
- export interface PasswordInputProps {
8
- id: string;
9
- labelKey: string;
10
- placeholderKey: string;
11
- value: string;
12
- onChange: (value: string) => void;
13
- translate: (key: string) => string;
14
- autoComplete?: string;
15
- disabled?: boolean;
16
- required?: boolean;
17
- error?: string | null;
18
- className?: string;
19
- }
20
-
21
- export const PasswordInput = forwardRef<HTMLInputElement, PasswordInputProps>(
22
- (
23
- {
24
- id,
25
- labelKey,
26
- placeholderKey,
27
- value,
28
- onChange,
29
- translate,
30
- autoComplete = "current-password",
31
- disabled = false,
32
- required = false,
33
- error = null,
34
- className,
35
- },
36
- ref,
37
- ) => {
38
- const [visible, setVisible] = useState(false);
39
-
40
- return (
41
- <div className={cn("udb-field", className)}>
42
- <label htmlFor={id} className="udb-field__label">
43
- {translate(labelKey)}
44
- {required && (
45
- <span className="udb-field__required" aria-hidden="true">
46
- *
47
- </span>
48
- )}
49
- </label>
50
- <div className="udb-password-wrap">
51
- <Input
52
- ref={ref}
53
- id={id}
54
- type={visible ? "text" : "password"}
55
- autoComplete={autoComplete}
56
- required={required}
57
- disabled={disabled}
58
- value={value}
59
- placeholder={translate(placeholderKey)}
60
- onChange={(e) => onChange(e.target.value)}
61
- aria-invalid={Boolean(error)}
62
- aria-describedby={error ? `${id}-error` : undefined}
63
- className="udb-input--with-toggle"
64
- />
65
- <Button
66
- type="button"
67
- variant="ghost"
68
- size="icon"
69
- tabIndex={-1}
70
- onClick={() => setVisible((prev) => !prev)}
71
- disabled={disabled}
72
- aria-label={
73
- visible
74
- ? translate('auth.a11y.hidePassword')
75
- : translate('auth.a11y.showPassword')
76
- }
77
- className="udb-password-toggle"
78
- >
79
- {visible ? (
80
- <EyeOff className="udb-password-toggle__icon" aria-hidden="true" />
81
- ) : (
82
- <Eye className="udb-password-toggle__icon" aria-hidden="true" />
83
- )}
84
- </Button>
85
- </div>
86
- {error && (
87
- <p
88
- id={`${id}-error`}
89
- className="udb-field__error"
90
- role="alert"
91
- >
92
- {error}
93
- </p>
94
- )}
95
- </div>
96
- );
97
- },
98
- );
99
-
100
- PasswordInput.displayName = "PasswordInput";