"use server"; import { db } from "@/db"; import { quotes, quote_items, clients, offer_micros, offer_phases } from "@/db/schema"; import { createQuoteSchema } from "@/lib/quote-validators"; import { eq } from "drizzle-orm"; import { nanoid } from "nanoid"; // Fetch offer with all phases and services for preview export async function getOfferWithPhases(offerMicroId: string) { const [micro] = await db .select() .from(offer_micros) .where(eq(offer_micros.id, offerMicroId)) .limit(1); if (!micro) return null; const phases = await db .select() .from(offer_phases) .where(eq(offer_phases.micro_id, offerMicroId)); return { ...micro, phases, }; } // Server action: create quote with validation export async function createQuote(input: unknown) { try { // Validate input const validated = createQuoteSchema.parse(input); // Verify client exists const [client] = await db .select() .from(clients) .where(eq(clients.id, validated.client_id)) .limit(1); if (!client) { return { success: false, error: "Cliente non trovato", }; } // Verify offer exists const [offer] = await db .select() .from(offer_micros) .where(eq(offer_micros.id, validated.offer_micro_id)) .limit(1); if (!offer) { return { success: false, error: "Offerta non trovata", }; } // Generate unique token (nanoid 21 chars = ~122 bits entropy) const token = nanoid(21); // Convert accepted_total to numeric for DB storage const totalAmount = parseFloat(validated.accepted_total); // Create quote (atomic transaction) const [insertedQuote] = await db .insert(quotes) .values({ client_id: validated.client_id, offer_micro_id: validated.offer_micro_id, token, state: "draft", accepted_total: totalAmount.toString(), }) .returning(); if (!insertedQuote) { return { success: false, error: "Errore nel salvataggio del preventivo", }; } // Return success with public link const publicLink = `/quote/${token}`; return { success: true as const, quote: insertedQuote, token: token as string, publicLink: publicLink as string, }; } catch (error) { const message = error instanceof Error ? error.message : "Errore sconosciuto"; // Check if it's a Zod validation error if (message.includes("validation")) { return { success: false, error: "Dati non validi. Controlla i campi obbligatori.", }; } return { success: false, error: message, }; } }