- Storage Integration: * Remove Firebase Storage dependency and useFirebaseStorage composable * Implement direct MinIO uploads via POST /storage/upload with multipart/form-data * Upload canvas JSON, preview PNG, and production PNG as separate objects * Store public URLs and metadata in design records - Authentication & Registration: * Add email/password registration page with validation * Integrate backend user session via /auth/login endpoint * Store backendUser.id as ownerId in design records * Auto-sync backend session on Firebase auth state changes - User Account Pages: * Create profile page showing user details and backend session info * Create orders page with transaction history filtered by customerEmail * Add server proxy /api/orders to forward GET /transactions queries - Navigation Improvements: * Replace inline auth buttons with avatar dropdown menu * Add Profile, Orders, and Logout options to dropdown * Implement outside-click and route-change handlers for dropdown * Display user initials in avatar badge - API Updates: * Update transactions endpoint to accept amount as string * Format amount with .toFixed(2) in checkout success flow * Query orders by customerEmail instead of ownerId for consistency
75 lines
1.8 KiB
TypeScript
75 lines
1.8 KiB
TypeScript
import Stripe from "stripe";
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const config = useRuntimeConfig();
|
|
const stripeSecretKey = config.stripeSecretKey;
|
|
|
|
if (!stripeSecretKey) {
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: "Stripe secret key not configured",
|
|
});
|
|
}
|
|
|
|
const stripe = new Stripe(stripeSecretKey, {
|
|
apiVersion: "2025-10-29.clover",
|
|
});
|
|
|
|
const body = await readBody<{
|
|
designId: string;
|
|
templateId?: string;
|
|
designName?: string;
|
|
amount: number;
|
|
currency?: string;
|
|
successUrl: string;
|
|
cancelUrl: string;
|
|
customerEmail?: string;
|
|
}>(event);
|
|
|
|
if (
|
|
!body?.designId ||
|
|
!body?.amount ||
|
|
!body?.successUrl ||
|
|
!body?.cancelUrl
|
|
) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: "Missing required fields",
|
|
});
|
|
}
|
|
|
|
const { currency = "usd" } = body;
|
|
|
|
const session = await stripe.checkout.sessions.create({
|
|
mode: "payment",
|
|
payment_method_types: ["card"],
|
|
billing_address_collection: "auto",
|
|
customer_email: body.customerEmail,
|
|
shipping_address_collection: { allowed_countries: ["US", "CA"] },
|
|
line_items: [
|
|
{
|
|
quantity: 1,
|
|
price_data: {
|
|
currency,
|
|
unit_amount: Math.round(body.amount * 100),
|
|
product_data: {
|
|
name: body.designName ?? `Slipmat design ${body.designId}`,
|
|
metadata: {
|
|
designId: body.designId,
|
|
...(body.templateId ? { templateId: body.templateId } : {}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
],
|
|
metadata: {
|
|
designId: body.designId,
|
|
...(body.templateId ? { templateId: body.templateId } : {}),
|
|
},
|
|
success_url: body.successUrl,
|
|
cancel_url: body.cancelUrl,
|
|
});
|
|
|
|
return { id: session.id, url: session.url };
|
|
});
|