import type { Metadata } from 'next'; import Link from 'next/link'; import { Boxes, Euro, ImageOff, Layers, PackageSearch } from 'lucide-react'; import { CollectorFilter } from '@/components/layout/collector-filter'; import { CollectionFilters } from '@/components/sammlung/collection-filters'; import { Badge } from '@/components/ui/badge'; import { Card, CardContent } from '@/components/ui/card'; import { formatDate, formatNumber, pluralize } from '@/lib/format'; import { collectorBadgeClass } from '@/lib/collector-colors'; import { setImageSrc } from '@/lib/images'; import { completenessLabel, statusLabel } from '@/lib/labels'; import { formatEuro } from '@/lib/money'; import { countMissingSets, countOpenMissingParts, getCollectionStats, listCollectionItems, type CollectionFilters as Filters, } from '@/lib/queries/collection'; import { listCollectors, resolveCollectorId } from '@/lib/queries/collectors'; import { listLocations, listManufacturers } from '@/lib/queries/master-data'; import { requireUser } from '@/lib/session'; import type { CollectionStatus, Completeness } from '@/db/types'; export const metadata: Metadata = { title: 'Sammlung' }; type SearchParams = Promise>; function single(value: string | string[] | undefined): string | undefined { const raw = Array.isArray(value) ? value[0] : value; return raw && raw.length > 0 ? raw : undefined; } export default async function SammlungPage({ searchParams }: { searchParams: SearchParams }) { await requireUser(); const params = await searchParams; const collectors = listCollectors(); const collectorId = resolveCollectorId(single(params.sammler)); const activeCollector = collectors.find((row) => row.id === collectorId) ?? null; const filters: Filters = { q: single(params.q), status: single(params.status) as CollectionStatus | undefined, completeness: single(params.zustand) as Completeness | undefined, locationId: single(params.standort), manufacturerId: single(params.hersteller), collectorId, }; const items = listCollectionItems(filters); const openParts = countOpenMissingParts(items.map((item) => item.id)); const stats = getCollectionStats(collectorId); const missing = countMissingSets(collectorId); const tiles = [ { icon: Boxes, label: 'Sets', value: formatNumber(stats.setCount) }, { icon: Layers, label: 'Teile gesamt', value: formatNumber(stats.pieceCount) }, { icon: Euro, // Notierte Preise gehen vor, sonst die UVP. label: stats.currentValueCents === stats.retailValueCents ? 'Wert nach UVP' : 'Aktueller Wert', value: formatEuro(stats.currentValueCents), }, { icon: PackageSearch, label: 'Fehlt noch', value: formatNumber(missing) }, ] as const; return (

Sammlung

{activeCollector ? `Alles, was ${activeCollector.name} tatsächlich hat.` : 'Alles, was tatsächlich da ist.'}

({ id: row.id, name: row.name, color: row.color }))} allLabel="Alle zusammen" />
{tiles.map((tile) => (

{tile.value}

{tile.label}

))}
{stats.byManufacturer.length > 0 ? (
{stats.byManufacturer.map((row) => ( {row.name}: {formatNumber(row.count)} ))}
) : null} ({ id: row.id, name: row.name }))} manufacturers={listManufacturers().map((row) => ({ id: row.id, name: row.name }))} />

{pluralize(items.length, 'Eintrag', 'Einträge')}

{items.length === 0 ? (

Hier ist noch nichts. Sets kommen über den Katalog in die Sammlung.

Zum Katalog
) : (
    {items.map((item) => { const image = setImageSrc(item); return (
  • {image ? ( // eslint-disable-next-line @next/next/no-img-element ) : (
    )}

    {item.setName}

    {[item.setNumber, item.manufacturerName, item.locationName] .filter(Boolean) .join(' · ')}

    {statusLabel(item.status)} {item.completeness !== 'unknown' ? ( {completenessLabel(item.completeness)} ) : null} {collectors.length > 1 && item.collectorName ? ( {item.collectorName} ) : null} {openParts.get(item.id) ? ( {openParts.get(item.id)} Fehlteile ) : null} {item.acquiredAt ? ( seit {formatDate(item.acquiredAt)} ) : null}
  • ); })}
)}
); }