"use client" /** * Customisable Data view dashboard canvas — drag reorder, width, chart type, KPI count. * Hub-specific chart bodies are supplied via `renderChartCard`. */ import * as React from "react" import { closestCorners, DndContext, type DragEndEvent, KeyboardSensor, PointerSensor, useSensor, useSensors, } from "@dnd-kit/core" import { arrayMove, rectSortingStrategy, SortableContext, sortableKeyboardCoordinates, useSortable, } from "@dnd-kit/sortable" import { CSS } from "@dnd-kit/utilities" import { ChartCard } from "@/components/charts-overview" import { KeyMetrics, type MetricInsight, type MetricItem } from "@/components/key-metrics" import { Button } from "@/components/ui/button" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { ViewSegmentedControl } from "@/components/ui/view-segmented-control" import { Tip } from "@/components/ui/tip" import { DragHandleGripIcon } from "@/components/ui/drag-handle-grip" import { KEY_METRICS_KPI_COUNT_MAX, KEY_METRICS_KPI_COUNT_MIN, } from "@/lib/dashboard-layout-merge" import { CHART_DASHBOARD_CELL_CLASS, CHART_DASHBOARD_ROW_GRID_CLASS, } from "@/lib/chart-dashboard-layout" import type { ChartType, DashboardCardDef } from "@/lib/data-view-dashboard-layout-types" import { applyVisibleReorder } from "@/lib/data-view-dashboard-layout-types" import { useChartVariant } from "@/contexts/chart-variant-context" import { cn } from "@/lib/utils" export interface DataViewDashboardCanvasProps { allCards: DashboardCardDef[] keyMetricsCardId: string keyMetrics: { metrics: MetricItem[]; insight: MetricInsight } visibleCards: string[] cardOrder: string[] cardSpans?: Record cardChartTypes?: Record keyMetricsKpiCount?: number layoutEditMode?: boolean onVisibleChange?: (visible: string[]) => void onOrderChange?: (order: string[]) => void onSpanChange?: (id: string, span: 1 | 2) => void onChartTypeChange?: (id: string, chartType: ChartType) => void onKeyMetricsKpiCountChange?: (count: number) => void onResetLayout?: () => void onLayoutEditDone?: () => void onLayoutEditCancel?: () => void renderChartCard: (cardId: string, chartType: ChartType) => React.ReactNode } function SortableDashboardChartCard({ card, span, chartType, cardIndex, totalCards, onSpanChange, onChartTypeChange, onRemove, onMoveStep, keyMetrics, keyMetricsKpiCount, onKeyMetricsKpiCountChange, keyMetricsCardId, renderChartCard, }: { card: DashboardCardDef span: 1 | 2 chartType: ChartType cardIndex: number totalCards: number onSpanChange: (id: string, span: 1 | 2) => void onChartTypeChange: (id: string, chartType: ChartType) => void onRemove: (id: string) => void onMoveStep: (direction: -1 | 1) => void keyMetrics: { metrics: MetricItem[]; insight: MetricInsight } | null keyMetricsKpiCount: number onKeyMetricsKpiCountChange?: (n: number) => void keyMetricsCardId: string renderChartCard: (cardId: string, chartType: ChartType) => React.ReactNode }) { const { attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging, } = useSortable({ id: card.id }) const { chartVariant } = useChartVariant() const style: React.CSSProperties = { ...(transform ? { transform: CSS.Transform.toString(transform) } : {}), transition, } const isKeyMetrics = card.id === keyMetricsCardId if (isKeyMetrics && !keyMetrics) return null const canMoveEarlier = cardIndex > 0 const canMoveLater = cardIndex < totalCards - 1 return (
{card.chartTypes.length > 0 ? ( onChartTypeChange(card.id, v as ChartType)} options={card.chartTypes.map(opt => ({ value: opt.type, label: opt.label, icon: opt.icon, }))} /> ) : null} {isKeyMetrics && onKeyMetricsKpiCountChange ? ( onKeyMetricsKpiCountChange(Number(v))} options={Array.from( { length: KEY_METRICS_KPI_COUNT_MAX - KEY_METRICS_KPI_COUNT_MIN + 1 }, (_, i) => { const n = KEY_METRICS_KPI_COUNT_MIN + i return { value: String(n), label: String(n) } }, )} /> ) : null} onSpanChange(card.id, Number(v) as 1 | 2)} options={[ { value: "1", label: "Half width", icon: "fa-light fa-table-columns" }, { value: "2", label: "Full width (all columns)", icon: "fa-light fa-maximize" }, ]} />