Rebuild the landing page as an order overview for the Speisekarte24 tool: - Two tabs: all orders and "Nicht übermittelt", the latter fed by the 15-minute rule and highlighted while it holds entries - Table, list and grid views behind an icon dropdown, plus search, filters, sorting and pagination - Escalation timeline (three transmissions, tag, voice message, direct call, SOS) rendered in the detail dialog, inline in the list view and condensed to the current step in the table - Action definitions live in one module and feed the row menu, the detail dialog and the card quick-action bar Co-Authored-By: Claude <noreply@anthropic.com>
181 lines
4.7 KiB
TypeScript
181 lines
4.7 KiB
TypeScript
import {
|
||
Ban,
|
||
ExternalLink,
|
||
MessageCircle,
|
||
PhoneCall,
|
||
PhoneForwarded,
|
||
ShieldAlert,
|
||
Smartphone,
|
||
Voicemail,
|
||
XCircle,
|
||
type LucideIcon,
|
||
} from "lucide-react";
|
||
|
||
import { telHref, whatsAppHref } from "@/lib/format";
|
||
import type { Order, OrderAction, OrderStatus } from "@/lib/types";
|
||
|
||
export type { OrderAction };
|
||
|
||
/** Status, den eine Aktion auf der Bestellung setzt. Aktionen ohne Eintrag ändern nichts. */
|
||
export const ACTION_STATUS: Partial<Record<OrderAction, OrderStatus>> = {
|
||
uebermittelt: "uebermittelt",
|
||
nicht_uebermittelt: "nicht_uebermittelt",
|
||
rueckruf: "rueckruf",
|
||
storno: "storniert",
|
||
fake: "fake",
|
||
stornieren: "storniert",
|
||
sos: "storniert",
|
||
telefonisch_uebermittelt: "telefonisch",
|
||
};
|
||
|
||
/** Aktionen, nach denen der Gastronom als bestätigt gilt. */
|
||
export const CONFIRMING_ACTIONS: OrderAction[] = ["uebermittelt", "telefonisch_uebermittelt"];
|
||
|
||
export const ACTION_TOAST: Partial<Record<OrderAction, string>> = {
|
||
uebermittelt: "Als übermittelt markiert",
|
||
gastronom_voice: "Voice-Message an Gastronom gesendet",
|
||
nicht_uebermittelt: "Als nicht übermittelt markiert – Kunde und Gastronom informiert",
|
||
rueckruf: "Rückrufhinweis an Kunden gesendet",
|
||
storno: "Bestellung storniert – Kunde per E-Mail informiert",
|
||
stornieren: "Bestellung storniert",
|
||
fake: "Als Fake markiert",
|
||
gastronom_anruf: "Direktanruf beim Gastronom vermerkt",
|
||
sos: "SOS ausgelöst – Bestellung storniert, Gastronom für heute geschlossen",
|
||
telefonisch_uebermittelt: "Als telefonisch übermittelt markiert",
|
||
};
|
||
|
||
export type ActionDef = {
|
||
key: string;
|
||
label: string;
|
||
/** Kurzform für die Schnellleiste auf der Karte. */
|
||
short: string;
|
||
icon: LucideIcon;
|
||
/** Gesetzt bei Links (Telefon, WhatsApp, ORDER WebApp). */
|
||
href?: string;
|
||
external?: boolean;
|
||
/** Reiner Telefonanschluss – steckt bereits im Anruf-Dialog. */
|
||
phone?: boolean;
|
||
/** Gesetzt bei Aktionen, die den Bestellstatus ändern oder eine Nachricht auslösen. */
|
||
action?: OrderAction;
|
||
destructive?: boolean;
|
||
};
|
||
|
||
/** Kontaktwege zum Gastronomen – Buttons 1–6 der alten Oberfläche. */
|
||
export function gastronomActions({ restaurant }: Order): ActionDef[] {
|
||
const defs: ActionDef[] = [
|
||
{
|
||
key: "phone1",
|
||
label: `Telefon 1 · ${restaurant.phone1}`,
|
||
short: "Telefon 1",
|
||
phone: true,
|
||
icon: PhoneCall,
|
||
href: telHref(restaurant.phone1),
|
||
action: "gastronom_anruf",
|
||
},
|
||
];
|
||
|
||
if (restaurant.phone2) {
|
||
defs.push({
|
||
key: "phone2",
|
||
label: `Telefon 2 · ${restaurant.phone2}`,
|
||
short: "Telefon 2",
|
||
phone: true,
|
||
icon: PhoneCall,
|
||
href: telHref(restaurant.phone2),
|
||
});
|
||
}
|
||
if (restaurant.mobile) {
|
||
defs.push({
|
||
key: "mobile",
|
||
label: `Mobil · ${restaurant.mobile}`,
|
||
short: "Mobil",
|
||
phone: true,
|
||
icon: Smartphone,
|
||
href: telHref(restaurant.mobile),
|
||
});
|
||
}
|
||
|
||
defs.push({
|
||
key: "voice",
|
||
label: "Voice-Message senden",
|
||
short: "Voice",
|
||
icon: Voicemail,
|
||
action: "gastronom_voice",
|
||
});
|
||
|
||
if (restaurant.mobile) {
|
||
defs.push({
|
||
key: "whatsapp",
|
||
label: "WhatsApp-Message senden",
|
||
short: "WhatsApp",
|
||
icon: MessageCircle,
|
||
href: whatsAppHref(restaurant.mobile),
|
||
external: true,
|
||
});
|
||
}
|
||
|
||
defs.push({
|
||
key: "order",
|
||
label: "ORDER WebApp öffnen",
|
||
short: "ORDER",
|
||
icon: ExternalLink,
|
||
href: restaurant.orderUrl,
|
||
external: true,
|
||
});
|
||
|
||
return defs;
|
||
}
|
||
|
||
/** Bearbeitungsschritte zur Bestellung – Buttons 7–13 der alten Oberfläche. */
|
||
export function bearbeitungActions({ customer }: Order): ActionDef[] {
|
||
return [
|
||
{
|
||
key: "call_customer",
|
||
label: `Kunde anrufen · ${customer.phone}`,
|
||
short: "Kunde anrufen",
|
||
phone: true,
|
||
icon: PhoneCall,
|
||
href: telHref(customer.phone),
|
||
action: "kunde_anrufen",
|
||
},
|
||
{
|
||
key: "phone_transfer",
|
||
label: "Telefonisch übermittelt",
|
||
short: "Telefonisch",
|
||
icon: PhoneForwarded,
|
||
action: "telefonisch_uebermittelt",
|
||
},
|
||
{
|
||
key: "not_transferred",
|
||
label: "Nicht übermittelt",
|
||
short: "Nicht übermittelt",
|
||
icon: Ban,
|
||
action: "nicht_uebermittelt",
|
||
},
|
||
{
|
||
key: "callback",
|
||
label: "Rückrufhinweis senden",
|
||
short: "Rückruf",
|
||
icon: PhoneForwarded,
|
||
action: "rueckruf",
|
||
},
|
||
{ key: "fake", label: "Als Fake markieren", short: "Fake", icon: ShieldAlert, action: "fake" },
|
||
{
|
||
key: "storno",
|
||
label: "Storno (Kunde per E-Mail)",
|
||
short: "Storno",
|
||
icon: XCircle,
|
||
action: "storno",
|
||
destructive: true,
|
||
},
|
||
{
|
||
key: "cancel",
|
||
label: "Stornieren (ohne E-Mail)",
|
||
short: "Stornieren",
|
||
icon: Ban,
|
||
action: "stornieren",
|
||
destructive: true,
|
||
},
|
||
];
|
||
}
|