From 4a17ea378e143d17496a99cbe4740e73d535d60a Mon Sep 17 00:00:00 2001 From: DanielS Date: Wed, 24 Jun 2026 01:37:01 +0200 Subject: [PATCH] feat: make orders list clearer and put navbar globally except for admin area --- shop/app/admin/orders/page.tsx | 83 +---------- shop/app/layout.tsx | 6 +- shop/app/page.tsx | 165 ++++++++++----------- shop/components/HeaderWrapper.tsx | 35 +++++ shop/components/admin/orders-table.tsx | 197 +++++++++++++++++++++++++ 5 files changed, 320 insertions(+), 166 deletions(-) create mode 100644 shop/components/HeaderWrapper.tsx create mode 100644 shop/components/admin/orders-table.tsx diff --git a/shop/app/admin/orders/page.tsx b/shop/app/admin/orders/page.tsx index b921661..b5cb8ca 100644 --- a/shop/app/admin/orders/page.tsx +++ b/shop/app/admin/orders/page.tsx @@ -1,19 +1,13 @@ import { createClient } from '@/lib/supabase/server' -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' -import { Badge } from '@/components/ui/badge' -import { Button } from '@/components/ui/button' -import { FileText, Download, ExternalLink } from 'lucide-react' -import Link from 'next/link' - +import { OrdersTable } from '@/components/admin/orders-table' import { Suspense } from 'react' export default async function AdminOrdersPage() { return ( -
+
-

Bestellungen & Rechnungen

+

Bestellungen & Rechnungen

Verwalten Sie alle Kundenbestellungen und greifen Sie auf generierte PDFs zu.

