"use client"; import { useState, useMemo, useRef } from "react"; import Link from "next/link"; import { Card, CardContent } from "@/components/ui/card"; import { buttonVariants } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import { ChevronLeft, ChevronRight, Menu } from "lucide-react"; import { Drawer, DrawerClose, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger, } from "@/components/ui/drawer"; // --------------------------------------------------------------------------- // Types // --------------------------------------------------------------------------- export type LetterItem = { slug: string; recipientDisplay: string; date: string | null; year: number | null; month: number | null; location: string | null; }; type YearGroup = { year: number; label: string; count: number; letters: LetterItem[]; }; type MonthGroup = { month: number; label: string; letters: LetterItem[]; }; // --------------------------------------------------------------------------- // Constants // --------------------------------------------------------------------------- const MONTH_NAMES = [ "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ]; // --------------------------------------------------------------------------- // Grouping helpers // --------------------------------------------------------------------------- function buildYearGroups(letters: LetterItem[]): YearGroup[] { const map = new Map(); for (const letter of letters) { const y = letter.year ?? 0; if (!map.has(y)) map.set(y, []); map.get(y)!.push(letter); } const groups: YearGroup[] = []; // Sorted years first, then undated (0) at the end const years = Array.from(map.keys()).sort((a, b) => a - b); for (const y of years) { if (y === 0) continue; const items = map.get(y)!; groups.push({ year: y, label: String(y), count: items.length, letters: items, }); } const undated = map.get(0); if (undated && undated.length > 0) { groups.push({ year: 0, label: "Undated", count: undated.length, letters: undated, }); } return groups; } function buildMonthGroups(letters: LetterItem[]): MonthGroup[] { const map = new Map(); for (const letter of letters) { const m = letter.month && letter.month >= 1 && letter.month <= 12 ? letter.month : 0; if (!map.has(m)) map.set(m, []); map.get(m)!.push(letter); } const groups: MonthGroup[] = []; for (let m = 1; m <= 12; m++) { const items = map.get(m); if (items && items.length > 0) { groups.push({ month: m, label: MONTH_NAMES[m], letters: items }); } } const unknown = map.get(0); if (unknown && unknown.length > 0) { groups.push({ month: 0, label: "Unknown Month", letters: unknown }); } return groups; } // --------------------------------------------------------------------------- // Year Sidebar — matches book chapter sidebar // --------------------------------------------------------------------------- function YearSidebar({ groups, activeYear, onSelect, }: { groups: YearGroup[]; activeYear: number; onSelect: (year: number) => void; }) { return ( ); } // --------------------------------------------------------------------------- // Mobile drawer — matches MobileNav // --------------------------------------------------------------------------- function YearMobileNav({ groups, activeYear, onSelect, title, }: { groups: YearGroup[]; activeYear: number; onSelect: (year: number) => void; title: string; }) { const [open, setOpen] = useState(false); return ( Years {title} ); } // --------------------------------------------------------------------------- // Prev / Next nav — matches BbdNav // --------------------------------------------------------------------------- function YearNav({ prev, next, groups, activeYear, onSelect, drawerTitle, }: { prev: YearGroup | null; next: YearGroup | null; groups: YearGroup[]; activeYear: number; onSelect: (year: number) => void; drawerTitle: string; }) { return (
{prev ? ( ) : (
)}
{next ? ( ) : (
)}
); } // --------------------------------------------------------------------------- // Month section — collapsible group of letters for a single month // --------------------------------------------------------------------------- function MonthSection({ group, defaultOpen, }: { group: MonthGroup; defaultOpen: boolean; }) { const [open, setOpen] = useState(defaultOpen); return (
{open && (
    {group.letters.map((letter) => (
  • To: {letter.recipientDisplay}

    {letter.date || "Undated"} {letter.location ? ` · ${letter.location}` : ""}

  • ))}
)}
); } // --------------------------------------------------------------------------- // Main component — header + sidebar (years) + content (month-grouped letters) // // Props: // letters — all letters for this filter (recipient or location) // filterName — display name for the filter ("Mukunda", "New York", etc.) // filterType — "recipient" | "location" (used for back link and title) // totalCount — total letter count // --------------------------------------------------------------------------- export function FilterYearBrowser({ letters, filterName, filterType, totalCount, }: { letters: LetterItem[]; filterName: string; filterType: "recipient" | "location"; totalCount: number; }) { const yearGroups = useMemo(() => buildYearGroups(letters), [letters]); const [activeYearRaw, setActiveYear] = useState( yearGroups.length > 0 ? yearGroups[0].year : 0, ); // Derive a safe active year — if the raw value is no longer valid, fall back to the first group const activeYear = useMemo(() => { if (yearGroups.length === 0) return activeYearRaw; if (yearGroups.find((g) => g.year === activeYearRaw)) return activeYearRaw; return yearGroups[0].year; }, [yearGroups, activeYearRaw]); const contentRef = useRef(null); const handleYearSelect = (year: number) => { setActiveYear(year); contentRef.current?.scrollIntoView({ behavior: "smooth", block: "start" }); }; // Active group + neighbors const activeIdx = yearGroups.findIndex((g) => g.year === activeYear); const activeGroup = activeIdx >= 0 ? yearGroups[activeIdx] : null; const prev = activeIdx > 0 ? yearGroups[activeIdx - 1] : null; const next = activeIdx >= 0 && activeIdx < yearGroups.length - 1 ? yearGroups[activeIdx + 1] : null; // Month groups within the active year const monthGroups = useMemo( () => buildMonthGroups(activeGroup?.letters ?? []), [activeGroup], ); // Header text const backHref = filterType === "recipient" ? "/letters?view=recipient" : "/letters?view=location"; const backLabel = filterType === "recipient" ? "Letters by Recipient" : "Letters by Location"; const titlePrefix = filterType === "recipient" ? "Letters to" : "Letters from"; const drawerTitle = `${titlePrefix} ${filterName}`; const activeYearLabel = activeGroup?.label ?? "Unknown"; return ( <> {/* Header */}
← {backLabel}

{titlePrefix} {filterName}:{" "} {activeYearLabel}

{activeGroup?.count ?? 0}{" "} {(activeGroup?.count ?? 0) === 1 ? "letter" : "letters"} in{" "} {activeYearLabel} · {totalCount} total

{/* Sidebar + Main */}
{/* Left sidebar — years */} {/* Main content */}
{/* Top navigation */} {/* Content — letters grouped by month */} {monthGroups.length === 0 ? (

No letters for this year

) : ( {monthGroups.map((mg, i) => ( ))} )} {/* Bottom navigation */}
); }