Files
arbeitarbeit/src/components/orders/actions.ts
Pascal Linxweiler 401b199978 Add order management UI
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>
2026-08-10 08:54:23 +02:00

181 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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,
},
];
}