@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,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";
@@ -1,63 +0,0 @@
1
- import { useMemo } from "react";
2
- import { calculatePasswordStrength } from "../../utils/auth";
3
- import { cn } from "@umituz/web-design-system/utils/cn";
4
-
5
- const STRENGTH_KEYS = {
6
- weak: 'auth.passwordStrength.weak',
7
- fair: 'auth.passwordStrength.fair',
8
- good: 'auth.passwordStrength.good',
9
- strong: 'auth.passwordStrength.strong',
10
- } as const;
11
-
12
- type StrengthBand = keyof typeof STRENGTH_KEYS;
13
-
14
- const scoreToBand = (score: number): StrengthBand => {
15
- if (score < 25) return 'weak';
16
- if (score < 50) return 'fair';
17
- if (score < 75) return 'good';
18
- return 'strong';
19
- };
20
-
21
- export interface PasswordStrengthIndicatorProps {
22
- password: string;
23
- translate: (key: string) => string;
24
- }
25
-
26
- export const PasswordStrengthIndicator = ({
27
- password,
28
- translate,
29
- }: PasswordStrengthIndicatorProps) => {
30
- const { band, filledSegments } = useMemo(() => {
31
- const value = calculatePasswordStrength(password);
32
- const resolvedBand = scoreToBand(value);
33
- const segments = Math.round(value / 25);
34
- return {
35
- band: resolvedBand,
36
- filledSegments: segments,
37
- };
38
- }, [password]);
39
-
40
- if (!password) return null;
41
-
42
- return (
43
- <div className="udb-strength" aria-live="polite">
44
- <div className="udb-strength__bars">
45
- {[0, 1, 2, 3].map((segment) => {
46
- const isActive = segment < filledSegments;
47
- return (
48
- <div
49
- key={segment}
50
- className={cn(
51
- "udb-strength__bar",
52
- isActive && `udb-strength__bar--${band}`,
53
- )}
54
- />
55
- );
56
- })}
57
- </div>
58
- <p className={cn("udb-strength__label", `udb-strength__label--${band}`)}>
59
- {translate(STRENGTH_KEYS[band])}
60
- </p>
61
- </div>
62
- );
63
- };
@@ -1,44 +0,0 @@
1
- import { Button } from "@umituz/web-design-system/atoms";
2
- import { GoogleIcon, AppleIcon } from "./SocialProviderIcons";
3
-
4
- export type SocialProviderId = 'google' | 'apple';
5
-
6
- export interface SocialLoginButtonsProps {
7
- onProvider: (id: SocialProviderId) => void;
8
- translate: (key: string) => string;
9
- disabled?: boolean;
10
- }
11
-
12
- const SOCIAL_PROVIDERS: ReadonlyArray<{
13
- id: SocialProviderId;
14
- labelKey: string;
15
- Icon: typeof GoogleIcon;
16
- }> = [
17
- { id: 'google', labelKey: 'auth.social.continueWithGoogle', Icon: GoogleIcon },
18
- { id: 'apple', labelKey: 'auth.social.continueWithApple', Icon: AppleIcon },
19
- ];
20
-
21
- export const SocialLoginButtons = ({
22
- onProvider,
23
- translate,
24
- disabled = false,
25
- }: SocialLoginButtonsProps) => {
26
- return (
27
- <div className="udb-social-grid">
28
- {SOCIAL_PROVIDERS.map(({ id, labelKey, Icon }) => (
29
- <Button
30
- key={id}
31
- type="button"
32
- variant="outline"
33
- onClick={() => onProvider(id)}
34
- disabled={disabled}
35
- aria-label={translate(labelKey)}
36
- className="udb-social-grid__btn"
37
- >
38
- <Icon className="udb-social-grid__icon" aria-hidden="true" />
39
- {translate(labelKey)}
40
- </Button>
41
- ))}
42
- </div>
43
- );
44
- };
@@ -1,48 +0,0 @@
1
- /**
2
- * Social Provider Icons
3
- *
4
- * Reusable SVG icon components for social auth providers.
5
- * Centralizes the brand mark assets so consuming forms
6
- * don't embed raw SVG paths in JSX.
7
- */
8
-
9
- import type { FC } from "react";
10
-
11
- interface IconProps {
12
- className?: string;
13
- "aria-hidden"?: boolean | "true" | "false";
14
- }
15
-
16
- const baseProps = {
17
- xmlns: "http://www.w3.org/2000/svg",
18
- viewBox: "0 0 24 24",
19
- fill: "currentColor",
20
- "aria-hidden": true as const,
21
- };
22
-
23
- export const GoogleIcon: FC<IconProps> = ({ className, ...rest }) => (
24
- <svg className={className} {...baseProps} {...rest}>
25
- <path
26
- d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
27
- fill="#4285F4"
28
- />
29
- <path
30
- d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
31
- fill="#34A853"
32
- />
33
- <path
34
- d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
35
- fill="#FBBC05"
36
- />
37
- <path
38
- d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
39
- fill="#EA4335"
40
- />
41
- </svg>
42
- );
43
-
44
- export const AppleIcon: FC<IconProps> = ({ className, ...rest }) => (
45
- <svg className={className} {...baseProps} {...rest}>
46
- <path d="M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z" />
47
- </svg>
48
- );
@@ -1,20 +0,0 @@
1
- /**
2
- * Shared auth form components — barrel export
3
- */
4
-
5
- export { AuthErrorBanner } from './AuthErrorBanner';
6
- export type { AuthErrorBannerProps } from './AuthErrorBanner';
7
-
8
- export { EmailInput } from './EmailInput';
9
- export type { EmailInputProps } from './EmailInput';
10
-
11
- export { PasswordInput } from './PasswordInput';
12
- export type { PasswordInputProps } from './PasswordInput';
13
-
14
- export { PasswordStrengthIndicator } from './PasswordStrengthIndicator';
15
- export type { PasswordStrengthIndicatorProps } from './PasswordStrengthIndicator';
16
-
17
- export { SocialLoginButtons } from './SocialLoginButtons';
18
- export type { SocialLoginButtonsProps, SocialProviderId } from './SocialLoginButtons';
19
-
20
- export { GoogleIcon, AppleIcon } from './SocialProviderIcons';
@@ -1,8 +0,0 @@
1
- /**
2
- * Auth Hooks
3
- *
4
- * Export all auth hooks
5
- */
6
-
7
- export { useAuth } from "./useAuth";
8
- export type { AuthProvider } from "./useAuth";