import { NextRequest, NextResponse } from 'next/server' import { Prisma } from '@prisma/client' import prisma from '@/lib/prisma' import { auth } from '@/auth' import { parseNote } from '@/lib/utils' import { CreateNoteSchema, UpdateNoteSchema, GetNotesQuerySchema } from '@/lib/validators' // GET /api/notes - Get all notes export async function GET(request: NextRequest) { const session = await auth() if (!session?.user?.id) { return NextResponse.json( { success: false, error: 'Unauthorized' }, { status: 401 } ) } try { const rawQuery = { archived: request.nextUrl.searchParams.get('archived') ?? undefined, search: request.nextUrl.searchParams.get('search') ?? undefined, notebookId: request.nextUrl.searchParams.get('notebookId') ?? undefined, limit: request.nextUrl.searchParams.get('limit') ?? undefined, } const queryResult = GetNotesQuerySchema.safeParse(rawQuery) if (!queryResult.success) { return NextResponse.json( { success: false, error: 'Invalid query parameters', details: queryResult.error.flatten() }, { status: 400 } ) } const { archived, search, notebookId, limit } = queryResult.data const includeArchived = archived === 'true' const where: Prisma.NoteWhereInput = { userId: session.user.id, trashedAt: null } if (!includeArchived) { where.isArchived = false } if (notebookId) { where.notebookId = notebookId } if (search) { where.OR = [ { title: { contains: search, mode: 'insensitive' } }, { content: { contains: search, mode: 'insensitive' } } ] } const notes = await prisma.note.findMany({ where, orderBy: [ { isPinned: 'desc' }, { order: 'asc' }, { updatedAt: 'desc' } ], ...(limit ? { take: limit } : {}), }) return NextResponse.json({ success: true, data: notes.map(parseNote) }) } catch (error) { console.error('Error fetching notes:', error) return NextResponse.json( { success: false, error: 'Failed to fetch notes' }, { status: 500 } ) } } // POST /api/notes - Create a new note export async function POST(request: NextRequest) { const session = await auth() if (!session?.user?.id) { return NextResponse.json( { success: false, error: 'Unauthorized' }, { status: 401 } ) } try { const body = await request.json() const parsed = CreateNoteSchema.safeParse(body) if (!parsed.success) { return NextResponse.json( { success: false, error: 'Invalid request body', details: parsed.error.flatten() }, { status: 400 } ) } const { title, content, color, type, checkItems, labels, images } = parsed.data const note = await prisma.note.create({ data: { userId: session.user.id, title: title ?? null, content: content ?? '', color: color ?? 'default', type: type ?? 'text', checkItems: checkItems != null ? JSON.stringify(checkItems) : null, labels: labels != null ? JSON.stringify(labels) : null, images: images != null ? JSON.stringify(images) : null, } }) return NextResponse.json({ success: true, data: parseNote(note) }, { status: 201 }) } catch (error) { console.error('Error creating note:', error) return NextResponse.json( { success: false, error: 'Failed to create note' }, { status: 500 } ) } } // PUT /api/notes - Update an existing note export async function PUT(request: NextRequest) { const session = await auth() if (!session?.user?.id) { return NextResponse.json( { success: false, error: 'Unauthorized' }, { status: 401 } ) } try { const body = await request.json() const parsed = UpdateNoteSchema.safeParse(body) if (!parsed.success) { return NextResponse.json( { success: false, error: 'Invalid request body', details: parsed.error.flatten() }, { status: 400 } ) } const { id, title, content, color, type, checkItems, labels, isPinned, isArchived, images } = parsed.data const updateData: Prisma.NoteUpdateInput = {} if (title !== undefined) updateData.title = title if (content !== undefined) updateData.content = content if (color !== undefined) updateData.color = color if (type !== undefined) updateData.type = type if (checkItems !== undefined) updateData.checkItems = checkItems ?? null if (labels !== undefined) updateData.labels = labels ?? null if (isPinned !== undefined) updateData.isPinned = isPinned if (isArchived !== undefined) updateData.isArchived = isArchived if (images !== undefined) updateData.images = images ?? null let note try { note = await prisma.note.update({ where: { id, userId: session.user.id }, data: updateData }) } catch (e) { if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2025') { return NextResponse.json( { success: false, error: 'Note not found or access denied' }, { status: 404 } ) } throw e } return NextResponse.json({ success: true, data: parseNote(note) }) } catch (error) { console.error('Error updating note:', error) return NextResponse.json( { success: false, error: 'Failed to update note' }, { status: 500 } ) } } // DELETE /api/notes?id=xxx - Delete a note export async function DELETE(request: NextRequest) { const session = await auth() if (!session?.user?.id) { return NextResponse.json( { success: false, error: 'Unauthorized' }, { status: 401 } ) } try { const searchParams = request.nextUrl.searchParams const id = searchParams.get('id') if (!id) { return NextResponse.json( { success: false, error: 'Note ID is required' }, { status: 400 } ) } try { await prisma.note.update({ where: { id, userId: session.user.id }, data: { trashedAt: new Date() } }) } catch (e) { if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2025') { return NextResponse.json( { success: false, error: 'Note not found or access denied' }, { status: 404 } ) } throw e } return NextResponse.json({ success: true, message: 'Note moved to trash' }) } catch (error) { console.error('Error deleting note:', error) return NextResponse.json( { success: false, error: 'Failed to delete note' }, { status: 500 } ) } }