"use client"; import { useState, useCallback, useEffect, useRef } from "react"; import { createStop } from "@/actions/stops/create-stop"; import { updateStop } from "@/actions/stops/update-stop"; import GlassModal from "@/components/admin/GlassModal"; type Stop = { id: string; city: string; state: string; location: string; date: string; time: string; address?: string | null; zip?: string | null; cutoff_time?: string | null; active: boolean; brand_id: string; }; type Props = { isOpen: boolean; onClose: () => void; brandId: string; stop?: Stop | null; onSuccess?: (stopId: string) => void; }; /* Pin icon for the modal header */ const PinIcon = () => ( ); export default function EditStopModal({ isOpen, onClose, brandId, stop, onSuccess }: Props) { const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [city, setCity] = useState(""); const [stateField, setStateField] = useState(""); const [location, setLocation] = useState(""); const [date, setDate] = useState(""); const [time, setTime] = useState(""); const [address, setAddress] = useState(""); const [zip, setZip] = useState(""); const [cutoffTime, setCutoffTime] = useState(""); const [status, setStatus] = useState<"draft" | "active">("draft"); const cityRef = useRef(null); const isEditing = Boolean(stop); useEffect(() => { if (isOpen) { if (stop) { // Edit mode - populate from existing stop. // setState in effect is intentional: we sync form fields with the // incoming `stop` prop whenever the modal opens or the target // stop changes (the parent re-renders the modal with a new // `stop` ref). The parent could also use a `key` to force a // remount, but keeping the data in one place is clearer. /* eslint-disable react-hooks/set-state-in-effect */ setCity(stop.city); setStateField(stop.state); setLocation(stop.location); setDate(stop.date); setTime(stop.time || ""); setAddress(stop.address ?? ""); setZip(stop.zip ?? ""); setCutoffTime(stop.cutoff_time ? stop.cutoff_time.slice(0, 16) : ""); setStatus(stop.active ? "active" : "draft"); } else { // Add mode - reset form setCity(""); setStateField(""); setLocation(""); setDate(""); setTime(""); setAddress(""); setZip(""); setCutoffTime(""); setStatus("draft"); } setError(null); requestAnimationFrame(() => cityRef.current?.focus()); /* eslint-enable react-hooks/set-state-in-effect */ } }, [isOpen, stop]); const handleSubmit = useCallback( async (e: React.FormEvent) => { e.preventDefault(); setError(null); if (!city.trim() || !stateField.trim() || !location.trim() || !date) { setError("City, state, location, and date are required."); return; } setLoading(true); try { let result; if (isEditing && stop) { result = await updateStop(stop.id, brandId, { city: city.trim(), state: stateField.trim(), location: location.trim(), date, time: time || "08:00", address: address || null, zip: zip || null, cutoff_time: cutoffTime || null, active: status === "active", }); } else { result = await createStop(brandId, { city: city.trim(), state: stateField.trim(), location: location.trim(), date, time: time || "08:00", address: address || undefined, zip: zip || undefined, cutoff_time: cutoffTime || undefined, active: status === "active", }); } if (result.success) { const newStopId = isEditing ? stop!.id : (result as { success: true; id: string }).id; onSuccess?.(newStopId); onClose(); } else { setError(result.error ?? `Failed to ${isEditing ? "update" : "create"} stop`); } } catch { setError("Network error. Please try again."); } finally { setLoading(false); } }, [ brandId, city, stateField, location, date, time, address, zip, cutoffTime, status, isEditing, stop, onSuccess, onClose, ] ); const title = isEditing ? "Edit Stop" : "Add Stop"; const eyebrow = isEditing ? `${stop?.city}, ${stop?.state}` : "New stop on the route"; const submitLabel = loading ? isEditing ? "Saving…" : "Creating…" : isEditing ? "Save Changes" : status === "active" ? "Create & Publish" : "Save as Draft"; if (!isOpen) return null; return ( {error && ( {error} )} {/* Row 1 — Where: City + State */} City * setCity(e.target.value)} placeholder="Denver" className="ha-field-input" required autoComplete="address-level2" /> State * setStateField(e.target.value.toUpperCase())} placeholder="CO" maxLength={2} className="ha-field-input ha-field-input-mono text-center" style={{ textTransform: "uppercase" }} required autoComplete="address-level1" /> {/* Row 2 — Where at: Location (full) */} Location / Venue * setLocation(e.target.value)} placeholder="Whole Foods Market — Highlands" className="ha-field-input" required /> {/* Row 3 — When: Date + Time */} Pickup Date * setDate(e.target.value)} className="ha-field-input ha-field-input-mono" required /> Pickup Time setTime(e.target.value)} className="ha-field-input ha-field-input-mono" /> {/* Row 4 — Address + ZIP + Cutoff */} Street Address setAddress(e.target.value)} placeholder="123 Main St" className="ha-field-input" autoComplete="street-address" /> ZIP setZip(e.target.value)} placeholder="80202" maxLength={10} className="ha-field-input ha-field-input-mono" autoComplete="postal-code" /> Cutoff setCutoffTime(e.target.value)} className="ha-field-input ha-field-input-mono" /> {/* Row 5 — Status: segmented control */} Visibility Draft is hidden from customers setStatus("draft")} className={`ha-segment-btn ${status === "draft" ? "ha-segment-btn--active ha-segment-active-draft" : ""}`} > Save as Draft setStatus("active")} className={`ha-segment-btn ${status === "active" ? "ha-segment-btn--active ha-segment-active-active" : ""}`} > Publish Now {/* Footer */} Esc to close Cancel {loading ? ( <> {submitLabel} > ) : ( <> {isEditing ? ( ) : status === "active" ? ( ) : ( )} {submitLabel} > )} ); } // Hook for easy integration export function useEditStopModal(brandId: string) { const [isOpen, setIsOpen] = useState(false); const [editingStop, setEditingStop] = useState<{ id: string; city: string; state: string; location: string; date: string; time: string; address?: string | null; zip?: string | null; cutoff_time?: string | null; active: boolean; brand_id: string; } | null>(null); const open = useCallback((stop?: typeof editingStop) => { setEditingStop(stop ?? null); setIsOpen(true); }, []); const close = useCallback(() => { setIsOpen(false); setEditingStop(null); }, []); const Modal = useCallback(() => ( ), [isOpen, close, brandId, editingStop]); return { open, close, Modal, editingStop }; }