"use client" import { useState, useEffect, useCallback } from "react" // Per-widget settings types export interface RecentActivitySettings { itemCount: number // 5, 10, 15 } export interface TopProductsSettings { itemCount: number // 3, 5, 10 showRevenue: boolean } export interface OverviewSettings { showChange: boolean // Show % change from previous period } export interface RevenueChartSettings { days: number // 7, 14, 30 showComparison: boolean } export interface LowStockSettings { threshold: number // Show items with stock below this itemCount: number } export interface RecentCustomersSettings { itemCount: number showSpent: boolean } export interface PendingChatsSettings { showPreview: boolean } export type WidgetSettings = | { type: "quick-actions" } | { type: "overview"; settings: OverviewSettings } | { type: "recent-activity"; settings: RecentActivitySettings } | { type: "top-products"; settings: TopProductsSettings } | { type: "revenue-chart"; settings: RevenueChartSettings } | { type: "low-stock"; settings: LowStockSettings } | { type: "recent-customers"; settings: RecentCustomersSettings } | { type: "pending-chats"; settings: PendingChatsSettings } export interface WidgetConfig { id: string title: string visible: boolean order: number colSpan: number // 1, 2, 3, 4 (full) settings?: Record } const DEFAULT_WIDGETS: WidgetConfig[] = [ { id: "quick-actions", title: "Quick Actions", visible: true, order: 0, colSpan: 4 }, { id: "overview", title: "Overview", visible: true, order: 1, colSpan: 4, settings: { showChange: false } }, { id: "recent-activity", title: "Recent Activity", visible: true, order: 2, colSpan: 2, settings: { itemCount: 10 } }, { id: "top-products", title: "Top Products", visible: true, order: 3, colSpan: 2, settings: { itemCount: 5, showRevenue: true } }, { id: "revenue-chart", title: "Revenue Chart", visible: false, order: 4, colSpan: 2, settings: { days: 7, showComparison: false } }, { id: "low-stock", title: "Low Stock Alerts", visible: false, order: 5, colSpan: 2, settings: { threshold: 5, itemCount: 5 } }, { id: "recent-customers", title: "Recent Customers", visible: false, order: 6, colSpan: 2, settings: { itemCount: 5, showSpent: true } }, { id: "pending-chats", title: "Pending Chats", visible: false, order: 7, colSpan: 2, settings: { showPreview: true } }, ] const STORAGE_KEY = "dashboard-widget-layout-v3" /** * useWidgetLayout - Persist and manage dashboard widget visibility, order, and settings */ export function useWidgetLayout() { const [widgets, setWidgets] = useState(DEFAULT_WIDGETS) const [isLoaded, setIsLoaded] = useState(false) // Load from localStorage on mount useEffect(() => { if (typeof window === "undefined") return try { const stored = localStorage.getItem(STORAGE_KEY) if (stored) { const parsed = JSON.parse(stored) as WidgetConfig[] // Merge with defaults to handle new widgets added in future const merged = DEFAULT_WIDGETS.map(defaultWidget => { const savedWidget = parsed.find(w => w.id === defaultWidget.id) return savedWidget ? { ...defaultWidget, ...savedWidget, settings: { ...defaultWidget.settings, ...savedWidget.settings } } : defaultWidget }) setWidgets(merged.sort((a, b) => a.order - b.order)) } } catch (e) { console.warn("Failed to load widget layout:", e) } setIsLoaded(true) }, []) // Save to localStorage whenever widgets change useEffect(() => { if (!isLoaded || typeof window === "undefined") return try { localStorage.setItem(STORAGE_KEY, JSON.stringify(widgets)) } catch (e) { console.warn("Failed to save widget layout:", e) } }, [widgets, isLoaded]) const toggleWidget = useCallback((widgetId: string) => { setWidgets(prev => prev.map(w => w.id === widgetId ? { ...w, visible: !w.visible } : w) ) }, []) const moveWidget = useCallback((widgetId: string, direction: "up" | "down") => { setWidgets(prev => { const index = prev.findIndex(w => w.id === widgetId) if (index === -1) return prev const newIndex = direction === "up" ? index - 1 : index + 1 if (newIndex < 0 || newIndex >= prev.length) return prev const newWidgets = [...prev] const [widget] = newWidgets.splice(index, 1) newWidgets.splice(newIndex, 0, widget) // Update order values return newWidgets.map((w, i) => ({ ...w, order: i })) }) }, []) const updateWidgetSettings = useCallback((widgetId: string, newSettings: Record) => { setWidgets(prev => prev.map(w => w.id === widgetId ? { ...w, settings: { ...w.settings, ...newSettings } } : w ) ) }, []) const updateWidgetColSpan = useCallback((widgetId: string, colSpan: number) => { setWidgets(prev => prev.map(w => w.id === widgetId ? { ...w, colSpan } : w) ) }, []) const getWidgetSettings = useCallback(>(widgetId: string): T | undefined => { return widgets.find(w => w.id === widgetId)?.settings as T | undefined }, [widgets]) const resetLayout = useCallback(() => { setWidgets(DEFAULT_WIDGETS) }, []) const getVisibleWidgets = useCallback(() => { return widgets.filter(w => w.visible).sort((a, b) => a.order - b.order) }, [widgets]) const isWidgetVisible = useCallback((widgetId: string) => { return widgets.find(w => w.id === widgetId)?.visible ?? true }, [widgets]) // Reorder widgets by moving activeId to overId's position const reorderWidgets = useCallback((activeId: string, overId: string) => { setWidgets(prev => { const oldIndex = prev.findIndex(w => w.id === activeId) const newIndex = prev.findIndex(w => w.id === overId) if (oldIndex === -1 || newIndex === -1) return prev const newWidgets = [...prev] const [removed] = newWidgets.splice(oldIndex, 1) newWidgets.splice(newIndex, 0, removed) // Update order values return newWidgets.map((w, i) => ({ ...w, order: i })) }) }, []) return { widgets, toggleWidget, moveWidget, reorderWidgets, updateWidgetSettings, updateWidgetColSpan, getWidgetSettings, resetLayout, getVisibleWidgets, isWidgetVisible, isLoaded } }