"use server"; import { revalidatePath } from "next/cache"; import { z } from "zod"; import { tr } from "@/i18n/tr"; import { fail, type ActionResult } from "@/lib/action-result"; import { getHouseholdActionContext } from "@/lib/dal"; import { shoppingCompletionSchema, shoppingItemFormSchema, shoppingItemUpdateSchema, shoppingListFormSchema, } from "@/shared/schemas/shopping"; import { completeShopping } from "./completion"; import { addShoppingItem, approveSuggestions, createShoppingList, deleteShoppingList, dismissSuggestion, moveShoppingItem, removeShoppingItem, setShoppingItemChecked, updateShoppingItem, updateShoppingList, } from "./service"; const idSchema = z.string().regex(/^[a-f0-9]{24}$/i); function fieldErrors(error: z.ZodError) { const out: Record = {}; for (const issue of error.issues) { const key = issue.path.join("."); if (key && !out[key]) out[key] = issue.message; } return out; } async function run( schema: z.ZodType, input: unknown, fn: (userId: string, householdId: string, data: T) => Promise>, ): Promise> { const ctx = await getHouseholdActionContext("member"); if (!ctx) return fail(tr.common.unauthorized); const parsed = schema.safeParse(input); if (!parsed.success) return fail(tr.adminUsers.errors.checkFields, fieldErrors(parsed.error)); const result = await fn(ctx.user.id, ctx.household.id, parsed.data); if (result.ok) revalidatePath("/", "layout"); return result; } const ids = (...keys: string[]) => z.object(Object.fromEntries(keys.map((k) => [k, idSchema]))); export async function saveShoppingListAction(listId: string | null, input: unknown) { if (listId === null) return run(shoppingListFormSchema, input, (u, h, d) => createShoppingList(u, h, d)); const id = idSchema.safeParse(listId); if (!id.success) return fail(tr.common.notFound); return run(shoppingListFormSchema, input, (u, h, d) => updateShoppingList(u, h, id.data, d)); } export async function deleteShoppingListAction(listId: unknown) { const id = idSchema.safeParse(listId); if (!id.success) return fail(tr.common.notFound); return run(z.unknown(), null, (u, h) => deleteShoppingList(u, h, id.data)); } export async function addShoppingItemAction(listId: unknown, input: unknown) { const id = idSchema.safeParse(listId); if (!id.success) return fail(tr.common.notFound); return run(shoppingItemFormSchema, input, (u, h, d) => addShoppingItem(u, h, id.data, d)); } export async function updateShoppingItemAction(listId: unknown, itemId: unknown, input: unknown) { const ref = ids("listId", "itemId").safeParse({ listId, itemId }); if (!ref.success) return fail(tr.common.notFound); return run(shoppingItemUpdateSchema, input, (u, h, d) => updateShoppingItem(u, h, ref.data.listId!, ref.data.itemId!, d), ); } export async function removeShoppingItemAction(listId: unknown, itemId: unknown) { const ref = ids("listId", "itemId").safeParse({ listId, itemId }); if (!ref.success) return fail(tr.common.notFound); return run(z.unknown(), null, (u, h) => removeShoppingItem(u, h, ref.data.listId!, ref.data.itemId!), ); } export async function setShoppingItemCheckedAction( listId: unknown, itemId: unknown, checked: unknown, ) { const ref = ids("listId", "itemId").safeParse({ listId, itemId }); if (!ref.success || typeof checked !== "boolean") return fail(tr.common.notFound); return run(z.unknown(), null, (u, h) => setShoppingItemChecked(u, h, ref.data.listId!, ref.data.itemId!, checked), ); } export async function moveShoppingItemAction(listId: unknown, itemId: unknown, target: unknown) { const ref = ids("listId", "itemId", "target").safeParse({ listId, itemId, target }); if (!ref.success) return fail(tr.common.notFound); return run(z.unknown(), null, (u, h) => moveShoppingItem(u, h, ref.data.listId!, ref.data.itemId!, ref.data.target!), ); } export async function approveSuggestionsAction(listId: unknown, productTypeIds: unknown) { const id = idSchema.safeParse(listId); const types = z.array(idSchema).min(1).max(200).safeParse(productTypeIds); if (!id.success || !types.success) return fail(tr.common.notFound); return run(z.unknown(), null, (u, h) => approveSuggestions(u, h, id.data, types.data)); } export async function dismissSuggestionAction(productTypeId: unknown) { const id = idSchema.safeParse(productTypeId); if (!id.success) return fail(tr.common.notFound); return run(z.unknown(), null, (u, h) => dismissSuggestion(u, h, id.data)); } export async function completeShoppingAction(listId: unknown, input: unknown) { const id = idSchema.safeParse(listId); if (!id.success) return fail(tr.common.notFound); return run(shoppingCompletionSchema, input, (u, h, d) => completeShopping(u, h, id.data, d)); }