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.
Files changed (42) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +1 -1
  3. package/dist/ThemeContext-BgclCB35.js +1856 -0
  4. package/dist/ThemeContext-DQUOeziy.cjs +1855 -0
  5. package/dist/VerifyEmailPage-RrUApqBN.js +3214 -0
  6. package/dist/VerifyEmailPage-VoMI7MYH.cjs +3213 -0
  7. package/dist/XerticaProvider-BSyFrmC0.js +49 -0
  8. package/dist/XerticaProvider-CiNKjMx1.cjs +48 -0
  9. package/dist/XerticaXLogo-B2svDGZh.cjs +251 -0
  10. package/dist/XerticaXLogo-CowGv7BC.js +252 -0
  11. package/dist/brand.cjs.js +2 -2
  12. package/dist/brand.es.js +2 -2
  13. package/dist/hooks.cjs.js +1 -1
  14. package/dist/hooks.es.js +1 -1
  15. package/dist/index.cjs.js +5 -5
  16. package/dist/index.es.js +5 -5
  17. package/dist/layout.cjs.js +1 -1
  18. package/dist/layout.es.js +1 -1
  19. package/dist/pages.cjs.js +1 -1
  20. package/dist/pages.es.js +1 -1
  21. package/dist/sidebar-CRMiBtAi.js +801 -0
  22. package/dist/sidebar-CZ2mWaMM.cjs +800 -0
  23. package/dist/xertica-ui.css +1 -1
  24. package/package.json +1 -1
  25. package/templates/CLAUDE.md +165 -180
  26. package/templates/package.json +2 -2
  27. package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +9 -7
  28. package/templates/src/features/auth/ui/LoginContent.tsx +10 -8
  29. package/templates/src/features/auth/ui/ResetPasswordContent.tsx +179 -177
  30. package/templates/src/features/auth/ui/SocialLoginButtons.tsx +9 -4
  31. package/templates/src/features/auth/ui/VerifyEmailContent.tsx +84 -82
  32. package/templates/src/features/template/ui/TemplateContent.tsx +1 -1
  33. package/templates/src/locales/en/components/assistant.json +14 -0
  34. package/templates/src/locales/en/pages/forgotPassword.json +10 -0
  35. package/templates/src/locales/en/pages/templates.json +1 -1
  36. package/templates/src/locales/es/components/assistant.json +14 -0
  37. package/templates/src/locales/es/pages/forgotPassword.json +10 -0
  38. package/templates/src/locales/es/pages/templates.json +1 -1
  39. package/templates/src/locales/pt-BR/components/assistant.json +14 -0
  40. package/templates/src/locales/pt-BR/pages/forgotPassword.json +10 -0
  41. package/templates/src/locales/pt-BR/pages/templates.json +1 -1
  42. package/templates/src/pages/AssistantPage.tsx +464 -463
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xertica-ui",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "description": "Xertica UI — Enterprise-grade React design system with Tailwind CSS v4, Radix UI, and AI-first documentation.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs.js",
@@ -1,180 +1,165 @@
1
- # Xertica UI — Project Rules
2
-
3
- This project uses **xertica-ui**, an enterprise React design system built on Tailwind CSS v4, Radix UI, and Lucide Icons.
4
-
5
- > For the complete component reference, read `node_modules/xertica-ui/llms-full.txt`.
6
- > For a compact quick-reference, read `node_modules/xertica-ui/llms-compact.txt`.
7
- > For component selection guidance, read `node_modules/xertica-ui/docs/decision-tree.md`.
8
-
9
- ---
10
-
11
- ## Import Rules
12
-
13
- Always use the most specific subpath — never import from a category you don't need:
14
-
15
- ```tsx
16
- import { Button, Card, Input, Badge, Table, Dialog } from 'xertica-ui/ui';
17
- import { Sidebar, Header } from 'xertica-ui/layout';
18
- import { XerticaProvider, XerticaLogo, ThemeToggle } from 'xertica-ui/brand';
19
- import { XerticaAssistant, generateDemoResponse } from 'xertica-ui/assistant';
20
- import { VideoPlayer, AudioPlayer } from 'xertica-ui/media';
21
- import { useLayout, useOptionalLayout, useTheme } from 'xertica-ui/hooks';
22
- import 'xertica-ui/style.css'; // import once at root only
23
- ```
24
-
25
- The root `from 'xertica-ui'` remains valid for backward compatibility, but scaffolded project code must prefer the subpaths above.
26
-
27
- Icons are **never** from xertica-ui always use `lucide-react`:
28
-
29
- ```tsx
30
- import { Home, Settings, Plus, Trash2, ChevronRight } from 'lucide-react';
31
- ```
32
-
33
- ---
34
-
35
- ## Non-Negotiable Rules
36
-
37
- ### HTML never use raw elements for UI
38
-
39
- | Never | Always |
40
- | -------------------------------- | ----------------------------------- |
41
- | `<button>` | `<Button>` from `xertica-ui/ui` |
42
- | `<input>` | `<Input>` from `xertica-ui/ui` |
43
- | `<select>` | `<Select>` from `xertica-ui/ui` |
44
- | `<h1>` / `<h2>` for page headers | `<PageHeader><PageHeaderHeading>` |
45
- | `<div class="card ...">` | `<Card>` from `xertica-ui/ui` |
46
- | custom scrollbar div | `<ScrollArea>` from `xertica-ui/ui` |
47
-
48
- ### Colors — context-dependent rules
49
-
50
- | ❌ Never (any context) | Reason |
51
- | ---------------------------------------- | -------------------------- |
52
- | `#3b82f6`, `rgb(59,130,246)`, `hsl(...)` | Raw values non-themeable |
53
- | `style={{ color: '#...' }}` for theming | Non-themeable inline style |
54
-
55
- | Wrong for semantic/status contexts | ✅ Required instead |
56
- | ------------------------------------- | ------------------- |
57
- | `bg-red-500` for error states | `bg-destructive` |
58
- | `text-red-500` for error text | `text-destructive` |
59
- | `bg-green-500` for success states | `bg-success` |
60
- | `bg-yellow-500` for warnings | `bg-warning` |
61
-
62
- > For **layout, spacing, and general non-semantic UI** (custom components, decorative elements, Storybook stories where no semantic token applies), standard Tailwind color utilities like `bg-blue-500` or `text-gray-700` are acceptable.
63
-
64
- Semantic token reference:
65
-
66
- ```
67
- bg-background / text-foreground → page background and primary text
68
- bg-card / text-card-foreground → card surfaces
69
- bg-muted / text-muted-foreground → subdued areas and secondary text
70
- bg-primary / text-primary-foreground → primary actions
71
- bg-destructive → danger / error states
72
- bg-success / bg-warning / bg-info → semantic status states
73
- bg-accent → hover states
74
- border-border → standard borders
75
- border-input → form field borders
76
- ```
77
-
78
- ### Layout — always use context, never hardcode
79
-
80
- ```tsx
81
- // Correct
82
- import { useLayout } from 'xertica-ui/hooks';
83
- const { sidebarExpanded, sidebarWidth } = useLayout();
84
- <div style={{ paddingLeft: sidebarExpanded ? `${sidebarWidth}px` : '80px' }}>
85
-
86
- // ✅ Correct for reusable components that may render without providers
87
- import { useOptionalLayout } from 'xertica-ui/hooks';
88
- const layout = useOptionalLayout();
89
- const fallbackSidebarWidth = layout?.sidebarWidth ?? 80;
90
-
91
- // ❌ Wrong — never hardcode sidebar width
92
- <div style={{ paddingLeft: '256px' }}>
93
- ```
94
-
95
- ### Destructive actions — always confirm
96
-
97
- ```tsx
98
- // Correctconfirm before executing
99
- <AlertDialog>
100
- <AlertDialogTrigger asChild>
101
- <Button variant="destructive">Delete</Button>
102
- </AlertDialogTrigger>
103
- <AlertDialogContent>...</AlertDialogContent>
104
- </AlertDialog>
105
-
106
- // Wrong never execute destructive action directly on click
107
- <Button variant="destructive" onClick={deleteRecord}>Delete</Button>
108
- ```
109
-
110
- ---
111
-
112
- ## Page Structure
113
-
114
- Every page must follow this structure:
115
-
116
- ```tsx
117
- import { PageHeader, PageHeaderHeading, PageHeaderDescription } from 'xertica-ui/ui';
118
-
119
- export function MyPage() {
120
- return (
121
- <>
122
- <PageHeader>
123
- <PageHeaderHeading>Page Title</PageHeaderHeading>
124
- <PageHeaderDescription>Optional subtitle</PageHeaderDescription>
125
- <Button>Primary Action</Button>
126
- </PageHeader>
127
- <div className="p-6 space-y-6">{/* Page content */}</div>
128
- </>
129
- );
130
- }
131
- ```
132
-
133
- ---
134
-
135
- ## App Root Structure
136
-
137
- ```tsx
138
- import { XerticaProvider } from 'xertica-ui/brand';
139
- import { BrowserRouter } from 'react-router-dom';
140
- import 'xertica-ui/style.css';
141
-
142
- function Root() {
143
- const geminiApiKey = import.meta.env.VITE_GEMINI_API_KEY;
144
- const googleMapsApiKey = import.meta.env.VITE_GOOGLE_MAPS_API_KEY;
145
-
146
- return (
147
- <XerticaProvider apiKey={geminiApiKey} googleMapsApiKey={googleMapsApiKey}>
148
- <BrowserRouter>
149
- <App />
150
- </BrowserRouter>
151
- </XerticaProvider>
152
- );
153
- }
154
- ```
155
-
156
- `XerticaProvider` is the app-level convenience wrapper used by this template. It composes theme, brand colors, language, layout, assistant/API keys, Google Maps, tooltips, and toasts. Most individual `xertica-ui` components are designed to render independently; use `useOptionalLayout()` when building reusable components that should keep working outside this provider.
157
-
158
- ---
159
-
160
- ## Toast Notifications
161
-
162
- ```tsx
163
- import { toast } from 'sonner'; // sonner is re-exported, no extra install needed
164
-
165
- toast.success('Saved successfully');
166
- toast.error('Something went wrong');
167
- toast.info('Processing...');
168
- toast.warning('Check your input');
169
- ```
170
-
171
- Never render `<Toaster>` manually — it is auto-injected by `<XerticaProvider>`.
172
-
173
- ---
174
-
175
- ## Before Writing Any Component
176
-
177
- 1. Check `node_modules/xertica-ui/llms-compact.txt` — the component may already exist.
178
- 2. Check `node_modules/xertica-ui/docs/decision-tree.md` — you may be choosing the wrong component.
179
- 3. Read the specific component doc at `node_modules/xertica-ui/docs/components/[name].md`.
180
- 4. Never create custom primitives that duplicate library components.
1
+ # Xertica UI — Project Rules
2
+
3
+ This project uses **xertica-ui**, an enterprise React design system built on Tailwind CSS v4, Radix UI, and Lucide Icons.
4
+
5
+ ## Command Reference
6
+
7
+ - **Dev Server**: `npm run dev`
8
+ - **Build Production**: `npm run build`
9
+ - **Linter**: `npm run lint` / `npm run lint:fix`
10
+ - **Type Checker**: `npm run type-check`
11
+ - **All Validation Checks**: `npm run check` (type-check + lint)
12
+ - **Code Formatter**: `npm run format`
13
+
14
+ ---
15
+
16
+ ## Architecture Feature-Sliced Design (FSD) + Feature-Driven Architecture (FDA)
17
+
18
+ This project follows **FSD (Feature-Sliced Design)** layered architecture combined with **FDA (Feature-Driven Architecture)** vertical slicing. Layers can only import from layers below them.
19
+
20
+ - **`src/app/`**: Application shell (BrowserRouter, AppLayout, AuthGuard, AuthContext). No business logic.
21
+ - **`src/shared/`**: Shared layer with no business domain (config/navigation, lib/auth, types). Importable by any layer.
22
+ - **`src/features/`**: Self-contained vertical slices by business capability (auth, home, template, assistant). Import only from the barrel `src/features/<name>/index.ts` never from internal feature paths.
23
+ - **`src/pages/`**: Thin route wrappers composing `AppLayout` + feature content. No logic or API calls here.
24
+
25
+ ### Adding a New Route
26
+ 1. **Create the feature content**: `src/features/<name>/ui/<NameContent>.tsx`
27
+ 2. **Export from the barrel**: `src/features/<name>/index.ts`
28
+ 3. **Create the page**: `src/pages/<NamePage>.tsx` (thin AppLayout wrapper)
29
+ 4. **Register the route**: Add route path, label, and icon to the `routes` array in `src/shared/config/navigation.ts`.
30
+ 5. **Register the `<Route>`**: Add the route element inside `<Routes>` in `src/app/components/AuthGuard.tsx`.
31
+
32
+ ---
33
+
34
+ ## Import Rules
35
+
36
+ Always use the correct `xertica-ui` subpath:
37
+ - **UI Primitives**: `xertica-ui/ui` (e.g. `Button`, `Card`, `Input`, `Badge`, `Table`, `Dialog`, `Select`)
38
+ - **Providers & Brand**: `xertica-ui/brand` (e.g. `XerticaProvider`, `XerticaLogo`, `ThemeToggle`, `LanguageSelector`)
39
+ - **Navigation Shell**: `xertica-ui/layout` (e.g. `Sidebar`, `Header`)
40
+ - **AI Assistant**: `xertica-ui/assistant` (e.g. `XerticaAssistant`, `generateDemoResponse`)
41
+ - **Media Players**: `xertica-ui/media` (e.g. `VideoPlayer`, `AudioPlayer`)
42
+ - **Hooks & Contexts**: `xertica-ui/hooks` (e.g. `useLayout`, `useOptionalLayout`, `useTheme`, `useLanguage`)
43
+ - **Styles**: Import `xertica-ui/style.css` once in `src/styles/index.css` (never directly inside components).
44
+
45
+ Icons always come from `lucide-react` — never from `xertica-ui`.
46
+
47
+ ---
48
+
49
+ ## Non-Negotiable Coding Rules
50
+
51
+ ### HTML & Radix Elements
52
+ Never use native HTML interactive elements where design system components exist:
53
+ - `<Button>` instead of `<button>`
54
+ - `<Input>` instead of `<input>`
55
+ - `<Select>` instead of `<select>`
56
+ - `<PageHeader>` + `<PageHeaderHeading>` instead of `<h1>`/`<h2>` for page titles
57
+ - `<Card>` instead of `<div className="card">`
58
+ - `<ScrollArea>` instead of custom scrollbars
59
+
60
+ ### Color & Border Radius Styling
61
+ - **Never use raw color values** (`#hex`, `rgb()`, `hsl()`) or inline styles for theming.
62
+ - **Never use standard Tailwind color classes for semantic/status contexts** (e.g., do not use `bg-red-500` or `text-green-500` for status/feedback/errors). Use semantic tokens: `bg-destructive`/`text-destructive` for errors, `bg-success` for success, `bg-warning` for warnings, `bg-info` for info.
63
+ - **Tailwind colors** (`bg-blue-500`, `text-gray-700`) are allowed **only** for layout, spacing, and general non-semantic UI where no semantic token applies.
64
+ - **Borders**: Always use `rounded-[var(--radius)]` — never use fixed radius classes like `rounded-lg` or `rounded-xl`.
65
+
66
+ ### Layout State
67
+ Never hardcode sidebar or layout widths (e.g. `256px`). Read them dynamically:
68
+ - `const { sidebarExpanded, sidebarWidth } = useLayout()`
69
+ - For components that might render outside the layout provider:
70
+ `const layout = useOptionalLayout(); const fallbackSidebarWidth = layout?.sidebarWidth ?? 80;`
71
+
72
+ ### Confirm Destructive Actions
73
+ Always wrap destructive actions in `<AlertDialog>` for confirmation:
74
+ ```tsx
75
+ <AlertDialog>
76
+ <AlertDialogTrigger asChild>
77
+ <Button variant="destructive">Delete</Button>
78
+ </AlertDialogTrigger>
79
+ <AlertDialogContent>
80
+ <AlertDialogHeader>
81
+ <AlertDialogTitle>Are you sure?</AlertDialogTitle>
82
+ <AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
83
+ </AlertDialogHeader>
84
+ <AlertDialogFooter>
85
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
86
+ <AlertDialogAction onClick={handleDelete}>Delete</AlertDialogAction>
87
+ </AlertDialogFooter>
88
+ </AlertDialogContent>
89
+ </AlertDialog>
90
+ ```
91
+
92
+ ### Toast Notifications
93
+ Always use `toast` from `sonner` and translate messages via `t()`:
94
+ ```tsx
95
+ toast.success(t('common.saveSuccess'));
96
+ toast.error(t('errors.somethingWentWrong'));
97
+ ```
98
+ Never render `<Toaster>` manually it is auto-injected by `<XerticaProvider>`.
99
+
100
+ ---
101
+
102
+ ## Internationalization (i18n)
103
+
104
+ Every user-facing string must go through `useTranslation()`:
105
+ - Translate all labels, placeholders, titles, aria-labels, tooltips, toasts, etc.
106
+ - Add translation keys to split JSON files in `src/locales/<lang>/` for all languages.
107
+ - **Monolingual Mode**: `<LanguageSelector>` auto-hides when a single language is configured. Use `<LanguageSelector showWhenMonolingual />` to override.
108
+ - **Dynamic mock data / outside React cycle**: Always use **factory functions** returning `i18n.t(...)` rather than static arrays, so translations update dynamically:
109
+ ```tsx
110
+ export function getMockOptions() {
111
+ return [i18n.t('feedback.notWhatIWanted')];
112
+ }
113
+ ```
114
+ - Inside components, wrap enum label maps in `useMemo([..., t])`.
115
+
116
+ ---
117
+
118
+ ## Server State (React Query)
119
+
120
+ - Place typed fetch functions in `data/mock.ts` and React Query wrappers in `hooks/use<Xxx>.ts`.
121
+ - **Language-aware queryKey is MANDATORY**: Every hook returning translated data must include `language` in its `queryKey` so switching languages invalidates the cache and triggers a refetch:
122
+ ```tsx
123
+ const { language } = useLanguage();
124
+ return useQuery({
125
+ queryKey: ['home', 'feature-cards', language],
126
+ queryFn: fetchFeatureCards,
127
+ staleTime: 10 * 60 * 1000
128
+ });
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Loading States (Skeletons)
134
+
135
+ Always render matching skeletons instead of spinners for data loading:
136
+ - Wrap cards/lists with their matching FSD skeleton companions (`ActivityCardSkeleton`, `ProfileCardSkeleton`, `ProjectCardSkeleton`, `NotificationCardSkeleton`, `QuickActionCardSkeleton`, `FeatureCardSkeleton`, `StatsCardSkeleton`).
137
+ - Pass `rows` to skeletons (e.g. `<ActivityCardSkeleton rows={5} />`) to match the loaded state height.
138
+ - For tables, build loading rows using `<TableRow>` + `<TableCell>` + `<Skeleton className="h-3.5 w-28" />`.
139
+
140
+ ---
141
+
142
+ ## Theme & Token Customization
143
+
144
+ - Customize colors, fonts, and dark mode classes by editing `src/styles/xertica/tokens.css`.
145
+ - Update theme or languages using the CLI: `npx xertica-ui update`.
146
+
147
+ ---
148
+
149
+ ## Authentication Pattern
150
+
151
+ The auth flow is managed in `src/app/context/AuthContext.tsx` via the `useAuth()` hook:
152
+ - `getStoredUser()` / `storeUser()` / `clearStoredUser()` — from `src/shared/lib/auth.ts`
153
+ - Auth pages (`/login`, `/forgot-password`, etc.) redirect to `/home` when user is already logged in
154
+ - Protected routes use `<ProtectedRoute>` wrapper that redirects to `/login` if user is null
155
+ - `useAuth().login(email, password)` stores the user
156
+ - `useAuth().logout()` clears storage and navigates to `/login`
157
+
158
+ ---
159
+
160
+ ## Before Writing Any Component
161
+
162
+ 1. Check `node_modules/xertica-ui/llms-compact.txt` — the component may already exist.
163
+ 2. Check `node_modules/xertica-ui/docs/decision-tree.md` you may be choosing the wrong component.
164
+ 3. Read the specific component doc at `node_modules/xertica-ui/docs/components/[name].md`.
165
+ 4. Never create custom primitives that duplicate library components.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xertica-ui-template",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -24,7 +24,7 @@
24
24
  "react-i18next": "^17.0.8",
25
25
  "react-router-dom": "^7.1.3",
26
26
  "sonner": "^1.7.3",
27
- "xertica-ui": "^2.2.0",
27
+ "xertica-ui": "^2.2.1",
28
28
  "zustand": "^5.0.13"
29
29
  },
30
30
  "devDependencies": {
@@ -5,9 +5,11 @@ import { ArrowLeft } from 'lucide-react';
5
5
  import { useNavigate } from 'react-router-dom';
6
6
  import { AuthPageShell } from './AuthPageShell';
7
7
  import { SocialLoginButtons } from './SocialLoginButtons';
8
+ import { useTranslation } from 'react-i18next';
8
9
 
9
10
  export function ForgotPasswordContent() {
10
11
  const navigate = useNavigate();
12
+ const { t } = useTranslation();
11
13
  const [email, setEmail] = useState('');
12
14
  const [isLoading, setIsLoading] = useState(false);
13
15
 
@@ -22,35 +24,35 @@ export function ForgotPasswordContent() {
22
24
  return (
23
25
  <AuthPageShell
24
26
  imageSrc="https://images.unsplash.com/photo-1557804506-669a67965ba0?w=1200&h=800&fit=crop&auto=format"
25
- imageAlt="Segurança e tecnologia"
27
+ imageAlt={t('forgotPassword.heroImageAlt')}
26
28
  >
27
29
  <div className="text-center">
28
30
  <div className="flex items-center justify-center mb-4">
29
31
  <XerticaLogo className="h-12 w-auto text-primary dark:text-foreground" variant="theme" />
30
32
  </div>
31
- <h2 className="text-sm text-muted-foreground">Recuperar senha</h2>
33
+ <h2 className="text-sm text-muted-foreground">{t('forgotPassword.heading')}</h2>
32
34
  <p className="mt-2 text-muted-foreground">
33
- Digite seu email e enviaremos instruções para redefinir sua senha
35
+ {t('forgotPassword.subheading')}
34
36
  </p>
35
37
  </div>
36
38
 
37
39
  <form className="space-y-6" onSubmit={handleSubmit}>
38
40
  <div className="form-group space-y-2">
39
- <Label htmlFor="email">E-mail</Label>
41
+ <Label htmlFor="email">{t('forgotPassword.emailLabel')}</Label>
40
42
  <Input
41
43
  id="email"
42
44
  name="email"
43
45
  type="email"
44
46
  required
45
47
  className="w-full"
46
- placeholder="seu@email.com"
48
+ placeholder={t('forgotPassword.emailPlaceholder')}
47
49
  value={email}
48
50
  onChange={e => setEmail(e.target.value)}
49
51
  />
50
52
  </div>
51
53
  <div className="space-y-3">
52
54
  <Button type="submit" className="w-full" disabled={isLoading}>
53
- {isLoading ? 'Enviando...' : 'Enviar instruções'}
55
+ {isLoading ? t('forgotPassword.submitting') : t('forgotPassword.submit')}
54
56
  </Button>
55
57
  <Button
56
58
  type="button"
@@ -59,7 +61,7 @@ export function ForgotPasswordContent() {
59
61
  className="w-full text-muted-foreground hover:text-foreground"
60
62
  >
61
63
  <ArrowLeft className="w-4 h-4 mr-2" />
62
- Voltar para login
64
+ {t('forgotPassword.backToLogin')}
63
65
  </Button>
64
66
  </div>
65
67
  </form>
@@ -4,6 +4,7 @@ import { XerticaLogo } from 'xertica-ui/brand';
4
4
  import { useNavigate } from 'react-router-dom';
5
5
  import { AuthPageShell } from './AuthPageShell';
6
6
  import { SocialLoginButtons } from './SocialLoginButtons';
7
+ import { useTranslation } from 'react-i18next';
7
8
 
8
9
  interface LoginContentProps {
9
10
  onLogin: (email: string, password: string) => boolean;
@@ -11,6 +12,7 @@ interface LoginContentProps {
11
12
 
12
13
  export function LoginContent({ onLogin }: LoginContentProps) {
13
14
  const navigate = useNavigate();
15
+ const { t } = useTranslation();
14
16
  const [email, setEmail] = useState('');
15
17
  const [password, setPassword] = useState('');
16
18
  const [isLoading, setIsLoading] = useState(false);
@@ -21,38 +23,38 @@ export function LoginContent({ onLogin }: LoginContentProps) {
21
23
  setError('');
22
24
  setIsLoading(true);
23
25
  await new Promise(resolve => setTimeout(resolve, 1000));
24
- if (!onLogin(email, password)) setError('Por favor, preencha todos os campos');
26
+ if (!onLogin(email, password)) setError(t('login.errorFillFields'));
25
27
  setIsLoading(false);
26
28
  };
27
29
 
28
30
  return (
29
31
  <AuthPageShell
30
32
  imageSrc="https://images.unsplash.com/photo-1551434678-e076c223a692?w=1200&h=800&fit=crop&auto=format"
31
- imageAlt="Equipe trabalhando com tecnologia"
33
+ imageAlt={t('login.heroImageAlt')}
32
34
  >
33
35
  <div className="text-center">
34
36
  <div className="flex items-center justify-center mb-4">
35
37
  <XerticaLogo className="h-12 w-auto text-primary dark:text-foreground" variant="theme" />
36
38
  </div>
37
- <h2 className="text-sm text-muted-foreground">Faça login em sua conta</h2>
39
+ <h2 className="text-sm text-muted-foreground">{t('login.heading')}</h2>
38
40
  </div>
39
41
 
40
42
  <form className="space-y-6" onSubmit={handleSubmit}>
41
43
  <div className="space-y-2">
42
- <Label htmlFor="email">E-mail</Label>
44
+ <Label htmlFor="email">{t('login.emailLabel')}</Label>
43
45
  <Input
44
46
  id="email"
45
47
  name="email"
46
48
  type="email"
47
49
  required
48
50
  className="w-full"
49
- placeholder="seu@email.com"
51
+ placeholder={t('login.emailPlaceholder')}
50
52
  value={email}
51
53
  onChange={e => setEmail(e.target.value)}
52
54
  />
53
55
  </div>
54
56
  <div className="space-y-2">
55
- <Label htmlFor="password">Senha</Label>
57
+ <Label htmlFor="password">{t('login.passwordLabel')}</Label>
56
58
  <Input
57
59
  id="password"
58
60
  name="password"
@@ -66,7 +68,7 @@ export function LoginContent({ onLogin }: LoginContentProps) {
66
68
  </div>
67
69
  {error && <div className="text-destructive text-sm text-center">{error}</div>}
68
70
  <Button type="submit" className="w-full" disabled={isLoading}>
69
- {isLoading ? 'Entrando...' : 'Entrar'}
71
+ {isLoading ? t('login.submitting') : t('login.submit')}
70
72
  </Button>
71
73
  <div className="text-center">
72
74
  <button
@@ -74,7 +76,7 @@ export function LoginContent({ onLogin }: LoginContentProps) {
74
76
  onClick={() => navigate('/forgot-password')}
75
77
  className="text-sm text-primary hover:opacity-80 transition-colors"
76
78
  >
77
- Esqueceu sua senha?
79
+ {t('login.forgotPassword')}
78
80
  </button>
79
81
  </div>
80
82
  </form>