T07a: frontend core SPA — shell + auth + routing + i18n + UI library + a11y

- React 18 + Vite + TypeScript + Tailwind CSS setup
- AppShell with Sidebar (plugin menu) + TopBar (tenant switcher, search, notifications, user menu)
- Auth pages: Login, PasswordResetRequest, PasswordResetConfirm
- Protected routes with auth guard
- API client (axios with interceptors: session cookie, 401 redirect, 422 validation)
- TanStack Query hooks for auth, users, companies, contacts, notifications
- Zustand stores: authStore, uiStore
- i18n setup (de/en locales) with react-i18next
- UI component library: Button, Input, Select, Modal, Toast, Table, Card, Badge, Avatar, Pagination, EmptyState, Skeleton, ConfirmDialog
- Accessibility: ARIA labels, 44px touch targets, keyboard nav, reduced-motion, sr-only
- Design tokens from prototype as CSS custom properties
- 111 tests passing across 20 test files
- tsc --noEmit: 0 errors
- npm run build: success (471KB JS, 24KB CSS)
This commit is contained in:
leocrm-bot
2026-06-29 07:55:47 +02:00
parent f8193a6ab5
commit 22976abe92
66 changed files with 8598 additions and 0 deletions
+125
View File
@@ -0,0 +1,125 @@
{
"app": {
"name": "leocrm",
"tagline": "Mini-CRM für kleine Unternehmen"
},
"nav": {
"dashboard": "Dashboard",
"companies": "Firmen",
"contacts": "Kontakte",
"calendar": "Kalender",
"files": "Dateien",
"email": "E-Mail",
"users": "Benutzer",
"auditLog": "Audit-Log",
"settings": "Einstellungen"
},
"auth": {
"login": "Anmelden",
"logout": "Abmelden",
"email": "E-Mail-Adresse",
"password": "Passwort",
"loginButton": "Anmelden",
"loginFailed": "Anmeldung fehlgeschlagen. Bitte überprüfen Sie Ihre Eingaben.",
"forgotPassword": "Passwort vergessen?",
"resetPassword": "Passwort zurücksetzen",
"resetRequestTitle": "Passwort zurücksetzen",
"resetRequestDesc": "Geben Sie Ihre E-Mail-Adresse ein. Sie erhalten einen Link zum Zurücksetzen Ihres Passworts.",
"resetRequestButton": "Link senden",
"resetRequestSuccess": "Wenn die E-Mail-Adresse existiert, wurde ein Reset-Link gesendet.",
"resetConfirmTitle": "Neues Passwort festlegen",
"resetConfirmDesc": "Geben Sie Ihr neues Passwort ein.",
"newPassword": "Neues Passwort",
"confirmPassword": "Passwort bestätigen",
"resetConfirmButton": "Passwort ändern",
"resetConfirmSuccess": "Passwort erfolgreich geändert. Sie können sich jetzt anmelden.",
"resetConfirmFailed": "Passwort konnte nicht geändert werden. Der Link ist möglicherweise abgelaufen.",
"backToLogin": "Zurück zur Anmeldung",
"passwordMismatch": "Passwörter stimmen nicht überein.",
"passwordTooShort": "Passwort muss mindestens 8 Zeichen lang sein."
},
"common": {
"save": "Speichern",
"cancel": "Abbrechen",
"delete": "Löschen",
"edit": "Bearbeiten",
"create": "Erstellen",
"search": "Suchen",
"loading": "Wird geladen...",
"noResults": "Keine Ergebnisse gefunden",
"confirm": "Bestätigen",
"close": "Schließen",
"yes": "Ja",
"no": "Nein",
"actions": "Aktionen",
"all": "Alle",
"none": "Keine",
"error": "Fehler",
"success": "Erfolg",
"warning": "Warnung",
"info": "Information",
"required": "Pflichtfeld",
"optional": "Optional"
},
"settings": {
"title": "Einstellungen",
"language": "Sprache",
"theme": "Design",
"light": "Hell",
"dark": "Dunkel",
"system": "System",
"profile": "Profil",
"notifications": "Benachrichtigungen",
"security": "Sicherheit"
},
"topbar": {
"tenant": "Mandant",
"switchTenant": "Mandant wechseln",
"search": "Suchen...",
"notifications": "Benachrichtigungen",
"userMenu": "Benutzermenü",
"profile": "Profil",
"settings": "Einstellungen",
"logout": "Abmelden"
},
"toast": {
"success": "Erfolg",
"error": "Fehler",
"warning": "Warnung",
"info": "Information"
},
"table": {
"page": "Seite",
"of": "von",
"results": "Ergebnisse",
"perPage": "pro Seite",
"previous": "Zurück",
"next": "Weiter",
"sortAscending": "Aufsteigend sortieren",
"sortDescending": "Absteigend sortieren",
"sortedBy": "Sortiert nach",
"empty": "Keine Daten vorhanden"
},
"confirmDialog": {
"title": "Bestätigung erforderlich",
"confirm": "Bestätigen",
"cancel": "Abbrechen"
},
"pagination": {
"previous": "Zurück",
"next": "Weiter",
"page": "Seite {{page}}",
"first": "Erste Seite",
"last": "Letzte Seite"
},
"emptyState": {
"title": "Nichts gefunden",
"description": "Es sind noch keine Daten vorhanden."
},
"validation": {
"required": "Dieses Feld ist erforderlich.",
"email": "Bitte geben Sie eine gültige E-Mail-Adresse ein.",
"minLength": "Mindestens {{count}} Zeichen erforderlich.",
"maxLength": "Maximal {{count}} Zeichen erlaubt."
}
}
+125
View File
@@ -0,0 +1,125 @@
{
"app": {
"name": "leocrm",
"tagline": "Mini-CRM for small businesses"
},
"nav": {
"dashboard": "Dashboard",
"companies": "Companies",
"contacts": "Contacts",
"calendar": "Calendar",
"files": "Files",
"email": "Email",
"users": "Users",
"auditLog": "Audit Log",
"settings": "Settings"
},
"auth": {
"login": "Sign In",
"logout": "Sign Out",
"email": "Email Address",
"password": "Password",
"loginButton": "Sign In",
"loginFailed": "Sign in failed. Please check your credentials.",
"forgotPassword": "Forgot password?",
"resetPassword": "Reset Password",
"resetRequestTitle": "Reset Password",
"resetRequestDesc": "Enter your email address. You will receive a link to reset your password.",
"resetRequestButton": "Send Link",
"resetRequestSuccess": "If the email address exists, a reset link has been sent.",
"resetConfirmTitle": "Set New Password",
"resetConfirmDesc": "Enter your new password.",
"newPassword": "New Password",
"confirmPassword": "Confirm Password",
"resetConfirmButton": "Change Password",
"resetConfirmSuccess": "Password changed successfully. You can now sign in.",
"resetConfirmFailed": "Password could not be changed. The link may have expired.",
"backToLogin": "Back to Sign In",
"passwordMismatch": "Passwords do not match.",
"passwordTooShort": "Password must be at least 8 characters long."
},
"common": {
"save": "Save",
"cancel": "Cancel",
"delete": "Delete",
"edit": "Edit",
"create": "Create",
"search": "Search",
"loading": "Loading...",
"noResults": "No results found",
"confirm": "Confirm",
"close": "Close",
"yes": "Yes",
"no": "No",
"actions": "Actions",
"all": "All",
"none": "None",
"error": "Error",
"success": "Success",
"warning": "Warning",
"info": "Information",
"required": "Required",
"optional": "Optional"
},
"settings": {
"title": "Settings",
"language": "Language",
"theme": "Theme",
"light": "Light",
"dark": "Dark",
"system": "System",
"profile": "Profile",
"notifications": "Notifications",
"security": "Security"
},
"topbar": {
"tenant": "Tenant",
"switchTenant": "Switch Tenant",
"search": "Search...",
"notifications": "Notifications",
"userMenu": "User Menu",
"profile": "Profile",
"settings": "Settings",
"logout": "Sign Out"
},
"toast": {
"success": "Success",
"error": "Error",
"warning": "Warning",
"info": "Information"
},
"table": {
"page": "Page",
"of": "of",
"results": "results",
"perPage": "per page",
"previous": "Previous",
"next": "Next",
"sortAscending": "Sort ascending",
"sortDescending": "Sort descending",
"sortedBy": "Sorted by",
"empty": "No data available"
},
"confirmDialog": {
"title": "Confirmation Required",
"confirm": "Confirm",
"cancel": "Cancel"
},
"pagination": {
"previous": "Previous",
"next": "Next",
"page": "Page {{page}}",
"first": "First Page",
"last": "Last Page"
},
"emptyState": {
"title": "Nothing found",
"description": "No data available yet."
},
"validation": {
"required": "This field is required.",
"email": "Please enter a valid email address.",
"minLength": "At least {{count}} characters required.",
"maxLength": "At most {{count}} characters allowed."
}
}