diff --git a/app/admin/page.tsx b/app/admin/page.tsx index 6c46ccb..a529058 100644 --- a/app/admin/page.tsx +++ b/app/admin/page.tsx @@ -10,6 +10,7 @@ interface Special { unlockSteps: string; launchDate?: string; endDate?: string; + curator?: string; _count?: { songs: number; }; @@ -66,6 +67,7 @@ export default function AdminPage() { const [newSpecialUnlockSteps, setNewSpecialUnlockSteps] = useState('[2,4,7,11,16,30,60]'); const [newSpecialLaunchDate, setNewSpecialLaunchDate] = useState(''); const [newSpecialEndDate, setNewSpecialEndDate] = useState(''); + const [newSpecialCurator, setNewSpecialCurator] = useState(''); const [editingSpecialId, setEditingSpecialId] = useState(null); const [editSpecialName, setEditSpecialName] = useState(''); @@ -73,6 +75,7 @@ export default function AdminPage() { const [editSpecialUnlockSteps, setEditSpecialUnlockSteps] = useState('[2,4,7,11,16,30,60]'); const [editSpecialLaunchDate, setEditSpecialLaunchDate] = useState(''); const [editSpecialEndDate, setEditSpecialEndDate] = useState(''); + const [editSpecialCurator, setEditSpecialCurator] = useState(''); // Edit state const [editingId, setEditingId] = useState(null); @@ -186,6 +189,7 @@ export default function AdminPage() { unlockSteps: newSpecialUnlockSteps, launchDate: newSpecialLaunchDate || null, endDate: newSpecialEndDate || null, + curator: newSpecialCurator || null, }), }); if (res.ok) { @@ -194,6 +198,7 @@ export default function AdminPage() { setNewSpecialUnlockSteps('[2,4,7,11,16,30,60]'); setNewSpecialLaunchDate(''); setNewSpecialEndDate(''); + setNewSpecialCurator(''); fetchSpecials(); } else { alert('Failed to create special'); @@ -275,6 +280,7 @@ export default function AdminPage() { setEditSpecialUnlockSteps(special.unlockSteps); setEditSpecialLaunchDate(special.launchDate ? new Date(special.launchDate).toISOString().split('T')[0] : ''); setEditSpecialEndDate(special.endDate ? new Date(special.endDate).toISOString().split('T')[0] : ''); + setEditSpecialCurator(special.curator || ''); }; const saveEditedSpecial = async () => { @@ -289,6 +295,7 @@ export default function AdminPage() { unlockSteps: editSpecialUnlockSteps, launchDate: editSpecialLaunchDate || null, endDate: editSpecialEndDate || null, + curator: editSpecialCurator || null, }), }); if (res.ok) { @@ -707,6 +714,10 @@ export default function AdminPage() { setNewSpecialEndDate(e.target.value)} className="form-input" /> +
+ + setNewSpecialCurator(e.target.value)} className="form-input" /> +
@@ -752,6 +763,10 @@ export default function AdminPage() { setEditSpecialEndDate(e.target.value)} className="form-input" /> +
+ + setEditSpecialCurator(e.target.value)} className="form-input" /> +
diff --git a/app/api/specials/[id]/route.ts b/app/api/specials/[id]/route.ts index e2f6c49..bca2c54 100644 --- a/app/api/specials/[id]/route.ts +++ b/app/api/specials/[id]/route.ts @@ -43,7 +43,7 @@ export async function PUT( try { const { id } = await params; const specialId = parseInt(id); - const { name, maxAttempts, unlockSteps, launchDate, endDate } = await request.json(); + const { name, maxAttempts, unlockSteps, launchDate, endDate, curator } = await request.json(); const special = await prisma.special.update({ where: { id: specialId }, @@ -53,6 +53,7 @@ export async function PUT( unlockSteps: typeof unlockSteps === 'string' ? unlockSteps : JSON.stringify(unlockSteps), launchDate: launchDate ? new Date(launchDate) : null, endDate: endDate ? new Date(endDate) : null, + curator: curator || null, } }); diff --git a/app/api/specials/route.ts b/app/api/specials/route.ts index 67c8ac1..09a939f 100644 --- a/app/api/specials/route.ts +++ b/app/api/specials/route.ts @@ -16,7 +16,7 @@ export async function GET() { } export async function POST(request: Request) { - const { name, maxAttempts = 7, unlockSteps = '[2,4,7,11,16,30,60]', launchDate, endDate } = await request.json(); + const { name, maxAttempts = 7, unlockSteps = '[2,4,7,11,16,30,60]', launchDate, endDate, curator } = await request.json(); if (!name) { return NextResponse.json({ error: 'Name is required' }, { status: 400 }); } @@ -27,6 +27,7 @@ export async function POST(request: Request) { unlockSteps, launchDate: launchDate ? new Date(launchDate) : null, endDate: endDate ? new Date(endDate) : null, + curator: curator || null, }, }); return NextResponse.json(special); @@ -42,7 +43,7 @@ export async function DELETE(request: Request) { } export async function PUT(request: Request) { - const { id, name, maxAttempts, unlockSteps, launchDate, endDate } = await request.json(); + const { id, name, maxAttempts, unlockSteps, launchDate, endDate, curator } = await request.json(); if (!id) { return NextResponse.json({ error: 'ID required' }, { status: 400 }); } @@ -54,6 +55,7 @@ export async function PUT(request: Request) { ...(unlockSteps && { unlockSteps }), launchDate: launchDate ? new Date(launchDate) : null, endDate: endDate ? new Date(endDate) : null, + curator: curator || null, }, }); return NextResponse.json(updated); diff --git a/app/page.tsx b/app/page.tsx index 3a716ad..c4437a8 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -44,17 +44,23 @@ export default async function Home() { {/* Active Specials */} {activeSpecials.map(s => ( - - ★ {s.name} - +
+ + ★ {s.name} + + {s.curator && ( + + Curated by {s.curator} + + )} +
))} diff --git a/prisma/migrations/20251123012306_add_special_curator/migration.sql b/prisma/migrations/20251123012306_add_special_curator/migration.sql new file mode 100644 index 0000000..523baf2 --- /dev/null +++ b/prisma/migrations/20251123012306_add_special_curator/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Special" ADD COLUMN "curator" TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 95b801e..a709036 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -37,6 +37,7 @@ model Special { createdAt DateTime @default(now()) launchDate DateTime? endDate DateTime? + curator String? songs SpecialSong[] puzzles DailyPuzzle[] }