003e8abe22
Adds a new user_billing_details table (1:1 with users, separate from the display name) with a form and GET/PUT API route. Full name is required by the form/API; address and phone stay optional. Not wired into Stripe invoicing yet — just captured for future use. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
49 lines
1.5 KiB
TypeScript
49 lines
1.5 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { db, userBillingDetails, eq } from "@epicure/db";
|
|
import { requireSession } from "@/lib/api-auth";
|
|
import { z } from "zod";
|
|
|
|
const PutSchema = z.object({
|
|
fullName: z.string().trim().min(1).max(200),
|
|
addressLine1: z.string().trim().max(200).optional(),
|
|
addressLine2: z.string().trim().max(200).optional(),
|
|
city: z.string().trim().max(120).optional(),
|
|
postalCode: z.string().trim().max(20).optional(),
|
|
country: z.string().trim().max(120).optional(),
|
|
phone: z.string().trim().max(40).optional(),
|
|
});
|
|
|
|
export async function GET() {
|
|
const { session, response } = await requireSession();
|
|
if (response) return response;
|
|
|
|
const details = await db.query.userBillingDetails.findFirst({
|
|
where: eq(userBillingDetails.userId, session!.user.id),
|
|
});
|
|
|
|
return NextResponse.json({ data: details ?? null });
|
|
}
|
|
|
|
export async function PUT(req: NextRequest) {
|
|
const { session, response } = await requireSession();
|
|
if (response) return response;
|
|
|
|
const parsed = PutSchema.safeParse(await req.json());
|
|
if (!parsed.success) {
|
|
return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 });
|
|
}
|
|
|
|
const body = parsed.data;
|
|
const userId = session!.user.id;
|
|
|
|
await db
|
|
.insert(userBillingDetails)
|
|
.values({ id: crypto.randomUUID(), userId, ...body, updatedAt: new Date() })
|
|
.onConflictDoUpdate({
|
|
target: userBillingDetails.userId,
|
|
set: { ...body, updatedAt: new Date() },
|
|
});
|
|
|
|
return NextResponse.json({ ok: true });
|
|
}
|