@umituz/web-dashboard 5.0.1 → 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 (34) hide show
  1. package/package.json +2 -12
  2. package/src/index.ts +0 -10
  3. package/src/styles/dashboard.css +0 -460
  4. package/src/domains/auth/components/AuthLayout.tsx +0 -99
  5. package/src/domains/auth/components/ForgotPasswordForm.tsx +0 -167
  6. package/src/domains/auth/components/LoginForm.tsx +0 -222
  7. package/src/domains/auth/components/RegisterForm.tsx +0 -281
  8. package/src/domains/auth/components/ResetPasswordForm.tsx +0 -173
  9. package/src/domains/auth/components/index.ts +0 -11
  10. package/src/domains/auth/components/shared/AuthErrorBanner.tsx +0 -25
  11. package/src/domains/auth/components/shared/EmailInput.tsx +0 -73
  12. package/src/domains/auth/components/shared/PasswordInput.tsx +0 -100
  13. package/src/domains/auth/components/shared/PasswordStrengthIndicator.tsx +0 -63
  14. package/src/domains/auth/components/shared/SocialLoginButtons.tsx +0 -44
  15. package/src/domains/auth/components/shared/SocialProviderIcons.tsx +0 -48
  16. package/src/domains/auth/components/shared/index.ts +0 -20
  17. package/src/domains/auth/hooks/index.ts +0 -8
  18. package/src/domains/auth/hooks/useAuth.ts +0 -230
  19. package/src/domains/auth/index.ts +0 -62
  20. package/src/domains/auth/types/auth.ts +0 -302
  21. package/src/domains/auth/types/index.ts +0 -25
  22. package/src/domains/auth/utils/auth.test.ts +0 -188
  23. package/src/domains/auth/utils/auth.ts +0 -221
  24. package/src/domains/auth/utils/i18nKeys.ts +0 -109
  25. package/src/domains/auth/utils/index.ts +0 -29
  26. package/src/domains/auth/utils/secureToken.ts +0 -33
  27. package/src/domains/auth/utils/validationKeys.ts +0 -23
  28. package/src/domains/session/DemoLogin.tsx +0 -42
  29. package/src/domains/session/OrgSwitcher.tsx +0 -102
  30. package/src/domains/session/SessionContext.tsx +0 -150
  31. package/src/domains/session/inMemoryAuthAdapter.ts +0 -53
  32. package/src/domains/session/index.ts +0 -18
  33. package/src/domains/session/types.ts +0 -47
  34. package/src/domains/session/utils/i18nKeys.ts +0 -12
