"use client"; import { useState } from "react"; import dynamic from "next/dynamic"; import { SortableColumnHeader } from "~/components/ui/SortableColumnHeader.js"; import { useTableSort } from "~/hooks/useTableSort.js"; import { ProficiencyBadge } from "./shared.js"; const SkillDistributionChart = dynamic( () => import("~/components/analytics/SkillDistributionChart.js"), { ssr: false, loading: () =>
}, ); interface AggregatedSkill { skill: string; category: string; count: number; avgProficiency: number; chapters: string[]; } interface OverviewTabProps { aggregated: AggregatedSkill[]; categories: string[]; totalResources: number; totalSkillEntries: number; } export function OverviewTab({ aggregated, categories, totalResources, totalSkillEntries }: OverviewTabProps) { const [categoryFilter, setCategoryFilter] = useState(""); const [minCount, setMinCount] = useState(1); const filtered = aggregated.filter((e) => { if (categoryFilter && e.category !== categoryFilter) return false; if (e.count < minCount) return false; return true; }); const { sorted, sortField, sortDir, toggle } = useTableSort(filtered); const top10 = filtered.slice(0, 10); const avgProf = aggregated.length > 0 ? Math.round(aggregated.reduce((s, e) => s + e.avgProficiency, 0) / aggregated.length * 10) / 10 : 0; const gapCount = aggregated.filter((e) => e.count < 3 && e.avgProficiency >= 3).length; async function exportXlsx() { const XLSX = await import("xlsx"); const rows = sorted.map((e) => ({ Skill: e.skill, Category: e.category, "# Resources": e.count, "Avg Proficiency": e.avgProficiency, Chapters: e.chapters.join(", "), })); const ws = XLSX.utils.json_to_sheet(rows); const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Skills Overview"); XLSX.writeFile(wb, `skills-overview-${Date.now()}.xlsx`); } return (
{/* KPI Cards */}
{[ { label: "Total Resources", value: totalResources, color: "text-brand-600 dark:text-brand-400" }, { label: "Distinct Skills", value: totalSkillEntries, color: "text-indigo-600 dark:text-indigo-400" }, { label: "Avg Proficiency", value: avgProf, color: "text-amber-600 dark:text-amber-400" }, { label: "Scarce Skills", value: gapCount, color: "text-red-600 dark:text-red-400" }, ].map((kpi) => (

{kpi.label}

{kpi.value}

))}
{/* Filters + Export */}
{filtered.length} skills shown
{/* Distribution Chart */} {top10.length > 0 && (

Top 10 Skills by Resource Count

Bar color = average proficiency (light to dark = low to high)

)} {/* Skills Table */}
{sorted.map((e) => ( ))} {sorted.length === 0 && ( )}
Chapters
{e.skill} {e.category} {e.count} {e.chapters.join(", ") || "---"}
No skills found matching the filters.
); }