"use client"; import Link from "next/link"; import { useEffect, useState } from "react"; import { useTranslations } from "next-intl"; import { Info, Lightbulb, MapPin, X } from "lucide-react"; import { formatDistance } from "@/lib/geo/distance"; import { formatDayShort, formatMinutes } from "@/lib/planning/text"; import { buttonCls } from "@/components/work-orders/button-cls"; import type { BoardOrder } from "@/server/services/planning/data"; export type Recommendation = { teamId: string; teamName: string; day: string; distanceKm: number; nearOrder: { id: string; number: string }; freeMinutes: number; requiredMinutes: number; tight: boolean; suggestedStart: string; text: string; }; type Response = { status: "ok" | "no_coordinates" | "not_schedulable"; hint: string | null; requiredMinutes: number; recommendations: Recommendation[]; nearby: { status: string; radiusKm: number; items: (BoardOrder & { distanceKm: number })[] }; }; /** Suggestions for one unplanned order (L13). "Übernehmen" only prefills the schedule popover. */ export function RecommendationsPanel({ workOrderId, locale, onTake, onPlanTogether, onClose, }: { workOrderId: string; locale: string; onTake: (rec: Recommendation) => void; onPlanTogether: (order: BoardOrder, rec: Recommendation | null, requiredMinutes: number) => void; onClose: () => void; }) { const t = useTranslations("planning"); const [data, setData] = useState(null); const [failed, setFailed] = useState(false); useEffect(() => { const ctrl = new AbortController(); fetch(`/api/v1/planning/recommendations?workOrderId=${encodeURIComponent(workOrderId)}&locale=${locale === "en" ? "en" : "de"}`, { signal: ctrl.signal }) .then((r) => (r.ok ? (r.json() as Promise) : Promise.reject(new Error(String(r.status))))) .then(setData) .catch(() => { if (!ctrl.signal.aborted) setFailed(true); }); return () => ctrl.abort(); }, [workOrderId, locale]); const headingId = `rec-${workOrderId}`; return (

{t("recommend.title")}

{t("recommend.sub")}

{!data && !failed && (

{t("recommend.loading")}

)} {failed && (

{t("recommend.failed")}

)} {data?.hint && (

{data.hint}

)} {data && data.recommendations.length > 0 && (
    {data.recommendations.map((r) => (
  • {t("recommend.card", { day: formatDayShort(r.day, locale), team: r.teamName, distance: formatDistance(r.distanceKm, locale), number: r.nearOrder.number, free: formatMinutes(r.freeMinutes, locale), })}

    {r.tight &&

    {t("recommend.tight")}

    }
  • ))}
)} {data && data.nearby.status === "ok" && (

{t("recommend.nearbyTitle")}

{data.nearby.items.length === 0 ? (

{t("recommend.nearbyEmpty")}

) : ( <>

{t("recommend.nearbyQuestion", { radius: data.nearby.radiusKm })}

    {data.nearby.items.map((o) => (
  • {o.number} · {formatDistance(o.distanceKm, locale)}

    {o.customerName}

  • ))}
)}
)}
); }