"use client"; import { useState, type FC } from "react"; import { motion, AnimatePresence, MotionConfig, type Transition, } from "framer-motion"; import useMeasure from "react-use-measure"; import { cn } from "@/lib/utils"; import { useDraggable } from "@dnd-kit/core"; import { CSS } from "@dnd-kit/utilities"; // 1. PhosphorIcon mask component export interface PhosphorIconProps { name: string; className?: string; } export const PhosphorIcon = ({ name, className }: PhosphorIconProps) => { const fileName = name.endsWith("-light") ? name : `${name}-light`; return ( ); }; export interface CollectionItem { id: string; name: string; price?: number; unit?: string; // e.g. "jiwa", "KK" — shown after the value instead of a "$" prefix icon: string; // Phosphor icon name isActive?: boolean; } export interface Collection { id: string; name: string; items: CollectionItem[]; } interface DisclosureCardProps { collections: Collection[]; compact?: boolean; onItemClick?: (itemId: string, collectionId: string) => void; dragDropEnabled?: boolean; } const springConfig: Transition = { type: "spring", stiffness: 200, damping: 20, mass: 1.1, }; export const DisclosureCard: FC = ({ collections, compact = false, onItemClick, dragDropEnabled = false, }) => { return ( {collections.map((collection) => ( ))} ); }; // Draggable wrapper for each expanded item const DraggableItem = ({ item, collectionId, compact, onItemClick, dragDropEnabled = false, }: { item: CollectionItem; collectionId: string; compact: boolean; onItemClick?: (itemId: string, collectionId: string) => void; dragDropEnabled?: boolean; }) => { const { attributes, listeners, setNodeRef, transform, isDragging } = useDraggable({ id: `${collectionId}::${item.id}`, data: { itemId: item.id, collectionId }, disabled: !dragDropEnabled || collectionId === "maps-settings" || collectionId === "demographics", }); const style = transform ? { transform: CSS.Translate.toString(transform), zIndex: isDragging ? 9999 : undefined, opacity: isDragging ? 0.8 : undefined } : undefined; return ( { if (isDragging) return; if (onItemClick) onItemClick(item.id, collectionId); }} > {item.isActive && ( )} {item.name} {item.price !== undefined && item.price > 0 && ( {item.unit ? `${item.price.toLocaleString("id-ID")} ${item.unit}` : `$${item.price}`} )} {item.isActive ? ( ) : ( )} ); }; const GridContainer = ({ items, title, compact = false, collectionId, onItemClick, dragDropEnabled = false, }: { items: CollectionItem[]; title: string; compact?: boolean; collectionId: string; onItemClick?: (itemId: string, collectionId: string) => void; dragDropEnabled?: boolean; }) => { const [isExpanded, setIsExpanded] = useState(false); const [ref, bounds] = useMeasure({ offsetSize: true }); const cardWidth = compact ? "w-[220px]" : "w-[300px]"; const cardBg = compact ? "border-border/60 bg-background/95 backdrop-blur-md shadow-md" : "border-gray-200 bg-zinc-100 dark:border-zinc-700 dark:bg-zinc-800"; const titleSize = compact ? "text-xs font-semibold text-foreground" : "text-lg text-zinc-900 dark:text-zinc-100"; const subtitleSize = compact ? "text-[10px] text-muted-foreground" : "text-sm text-zinc-500 dark:text-zinc-400"; const circleSize = compact ? "size-5" : "size-6"; const circleIconSize = compact ? "size-3" : "size-4"; const chevronSize = compact ? "size-3.5" : "size-6"; return ( 0 ? bounds.height : "auto", }} > {!isExpanded ? ( setIsExpanded(true)} exit={{ opacity: 0 }} transition={{ duration: 0.1, ease: "easeOut" }} > {items.slice(0, 4).map((item, index) => ( ))} {title} {items.length} Item ) : ( {title} { e.stopPropagation(); setIsExpanded(false); }} > {items.map((item) => ( ))} )} ); }; // 2. Specialized Poverty Disclosure Card interface DashboardDisclosureCardProps { mapStyle: "street" | "satellite"; onMapStyleChange: (style: "street" | "satellite") => void; onToolSelect: (toolId: string | null) => void; activeTool: string | null; compact?: boolean; dragDropEnabled: boolean; onDragDropToggle: (enabled: boolean) => void; } export interface PovertyDemographics { population: number; // total jiwa across all registered households beneficiaries: number; // households (KK) classified Extreme/Miskin socialSecurity: number; // households (KK) classified Rentan } interface PovertyDisclosureCardProps extends DashboardDisclosureCardProps { demographics?: PovertyDemographics; } export const PovertyDisclosureCard: FC = ({ mapStyle, onMapStyleChange, onToolSelect, activeTool, compact = true, demographics, dragDropEnabled, onDragDropToggle, }) => { const collections: Collection[] = [ { id: "maps-settings", name: "Pengaturan Peta", items: [ { id: "street", name: "Tampilan Jalan", icon: "map-trifold", isActive: mapStyle === "street" }, { id: "satellite", name: "Tampilan Satelit", icon: "globe", isActive: mapStyle === "satellite" }, { id: "drag-drop", name: "Seret & Lepas", icon: "hand-grabbing", isActive: dragDropEnabled }, ], }, { id: "poverty-tools", name: "Alat Peta Kemiskinan", items: [ { id: "marker", name: "Tambah Data Warga", icon: "map-pin", isActive: activeTool === "marker" }, { id: "religion", name: "Tambah Rumah Ibadah", icon: "church", isActive: activeTool === "religion" }, { id: "clinic", name: "Tambah Klinik", icon: "first-aid", isActive: activeTool === "clinic" }, { id: "food-bank", name: "Tambah Lumbung Pangan", icon: "bowl-food", isActive: activeTool === "food-bank" }, { id: "school", name: "Tambah Sekolah", icon: "graduation-cap", isActive: activeTool === "school" }, ], }, { id: "demographics", name: "Demografi", items: [ { id: "dm-1", name: "Total Warga Terdata", price: demographics?.population ?? 0, unit: "jiwa", icon: "users" }, { id: "dm-2", name: "KK Miskin & Ekstrem", price: demographics?.beneficiaries ?? 0, unit: "KK", icon: "hand-heart" }, { id: "dm-3", name: "KK Rentan", price: demographics?.socialSecurity ?? 0, unit: "KK", icon: "shield-check" }, ], }, ]; return ( { if (collectionId === "maps-settings") { if (itemId === "drag-drop") { onDragDropToggle(!dragDropEnabled); } else { onMapStyleChange(itemId as "street" | "satellite"); } } else if (collectionId === "poverty-tools") { onToolSelect(activeTool === itemId ? null : itemId); } }} dragDropEnabled={dragDropEnabled} /> ); }; // 3. Specialized Land Disclosure Card export const LandDisclosureCard: FC = ({ mapStyle, onMapStyleChange, onToolSelect, activeTool, compact = true, dragDropEnabled, onDragDropToggle, }) => { const collections: Collection[] = [ { id: "maps-settings", name: "Pengaturan Peta", items: [ { id: "street", name: "Tampilan Jalan", icon: "map-trifold", isActive: mapStyle === "street" }, { id: "satellite", name: "Tampilan Satelit", icon: "globe", isActive: mapStyle === "satellite" }, { id: "drag-drop", name: "Seret & Lepas", icon: "hand-grabbing", isActive: dragDropEnabled }, ], }, { id: "land-tools", name: "Alat Peta Lahan", items: [ { id: "marker", name: "Tambah Penanda", icon: "map-pin", isActive: activeTool === "marker" }, { id: "flag", name: "Tambah Tengara", icon: "flag", isActive: activeTool === "flag" }, { id: "protected", name: "Tambah Kawasan Lindung", icon: "tree", isActive: activeTool === "protected" }, { id: "registry", name: "Tambah Kantor Pendaftaran", icon: "bank", isActive: activeTool === "registry" }, { id: "line", name: "Gambar Garis", icon: "bezier-curve", isActive: activeTool === "line" }, { id: "polygon", name: "Gambar Poligon", icon: "hexagon", isActive: activeTool === "polygon" }, { id: "circle", name: "Gambar Lingkaran", icon: "circle", isActive: activeTool === "circle" }, ], }, { id: "land-permits", name: "Izin Lahan", items: [ { id: "lp-1", name: "Izin Mendirikan Bangunan (IMB)", price: 342, icon: "building" }, { id: "lp-2", name: "Sertifikat Tanah", price: 1580, icon: "certificate" }, { id: "lp-3", name: "Banding Zonasi", price: 47, icon: "gavel" }, ], }, { id: "environmental", name: "Lingkungan", items: [ { id: "ev-1", name: "Tutupan Hijau", price: 67.8, icon: "leaf" }, { id: "ev-2", name: "Aliran Air", price: 23.4, icon: "drop" }, { id: "ev-3", name: "Jaringan Jalan", price: 1420, icon: "road-horizon" }, ], }, ]; return ( { if (collectionId === "maps-settings") { if (itemId === "drag-drop") { onDragDropToggle(!dragDropEnabled); } else { onMapStyleChange(itemId as "street" | "satellite"); } } else if (collectionId === "land-tools") { onToolSelect(activeTool === itemId ? null : itemId); } }} dragDropEnabled={dragDropEnabled} /> ); }; // 4. Specialized Gas Station Disclosure Card export const GasStationDisclosureCard: FC = ({ mapStyle, onMapStyleChange, onToolSelect, activeTool, compact = true, dragDropEnabled, onDragDropToggle, }) => { const collections: Collection[] = [ { id: "maps-settings", name: "Pengaturan Peta", items: [ { id: "street", name: "Tampilan Jalan", icon: "map-trifold", isActive: mapStyle === "street" }, { id: "satellite", name: "Tampilan Satelit", icon: "globe", isActive: mapStyle === "satellite" }, { id: "drag-drop", name: "Seret & Lepas", icon: "hand-grabbing", isActive: dragDropEnabled }, ], }, { id: "station-tools", name: "Alat Peta Stasiun", items: [ { id: "charging-station", name: "Tambah Pengisi Daya EV", icon: "charging-station", isActive: activeTool === "charging-station" }, { id: "gas-pump", name: "Tambah SPBU", icon: "gas-pump", isActive: activeTool === "gas-pump" }, { id: "wrench", name: "Tambah Bengkel", icon: "wrench", isActive: activeTool === "wrench" }, ], }, { id: "station-services", name: "Layanan Stasiun", items: [ { id: "ss-1", name: "Toko Kelontong", price: 450, icon: "shopping-bag" }, { id: "ss-2", name: "Pencucian Mobil", price: 75, icon: "bathtub" }, { id: "ss-3", name: "Mekanik", price: 320, icon: "wrench" }, { id: "ss-4", name: "Tukar Baterai", price: 180, icon: "car-battery" }, ], }, { id: "fleet-logistics", name: "Armada & Logistik", items: [ { id: "fl-1", name: "Kartu Armada", price: 1240, icon: "credit-card" }, { id: "fl-2", name: "Rencana Rute", price: 89, icon: "paper-plane" }, { id: "fl-3", name: "Laporan Bahan Bakar", price: 56, icon: "file-text" }, ], }, ]; return ( { if (collectionId === "maps-settings") { if (itemId === "drag-drop") { onDragDropToggle(!dragDropEnabled); } else { onMapStyleChange(itemId as "street" | "satellite"); } } else if (collectionId === "station-tools") { onToolSelect(activeTool === itemId ? null : itemId); } }} dragDropEnabled={dragDropEnabled} /> ); };
{item.unit ? `${item.price.toLocaleString("id-ID")} ${item.unit}` : `$${item.price}`}