@umituz/web-dashboard 5.0.0 → 6.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 (35) hide show
  1. package/README.md +4 -3
  2. package/package.json +2 -12
  3. package/src/index.ts +0 -10
  4. package/src/styles/dashboard.css +93 -544
  5. package/src/domains/auth/components/AuthLayout.tsx +0 -99
  6. package/src/domains/auth/components/ForgotPasswordForm.tsx +0 -167
  7. package/src/domains/auth/components/LoginForm.tsx +0 -222
  8. package/src/domains/auth/components/RegisterForm.tsx +0 -281
  9. package/src/domains/auth/components/ResetPasswordForm.tsx +0 -173
  10. package/src/domains/auth/components/index.ts +0 -11
  11. package/src/domains/auth/components/shared/AuthErrorBanner.tsx +0 -25
  12. package/src/domains/auth/components/shared/EmailInput.tsx +0 -73
  13. package/src/domains/auth/components/shared/PasswordInput.tsx +0 -100
  14. package/src/domains/auth/components/shared/PasswordStrengthIndicator.tsx +0 -63
  15. package/src/domains/auth/components/shared/SocialLoginButtons.tsx +0 -44
  16. package/src/domains/auth/components/shared/SocialProviderIcons.tsx +0 -48
  17. package/src/domains/auth/components/shared/index.ts +0 -20
  18. package/src/domains/auth/hooks/index.ts +0 -8
  19. package/src/domains/auth/hooks/useAuth.ts +0 -230
  20. package/src/domains/auth/index.ts +0 -62
  21. package/src/domains/auth/types/auth.ts +0 -302
  22. package/src/domains/auth/types/index.ts +0 -25
  23. package/src/domains/auth/utils/auth.test.ts +0 -188
  24. package/src/domains/auth/utils/auth.ts +0 -221
  25. package/src/domains/auth/utils/i18nKeys.ts +0 -109
  26. package/src/domains/auth/utils/index.ts +0 -29
  27. package/src/domains/auth/utils/secureToken.ts +0 -33
  28. package/src/domains/auth/utils/validationKeys.ts +0 -23
  29. package/src/domains/session/DemoLogin.tsx +0 -42
  30. package/src/domains/session/OrgSwitcher.tsx +0 -102
  31. package/src/domains/session/SessionContext.tsx +0 -150
  32. package/src/domains/session/inMemoryAuthAdapter.ts +0 -53
  33. package/src/domains/session/index.ts +0 -18
  34. package/src/domains/session/types.ts +0 -47
  35. 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;