"use client"; /* eslint-disable @typescript-eslint/no-explicit-any, react-hooks/set-state-in-effect */ import { useState, useEffect } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { cn } from "@/lib/utils"; import type { UserMarker } from "@/components/leaflet-map"; /* ─── Selectors Options ────────────────────────── */ const EV_TYPES = [ { value: "DC Fast", label: "DC Fast", color: "#10b981" }, { value: "Supercharger", label: "Supercharger", color: "#14b8a6" }, { value: "AC Level 2", label: "AC Level 2", color: "#3b82f6" }, ]; const EV_STATUSES = [ { value: "Active", label: "Active", color: "#10b981" }, { value: "Maintenance", label: "Maintenance", color: "#eab308" }, { value: "Offline", label: "Offline", color: "#ef4444" }, ]; const GAS_BRANDS = [ { value: "Pertamina", label: "Pertamina", color: "#ef4444" }, { value: "Shell", label: "Shell", color: "#eab308" }, { value: "BP", label: "BP", color: "#10b981" }, { value: "Vivo", label: "Vivo", color: "#3b82f6" }, ]; const GAS_TYPES_BY_BRAND: Record = { Pertamina: ["Pertalite", "Pertamax", "Pertamax Green", "Pertamax Turbo", "Dexlite", "Pertamina Dex", "Solar"], Shell: ["Shell Super", "Shell V-Power", "Shell V-Power Nitro+", "Shell V-Power Diesel"], BP: ["BP 92", "BP 95", "BP Ultimate", "BP Ultimate Diesel"], Vivo: ["Revvo 90", "Revvo 92", "Revvo 95"], }; const REPAIR_SPECIALITIES = [ { value: "Umum", label: "Umum", color: "#6b7280" }, { value: "AC & Kelistrikan",label: "AC & Kelistrikan",color: "#0ea5e9" }, { value: "Mesin", label: "Mesin", color: "#f97316" }, { value: "Ban & Velg", label: "Ban & Velg", color: "#f59e0b" }, ]; /* ─── Helpers ───────────────────────────────────── */ function Field({ label, children, className }: { label: string; children: React.ReactNode; className?: string }) { return (
{label} {children}
); } function ChipSelector({ options, value, onChange, }: { options: { value: string; label: string; color: string }[]; value: string; onChange: (v: string) => void; }) { return (
{options.map((opt) => { const isSelected = value === opt.value; return ( ); })}
); } function MultiChipSelector({ options, values, onChange, color, }: { options: string[]; values: string[]; onChange: (v: string[]) => void; color: string; }) { return (
{options.map((opt) => { const isSelected = values.includes(opt); return ( ); })}
); } /* ─── Placement Dialog ─────────────────────────── */ interface StationPlacementDialogProps { open: boolean; onOpenChange: (open: boolean) => void; pendingClick: { lat: number; lng: number } | null; markerType: string | null; onConfirm: (marker: UserMarker) => void; } export function StationPlacementDialog({ open, onOpenChange, pendingClick, markerType, onConfirm, }: StationPlacementDialogProps) { const [category, setCategory] = useState("gas-pump"); const [name, setName] = useState(""); // Form fields for EV Charger const [evType, setEvType] = useState("DC Fast"); const [evStatus, setEvStatus] = useState("Active"); // Form fields for Gas Station const [gasBrand, setGasBrand] = useState("Pertamina"); const [gasHours, setGasHours] = useState("24 Jam"); const [selectedGasTypes, setSelectedGasTypes] = useState([]); // Form fields for Repair Shop const [repairSpeciality, setRepairSpeciality] = useState("Umum"); const [repairStatus, setRepairStatus] = useState("Buka 08:00 - 17:00"); // Submission state const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(null); const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL ?? "http://localhost:4000"; // Synchronize with initial markerType when dialog opens useEffect(() => { if (open && markerType) { setCategory(markerType); setName(""); setEvType("DC Fast"); setEvStatus("Active"); setGasBrand("Pertamina"); setGasHours("24 Jam"); setSelectedGasTypes(GAS_TYPES_BY_BRAND["Pertamina"]); setRepairSpeciality("Umum"); setRepairStatus("Buka 08:00 - 17:00"); setError(null); setIsSubmitting(false); } }, [open, markerType]); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); if (!pendingClick) return; setIsSubmitting(true); setError(null); let finalPoiType = ""; let finalNotes = ""; const brand = category === "gas-pump" ? gasBrand : null; const sub_type = category === "charging-station" ? evType : (category === "wrench" ? repairSpeciality : null); const gas_types = category === "gas-pump" ? selectedGasTypes : null; const operating_hours = category === "gas-pump" ? gasHours : null; const status = category === "charging-station" ? evStatus : (category === "wrench" ? repairStatus : null); if (category === "charging-station") { finalPoiType = evType; finalNotes = `Status: ${evStatus}`; } else if (category === "gas-pump") { finalPoiType = gasBrand; finalNotes = `Jam: ${gasHours}`; } else if (category === "wrench") { finalPoiType = repairSpeciality; finalNotes = repairStatus; } try { const token = localStorage.getItem("auth_token"); const res = await fetch(`${BACKEND_URL}/gas-station/markers`, { method: "POST", headers: { "Content-Type": "application/json", ...(token ? { Authorization: `Bearer ${token}` } : {}), }, body: JSON.stringify({ name: name.trim() || `New ${category.replace("-", " ")}`, marker_category: category, brand, sub_type, gas_types, operating_hours, status, latitude: pendingClick.lat, longitude: pendingClick.lng, notes: null, }), }); if (!res.ok) { const data = await res.json().catch(() => ({})); throw new Error(data.error ?? "Gagal menyimpan data"); } const saved = await res.json(); const savedMarker: UserMarker = { id: `gsm-${saved.id}`, lat: pendingClick.lat, lng: pendingClick.lng, type: category, name: saved.name, meta: { poi_type: finalPoiType, notes: finalNotes, gas_types: category === "gas-pump" ? selectedGasTypes : undefined, }, }; onConfirm(savedMarker); handleCancel(); } catch (err: unknown) { setError(err instanceof Error ? err.message : "Terjadi kesalahan"); } finally { setIsSubmitting(false); } } function handleCancel() { setName(""); setError(null); setIsSubmitting(false); onOpenChange(false); } const categoryLabels: Record = { "charging-station": "EV Charger Baru", "gas-pump": "Gas Station Baru", wrench: "Bengkel Baru", }; const titleLabel = categoryLabels[category] || "Lokasi Baru"; return ( { if (!v) handleCancel(); }}>
{/* Header */} {titleLabel}

{pendingClick ? `${pendingClick.lat.toFixed(5)}, ${pendingClick.lng.toFixed(5)}` : ""}

{/* Body */}
{/* Category Selector */} {/* Location Name */} setName(e.target.value)} placeholder={ category === "charging-station" ? "Contoh: VoltCharge EV Station" : category === "gas-pump" ? "Contoh: EcoFuel Station Menteng" : "Contoh: Bengkel Motor Jaya" } required autoFocus className="bg-muted/50 border border-border focus-visible:border-ring" /> {/* Dynamic Fields: EV Charger */} {category === "charging-station" && ( <> )} {/* Dynamic Fields: Gas Station */} {category === "gas-pump" && ( <> { setGasBrand(brand); setSelectedGasTypes(GAS_TYPES_BY_BRAND[brand] ?? []); }} /> b.value === gasBrand)?.color ?? "#ff3b1f"} /> setGasHours(e.target.value)} placeholder="Contoh: 24 Jam atau 06:00 - 22:00" required className="bg-muted/50 border border-border focus-visible:border-ring" />
{["24 Jam", "06:00 - 22:00", "07:00 - 21:00"].map((h) => ( ))}
)} {/* Dynamic Fields: Repair Shop */} {category === "wrench" && ( <> setRepairStatus(e.target.value)} placeholder="Contoh: Buka 08:00 - 17:00 atau Tutup" required className="bg-muted/50 border border-border focus-visible:border-ring" />
{["Buka 24 Jam", "Buka 08:00 - 17:00", "Tutup"].map((s) => ( ))}
)} {error && (

{error}

)}
{/* Footer */}
); } export { EV_TYPES, EV_STATUSES, GAS_BRANDS, REPAIR_SPECIALITIES, GAS_TYPES_BY_BRAND };