"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { useTranslations } from "next-intl"; import { CircleCheck, LoaderCircle, Pause, Play, TriangleAlert, Truck, Wrench, Handshake } from "lucide-react"; import type { WorkOrderStatus } from "@/lib/work-orders/status"; import { errorKey, isSuccess, newClientId, submitOp } from "@/lib/field/client-ops"; import { currentPosition } from "@/lib/field/image"; import { btnPrimary, btnSecondary, noticeError, noticeWarn } from "./ui"; type SessionState = "en_route" | "running" | "paused" | null; type ActionKey = "accept" | "travel" | "start" | "pause" | "resume" | "complete"; const WORKING: WorkOrderStatus[] = ["in_progress", "paused", "waiting_material", "daily_report_created"]; /** One primary action per state (Brandbook §12.1): Annehmen → Losfahren → Arbeit starten → Pause/Weiter → Abschließen. */ export function resolveActions(status: WorkOrderStatus, mySession: SessionState): { primary: ActionKey | null; secondary: ActionKey | null } { if (status === "assigned") return { primary: "accept", secondary: null }; if (status === "accepted") return { primary: "travel", secondary: "start" }; if (status === "en_route") return { primary: "start", secondary: null }; if (WORKING.includes(status)) { if (mySession === "running") return { primary: "complete", secondary: "pause" }; if (mySession === "paused") return { primary: "resume", secondary: "complete" }; return { primary: "start", secondary: status === "in_progress" ? "complete" : null }; } return { primary: null, secondary: null }; } const ICONS = { accept: Handshake, travel: Truck, start: Wrench, pause: Pause, resume: Play, complete: CircleCheck } as const; async function sessionStartPayload(workOrderId: string, mode: "travel" | "work") { const pos = await currentPosition(3000); return { workOrderId, mode, clientId: newClientId(), at: new Date().toISOString(), offline: typeof navigator !== "undefined" ? !navigator.onLine : false, deviceInfo: typeof navigator !== "undefined" ? navigator.userAgent.slice(0, 200) : undefined, ...(pos ?? {}), }; } export function PrimaryAction({ workOrderId, status, version, mySession, blockers, }: { workOrderId: string; status: WorkOrderStatus; version: number; mySession: SessionState; /** translated completion blockers (without the user's own session, which is ended on completion) */ blockers: string[]; }) { const t = useTranslations("field"); const router = useRouter(); const [busy, setBusy] = useState(null); const [error, setError] = useState(null); const [confirm, setConfirm] = useState(false); const { primary, secondary } = resolveActions(status, mySession); async function run(action: ActionKey) { if (action === "complete" && !confirm) { setConfirm(true); return; } setBusy(action); setError(null); const at = new Date().toISOString(); let result; switch (action) { case "accept": result = await submitOp({ opType: "work_order.transition", baseVersion: version, payload: { workOrderId, to: "accepted" } }); break; case "travel": result = await submitOp({ opType: "session.start", payload: await sessionStartPayload(workOrderId, "travel") }); break; case "start": result = await submitOp({ opType: "session.start", payload: await sessionStartPayload(workOrderId, "work") }); break; case "pause": result = await submitOp({ opType: "session.pause", payload: { workOrderId, at } }); break; case "resume": result = await submitOp({ opType: "session.resume", payload: { workOrderId, at } }); break; case "complete": { let base = version; if (mySession) { const ended = await submitOp({ opType: "session.end", payload: { workOrderId, at } }); if (!isSuccess(ended)) { result = ended; break; } base = ended.entityVersion ?? version; } result = await submitOp({ opType: "work_order.transition", baseVersion: base, payload: { workOrderId, to: "technically_completed" } }); break; } } setBusy(null); setConfirm(false); if (!isSuccess(result)) setError(t(`errors.${errorKey(result)}`)); router.refresh(); } if (!primary) { return

{["technically_completed", "signature_pending"].includes(status) ? t("action.reportNext") : t("action.nothing")}

; } const completeBlocked = blockers.length > 0; const renderButton = (action: ActionKey, variant: "primary" | "secondary") => { const Icon = busy === action ? LoaderCircle : ICONS[action]; const disabled = busy !== null || (action === "complete" && completeBlocked); return ( ); }; return (
{renderButton(primary, "primary")} {secondary && renderButton(secondary, "secondary")} {confirm && (
{t("action.confirmHint")}{" "}
)} {completeBlocked && (primary === "complete" || secondary === "complete") && (

{t("action.blocked")}

    {blockers.map((b) => (
  • {b}
  • ))}
)} {error && (

{error}

)}
); }