"use client"; import { useState, useEffect, useMemo } from "react"; import { useTranslations } from "next-intl"; import { cn } from "@/lib/utils"; import { Input } from "@/components/ui/input"; import { useResourceStore } from "@/stores/resource-store"; import type { Resource } from "@/lib/resources/client"; import { Building2, Car, Wrench, Box, MapPin, Users, Search, X, Check, } from "lucide-react"; interface ResourcePickerProps { start?: string; end?: string; compact?: boolean; } const typeIcons: Record = { room: Building2, vehicle: Car, equipment: Wrench, other: Box, }; type TypeFilter = "all" | Resource["type"]; export function ResourcePicker({ start, end, compact = false }: ResourcePickerProps) { const t = useTranslations("calendar"); const { resources, selectedResources, isLoading, fetchResources, searchResources, toggleResource, deselectResource, clearSelection, } = useResourceStore(); const [typeFilter, setTypeFilter] = useState("all"); const [query, setQuery] = useState(""); const [availabilityMap, setAvailabilityMap] = useState>({}); useEffect(() => { fetchResources(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const filtered = useMemo(() => { let list = typeFilter === "all" ? resources : resources.filter((r) => r.type === typeFilter); if (query.trim()) { list = searchResources(query).filter((r) => typeFilter === "all" || r.type === typeFilter); } return list; }, [resources, typeFilter, query, searchResources]); useEffect(() => { if (!start || !end) return; let cancelled = false; const checkAll = async () => { const map: Record = {}; for (const resource of filtered) { try { const params = new URLSearchParams({ start, end }); const { apiFetch } = await import("@/lib/browser-navigation"); const res = await apiFetch( `/api/resources/${resource.id}/availability?${params.toString()}` ); if (res.ok) { const data = await res.json(); map[resource.id] = data.available ? "available" : "conflict"; } else { map[resource.id] = "unknown"; } } catch { map[resource.id] = "unknown"; } } if (!cancelled) setAvailabilityMap(map); }; checkAll(); return () => { cancelled = true; }; }, [filtered, start, end]); const filters: { key: TypeFilter; label: string }[] = [ { key: "all", label: t("resources.filter_all") }, { key: "room", label: t("resources.type_room") }, { key: "vehicle", label: t("resources.type_vehicle") }, { key: "equipment", label: t("resources.type_equipment") }, { key: "other", label: t("resources.type_other") }, ]; return (
{filters.map((f) => ( ))}
setQuery(e.target.value)} placeholder={t("resources.search_placeholder")} className="pl-8" />
{isLoading ? (
) : filtered.length === 0 ? (

{t("resources.no_resources")}

) : (
{filtered.map((resource) => { const TypeIcon = typeIcons[resource.type]; const isSelected = selectedResources.some((r) => r.id === resource.id); const avail = availabilityMap[resource.id] || "unknown"; return ( ); })}
)} {selectedResources.length > 0 && (
{selectedResources.map((resource) => ( {resource.name} ))} {selectedResources.length > 0 && ( )}
)}
); }