"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 { RiAddFill, RiCheckLine, RiCloseLine, RiDragMove2Line, RiEyeOffLine, RiTodoLine, } from "@remixicon/react"; import { useMemo, useState, useTransition } from "react"; import { toast } from "sonner"; import { SortableWidget } from "@/features/dashboard/components/widgets/sortable-widget"; import { WidgetSettingsDialog } from "@/features/dashboard/components/widgets/widget-settings-dialog"; import type { DashboardData } from "@/features/dashboard/fetch-dashboard-data"; import { resetWidgetPreferences, updateWidgetPreferences, type WidgetPreferences, } from "@/features/dashboard/widget-registry/widget-actions"; import { type DashboardWidgetQuickActionOptions, type WidgetConfig, widgetsConfig, } from "@/features/dashboard/widget-registry/widget-config"; import { NoteDialog } from "@/features/notes/components/note-dialog"; import { TransactionDialog } from "@/features/transactions/components/dialogs/transaction-dialog/transaction-dialog"; import { Button } from "@/shared/components/ui/button"; import { ExpandableWidgetCard } from "@/shared/components/widgets/expandable-widget-card"; type DashboardGridEditableProps = { data: DashboardData; period: string; initialPreferences: WidgetPreferences | null; quickActionOptions: DashboardWidgetQuickActionOptions; }; const DEFAULT_WIDGET_ORDER = widgetsConfig.map((widget) => widget.id); export function DashboardGridEditable({ data, period, initialPreferences, quickActionOptions, }: DashboardGridEditableProps) { const [isEditing, setIsEditing] = useState(false); const [isPending, startTransition] = useTransition(); // Initialize widget order and hidden state const [widgetOrder, setWidgetOrder] = useState( initialPreferences?.order ?? DEFAULT_WIDGET_ORDER, ); const [hiddenWidgets, setHiddenWidgets] = useState( initialPreferences?.hidden ?? [], ); const [myAccountsShowExcluded, setMyAccountsShowExcluded] = useState( initialPreferences?.myAccountsShowExcluded ?? true, ); // 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 = (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 = (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, }); }); }; const handleHideWidget = (widgetId: string) => { setHiddenWidgets((prev) => [...prev, widgetId]); }; const handleStartEditing = () => { setOriginalOrder(widgetOrder); setOriginalHidden(hiddenWidgets); setIsEditing(true); }; const handleCancelEditing = () => { setWidgetOrder(originalOrder); setHiddenWidgets(originalHidden); setIsEditing(false); }; const handleSave = () => { 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"); } }); }; const handleReset = () => { startTransition(async () => { const result = await resetWidgetPreferences(); if (result.success) { setWidgetOrder(DEFAULT_WIDGET_ORDER); setHiddenWidgets([]); setMyAccountsShowExcluded(true); toast.success("Preferências restauradas!"); } else { toast.error(result.error ?? "Erro ao restaurar"); } }); }; return (
{/* Toolbar */}
{!isEditing ? (
Receita Nova receita } /> Despesa Nova despesa } /> Anotação Nova anotação } />
) : (
)}
{isEditing ? ( <> ) : (
)}
{/* Grid */} w.id)} strategy={rectSortingStrategy} >
{orderedWidgets.map((widget) => (
{isEditing && (
Arraste para mover
)} {widget.component({ data, period, adminPayerSlug: quickActionOptions.payerOptions.find( (p) => p.value === quickActionOptions.defaultPayerId, )?.slug ?? null, widgetPreferences: { order: widgetOrder, hidden: hiddenWidgets, myAccountsShowExcluded, }, quickActionOptions, onMyAccountsShowExcludedChange: setMyAccountsShowExcluded, })}
))}
{/* Hidden widgets indicator */} {hiddenWidgets.length > 0 && !isEditing && (

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

)}
); }