diff --git a/frontend/app/(auth)/login/page.tsx b/frontend/app/(auth)/login/page.tsx
index a177528..fa5b3f7 100644
--- a/frontend/app/(auth)/login/page.tsx
+++ b/frontend/app/(auth)/login/page.tsx
@@ -41,7 +41,7 @@ function LoginForm() {
const tokens = await apiLogin(email, password);
setTokens(tokens);
showToast(t('login.success'), 'success');
- router.push('/de/fahrzeuge');
+ router.push('/de/dashboard');
} catch (err) {
const message = (err as any)?.error?.message || t('login.error.invalidCredentials');
showToast(message, 'error');
diff --git a/frontend/app/[locale]/dashboard/page.tsx b/frontend/app/[locale]/dashboard/page.tsx
new file mode 100644
index 0000000..bb93abc
--- /dev/null
+++ b/frontend/app/[locale]/dashboard/page.tsx
@@ -0,0 +1,5 @@
+import { Dashboard } from '@/components/Dashboard';
+
+export default function DashboardPage() {
+ return ;
+}
diff --git a/frontend/app/[locale]/page.tsx b/frontend/app/[locale]/page.tsx
new file mode 100644
index 0000000..209dd96
--- /dev/null
+++ b/frontend/app/[locale]/page.tsx
@@ -0,0 +1,5 @@
+import { Dashboard } from '@/components/Dashboard';
+
+export default function LocaleHomePage() {
+ return ;
+}
diff --git a/frontend/components/Dashboard.tsx b/frontend/components/Dashboard.tsx
new file mode 100644
index 0000000..53f4404
--- /dev/null
+++ b/frontend/components/Dashboard.tsx
@@ -0,0 +1,249 @@
+'use client';
+
+import { useState, useEffect, useCallback } from 'react';
+import { useRouter } from 'next/navigation';
+import { Card } from '@/components/ui/Card';
+import { Button } from '@/components/ui/Button';
+import { Table } from '@/components/ui/Table';
+import { useI18n } from '@/lib/i18n';
+import { listVehicles, type VehicleResponse } from '@/lib/vehicles';
+
+interface DashboardStats {
+ total: number;
+ available: number;
+ reserved: number;
+ sold: number;
+ totalValue: number;
+}
+
+interface StatCardProps {
+ icon: React.ReactNode;
+ label: string;
+ value: string;
+ testId: string;
+}
+
+function StatCard({ icon, label, value, testId }: StatCardProps) {
+ return (
+
+
+ {icon}
+ {label}
+
+
{value}
+
+ );
+}
+
+const CarIcon = (
+
+);
+
+const CheckCircleIcon = (
+
+);
+
+const ClockIcon = (
+
+);
+
+const TagIcon = (
+
+);
+
+const EuroIcon = (
+
+);
+
+export function Dashboard() {
+ const router = useRouter();
+ const { t } = useI18n();
+ const [recentVehicles, setRecentVehicles] = useState([]);
+ const [stats, setStats] = useState({
+ total: 0,
+ available: 0,
+ reserved: 0,
+ sold: 0,
+ totalValue: 0,
+ });
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ const fetchDashboardData = useCallback(async () => {
+ setLoading(true);
+ setError(null);
+ try {
+ const [recentResponse, allResponse] = await Promise.all([
+ listVehicles({ page: 1, page_size: 5, sort: '-created_at' }),
+ listVehicles({ page: 1, page_size: 1000 }),
+ ]);
+
+ setRecentVehicles(recentResponse.items);
+
+ const allVehicles = allResponse.items;
+ const computedStats: DashboardStats = {
+ total: allResponse.total,
+ available: allVehicles.filter(v => v.availability === 'available').length,
+ reserved: allVehicles.filter(v => v.availability === 'reserved').length,
+ sold: allVehicles.filter(v => v.availability === 'sold').length,
+ totalValue: allVehicles.reduce((sum, v) => sum + v.price, 0),
+ };
+ setStats(computedStats);
+ } catch (err: unknown) {
+ const apiErr = err as { error?: { message?: string } };
+ setError(apiErr?.error?.message || t('dashboard.error'));
+ } finally {
+ setLoading(false);
+ }
+ }, [t]);
+
+ useEffect(() => {
+ fetchDashboardData();
+ }, [fetchDashboardData]);
+
+ const currencyFormatter = new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' });
+
+ const vehicleColumns = [
+ {
+ key: 'make',
+ label: t('dashboard.make'),
+ render: (row: VehicleResponse) => (
+
+ ),
+ },
+ { key: 'model', label: t('dashboard.model') },
+ { key: 'fin', label: t('dashboard.fin') },
+ {
+ key: 'price',
+ label: t('dashboard.price'),
+ render: (row: VehicleResponse) => currencyFormatter.format(row.price),
+ },
+ { key: 'availability', label: t('dashboard.availability') },
+ ];
+
+ if (loading) {
+ return (
+
+ {t('common.loading')}
+
+ );
+ }
+
+ if (error) {
+ return (
+
+ {error}
+
+ );
+ }
+
+ return (
+
+
+ {t('dashboard.title')}
+
+
+
+
+
+
+
+
+
+
+
+ {EuroIcon}
+ {t('dashboard.totalValue')}
+
+
+ {currencyFormatter.format(stats.totalValue)}
+
+
+
+
+
{t('dashboard.quickActions')}
+
+
+
+
+
+
+
+
+
{t('dashboard.recentVehicles')}
+
+ {recentVehicles.length > 0 ? (
+ row.id} />
+ ) : (
+
+ {t('dashboard.noVehicles')}
+
+ )}
+
+
+
+ );
+}
diff --git a/frontend/components/Navigation.tsx b/frontend/components/Navigation.tsx
index 5ecd351..4c410b7 100644
--- a/frontend/components/Navigation.tsx
+++ b/frontend/components/Navigation.tsx
@@ -13,6 +13,15 @@ interface NavItem {
}
const navItems: NavItem[] = [
+ {
+ href: '/de/dashboard',
+ labelKey: 'nav.dashboard',
+ icon: (
+
+ ),
+ },
{
href: '/de/fahrzeuge',
labelKey: 'nav.vehicles',
diff --git a/frontend/messages/de.json b/frontend/messages/de.json
index fea554e..2186a9d 100644
--- a/frontend/messages/de.json
+++ b/frontend/messages/de.json
@@ -19,6 +19,24 @@
"nav.retouch": "Bildretusche",
"nav.menu": "Menü",
"nav.appName": "ERP Nutzfahrzeuge",
+ "dashboard.title": "Dashboard",
+ "dashboard.totalVehicles": "Fahrzeuge gesamt",
+ "dashboard.available": "Verfügbar",
+ "dashboard.reserved": "Reserviert",
+ "dashboard.sold": "Verkauft",
+ "dashboard.totalValue": "Gesamtwert",
+ "dashboard.quickActions": "Schnellaktionen",
+ "dashboard.newVehicle": "Neues Fahrzeug",
+ "dashboard.newContact": "Neuer Kontakt",
+ "dashboard.newSale": "Neuer Verkauf",
+ "dashboard.recentVehicles": "Letzte Fahrzeuge",
+ "dashboard.noVehicles": "Keine Fahrzeuge vorhanden",
+ "dashboard.error": "Fehler beim Laden der Daten",
+ "dashboard.make": "Marke",
+ "dashboard.model": "Modell",
+ "dashboard.fin": "FIN",
+ "dashboard.price": "Preis",
+ "dashboard.availability": "Verfügbarkeit",
"common.save": "Speichern",
"common.cancel": "Abbrechen",
"common.delete": "Löschen",
diff --git a/frontend/messages/en.json b/frontend/messages/en.json
index c90343b..980b89f 100644
--- a/frontend/messages/en.json
+++ b/frontend/messages/en.json
@@ -19,6 +19,24 @@
"nav.retouch": "Image Retouch",
"nav.menu": "Menu",
"nav.appName": "ERP Commercial Vehicles",
+ "dashboard.title": "Dashboard",
+ "dashboard.totalVehicles": "Total Vehicles",
+ "dashboard.available": "Available",
+ "dashboard.reserved": "Reserved",
+ "dashboard.sold": "Sold",
+ "dashboard.totalValue": "Total Value",
+ "dashboard.quickActions": "Quick Actions",
+ "dashboard.newVehicle": "New Vehicle",
+ "dashboard.newContact": "New Contact",
+ "dashboard.newSale": "New Sale",
+ "dashboard.recentVehicles": "Recent Vehicles",
+ "dashboard.noVehicles": "No vehicles available",
+ "dashboard.error": "Error loading data",
+ "dashboard.make": "Make",
+ "dashboard.model": "Model",
+ "dashboard.fin": "VIN",
+ "dashboard.price": "Price",
+ "dashboard.availability": "Availability",
"common.save": "Save",
"common.cancel": "Cancel",
"common.delete": "Delete",