"use client" /** * Library **Data** view — KPI strip + Recharts cards with layout customise canvas. */ import * as React from "react" import { Bar, BarChart, CartesianGrid, Cell, Pie, PieChart, XAxis, YAxis } from "recharts" import { ChartDataTable, ChartFigure } from "@/components/charts-overview" import { DataViewDashboardCanvas } from "@/components/data-view-dashboard-canvas" import { ChartContainer, ChartTooltip, chartTooltipKeyboardSyncProps, ChartTooltipContent, type ChartConfig, } from "@/components/ui/chart" import { CHART_KBD_ACTIVE_BAR, CHART_KBD_ACTIVE_PIE_SHAPE, } from "@/lib/chart-keyboard-selection" import { CHART_AXIS_TICK, } from "@/lib/chart-typography" import type { ChartType } from "@/lib/data-view-dashboard-layout-types" import { ALL_DASHBOARD_CARDS, DEFAULT_CHART_TYPES, DEFAULT_SPANS, DEFAULT_VISIBLE_CARDS, KEY_METRICS_CARD_ID, } from "@/lib/data-view-dashboard-library-layout" import type { LibraryItem, LibraryItemType } from "@/lib/mock/library" import { libraryKpiInsight, libraryKpiMetrics } from "@/lib/mock/library-kpi" import { KEY_METRICS_KPI_COUNT_DEFAULT } from "@/lib/dashboard-layout-merge" import type { MetricInsight, MetricItem } from "@/components/key-metrics" const activeIndexProps = (activeIndex: number | null) => activeIndex == null ? {} : ({ activeIndex } as Record) const BAR_CFG: ChartConfig = { count: { label: "Questions", color: "var(--color-chart-2)" }, } const TYPE_LABEL: Record = { multiple_choice: "Multiple choice", true_false: "True / false", short_answer: "Short answer", } function aggregateByType(rows: LibraryItem[]) { const c: Record = { multiple_choice: 0, true_false: 0, short_answer: 0, } for (const r of rows) c[r.type]++ return (Object.keys(c) as LibraryItemType[]).map(key => ({ name: TYPE_LABEL[key], value: c[key], key, })) } function aggregateByTopic(rows: LibraryItem[]) { const map = new Map() for (const r of rows) map.set(r.topic, (map.get(r.topic) ?? 0) + 1) return [...map.entries()] .map(([name, value]) => ({ name: name.length > 20 ? `${name.slice(0, 18)}…` : name, value })) .sort((a, b) => b.value - a.value) .slice(0, 8) } function QuestionsByTypeChart({ rows, chartType = "bar", }: { rows: LibraryItem[] chartType?: ChartType }) { const data = React.useMemo(() => aggregateByType(rows), [rows]) if (rows.length === 0) { return (
No questions in this view.
) } const summary = `Item types: ${data.map(d => `${d.name} ${d.value}`).join(", ")}. Total ${rows.length}.` if (chartType === "pie") { return ( {(activeIndex) => ( <> } /> {data.map((_, i) => ( ))} [d.name, d.value])} /> )} ) } return ( {(activeIndex) => ( <> } /> {data.map((_, i) => ( ))} [d.name, d.value])} /> )} ) } function QuestionsByTopicChart({ rows, chartType = "horizontal-bar", }: { rows: LibraryItem[] chartType?: ChartType }) { const data = React.useMemo(() => aggregateByTopic(rows), [rows]) if (rows.length === 0) { return (
No questions in this view.
) } const summary = `Topics: ${data.map(d => `${d.name} ${d.value}`).join(", ")}.` if (chartType === "bar") { return ( {(activeIndex) => ( <> } /> {data.map((_, i) => ( ))} [d.name, d.value])} /> )} ) } return ( {(activeIndex) => ( <> } /> {data.map((_, i) => ( ))} [d.name, d.value])} /> )} ) } export interface LibraryDashboardChartsSectionProps { rows: LibraryItem[] 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 } export function LibraryDashboardChartsSection({ rows, visibleCards = DEFAULT_VISIBLE_CARDS, cardOrder = ALL_DASHBOARD_CARDS.map(c => c.id), cardSpans = DEFAULT_SPANS, cardChartTypes = DEFAULT_CHART_TYPES, keyMetricsKpiCount = KEY_METRICS_KPI_COUNT_DEFAULT, layoutEditMode = false, onVisibleChange, onOrderChange, onSpanChange, onChartTypeChange, onKeyMetricsKpiCountChange, onResetLayout, onLayoutEditDone, onLayoutEditCancel, }: LibraryDashboardChartsSectionProps) { const keyMetrics = React.useMemo( () => ({ metrics: libraryKpiMetrics(rows) as MetricItem[], insight: libraryKpiInsight(rows) as MetricInsight, }), [rows], ) const renderChartCard = React.useCallback( (cardId: string, chartType: ChartType) => { if (cardId === "by-item-type") return if (cardId === "by-topic") return return null }, [rows], ) return ( ) }