"use client"; import { closestCorners, DndContext, type DragEndEvent, KeyboardSensor, PointerSensor, useSensor, useSensors, } from "@dnd-kit/core"; import { arrayMove, rectSortingStrategy, SortableContext, sortableKeyboardCoordinates, } from "@dnd-kit/sortable"; import { RiArrowDownLine, RiArrowUpLine, RiCheckLine, RiCloseLine, RiDragMove2Line, RiEyeOffLine, RiTodoLine, } from "@remixicon/react"; import { useCallback, useMemo, useState, useTransition } from "react"; import { toast } from "sonner"; import { NoteDialog } from "@/components/anotacoes/note-dialog"; import { SortableWidget } from "@/components/dashboard/sortable-widget"; import { WidgetSettingsDialog } from "@/components/dashboard/widget-settings-dialog"; import { LancamentoDialog } from "@/components/lancamentos/dialogs/lancamento-dialog/lancamento-dialog"; import type { SelectOption } from "@/components/lancamentos/types"; import { Button } from "@/components/ui/button"; import WidgetCard from "@/components/widget-card"; import type { DashboardData } from "@/lib/dashboard/fetch-dashboard-data"; import { resetWidgetPreferences, updateWidgetPreferences, type WidgetPreferences, } from "@/lib/dashboard/widgets/actions"; import { type WidgetConfig, widgetsConfig, } from "@/lib/dashboard/widgets/widgets-config"; type DashboardGridEditableProps = { data: DashboardData; period: string; initialPreferences: WidgetPreferences | null; quickActionOptions: { pagadorOptions: SelectOption[]; splitPagadorOptions: SelectOption[]; defaultPagadorId: string | null; contaOptions: SelectOption[]; cartaoOptions: SelectOption[]; categoriaOptions: SelectOption[]; estabelecimentos: string[]; }; }; export function DashboardGridEditable({ data, period, initialPreferences, quickActionOptions, }: DashboardGridEditableProps) { const [isEditing, setIsEditing] = useState(false); const [isPending, startTransition] = useTransition(); // Initialize widget order and hidden state const defaultOrder = widgetsConfig.map((w) => w.id); const [widgetOrder, setWidgetOrder] = useState( initialPreferences?.order ?? defaultOrder, ); const [hiddenWidgets, setHiddenWidgets] = useState( initialPreferences?.hidden ?? [], ); // Keep track of original state for cancel const [originalOrder, setOriginalOrder] = useState(widgetOrder); const [originalHidden, setOriginalHidden] = useState(hiddenWidgets); const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 8, }, }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates, }), ); // Get ordered and visible widgets const orderedWidgets = useMemo(() => { // Create a map for quick lookup const widgetMap = new Map(widgetsConfig.map((w) => [w.id, w])); // Get widgets in order, filtering out hidden ones const ordered: WidgetConfig[] = []; for (const id of widgetOrder) { const widget = widgetMap.get(id); if (widget && !hiddenWidgets.includes(id)) { ordered.push(widget); } } // Add any new widgets that might not be in the order yet for (const widget of widgetsConfig) { if ( !widgetOrder.includes(widget.id) && !hiddenWidgets.includes(widget.id) ) { ordered.push(widget); } } return ordered; }, [widgetOrder, hiddenWidgets]); const handleDragEnd = useCallback((event: DragEndEvent) => { const { active, over } = event; if (over && active.id !== over.id) { setWidgetOrder((items) => { const oldIndex = items.indexOf(active.id as string); const newIndex = items.indexOf(over.id as string); return arrayMove(items, oldIndex, newIndex); }); } }, []); const handleToggleWidget = useCallback( (widgetId: string) => { const newHidden = hiddenWidgets.includes(widgetId) ? hiddenWidgets.filter((id) => id !== widgetId) : [...hiddenWidgets, widgetId]; setHiddenWidgets(newHidden); // Salvar automaticamente ao toggle startTransition(async () => { await updateWidgetPreferences({ order: widgetOrder, hidden: newHidden, }); }); }, [hiddenWidgets, widgetOrder], ); const handleHideWidget = useCallback((widgetId: string) => { setHiddenWidgets((prev) => [...prev, widgetId]); }, []); const handleStartEditing = useCallback(() => { setOriginalOrder(widgetOrder); setOriginalHidden(hiddenWidgets); setIsEditing(true); }, [widgetOrder, hiddenWidgets]); const handleCancelEditing = useCallback(() => { setWidgetOrder(originalOrder); setHiddenWidgets(originalHidden); setIsEditing(false); }, [originalOrder, originalHidden]); const handleSave = useCallback(() => { startTransition(async () => { const result = await updateWidgetPreferences({ order: widgetOrder, hidden: hiddenWidgets, }); if (result.success) { toast.success("Preferências salvas!"); setIsEditing(false); } else { toast.error(result.error ?? "Erro ao salvar"); } }); }, [widgetOrder, hiddenWidgets]); const handleReset = useCallback(() => { startTransition(async () => { const result = await resetWidgetPreferences(); if (result.success) { setWidgetOrder(defaultOrder); setHiddenWidgets([]); toast.success("Preferências restauradas!"); } else { toast.error(result.error ?? "Erro ao restaurar"); } }); }, [defaultOrder]); return (
{/* Toolbar */}
{!isEditing ? (
Ações rápidas
Nova receita } /> Nova despesa } /> Nova anotação } />
) : (
)}
{isEditing ? ( <> ) : ( <> )}
{/* Grid */} w.id)} strategy={rectSortingStrategy} >
{orderedWidgets.map((widget) => (
{isEditing && (
Arraste para mover
)} {widget.component({ data, period })}
))}
{/* Hidden widgets indicator */} {hiddenWidgets.length > 0 && !isEditing && (

{hiddenWidgets.length} widget(s) oculto(s) •{" "}

)}
); }