Der Katalog bleibt gemeinsam - ein Set existiert einmal, unabhaengig davon, wer es hat. Besitz und Wunschlisten gehoeren dagegen je einem Sammler. Damit beantwortet "hat er das schon?" jetzt die Frage "hat *er* das schon?": ein Set, das nur die Schwester besitzt, faellt fuer den Bruder wieder unter "fehlt noch" und darf auf seine Wunschliste. Wichtig fuer den Alltag: Solange es nur einen Sammler gibt, taucht die Unterscheidung nirgends in der Oberflaeche auf. Kein Umschalter, keine Abfrage beim Hinzufuegen, keine Badges - die App bleibt exakt so einfach wie vorher. Erst der zweite Sammler schaltet all das frei. Die Besitzlogik liegt weiterhin an genau einer Stelle (src/lib/ownership.ts) und hat nur eine Dimension dazubekommen. Das automatische "erfuellt" auf Wunschlisten fragt jetzt ebenfalls je Liste: ein Wunsch auf Max' Liste ist erfuellt, wenn Max das Set bekommt - nicht wenn Mia es hat. Listen ohne Sammler verhalten sich wie bisher. Die Migration legt einen Sammler "Sammlung" an und ordnet ihm alles Vorhandene zu; umbenennen laesst er sich unter Verwaltung -> Sammler. Der Seed uebernimmt ihn statt einen dritten anzulegen. Refs Phase 3 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
88 lines
2.8 KiB
TypeScript
88 lines
2.8 KiB
TypeScript
'use client';
|
||
|
||
import {
|
||
createCollector,
|
||
deleteCollector,
|
||
updateCollector,
|
||
} from '@/app/(app)/verwaltung/sammler/actions';
|
||
import { COLLECTOR_COLOR_LABELS } from '@/lib/collector-colors';
|
||
import { toDateInputValue } from '@/lib/format';
|
||
import { CrudSection, type CrudItem } from './crud-section';
|
||
import { Field } from '@/components/ui/field';
|
||
import { Input } from '@/components/ui/input';
|
||
import { NativeSelect } from '@/components/ui/native-select';
|
||
import { Textarea } from '@/components/ui/textarea';
|
||
|
||
export type CollectorRowItem = CrudItem & {
|
||
color: string;
|
||
birthday: Date | null;
|
||
notes: string | null;
|
||
itemCount: number;
|
||
};
|
||
|
||
export function CollectorList({ collectors }: { collectors: CollectorRowItem[] }) {
|
||
return (
|
||
<CrudSection<CollectorRowItem>
|
||
items={collectors}
|
||
emptyText="Noch kein Sammler angelegt."
|
||
createLabel="Sammler anlegen"
|
||
dialogTitle={(item) => (item ? 'Sammler bearbeiten' : 'Neuer Sammler')}
|
||
dialogDescription="Der Katalog bleibt gemeinsam – Sammlung und Wunschlisten gehören je einem Sammler."
|
||
onCreate={createCollector}
|
||
onUpdate={updateCollector}
|
||
onDelete={deleteCollector}
|
||
deleteWarning={(item) =>
|
||
item.itemCount > 0
|
||
? `„${item.title}“ hat ${item.itemCount} Sets in der Sammlung. Ordne sie erst jemand anderem zu – erst dann lässt sich der Sammler löschen.`
|
||
: `„${item.title}“ wird gelöscht. Der Katalog bleibt unverändert.`
|
||
}
|
||
renderFields={(item) => (
|
||
<>
|
||
<Field label="Name" htmlFor="name" required>
|
||
<Input
|
||
id="name"
|
||
name="name"
|
||
defaultValue={item?.title ?? ''}
|
||
required
|
||
maxLength={60}
|
||
placeholder="Max"
|
||
/>
|
||
</Field>
|
||
|
||
<Field
|
||
label="Farbe"
|
||
htmlFor="color"
|
||
hint="Nur zur Unterscheidung auf einen Blick."
|
||
>
|
||
<NativeSelect id="color" name="color" defaultValue={item?.color ?? 'blue'}>
|
||
{Object.entries(COLLECTOR_COLOR_LABELS).map(([value, label]) => (
|
||
<option key={value} value={value}>
|
||
{label}
|
||
</option>
|
||
))}
|
||
</NativeSelect>
|
||
</Field>
|
||
|
||
<Field label="Geburtstag" htmlFor="birthday" hint="Optional.">
|
||
<Input
|
||
id="birthday"
|
||
name="birthday"
|
||
type="date"
|
||
defaultValue={toDateInputValue(item?.birthday)}
|
||
/>
|
||
</Field>
|
||
|
||
<Field label="Notizen" htmlFor="collector-notes">
|
||
<Textarea
|
||
id="collector-notes"
|
||
name="notes"
|
||
defaultValue={item?.notes ?? ''}
|
||
rows={3}
|
||
/>
|
||
</Field>
|
||
</>
|
||
)}
|
||
/>
|
||
);
|
||
}
|