xertica-ui 2.2.0 → 2.2.1
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.
- package/CHANGELOG.md +1 -1
- package/README.md +1 -1
- package/dist/ThemeContext-BgclCB35.js +1856 -0
- package/dist/ThemeContext-DQUOeziy.cjs +1855 -0
- package/dist/VerifyEmailPage-RrUApqBN.js +3214 -0
- package/dist/VerifyEmailPage-VoMI7MYH.cjs +3213 -0
- package/dist/XerticaProvider-BSyFrmC0.js +49 -0
- package/dist/XerticaProvider-CiNKjMx1.cjs +48 -0
- package/dist/XerticaXLogo-B2svDGZh.cjs +251 -0
- package/dist/XerticaXLogo-CowGv7BC.js +252 -0
- package/dist/brand.cjs.js +2 -2
- package/dist/brand.es.js +2 -2
- package/dist/hooks.cjs.js +1 -1
- package/dist/hooks.es.js +1 -1
- package/dist/index.cjs.js +5 -5
- package/dist/index.es.js +5 -5
- package/dist/layout.cjs.js +1 -1
- package/dist/layout.es.js +1 -1
- package/dist/pages.cjs.js +1 -1
- package/dist/pages.es.js +1 -1
- package/dist/sidebar-CRMiBtAi.js +801 -0
- package/dist/sidebar-CZ2mWaMM.cjs +800 -0
- package/dist/xertica-ui.css +1 -1
- package/package.json +1 -1
- package/templates/CLAUDE.md +165 -180
- package/templates/package.json +2 -2
- package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +9 -7
- package/templates/src/features/auth/ui/LoginContent.tsx +10 -8
- package/templates/src/features/auth/ui/ResetPasswordContent.tsx +179 -177
- package/templates/src/features/auth/ui/SocialLoginButtons.tsx +9 -4
- package/templates/src/features/auth/ui/VerifyEmailContent.tsx +84 -82
- package/templates/src/features/template/ui/TemplateContent.tsx +1 -1
- package/templates/src/locales/en/components/assistant.json +14 -0
- package/templates/src/locales/en/pages/forgotPassword.json +10 -0
- package/templates/src/locales/en/pages/templates.json +1 -1
- package/templates/src/locales/es/components/assistant.json +14 -0
- package/templates/src/locales/es/pages/forgotPassword.json +10 -0
- package/templates/src/locales/es/pages/templates.json +1 -1
- package/templates/src/locales/pt-BR/components/assistant.json +14 -0
- package/templates/src/locales/pt-BR/pages/forgotPassword.json +10 -0
- package/templates/src/locales/pt-BR/pages/templates.json +1 -1
- package/templates/src/pages/AssistantPage.tsx +464 -463
|
@@ -1,177 +1,179 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { Button, Input, Label } from 'xertica-ui/ui';
|
|
3
|
-
import { XerticaLogo } from 'xertica-ui/brand';
|
|
4
|
-
import { ArrowLeft, CheckCircle2, AlertCircle } from 'lucide-react';
|
|
5
|
-
import { useNavigate } from 'react-router-dom';
|
|
6
|
-
import { AuthPageShell } from './AuthPageShell';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const [
|
|
13
|
-
const [
|
|
14
|
-
const [
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
case '
|
|
56
|
-
return 'text-
|
|
57
|
-
case '
|
|
58
|
-
return 'text-[var(--chart-
|
|
59
|
-
|
|
60
|
-
return 'text-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
case '
|
|
69
|
-
return '
|
|
70
|
-
case '
|
|
71
|
-
return '
|
|
72
|
-
|
|
73
|
-
return '';
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Button, Input, Label } from 'xertica-ui/ui';
|
|
3
|
+
import { XerticaLogo } from 'xertica-ui/brand';
|
|
4
|
+
import { ArrowLeft, CheckCircle2, AlertCircle } from 'lucide-react';
|
|
5
|
+
import { useNavigate } from 'react-router-dom';
|
|
6
|
+
import { AuthPageShell } from './AuthPageShell';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
8
|
+
|
|
9
|
+
export function ResetPasswordContent() {
|
|
10
|
+
const navigate = useNavigate();
|
|
11
|
+
const { t } = useTranslation();
|
|
12
|
+
const [password, setPassword] = useState('');
|
|
13
|
+
const [confirmPassword, setConfirmPassword] = useState('');
|
|
14
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
15
|
+
const [error, setError] = useState('');
|
|
16
|
+
const [passwordStrength, setPasswordStrength] = useState<'weak' | 'medium' | 'strong' | null>(
|
|
17
|
+
null
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const checkPasswordStrength = (pwd: string) => {
|
|
21
|
+
if (pwd.length === 0) {
|
|
22
|
+
setPasswordStrength(null);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (pwd.length < 6) setPasswordStrength('weak');
|
|
26
|
+
else if (pwd.length < 10) setPasswordStrength('medium');
|
|
27
|
+
else setPasswordStrength('strong');
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const handlePasswordChange = (value: string) => {
|
|
31
|
+
setPassword(value);
|
|
32
|
+
checkPasswordStrength(value);
|
|
33
|
+
setError('');
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
37
|
+
e.preventDefault();
|
|
38
|
+
setError('');
|
|
39
|
+
if (password.length < 6) {
|
|
40
|
+
setError(t('resetPassword.errorMinLength'));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (password !== confirmPassword) {
|
|
44
|
+
setError(t('resetPassword.errorMismatch'));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
setIsLoading(true);
|
|
48
|
+
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
49
|
+
navigate('/login', { state: { resetSuccess: true } });
|
|
50
|
+
setIsLoading(false);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const getStrengthColor = () => {
|
|
54
|
+
switch (passwordStrength) {
|
|
55
|
+
case 'weak':
|
|
56
|
+
return 'text-destructive';
|
|
57
|
+
case 'medium':
|
|
58
|
+
return 'text-[var(--chart-3)]';
|
|
59
|
+
case 'strong':
|
|
60
|
+
return 'text-[var(--chart-2)]';
|
|
61
|
+
default:
|
|
62
|
+
return 'text-muted-foreground';
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const getStrengthText = () => {
|
|
67
|
+
switch (passwordStrength) {
|
|
68
|
+
case 'weak':
|
|
69
|
+
return t('resetPassword.strengthWeak');
|
|
70
|
+
case 'medium':
|
|
71
|
+
return t('resetPassword.strengthMedium');
|
|
72
|
+
case 'strong':
|
|
73
|
+
return t('resetPassword.strengthStrong');
|
|
74
|
+
default:
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<AuthPageShell
|
|
81
|
+
imageSrc="https://images.unsplash.com/photo-1555949963-aa79dcee981c?w=1200&h=800&fit=crop&auto=format"
|
|
82
|
+
imageAlt={t('resetPassword.heroImageAlt')}
|
|
83
|
+
>
|
|
84
|
+
<button
|
|
85
|
+
onClick={() => navigate('/login')}
|
|
86
|
+
className="flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors"
|
|
87
|
+
>
|
|
88
|
+
<ArrowLeft className="w-4 h-4" />
|
|
89
|
+
<span className="text-small">{t('resetPassword.backToLogin')}</span>
|
|
90
|
+
</button>
|
|
91
|
+
|
|
92
|
+
<div className="text-center">
|
|
93
|
+
<div className="flex items-center justify-center mb-4">
|
|
94
|
+
<XerticaLogo className="h-12 w-auto text-primary dark:text-foreground" variant="theme" />
|
|
95
|
+
</div>
|
|
96
|
+
<h2 className="text-sm text-muted-foreground">{t('resetPassword.heading')}</h2>
|
|
97
|
+
<p className="mt-2 text-muted-foreground">{t('resetPassword.subheading')}</p>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<form className="space-y-6" onSubmit={handleSubmit}>
|
|
101
|
+
<div className="space-y-2">
|
|
102
|
+
<Label htmlFor="password">{t('resetPassword.newPasswordLabel')}</Label>
|
|
103
|
+
<Input
|
|
104
|
+
id="password"
|
|
105
|
+
name="password"
|
|
106
|
+
type="password"
|
|
107
|
+
required
|
|
108
|
+
className="w-full"
|
|
109
|
+
placeholder="••••••••"
|
|
110
|
+
value={password}
|
|
111
|
+
onChange={e => handlePasswordChange(e.target.value)}
|
|
112
|
+
/>
|
|
113
|
+
{passwordStrength && (
|
|
114
|
+
<div className="flex items-center gap-2">
|
|
115
|
+
<div className="flex-1 h-1 bg-muted rounded-full overflow-hidden">
|
|
116
|
+
<div
|
|
117
|
+
className={`h-full transition-all duration-300 ${
|
|
118
|
+
passwordStrength === 'weak'
|
|
119
|
+
? 'w-1/3 bg-destructive'
|
|
120
|
+
: passwordStrength === 'medium'
|
|
121
|
+
? 'w-2/3 bg-[var(--chart-3)]'
|
|
122
|
+
: 'w-full bg-[var(--chart-2)]'
|
|
123
|
+
}`}
|
|
124
|
+
/>
|
|
125
|
+
</div>
|
|
126
|
+
<span className={`text-small ${getStrengthColor()}`}>{getStrengthText()}</span>
|
|
127
|
+
</div>
|
|
128
|
+
)}
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<div className="space-y-2">
|
|
132
|
+
<Label htmlFor="confirmPassword">{t('resetPassword.confirmPasswordLabel')}</Label>
|
|
133
|
+
<Input
|
|
134
|
+
id="confirmPassword"
|
|
135
|
+
name="confirmPassword"
|
|
136
|
+
type="password"
|
|
137
|
+
required
|
|
138
|
+
className="w-full"
|
|
139
|
+
placeholder="••••••••"
|
|
140
|
+
value={confirmPassword}
|
|
141
|
+
onChange={e => {
|
|
142
|
+
setConfirmPassword(e.target.value);
|
|
143
|
+
setError('');
|
|
144
|
+
}}
|
|
145
|
+
/>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<div className="bg-accent rounded-[var(--radius)] p-4 space-y-2">
|
|
149
|
+
<p className="text-sm">{t('resetPassword.requirements')}</p>
|
|
150
|
+
<div className="space-y-1">
|
|
151
|
+
<div className="flex items-center gap-2">
|
|
152
|
+
<CheckCircle2
|
|
153
|
+
className={`w-4 h-4 ${password.length >= 6 ? 'text-[var(--chart-2)]' : 'text-muted-foreground'}`}
|
|
154
|
+
/>
|
|
155
|
+
<span className="text-sm text-muted-foreground">{t('resetPassword.requirementMinChars')}</span>
|
|
156
|
+
</div>
|
|
157
|
+
<div className="flex items-center gap-2">
|
|
158
|
+
<CheckCircle2
|
|
159
|
+
className={`w-4 h-4 ${password === confirmPassword && password.length > 0 ? 'text-[var(--chart-2)]' : 'text-muted-foreground'}`}
|
|
160
|
+
/>
|
|
161
|
+
<span className="text-sm text-muted-foreground">{t('resetPassword.requirementMatch')}</span>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
{error && (
|
|
167
|
+
<div className="flex items-center gap-2 text-destructive bg-destructive/10 rounded-[var(--radius)] p-3">
|
|
168
|
+
<AlertCircle className="w-4 h-4 flex-shrink-0" />
|
|
169
|
+
<span className="text-sm">{error}</span>
|
|
170
|
+
</div>
|
|
171
|
+
)}
|
|
172
|
+
|
|
173
|
+
<Button type="submit" className="w-full" disabled={isLoading}>
|
|
174
|
+
{isLoading ? t('resetPassword.submitting') : t('resetPassword.submit')}
|
|
175
|
+
</Button>
|
|
176
|
+
</form>
|
|
177
|
+
</AuthPageShell>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Button } from 'xertica-ui/ui';
|
|
3
3
|
import { Lock } from 'lucide-react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
4
5
|
|
|
5
6
|
interface SocialLoginButtonsProps {
|
|
6
7
|
onSocialLogin: (provider: string) => void;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
export function SocialLoginButtons({ onSocialLogin }: SocialLoginButtonsProps) {
|
|
11
|
+
const { t } = useTranslation();
|
|
12
|
+
|
|
10
13
|
return (
|
|
11
14
|
<>
|
|
12
15
|
<div className="relative">
|
|
@@ -14,7 +17,7 @@ export function SocialLoginButtons({ onSocialLogin }: SocialLoginButtonsProps) {
|
|
|
14
17
|
<div className="w-full border-t border-border" />
|
|
15
18
|
</div>
|
|
16
19
|
<div className="relative flex justify-center text-sm">
|
|
17
|
-
<span className="bg-muted px-2 text-muted-foreground">
|
|
20
|
+
<span className="bg-muted px-2 text-muted-foreground">{t('login.orContinueWith')}</span>
|
|
18
21
|
</div>
|
|
19
22
|
</div>
|
|
20
23
|
|
|
@@ -44,7 +47,7 @@ export function SocialLoginButtons({ onSocialLogin }: SocialLoginButtonsProps) {
|
|
|
44
47
|
/>
|
|
45
48
|
<path fill="none" d="M0 0h48v48H0z" />
|
|
46
49
|
</svg>
|
|
47
|
-
<span>
|
|
50
|
+
<span>{t('login.signInWithGoogle')}</span>
|
|
48
51
|
</Button>
|
|
49
52
|
|
|
50
53
|
<Button
|
|
@@ -54,7 +57,7 @@ export function SocialLoginButtons({ onSocialLogin }: SocialLoginButtonsProps) {
|
|
|
54
57
|
onClick={() => onSocialLogin('MT Login')}
|
|
55
58
|
>
|
|
56
59
|
<Lock className="w-5 h-5 mr-2 text-[var(--chart-4)]" />
|
|
57
|
-
<span>
|
|
60
|
+
<span>{t('login.signInWithMTLogin')}</span>
|
|
58
61
|
</Button>
|
|
59
62
|
|
|
60
63
|
<Button
|
|
@@ -64,7 +67,9 @@ export function SocialLoginButtons({ onSocialLogin }: SocialLoginButtonsProps) {
|
|
|
64
67
|
onClick={() => onSocialLogin('gov.br')}
|
|
65
68
|
>
|
|
66
69
|
<span>
|
|
67
|
-
|
|
70
|
+
{t('login.signInWithGovBr').split('gov.br')[0]}
|
|
71
|
+
<strong className="font-semibold">gov.br</strong>
|
|
72
|
+
{t('login.signInWithGovBr').split('gov.br')[1] || ''}
|
|
68
73
|
</span>
|
|
69
74
|
</Button>
|
|
70
75
|
</div>
|
|
@@ -1,82 +1,84 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { Button } from 'xertica-ui/ui';
|
|
3
|
-
import { XerticaLogo } from 'xertica-ui/brand';
|
|
4
|
-
import { ArrowLeft, Mail, CheckCircle2 } from 'lucide-react';
|
|
5
|
-
import { useNavigate, useLocation } from 'react-router-dom';
|
|
6
|
-
import { AuthPageShell } from './AuthPageShell';
|
|
7
|
-
import { SocialLoginButtons } from './SocialLoginButtons';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Button } from 'xertica-ui/ui';
|
|
3
|
+
import { XerticaLogo } from 'xertica-ui/brand';
|
|
4
|
+
import { ArrowLeft, Mail, CheckCircle2 } from 'lucide-react';
|
|
5
|
+
import { useNavigate, useLocation } from 'react-router-dom';
|
|
6
|
+
import { AuthPageShell } from './AuthPageShell';
|
|
7
|
+
import { SocialLoginButtons } from './SocialLoginButtons';
|
|
8
|
+
import { useTranslation } from 'react-i18next';
|
|
9
|
+
|
|
10
|
+
export function VerifyEmailContent() {
|
|
11
|
+
const navigate = useNavigate();
|
|
12
|
+
const location = useLocation();
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
const email = location.state?.email || 'seu@email.com';
|
|
15
|
+
const [isResending, setIsResending] = useState(false);
|
|
16
|
+
const [resendSuccess, setResendSuccess] = useState(false);
|
|
17
|
+
|
|
18
|
+
const handleResend = async () => {
|
|
19
|
+
setIsResending(true);
|
|
20
|
+
setResendSuccess(false);
|
|
21
|
+
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
22
|
+
setIsResending(false);
|
|
23
|
+
setResendSuccess(true);
|
|
24
|
+
setTimeout(() => setResendSuccess(false), 3000);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<AuthPageShell
|
|
29
|
+
imageSrc="https://images.unsplash.com/photo-1563986768609-322da13575f3?w=1200&h=800&fit=crop&auto=format"
|
|
30
|
+
imageAlt={t('verifyEmail.heroImageAlt')}
|
|
31
|
+
>
|
|
32
|
+
<div className="text-center">
|
|
33
|
+
<div className="flex items-center justify-center mb-4">
|
|
34
|
+
<XerticaLogo className="h-12 w-auto text-primary dark:text-foreground" variant="theme" />
|
|
35
|
+
</div>
|
|
36
|
+
<div className="flex items-center justify-center mb-4">
|
|
37
|
+
<div className="p-4 bg-primary/10 rounded-[var(--radius)]">
|
|
38
|
+
<Mail className="w-12 h-12 text-primary" />
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
<h2 className="text-sm text-muted-foreground">{t('verifyEmail.heading')}</h2>
|
|
42
|
+
<p className="mt-2 text-muted-foreground">
|
|
43
|
+
{t('verifyEmail.instructionsSent')}
|
|
44
|
+
</p>
|
|
45
|
+
<p className="mt-1 text-primary">{email}</p>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div className="bg-accent rounded-[var(--radius)] p-4 space-y-3">
|
|
49
|
+
<p className="text-muted-foreground">
|
|
50
|
+
{t('verifyEmail.instructions')}
|
|
51
|
+
</p>
|
|
52
|
+
<div className="flex items-start gap-2 text-muted-foreground">
|
|
53
|
+
<CheckCircle2 className="w-4 h-4 mt-0.5 flex-shrink-0 text-[var(--chart-2)]" />
|
|
54
|
+
<span className="text-sm">{t('verifyEmail.checkSpam')}</span>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
{resendSuccess && (
|
|
59
|
+
<div className="bg-[var(--chart-2)]/10 border border-[var(--chart-2)]/20 rounded-[var(--radius)] p-3 flex items-center gap-2">
|
|
60
|
+
<CheckCircle2 className="w-5 h-5 text-[var(--chart-2)] flex-shrink-0" />
|
|
61
|
+
<span className="text-sm text-[var(--chart-2)]">{t('verifyEmail.resentSuccess')}</span>
|
|
62
|
+
</div>
|
|
63
|
+
)}
|
|
64
|
+
|
|
65
|
+
<div className="space-y-3">
|
|
66
|
+
<p className="text-center text-muted-foreground">{t('verifyEmail.notReceived')}</p>
|
|
67
|
+
<Button variant="outline" className="w-full" onClick={handleResend} disabled={isResending}>
|
|
68
|
+
{isResending ? t('verifyEmail.resending') : t('verifyEmail.resend')}
|
|
69
|
+
</Button>
|
|
70
|
+
<Button
|
|
71
|
+
type="button"
|
|
72
|
+
onClick={() => navigate('/login')}
|
|
73
|
+
variant="outline"
|
|
74
|
+
className="w-full text-muted-foreground hover:text-foreground"
|
|
75
|
+
>
|
|
76
|
+
<ArrowLeft className="w-4 h-4 mr-2" />
|
|
77
|
+
{t('verifyEmail.backToLogin')}
|
|
78
|
+
</Button>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<SocialLoginButtons onSocialLogin={provider => console.log(`Login com ${provider}`)} />
|
|
82
|
+
</AuthPageShell>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -1114,7 +1114,7 @@ export function TemplateContent() {
|
|
|
1114
1114
|
|
|
1115
1115
|
<Separator className="my-8" />
|
|
1116
1116
|
|
|
1117
|
-
{/* ── v2.2.
|
|
1117
|
+
{/* ── v2.2.1 Components ──────────────────────────────────── */}
|
|
1118
1118
|
<Separator className="my-8" />
|
|
1119
1119
|
|
|
1120
1120
|
<section>
|
|
@@ -101,5 +101,19 @@
|
|
|
101
101
|
"incorrectInfo": "Incorrect information",
|
|
102
102
|
"incompleteAnswer": "Incomplete answer",
|
|
103
103
|
"other": "Other..."
|
|
104
|
+
},
|
|
105
|
+
"page": {
|
|
106
|
+
"today": "Today",
|
|
107
|
+
"yesterday": "Yesterday",
|
|
108
|
+
"thisWeek": "This week",
|
|
109
|
+
"searchConversations": "Search conversations...",
|
|
110
|
+
"rename": "Rename",
|
|
111
|
+
"delete": "Delete",
|
|
112
|
+
"cancel": "Cancel",
|
|
113
|
+
"save": "Save",
|
|
114
|
+
"deleteConversationTitle": "Delete conversation",
|
|
115
|
+
"deleteConversationDesc": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.",
|
|
116
|
+
"renameConversationTitle": "Rename conversation",
|
|
117
|
+
"conversationNameLabel": "Conversation name"
|
|
104
118
|
}
|
|
105
119
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"heading": "Recover password",
|
|
3
|
+
"subheading": "Enter your email and we will send instructions to reset your password",
|
|
4
|
+
"emailLabel": "Email",
|
|
5
|
+
"emailPlaceholder": "your@email.com",
|
|
6
|
+
"submit": "Send instructions",
|
|
7
|
+
"submitting": "Sending...",
|
|
8
|
+
"backToLogin": "Back to login",
|
|
9
|
+
"heroImageAlt": "Security and technology"
|
|
10
|
+
}
|