@@ -1,188 +0,0 @@
1
- /**
2
- * Tests for pure auth utility functions.
3
- */
4
-
5
- import { describe, it, expect } from "vitest";
6
- import {
7
- isValidEmail,
8
- isValidPassword,
9
- validateLogin,
10
- validateRegister,
11
- validateResetPassword,
12
- getUserDisplayName,
13
- getUserInitials,
14
- calculatePasswordStrength,
15
- getPasswordStrengthBand,
16
- maskEmail,
17
- sanitizeInput,
18
- } from "./auth";
19
- import { generateResetToken } from "./secureToken";
20
- import { AUTH_VALIDATION_KEYS } from "./validationKeys";
21
-
22
- describe("isValidEmail", () => {
23
- it("accepts plain addresses", () => {
24
- expect(isValidEmail("user@example.com")).toBe(true);
25
- });
26
-
27
- it("rejects missing local part, domain, or TLD", () => {
28
- expect(isValidEmail("@example.com")).toBe(false);
29
- expect(isValidEmail("user@")).toBe(false);
30
- expect(isValidEmail("user@example")).toBe(false);
31
- expect(isValidEmail("user example.com")).toBe(false);
32
- });
33
- });
34
-
35
- describe("isValidPassword", () => {
36
- it("enforces the minimum length", () => {
37
- expect(isValidPassword("short")).toBe(false);
38
- expect(isValidPassword("longenough")).toBe(true);
39
- });
40
-
41
- it("honors a custom minimum", () => {
42
- expect(isValidPassword("12345678", 12)).toBe(false);
43
- expect(isValidPassword("123456789012", 12)).toBe(true);
44
- });
45
- });
46
-
47
- describe("validateLogin", () => {
48
- it("passes valid credentials", () => {
49
- expect(validateLogin({ email: "a@b.co", password: "x".repeat(8) })).toEqual({ valid: true });
50
- });
51
-
52
- it("requires an email first", () => {
53
- expect(validateLogin({ email: "", password: "x" })).toEqual({
54
- valid: false,
55
- error: AUTH_VALIDATION_KEYS.emailRequired,
56
- });
57
- });
58
-
59
- it("rejects a malformed email", () => {
60
- expect(validateLogin({ email: "nope", password: "x" })).toEqual({
61
- valid: false,
62
- error: AUTH_VALIDATION_KEYS.emailInvalid,
63
- });
64
- });
65
-
66
- it("requires a password", () => {
67
- expect(validateLogin({ email: "a@b.co", password: "" })).toEqual({
68
- valid: false,
69
- error: AUTH_VALIDATION_KEYS.passwordRequired,
70
- });
71
- });
72
- });
73
-
74
- describe("validateRegister", () => {
75
- const base = { email: "a@b.co", password: "longenough1" };
76
-
77
- it("passes with minimal data", () => {
78
- expect(validateRegister(base)).toEqual({ valid: true });
79
- });
80
-
81
- it("requires a name when asked to", () => {
82
- expect(validateRegister(base, true)).toEqual({
83
- valid: false,
84
- error: AUTH_VALIDATION_KEYS.nameRequired,
85
- });
86
- });
87
-
88
- it("enforces password length", () => {
89
- expect(validateRegister({ ...base, password: "short" })).toEqual({
90
- valid: false,
91
- error: AUTH_VALIDATION_KEYS.passwordTooShort,
92
- });
93
- });
94
-
95
- it("checks confirmation when required", () => {
96
- expect(
97
- validateRegister({ ...base, confirmPassword: "different" }, false, true),
98
- ).toEqual({
99
- valid: false,
100
- error: AUTH_VALIDATION_KEYS.passwordsDoNotMatch,
101
- });
102
- });
103
-
104
- it("accepts matching confirmation when required (the RegisterForm call shape)", () => {
105
- expect(
106
- validateRegister({ ...base, name: "A", confirmPassword: base.password }, false, true),
107
- ).toEqual({ valid: true });
108
- });
109
- });
110
-
111
- describe("validateResetPassword", () => {
112
- const base = { token: "tok", password: "longenough", confirmPassword: "longenough" };
113
-
114
- it("passes matching valid data", () => {
115
- expect(validateResetPassword(base)).toEqual({ valid: true });
116
- });
117
-
118
- it("requires a token", () => {
119
- expect(validateResetPassword({ ...base, token: "" })).toEqual({
120
- valid: false,
121
- error: AUTH_VALIDATION_KEYS.invalidResetToken,
122
- });
123
- });
124
-
125
- it("rejects mismatched confirmation", () => {
126
- expect(validateResetPassword({ ...base, confirmPassword: "other" })).toEqual({
127
- valid: false,
128
- error: AUTH_VALIDATION_KEYS.passwordsDoNotMatch,
129
- });
130
- });
131
- });
132
-
133
- describe("display helpers", () => {
134
- it("getUserDisplayName prefers name, then email, then null", () => {
135
- expect(getUserDisplayName({ id: "1", name: "Ada", email: "a@b.co" } as never)).toBe("Ada");
136
- expect(getUserDisplayName({ id: "1", email: "a@b.co" } as never)).toBe("a@b.co");
137
- expect(getUserDisplayName(null)).toBeNull();
138
- });
139
-
140
- it("getUserInitials uses first and last name parts", () => {
141
- expect(getUserInitials({ id: "1", name: "Ada Lovelace" } as never)).toBe("AL");
142
- expect(getUserInitials({ id: "1", name: "ada" } as never)).toBe("AD");
143
- expect(getUserInitials(null)).toBeNull();
144
- });
145
- });
146
-
147
- describe("password strength", () => {
148
- it("scores a strong password at 100", () => {
149
- expect(calculatePasswordStrength("Str0ng!Password")).toBe(100);
150
- expect(getPasswordStrengthBand("Str0ng!Password")).toBe("strong");
151
- });
152
-
153
- it("scores a weak password low", () => {
154
- expect(getPasswordStrengthBand("abc")).toBe("weak");
155
- });
156
-
157
- it("never exceeds 100", () => {
158
- expect(calculatePasswordStrength("aaaaaaaaaaaaaaaaaaaa!A1")).toBeLessThanOrEqual(100);
159
- });
160
- });
161
-
162
- describe("maskEmail", () => {
163
- it("masks the local part", () => {
164
- expect(maskEmail("umit@example.com")).toBe("u***@example.com");
165
- });
166
-
167
- it("returns null for invalid input", () => {
168
- expect(maskEmail("not-an-email")).toBeNull();
169
- });
170
- });
171
-
172
- describe("sanitizeInput", () => {
173
- it("trims and truncates", () => {
174
- expect(sanitizeInput(" hello ")).toBe("hello");
175
- expect(sanitizeInput("abcdef", 3)).toBe("abc");
176
- });
177
- });
178
-
179
- describe("generateResetToken", () => {
180
- it("produces a hex string of 2 * length chars", () => {
181
- const token = generateResetToken(16);
182
- expect(token).toMatch(/^[0-9a-f]{32}$/);
183
- });
184
-
185
- it("produces different tokens on each call", () => {
186
- expect(generateResetToken()).not.toBe(generateResetToken());
187
- });
188
- });
@@ -1,221 +0,0 @@
1
- /**
2
- * Auth Utilities
3
- *
4
- * Validation and helper functions for authentication.
5
- * Validation messages are i18n keys, not hardcoded strings —
6
- * the consumer renders the localized text in its UI layer.
7
- */
8
-
9
- import type { LoginCredentials, RegisterData, User } from "../types/auth";
10
- import { AUTH_VALIDATION_KEYS } from './validationKeys';
11
-
12
- export { generateResetToken } from './secureToken';
13
- export { AUTH_VALIDATION_KEYS } from './validationKeys';
14
- export type { AuthValidationKey } from './validationKeys';
15
-
16
- /**
17
- * Validation result type — error is now an i18n key.
18
- */
19
- export type ValidationResult =
20
- | { valid: true }
21
- | { valid: false; error: string };
22
-
23
- /**
24
- * Validate email format
25
- */
26
- export function isValidEmail(email: string): boolean {
27
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
28
- return emailRegex.test(email);
29
- }
30
-
31
- /**
32
- * Validate password length
33
- */
34
- export function isValidPassword(password: string, minLength: number = 8): boolean {
35
- return password.length >= minLength;
36
- }
37
-
38
- /**
39
- * Validate login credentials
40
- */
41
- export function validateLogin(credentials: LoginCredentials): ValidationResult {
42
- if (!credentials.email) {
43
- return { valid: false, error: AUTH_VALIDATION_KEYS.emailRequired };
44
- }
45
- if (!isValidEmail(credentials.email)) {
46
- return { valid: false, error: AUTH_VALIDATION_KEYS.emailInvalid };
47
- }
48
- if (!credentials.password) {
49
- return { valid: false, error: AUTH_VALIDATION_KEYS.passwordRequired };
50
- }
51
- return { valid: true };
52
- }
53
-
54
- /**
55
- * Validate registration data
56
- */
57
- export function validateRegister(
58
- data: RegisterData & { confirmPassword?: string },
59
- requireName: boolean = false,
60
- requirePasswordConfirm?: boolean,
61
- ): ValidationResult {
62
- if (!data.email) {
63
- return { valid: false, error: AUTH_VALIDATION_KEYS.emailRequired };
64
- }
65
- if (!isValidEmail(data.email)) {
66
- return { valid: false, error: AUTH_VALIDATION_KEYS.emailInvalid };
67
- }
68
- if (requireName && !data.name) {
69
- return { valid: false, error: AUTH_VALIDATION_KEYS.nameRequired };
70
- }
71
- if (!data.password) {
72
- return { valid: false, error: AUTH_VALIDATION_KEYS.passwordRequired };
73
- }
74
- if (!isValidPassword(data.password)) {
75
- return { valid: false, error: AUTH_VALIDATION_KEYS.passwordTooShort };
76
- }
77
- if (requirePasswordConfirm && data.password !== data.confirmPassword) {
78
- return { valid: false, error: AUTH_VALIDATION_KEYS.passwordsDoNotMatch };
79
- }
80
- return { valid: true };
81
- }
82
-
83
- /**
84
- * Validate forgot-password request
85
- */
86
- export function validateForgotPassword(data: { email: string }): ValidationResult {
87
- if (!data.email) {
88
- return { valid: false, error: AUTH_VALIDATION_KEYS.emailRequired };
89
- }
90
- if (!isValidEmail(data.email)) {
91
- return { valid: false, error: AUTH_VALIDATION_KEYS.emailInvalid };
92
- }
93
- return { valid: true };
94
- }
95
-
96
- /**
97
- * Validate password reset confirmation
98
- */
99
- export function validateResetPassword(data: {
100
- token: string;
101
- password: string;
102
- confirmPassword: string;
103
- }): ValidationResult {
104
- if (!data.token) {
105
- return { valid: false, error: AUTH_VALIDATION_KEYS.invalidResetToken };
106
- }
107
- if (!data.password) {
108
- return { valid: false, error: AUTH_VALIDATION_KEYS.passwordRequired };
109
- }
110
- if (!isValidPassword(data.password)) {
111
- return { valid: false, error: AUTH_VALIDATION_KEYS.passwordTooShort };
112
- }
113
- if (data.password !== data.confirmPassword) {
114
- return { valid: false, error: AUTH_VALIDATION_KEYS.passwordsDoNotMatch };
115
- }
116
- return { valid: true };
117
- }
118
-
119
- /**
120
- * Get user display name
121
- *
122
- * Returns null when no usable identifier exists, letting the caller
123
- * decide on a localized fallback. Avoids hardcoded "Guest"/"User" strings.
124
- */
125
- export function getUserDisplayName(user: User | null): string | null {
126
- if (!user) return null;
127
- return user.name || user.email || null;
128
- }
129
-
130
- /**
131
- * Get user initials
132
- *
133
- * Returns null when no name is available, so the caller can decide
134
- * whether to render a placeholder or hide the avatar.
135
- */
136
- export function getUserInitials(user: User | null): string | null {
137
- if (!user) return null;
138
- const name = user.name || user.email || "";
139
- if (!name) return null;
140
- const parts = name.trim().split(" ");
141
- if (parts.length >= 2 && parts[0] && parts[parts.length - 1]) {
142
- return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
143
- }
144
- return name.slice(0, 2).toUpperCase();
145
- }
146
-
147
- /**
148
- * Check if user has verified email
149
- */
150
- export function isEmailVerified(user: User | null): boolean {
151
- return user?.emailVerified === true;
152
- }
153
-
154
- /**
155
- * Format user creation date
156
- *
157
- * Returns null when the user has no createdAt; the caller decides
158
- * whether to display "—" or hide the field.
159
- */
160
- export function formatUserCreatedAt(
161
- user: User | null,
162
- locale: string = "en-US",
163
- ): string | null {
164
- if (!user?.createdAt) return null;
165
- return new Date(user.createdAt).toLocaleDateString(locale, {
166
- year: "numeric",
167
- month: "long",
168
- day: "numeric",
169
- });
170
- }
171
-
172
- /**
173
- * Mask email for privacy (e.g., u***@example.com)
174
- *
175
- * Returns null when the email is invalid so the caller can show
176
- * a "—" placeholder rather than the raw input.
177
- */
178
- export function maskEmail(email: string): string | null {
179
- const [local, domain] = email.split("@");
180
- if (!local || !domain) return null;
181
- const maskedLocal = local[0] + "***";
182
- return `${maskedLocal}@${domain}`;
183
- }
184
-
185
- /**
186
- * Password strength score (0-100)
187
- */
188
- export function calculatePasswordStrength(password: string): number {
189
- let score = 0;
190
-
191
- if (password.length >= 8) score += 25;
192
- if (password.length >= 12) score += 25;
193
-
194
- if (/[a-z]/.test(password)) score += 12.5;
195
- if (/[A-Z]/.test(password)) score += 12.5;
196
- if (/[0-9]/.test(password)) score += 12.5;
197
- if (/[^a-zA-Z0-9]/.test(password)) score += 12.5;
198
-
199
- return Math.min(score, 100);
200
- }
201
-
202
- /**
203
- * Password strength band. Numeric so the UI can map it to a label
204
- * via its own translation catalog.
205
- */
206
- export type PasswordStrengthBand = 'weak' | 'fair' | 'good' | 'strong';
207
-
208
- export function getPasswordStrengthBand(password: string): PasswordStrengthBand {
209
- const score = calculatePasswordStrength(password);
210
- if (score < 25) return 'weak';
211
- if (score < 50) return 'fair';
212
- if (score < 75) return 'good';
213
- return 'strong';
214
- }
215
-
216
- /**
217
- * Sanitize user input for display
218
- */
219
- export function sanitizeInput(input: string, maxLength: number = 1000): string {
220
- return input.trim().slice(0, maxLength);
221
- }
@@ -1,109 +0,0 @@
1
- export const AUTH_KEYS = {
2
- login: {
3
- welcomeBack: 'auth.login.welcomeBack',
4
- signInTo: 'auth.login.signInTo',
5
- submit: 'auth.login.submit',
6
- submitting: 'auth.login.submitting',
7
- rememberMe: 'auth.login.rememberMe',
8
- forgotPassword: 'auth.login.forgotPassword',
9
- noAccount: 'auth.login.noAccount',
10
- signUp: 'auth.login.signUp',
11
- orContinueWith: 'auth.login.orContinueWith',
12
- },
13
-
14
- register: {
15
- createAccount: 'auth.register.createAccount',
16
- join: 'auth.register.join',
17
- fullName: 'auth.register.fullName',
18
- fullNamePlaceholder: 'auth.placeholders.fullName',
19
- confirmPassword: 'auth.register.confirmPassword',
20
- confirmPasswordPlaceholder: 'auth.placeholders.confirmPassword',
21
- acceptTerms: 'auth.register.acceptTerms',
22
- termsOfService: 'auth.register.termsOfService',
23
- privacyPolicy: 'auth.register.privacyPolicy',
24
- submit: 'auth.register.submit',
25
- submitting: 'auth.register.submitting',
26
- haveAccount: 'auth.register.haveAccount',
27
- signIn: 'auth.register.signIn',
28
- mustAcceptTerms: 'auth.register.mustAcceptTerms',
29
- passwordsDoNotMatch: 'auth.register.passwordsDoNotMatch',
30
- },
31
-
32
- forgotPassword: {
33
- title: 'auth.forgotPassword.title',
34
- description: 'auth.forgotPassword.description',
35
- submit: 'auth.forgotPassword.submit',
36
- submitting: 'auth.forgotPassword.submitting',
37
- backToSignIn: 'auth.forgotPassword.backToSignIn',
38
- successTitle: 'auth.forgotPassword.successTitle',
39
- successMessage: 'auth.forgotPassword.successMessage',
40
- sentTo: 'auth.forgotPassword.sentTo',
41
- checkEmail: 'auth.forgotPassword.checkEmail',
42
- step1: 'auth.forgotPassword.steps.step1',
43
- step2: 'auth.forgotPassword.steps.step2',
44
- step3: 'auth.forgotPassword.steps.step3',
45
- },
46
-
47
- resetPassword: {
48
- title: 'auth.resetPassword.title',
49
- description: 'auth.resetPassword.description',
50
- newPassword: 'auth.resetPassword.newPassword',
51
- confirmNewPassword: 'auth.resetPassword.confirmNewPassword',
52
- submit: 'auth.resetPassword.submit',
53
- submitting: 'auth.resetPassword.submitting',
54
- successTitle: 'auth.resetPassword.successTitle',
55
- successMessage: 'auth.resetPassword.successMessage',
56
- goToSignIn: 'auth.resetPassword.goToSignIn',
57
- },
58
-
59
- fields: {
60
- email: 'auth.fields.email',
61
- password: 'auth.fields.password',
62
- name: 'auth.fields.name',
63
- },
64
-
65
- placeholders: {
66
- emailExample: 'auth.placeholders.emailExample',
67
- password: 'auth.placeholders.password',
68
- fullName: 'auth.placeholders.fullName',
69
- },
70
-
71
- errors: {
72
- invalidCredentials: 'auth.errors.invalidCredentials',
73
- loginFailed: 'auth.errors.loginFailed',
74
- noAuthProvider: 'auth.errors.noAuthProvider',
75
- registrationFailed: 'auth.errors.registrationFailed',
76
- emailRequired: 'auth.errors.emailRequired',
77
- emailInvalid: 'auth.errors.emailInvalid',
78
- passwordRequired: 'auth.errors.passwordRequired',
79
- passwordTooShort: 'auth.errors.passwordTooShort',
80
- passwordsDoNotMatch: 'auth.errors.passwordsDoNotMatch',
81
- sendResetFailed: 'auth.errors.sendResetFailed',
82
- resetFailed: 'auth.errors.resetFailed',
83
- },
84
-
85
- passwordStrength: {
86
- weak: 'auth.passwordStrength.weak',
87
- fair: 'auth.passwordStrength.fair',
88
- good: 'auth.passwordStrength.good',
89
- strong: 'auth.passwordStrength.strong',
90
- },
91
-
92
- social: {
93
- continueWithGoogle: 'auth.social.continueWithGoogle',
94
- continueWithApple: 'auth.social.continueWithApple',
95
- },
96
-
97
- layout: {
98
- backToHome: 'auth.layout.backToHome',
99
- orContinueWith: 'auth.layout.orContinueWith',
100
- allRightsReserved: 'auth.layout.allRightsReserved',
101
- },
102
-
103
- a11y: {
104
- showPassword: 'auth.a11y.showPassword',
105
- hidePassword: 'auth.a11y.hidePassword',
106
- },
107
- } as const;
108
-
109
- export type AuthI18nKey = string;
@@ -1,29 +0,0 @@
1
- /**
2
- * Auth Utilities
3
- *
4
- * Export all auth utilities
5
- */
6
-
7
- export {
8
- isValidEmail,
9
- isValidPassword,
10
- validateLogin,
11
- validateRegister,
12
- validateForgotPassword,
13
- validateResetPassword,
14
- getUserDisplayName,
15
- getUserInitials,
16
- isEmailVerified,
17
- formatUserCreatedAt,
18
- maskEmail,
19
- generateResetToken,
20
- calculatePasswordStrength,
21
- getPasswordStrengthBand,
22
- sanitizeInput,
23
- type ValidationResult,
24
- type PasswordStrengthBand,
25
- } from "./auth";
26
-
27
- export { AUTH_KEYS } from "./i18nKeys";
28
- export { AUTH_VALIDATION_KEYS } from "./validationKeys";
29
- export type { AuthValidationKey } from "./validationKeys";
@@ -1,33 +0,0 @@
1
- /**
2
- * Auth Utilities - Secure Token
3
- *
4
- * Cryptographically secure token generation utilities
5
- */
6
-
7
- /**
8
- * Generate a cryptographically secure random token.
9
- *
10
- * Requires the Web Crypto API (`crypto.getRandomValues`), available in
11
- * all modern browsers, Node.js >= 19 (and >= 15 via `globalThis.crypto`),
12
- * and React Native with a crypto polyfill. Throws instead of silently
13
- * degrading to an insecure PRNG — predictable tokens are worse than
14
- * a loud failure.
15
- *
16
- * @param length - Token length in bytes (default: 32)
17
- * @returns Hex-encoded random token
18
- * @throws Error when no CSPRNG is available in the runtime
19
- */
20
- export function generateResetToken(length: number = 32): string {
21
- if (typeof crypto === 'undefined' || typeof crypto.getRandomValues !== 'function') {
22
- throw new Error(
23
- 'generateResetToken: no cryptographic random source available in this runtime ' +
24
- '(requires crypto.getRandomValues — Web Crypto, Node >= 19, or a polyfill)',
25
- );
26
- }
27
-
28
- const byteLength = Math.max(1, Math.floor(length));
29
- const bytes = new Uint8Array(byteLength);
30
- crypto.getRandomValues(bytes);
31
-
32
- return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
33
- }
@@ -1,23 +0,0 @@
1
- /**
2
- * Auth Validation Error Keys
3
- *
4
- * Stable i18n keys for validation errors. The auth UI maps these to
5
- * localized messages via the consumer's translation system.
6
- *
7
- * Why keys instead of literal strings:
8
- * - No hardcoded user-facing strings in source code
9
- * - Centralized catalog: easier to audit and translate
10
- * - Validators stay pure and testable
11
- */
12
-
13
- export const AUTH_VALIDATION_KEYS = {
14
- emailRequired: 'auth.validation.emailRequired',
15
- emailInvalid: 'auth.validation.emailInvalid',
16
- passwordRequired: 'auth.validation.passwordRequired',
17
- passwordTooShort: 'auth.validation.passwordTooShort',
18
- passwordsDoNotMatch: 'auth.validation.passwordsDoNotMatch',
19
- nameRequired: 'auth.validation.nameRequired',
20
- invalidResetToken: 'auth.validation.invalidResetToken',
21
- } as const;
22
-
23
- export type AuthValidationKey = (typeof AUTH_VALIDATION_KEYS)[keyof typeof AUTH_VALIDATION_KEYS];
@@ -1,42 +0,0 @@
1
- import { UserRound } from "lucide-react";
2
- import { Button } from "@umituz/web-design-system/atoms";
3
- import { useT } from "@umituz/web-localization/react";
4
- import { SESSION_KEYS } from "./utils/i18nKeys";
5
-
6
- export interface DemoLoginProps {
7
- onDemo: (userId: string) => void | Promise<void>;
8
- userId: string;
9
- label?: string;
10
- variant?: "default" | "outline" | "ghost";
11
- size?: "default" | "sm";
12
- disabled?: boolean;
13
- className?: string;
14
- }
15
-
16
- export const DemoLogin = ({
17
- onDemo,
18
- userId,
19
- label,
20
- variant = "outline",
21
- size = "default",
22
- disabled = false,
23
- className,
24
- }: DemoLoginProps) => {
25
- const t = useT();
26
-
27
- return (
28
- <Button
29
- type="button"
30
- variant={variant}
31
- size={size}
32
- disabled={disabled}
33
- className={className}
34
- onClick={() => void onDemo(userId)}
35
- >
36
- <UserRound aria-hidden="true" />
37
- {label ?? t(SESSION_KEYS.demoLogin.action)}
38
- </Button>
39
- );
40
- };
41
-
42
- export default DemoLogin;