"use server"; import { redirect } from "next/navigation"; import { revalidatePath } from "next/cache"; import { createClient } from "@/lib/supabase/server"; import { verifySession } from "@/lib/dal"; import { OfferFormSchema, type OfferFormState } from "@/lib/validations/offers"; const MAX_IMAGES = 5; const MAX_IMAGE_SIZE = 5 * 1024 * 1024; // 5 Mo export async function createOffer( _state: OfferFormState, formData: FormData ): Promise { const user = await verifySession(); const needId = formData.get("needId"); if (typeof needId !== "string" || !needId) { return { message: "Besoin introuvable." }; } const validatedFields = OfferFormSchema.safeParse({ title: formData.get("title"), description: formData.get("description"), price: formData.get("price"), }); if (!validatedFields.success) { return { errors: validatedFields.error.flatten().fieldErrors }; } const { title, description, price } = validatedFields.data; const parsedPrice = Number(price); if (Number.isNaN(parsedPrice) || parsedPrice <= 0) { return { message: "Prix invalide." }; } const images = formData .getAll("images") .filter((entry): entry is File => entry instanceof File && entry.size > 0); if (images.length > MAX_IMAGES) { return { message: `${MAX_IMAGES} images maximum.` }; } if (images.some((file) => file.size > MAX_IMAGE_SIZE)) { return { message: "Chaque image doit faire moins de 5 Mo." }; } const supabase = await createClient(); const { data: offer, error } = await supabase .from("offers") .insert({ need_id: needId, merchant_id: user.id, title, description, price: parsedPrice, }) .select("id") .single(); if (error || !offer) { return { message: "Impossible de créer l'offre (le besoin n'est peut-être plus ouvert, ou tu as déjà proposé une offre).", }; } for (const [index, file] of images.entries()) { const path = `${user.id}/${offer.id}/${index}-${file.name}`; const { error: uploadError } = await supabase.storage .from("offer-images") .upload(path, file); if (!uploadError) { await supabase .from("offer_images") .insert({ offer_id: offer.id, storage_path: path, position: index }); } } revalidatePath(`/needs/${needId}`); redirect(`/needs/${needId}`); } export async function withdrawOffer(offerId: string, needId: string) { await verifySession(); const supabase = await createClient(); await supabase .from("offers") .update({ status: "withdrawn" }) .eq("id", offerId) .eq("status", "pending"); revalidatePath(`/needs/${needId}`); } export async function acceptOffer(offerId: string, needId: string) { await verifySession(); const supabase = await createClient(); const { data: conversationId, error } = await supabase.rpc("accept_offer", { p_offer_id: offerId, }); if (error || !conversationId) { revalidatePath(`/needs/${needId}`); return; } redirect(`/messages/${conversationId}`); }