@@ -34,75 +28,8 @@ async function OrdersData() { .order('created_at', { ascending: false }) if (error) { - return
Fehler beim Laden der Bestellungen: {error.message}
+ return
Fehler beim Laden der Bestellungen: {error.message}
} - return ( - - - - - - Bestellnr. - Datum - Kunde - Betrag - Status - Rechnung - - - - {orders?.length === 0 ? ( - - - Noch keine Bestellungen vorhanden. - - - ) : ( - orders?.map((order) => ( - - - {order.order_number ?? order.id.slice(0, 8) + '...'} - - - {new Date(order.created_at).toLocaleDateString('de-DE')} - - -
{order.customer_data?.company_name || 'Privatkunde'}
-
{order.customer_data?.first_name} {order.customer_data?.last_name}
-
- - {new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(order.total_price)} - - - - {order.status} - - - - {order.pdf_url ? ( -
- - -
- ) : ( - Kein PDF - )} -
-
- )) - )} -
-
-
-
- ) + return } diff --git a/shop/app/layout.tsx b/shop/app/layout.tsx index 8c5172d..1902e47 100644 --- a/shop/app/layout.tsx +++ b/shop/app/layout.tsx @@ -2,6 +2,8 @@ import type { Metadata } from "next"; import { Geist } from "next/font/google"; import { ThemeProvider } from "next-themes"; import { InactivityTracker } from "@/components/inactivity-tracker"; +import { HeaderWrapper } from "@/components/HeaderWrapper"; +import { Navbar } from "@/components/Navbar"; import "./globals.css"; const defaultUrl = process.env.VERCEL_URL @@ -35,7 +37,9 @@ export default function RootLayout({ disableTransitionOnChange > - {children} + }> + {children} + diff --git a/shop/app/page.tsx b/shop/app/page.tsx index c2450a8..77283c4 100644 --- a/shop/app/page.tsx +++ b/shop/app/page.tsx @@ -5,106 +5,97 @@ import { Navbar } from '@/components/Navbar' export default function Home() { return ( -
- {/* Demo Banner */} -
- ⚠️ Dies ist eine **Demo-Webseite (Dummy-Shop)**. Es werden keine echten Bestellungen verarbeitet oder Zahlungen abgewickelt. -
- - - -
- {/* Hero Section: Zielgerichtet auf Lizenzen */} -
-
-
-
-
-
- CASPOS Lizenz-Management-Server -
-

- POS Software Lizenzen & Module -

-

- Erwerben und verwalten Sie digitale Lizenzen für CASPOS Kassensysteme. Sofortige Aktivierung und automatische Bereitstellung für Ihre Kunden. -

+ <> + {/* Hero Section: Zielgerichtet auf Lizenzen */} +
+
+
+
+
+
+ CASPOS Lizenz-Management-Server
+

+ POS Software Lizenzen & Module +

+

+ Erwerben und verwalten Sie digitale Lizenzen für CASPOS Kassensysteme. Sofortige Aktivierung und automatische Bereitstellung für Ihre Kunden. +

+
- {/* High-Contrast Buttons (Light/Dark Ready) */} -
- - - - - - -
+ {/* High-Contrast Buttons (Light/Dark Ready) */} +
+ + + + + +
-
+
+
- {/* Feature Grid: Aufgeteilt nach echten POS-Modulen */} -
-
-
+ {/* Feature Grid: Aufgeteilt nach echten POS-Modulen */} +
+
+
- {/* Modul 1 */} -
-
- -
-

Handel & ERP

-

Erweiterungen für Handelskassen, Bestandsführung und vollwertige Warenwirtschaftssysteme (ERP).

+ {/* Modul 1 */} +
+
+
+

Handel & ERP

+

Erweiterungen für Handelskassen, Bestandsführung und vollwertige Warenwirtschaftssysteme (ERP).

+
- {/* Modul 2 */} -
-
- -
-

Gastronomie

-

Lizenzen für mobiles Bestellen (Orderman), digitale Küchen-Monitore und interaktive Abhol-Boards.

+ {/* Modul 2 */} +
+
+
+

Gastronomie

+

Lizenzen für mobiles Bestellen (Orderman), digitale Küchen-Monitore und interaktive Abhol-Boards.

+
- {/* Modul 3 */} -
-
- -
-

Hybride Systeme

-

Das beste aus beiden Welten. Handel mit Gastronomie und umgekehrt.

+ {/* Modul 3 */} +
+
+
+

Hybride Systeme

+

Das beste aus beiden Welten. Handel mit Gastronomie und umgekehrt.

+
+
+
+
+ + {/* Kurze Info-Sektion für Partner / Händler */} +
+
+

Wie funktioniert die Bereitstellung?

+
+
+ +

1. Lizenz wählen: Gewünschtes POS-Modul im Shop selektieren.

+
+
+ +

2. Kunde zuweisen: Lizenz direkt einem Kunden-Account zuordnen.

+
+
+ +

3. Live gehen: Lizenz-Key (`.key`) wird sofort serverseitig aktiviert.

-
- - {/* Kurze Info-Sektion für Partner / Händler */} -
-
-

Wie funktioniert die Bereitstellung?

-
-
- -

1. Lizenz wählen: Gewünschtes POS-Modul im Shop selektieren.

-
-
- -

2. Kunde zuweisen: Lizenz direkt einem Kunden-Account zuordnen.

-
-
- -

3. Live gehen: Lizenz-Key (`.key`) wird sofort serverseitig aktiviert.

-
-
-
-
-
+
+ {/* Footer */}
@@ -114,6 +105,6 @@ export default function Home() { Datenschutz
-
+ ) } \ No newline at end of file diff --git a/shop/components/HeaderWrapper.tsx b/shop/components/HeaderWrapper.tsx new file mode 100644 index 0000000..b080694 --- /dev/null +++ b/shop/components/HeaderWrapper.tsx @@ -0,0 +1,35 @@ +"use client"; + +import { usePathname } from "next/navigation"; + +interface HeaderWrapperProps { + navbar: React.ReactNode; + children: React.ReactNode; +} + +export function HeaderWrapper({ navbar, children }: HeaderWrapperProps) { + const pathname = usePathname(); + const isAdmin = pathname?.startsWith("/admin"); + + if (isAdmin) { + return <>{children}; + } + + return ( +
+ {/* Demo Banner */} +
+ ⚠️ Dies ist eine **Demo-Webseite (Dummy-Shop)**. Es werden keine echten Bestellungen verarbeitet oder Zahlungen abgewickelt. +
+ + {navbar} + +
+ {children} +
+
+ ); +} diff --git a/shop/components/admin/orders-table.tsx b/shop/components/admin/orders-table.tsx new file mode 100644 index 0000000..16bd912 --- /dev/null +++ b/shop/components/admin/orders-table.tsx @@ -0,0 +1,197 @@ +"use client"; + +import { useState } from "react"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Download, ExternalLink, Search } from "lucide-react"; + +interface OrdersTableProps { + initialOrders: any[]; +} + +const statusLabel: Record = { + pending: 'Eingegangen', + active: 'In Bearbeitung', + completed: 'Abgeschlossen', + cancelled: 'Storniert', +}; + +const statusClass: Record = { + pending: 'bg-amber-500/20 text-amber-400 border border-amber-500/30', + active: 'bg-blue-500/20 text-blue-400 border border-blue-500/30', + completed: 'bg-green-500/20 text-green-400 border border-green-500/30', + cancelled: 'bg-red-500/20 text-red-400 border border-red-500/30', +}; + +export function OrdersTable({ initialOrders }: OrdersTableProps) { + const [search, setSearch] = useState(""); + const [statusFilter, setStatusFilter] = useState("all"); + + const filteredOrders = initialOrders.filter((order) => { + const orderNum = (order.order_number || "").toLowerCase(); + const company = (order.customer_data?.company_name || "").toLowerCase(); + const contact = `${order.customer_data?.first_name || ""} ${order.customer_data?.last_name || ""}`.toLowerCase(); + + const matchesSearch = + orderNum.includes(search.toLowerCase()) || + company.includes(search.toLowerCase()) || + contact.includes(search.toLowerCase()); + + const matchesStatus = statusFilter === "all" || order.status === statusFilter; + + return matchesSearch && matchesStatus; + }); + + return ( +
+ {/* Filterleiste */} +
+
+ + setSearch(e.target.value)} + className="pl-10 bg-slate-950/40 border-white/10 text-white placeholder:text-slate-500" + /> +
+ +
+ + + + + +
+
+ + {/* Tabelle */} +
+ + + + Bestellnr. + Datum + Kunde + Auswahl + Betrag + Status + Aktionen + + + + {filteredOrders.length === 0 ? ( + + + Keine Bestellungen gefunden. + + + ) : ( + filteredOrders.map((order) => { + const items = order.order_data?.items || []; + return ( + + + #{order.order_number || order.id.slice(0, 8)} + + + {new Date(order.created_at).toLocaleDateString('de-DE', { + day: '2-digit', month: '2-digit', year: 'numeric' + })} + + +
+ {order.customer_data?.company_name || 'Privatkunde'} +
+
+ {order.customer_data?.first_name} {order.customer_data?.last_name} +
+
+ +
+ {items.map((item: any) => ( + + {item.product_name} + {item.selected_modules?.length > 0 && ( + +{item.selected_modules.length} + )} + + ))} +
+
+ + {new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(order.total_price)} + + + + {statusLabel[order.status] ?? order.status} + + + + {order.pdf_url ? ( +
+ + +
+ ) : ( + Keine Rechnung + )} +
+
+ ); + }) + )} +
+
+
+
+ ); +}