"use server"; import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { api, ApiError, unwrap } from "@/lib/api"; import { attempt, field, type ActionState } from "@/lib/actions"; const done = (id: string) => { revalidatePath(`/products/${id}`); revalidatePath("/library"); }; /** The person's library and a product: get it, remove it, stay on a revision or follow the latest. */ export async function libraryAction(_: ActionState, form: FormData): Promise { const id = field(form, "id"); return attempt(async () => { const lib = api.library({ id }); switch (field(form, "intent")) { case "get": unwrap(await lib.put()); break; case "remove": unwrap(await lib.delete()); break; case "stay": unwrap(await lib.patch({ stayOn: Number(field(form, "revision")) })); break; case "follow": unwrap(await lib.patch({ stayOn: null })); break; } done(id); }); } /** Its creator deletes the product. */ export async function deleteProduct(_: ActionState, form: FormData): Promise { const id = field(form, "id"); const state = await attempt(async () => { unwrap(await api.products({ id }).delete()); done(id); revalidatePath("/products"); }); if (state?.error) return state; redirect(`/products/${id}`); } /** Moderation removes the product. */ export async function removeProduct(_: ActionState, form: FormData): Promise { const id = field(form, "id"); const state = await attempt(async () => { unwrap(await api.products({ id }).remove.post({ reason: field(form, "reason") })); done(id); revalidatePath("/products"); }); if (state?.error) return state; redirect("/products"); } export async function retract(_: ActionState, form: FormData): Promise { const id = field(form, "id"); return attempt(async () => { unwrap(await api.products({ id }).revisions({ n: Number(field(form, "revision")) }).retract.post()); done(id); }); } export async function saveProduct(_: ActionState, form: FormData): Promise { const id = field(form, "id"); const rating = field(form, "rating"); const state = await attempt(async () => { unwrap( await api.products({ id }).patch({ name: field(form, "name"), description: typeof form.get("description") === "string" ? String(form.get("description")) : "", ...(rating === "adult" ? { rating: "adult" as const } : {}), }), ); done(id); revalidatePath("/products"); }); if (state?.error) return state; redirect(`/products/${id}`); } /** An upload token and the catalog's upload address, for the browser to send the file there itself. */ export async function startUpload( catalog: string, product?: string, ): Promise<{ token: string; url: string } | { error: string }> { try { return unwrap(await api.products.upload.post({ catalog, ...(product ? { product } : {}) })); } catch (e) { if (e instanceof ApiError) return { error: e.message }; throw e; } }