diff --git a/src/app/heimservice/page.tsx b/src/app/heimservice/page.tsx
new file mode 100644
index 0000000..c8a3a91
--- /dev/null
+++ b/src/app/heimservice/page.tsx
@@ -0,0 +1,21 @@
+import { RestaurantPanel } from "@/components/heimservice/restaurant-panel";
+import { restaurants } from "@/lib/data";
+
+export default function HeimservicePage() {
+ return (
+
+
+
+
+ {restaurants.map((restaurant) => (
+
+ ))}
+
+
+ );
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 5eece91..909261c 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -3,6 +3,7 @@ import { Geist, Geist_Mono } from "next/font/google";
import { Toaster } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip";
+import { TopNav } from "@/components/top-nav";
import "./globals.css";
@@ -28,7 +29,10 @@ export default function RootLayout({ children }: LayoutProps<"/">) {
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
>
- {children}
+
+
+ {children}
+
{/* App läuft bewusst nur im Light Mode – Systemtheme nicht übernehmen. */}
diff --git a/src/components/heimservice/restaurant-panel.tsx b/src/components/heimservice/restaurant-panel.tsx
new file mode 100644
index 0000000..e2e27c6
--- /dev/null
+++ b/src/components/heimservice/restaurant-panel.tsx
@@ -0,0 +1,328 @@
+"use client";
+
+import * as React from "react";
+import {
+ Check,
+ ExternalLink,
+ KeyRound,
+ Pencil,
+ Phone,
+ PhoneCall,
+ Power,
+ Smartphone,
+ Voicemail,
+ type LucideIcon,
+} from "lucide-react";
+import { toast } from "sonner";
+
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+} from "@/components/ui/alert-dialog";
+import { Button } from "@/components/ui/button";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import {
+ Dialog,
+ DialogClose,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import { telHref } from "@/lib/format";
+import { cn } from "@/lib/utils";
+import type { Restaurant } from "@/lib/types";
+
+type Props = { restaurant: Restaurant };
+
+/** Ein Kontroll-Panel je Gastronom – Nachbau der 10 Buttons der alten Heimservice-Oberfläche. */
+export function RestaurantPanel({ restaurant }: Props) {
+ const [windowOn, setWindowOn] = React.useState<[boolean, boolean]>([true, true]);
+ const [resetOpen, setResetOpen] = React.useState(false);
+ const [editOpen, setEditOpen] = React.useState(false);
+ const [callOpen, setCallOpen] = React.useState(false);
+ const [mobile1, setMobile1] = React.useState(restaurant.mobile ?? "");
+ const [mobile2, setMobile2] = React.useState(restaurant.mobile2 ?? "");
+
+ const numbers = [
+ { label: "Telefon 1", phone: restaurant.phone1, icon: PhoneCall },
+ restaurant.phone2 && { label: "Telefon 2", phone: restaurant.phone2, icon: PhoneCall },
+ mobile1 && { label: "Mobil 1", phone: mobile1, icon: Smartphone },
+ mobile2 && { label: "Mobil 2", phone: mobile2, icon: Smartphone },
+ ].filter((n): n is { label: string; phone: string; icon: LucideIcon } => Boolean(n));
+
+ const [window1, window2] = restaurant.heimserviceWindows;
+
+ function toggleWindow(index: 0 | 1) {
+ setWindowOn((prev) => {
+ const next: [boolean, boolean] = [...prev];
+ next[index] = !next[index];
+ toast.success(
+ next[index] ? `Zeitfenster ${index + 1} aktiviert` : `Zeitfenster ${index + 1} deaktiviert`,
+ { description: restaurant.name },
+ );
+ return next;
+ });
+ }
+
+ function resetPassword() {
+ setResetOpen(false);
+ toast.success("Passwort zurückgesetzt", {
+ description: `Neue Zugangsdaten für ${restaurant.name} wurden versendet.`,
+ });
+ }
+
+ function saveMobiles() {
+ setEditOpen(false);
+ toast.success("Mobilrufnummern aktualisiert", { description: restaurant.name });
+ }
+
+ function sendVoiceTest() {
+ toast.success("Voice-Message an Telefon 1 gesendet", { description: restaurant.name });
+ }
+
+ return (
+
+
+ {restaurant.name}
+ {restaurant.city}
+
+
+
+
+
+ Zeitfenster 1: {window1}
+
+ {window2 && (
+ <>
+ ·
+
+ Zeitfenster 2: {window2}
+
+ >
+ )}
+
+
+
+ toggleWindow(0)}
+ />
+ toggleWindow(1)}
+ disabled={!window2}
+ />
+ }
+ />
+
+
+
+ setResetOpen(true)}
+ />
+ setEditOpen(true)}
+ />
+
+
+
+ setCallOpen(true)}
+ />
+
+
+
+
+
+
+
+
+
+ Passwort zurücksetzen?
+
+ Die ORDER-Zugangsdaten von {restaurant.name} werden neu vergeben und an den
+ Gastronomen versendet.
+
+
+
+ Abbrechen
+ Zurücksetzen
+
+
+
+
+
+
+ );
+}
+
+function Section({ label, children }: { label: string; children: React.ReactNode }) {
+ return (
+
+ );
+}
+
+function WindowToggle({
+ index,
+ time,
+ on,
+ onToggle,
+ disabled,
+}: {
+ index: 0 | 1;
+ time: string | undefined;
+ on: boolean;
+ onToggle: () => void;
+ disabled?: boolean;
+}) {
+ return (
+
+ );
+}
+
+function Tile({
+ icon: Icon,
+ label,
+ sublabel,
+ onClick,
+ nativeButton,
+ render,
+}: {
+ icon: typeof Phone;
+ label: string;
+ sublabel: string;
+ onClick?: () => void;
+ nativeButton?: boolean;
+ render?: React.ReactElement;
+}) {
+ return (
+
+ );
+}
diff --git a/src/components/top-nav.tsx b/src/components/top-nav.tsx
new file mode 100644
index 0000000..a8c3661
--- /dev/null
+++ b/src/components/top-nav.tsx
@@ -0,0 +1,55 @@
+"use client";
+
+import Link from "next/link";
+import { usePathname } from "next/navigation";
+import { LogOut } from "lucide-react";
+import { toast } from "sonner";
+
+import { Button } from "@/components/ui/button";
+import { cn } from "@/lib/utils";
+
+const NAV_ITEMS = [
+ { href: "/", label: "Bestellübersicht" },
+ { href: "/heimservice", label: "Heimservice" },
+];
+
+export function TopNav() {
+ const pathname = usePathname();
+
+ return (
+
+ );
+}
diff --git a/src/lib/data.ts b/src/lib/data.ts
index 5d7a01b..d85485e 100644
--- a/src/lib/data.ts
+++ b/src/lib/data.ts
@@ -7,7 +7,7 @@ import {
type Restaurant,
} from "./types";
-const restaurants: Restaurant[] = [
+export const restaurants: Restaurant[] = [
{
name: "Muster Ristorante",
city: "Taben-Rodt",
@@ -15,7 +15,9 @@ const restaurants: Restaurant[] = [
phone1: "+49 6582 123456",
phone2: "+49 6582 123457",
mobile: "+49 171 2223344",
+ mobile2: "+49 171 2223345",
orderUrl: "https://order.speisekarte24.de/muster-ristorante",
+ heimserviceWindows: ["10:00 bis 14:30", "17:00 bis 23:00"],
},
{
name: "Pizzeria Da Vinci",
@@ -24,6 +26,7 @@ const restaurants: Restaurant[] = [
phone1: "+49 651 998877",
mobile: "+49 160 5544332",
orderUrl: "https://order.speisekarte24.de/da-vinci",
+ heimserviceWindows: ["11:00 bis 14:30", "17:30 bis 22:30"],
},
{
name: "Sushi Yama",
@@ -32,7 +35,9 @@ const restaurants: Restaurant[] = [
phone1: "+49 681 445566",
phone2: "+49 681 445567",
mobile: "+49 175 1112233",
+ mobile2: "+49 175 1112234",
orderUrl: "https://order.speisekarte24.de/sushi-yama",
+ heimserviceWindows: ["12:00 bis 15:00", "18:00 bis 23:00"],
},
{
name: "Burger Station",
@@ -41,6 +46,7 @@ const restaurants: Restaurant[] = [
phone1: "+49 6501 334455",
mobile: "+49 152 9988776",
orderUrl: "https://order.speisekarte24.de/burger-station",
+ heimserviceWindows: ["11:30 bis 15:00", "17:00 bis 21:00"],
},
{
name: "Athen Grill",
@@ -48,6 +54,8 @@ const restaurants: Restaurant[] = [
hours: "17:00 bis 23:30",
phone1: "+49 6571 220011",
orderUrl: "https://order.speisekarte24.de/athen-grill",
+ // Nur Abendschicht, kein zweites Zeitfenster.
+ heimserviceWindows: ["17:00 bis 23:30", undefined],
},
];
diff --git a/src/lib/types.ts b/src/lib/types.ts
index e5c6a7f..770ab10 100644
--- a/src/lib/types.ts
+++ b/src/lib/types.ts
@@ -36,7 +36,10 @@ export type Restaurant = {
phone1: string;
phone2?: string;
mobile?: string;
+ mobile2?: string;
orderUrl: string;
+ /** Zeitfenster für den Heimservice, z. B. Mittags- und Abendschicht. Zweites Fenster optional. */
+ heimserviceWindows: [string, string | undefined];
};
export type Customer = {