'use client'; import { useState } from 'react'; import WaveformEditor from '@/components/WaveformEditor'; export type LocalizedString = string | { de: string; en: string }; export interface CurateSpecialSong { id: number; songId: number; startTime: number; order: number | null; song: { id: number; title: string; artist: string; filename: string; }; } export interface CurateSpecial { id: number; name: LocalizedString; subtitle?: LocalizedString | null; maxAttempts: number; unlockSteps: string; songs: CurateSpecialSong[]; } export interface CurateSpecialEditorProps { special: CurateSpecial; locale: 'de' | 'en'; onBack: () => void; onSaveStartTime: (songId: number, startTime: number) => Promise; backLabel?: string; headerPrefix?: string; noSongsHint?: string; noSongsSubHint?: string; instructionsText?: string; savingLabel?: string; saveChangesLabel?: string; savedLabel?: string; } const resolveLocalized = (value: LocalizedString | null | undefined, locale: 'de' | 'en'): string | undefined => { if (!value) return undefined; if (typeof value === 'string') return value; return value[locale] ?? value.en ?? value.de; }; export default function CurateSpecialEditor({ special, locale, onBack, onSaveStartTime, backLabel = '← Back', headerPrefix = 'Edit Special:', noSongsHint = 'No songs assigned to this special yet.', noSongsSubHint = 'Go back to the dashboard to add songs to this special.', instructionsText = 'Click on the waveform to select where the puzzle should start. The highlighted region shows what players will hear.', savingLabel = '💾 Saving...', saveChangesLabel = '💾 Save Changes', savedLabel = '✓ Saved', }: CurateSpecialEditorProps) { const [selectedSongId, setSelectedSongId] = useState( special.songs.length > 0 ? special.songs[0].songId : null ); const [pendingStartTime, setPendingStartTime] = useState( special.songs.length > 0 ? special.songs[0].startTime : null ); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); const [saving, setSaving] = useState(false); const specialName = resolveLocalized(special.name, locale) ?? `Special #${special.id}`; const specialSubtitle = resolveLocalized(special.subtitle ?? null, locale); const unlockSteps = JSON.parse(special.unlockSteps); const totalDuration = unlockSteps[unlockSteps.length - 1]; const selectedSpecialSong = special.songs.find(ss => ss.songId === selectedSongId) ?? null; const handleStartTimeChange = (newStartTime: number) => { setPendingStartTime(newStartTime); setHasUnsavedChanges(true); }; const handleSave = async () => { if (!selectedSongId || pendingStartTime === null) return; setSaving(true); try { await onSaveStartTime(selectedSongId, pendingStartTime); setHasUnsavedChanges(false); } finally { setSaving(false); } }; return (

{headerPrefix} {specialName}

{specialSubtitle && (

{specialSubtitle}

)}

Max Attempts: {special.maxAttempts} | Puzzle Duration: {totalDuration}s

{special.songs.length === 0 ? (

{noSongsHint}

{noSongsSubHint}

) : (

Select Song to Curate

{special.songs.map(ss => (
{ setSelectedSongId(ss.songId); setPendingStartTime(ss.startTime); setHasUnsavedChanges(false); }} style={{ padding: '1rem', background: selectedSongId === ss.songId ? '#4f46e5' : '#f3f4f6', color: selectedSongId === ss.songId ? 'white' : 'black', borderRadius: '0.5rem', cursor: 'pointer', border: selectedSongId === ss.songId ? '2px solid #4f46e5' : '2px solid transparent' }} >
{ss.song.title}
{ss.song.artist}
Start: {ss.startTime}s
))}
{selectedSpecialSong && (

Curate: {selectedSpecialSong.song.title}

{instructionsText}

)}
)}
); }