import type { APIRoute } from 'astro'; import { db } from '../../../db'; import { timeEntries, members, timeEntryTags, categories } from '../../../db/schema'; import { eq, and, isNull } from 'drizzle-orm'; import { nanoid } from 'nanoid'; export const POST: APIRoute = async ({ request, locals }) => { if (!locals.user) return new Response('Unauthorized', { status: 401 }); const body = await request.json(); const description = body.description || ''; const clientId = body.clientId; const categoryId = body.categoryId; const tags = body.tags || []; if (!clientId) { return new Response('Client is required', { status: 400 }); } if (!categoryId) { return new Response('Category is required', { status: 400 }); } // Check for running entry const runningEntry = await db.select().from(timeEntries).where( and( eq(timeEntries.userId, locals.user.id), isNull(timeEntries.endTime) ) ).get(); if (runningEntry) { return new Response('Timer already running', { status: 400 }); } // Get default org (first one) const member = await db.select().from(members).where(eq(members.userId, locals.user.id)).limit(1).get(); if (!member) { return new Response('No organization found', { status: 400 }); } // Verify category belongs to user's organization const category = await db.select().from(categories).where( and( eq(categories.id, categoryId), eq(categories.organizationId, member.organizationId) ) ).get(); if (!category) { return new Response('Invalid category', { status: 400 }); } const startTime = new Date(); const id = nanoid(); await db.insert(timeEntries).values({ id, userId: locals.user.id, organizationId: member.organizationId, clientId, categoryId, startTime, description, }); // Add tags if provided if (tags.length > 0) { await db.insert(timeEntryTags).values( tags.map((tagId: string) => ({ timeEntryId: id, tagId, })) ); } return new Response(JSON.stringify({ id, startTime }), { status: 200 }); };