"use client"; import Link from "next/link"; import { useEffect, useMemo, useState } from "react"; import { useLocale } from "@/components/providers/locale-provider"; import { formatQuantity } from "@/lib/formatters"; import type { ApiErrorResponse, DetailResponse } from "@/types/api"; import type { AdjustmentReasonRecord } from "@/types/master-data"; import type { LotListItem } from "@/types/lot"; import type { StockAdjustmentListItem } from "@/types/stock-adjustment"; type StockAdjustmentForm = { lot_id: string; adjustment_reason_id: string; adjustment_date: string; qty_change: string; notes: string; }; const emptyForm = (): StockAdjustmentForm => ({ lot_id: "", adjustment_reason_id: "", adjustment_date: new Date().toISOString().slice(0, 10), qty_change: "", notes: "" }); const adjustmentReasonCategoryLabels: Record = { ADJUSTMENT: "Penyesuaian / Adjustment", SHRINKAGE: "Penyusutan / Shrinkage", DAMAGE: "Kerusakan / Damage", REGRADE: "Regrade / Regrade" }; export function StockAdjustmentsClient() { const { dict, locale } = useLocale(); const [items, setItems] = useState([]); const [lots, setLots] = useState([]); const [reasons, setReasons] = useState([]); const [form, setForm] = useState(emptyForm); const [loading, setLoading] = useState(true); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); async function loadAll() { setLoading(true); setError(null); try { const [itemsRes, lotsRes, reasonsRes] = await Promise.all([ fetch("/api/v1/stock-adjustments", { cache: "no-store" }), fetch("/api/v1/lots", { cache: "no-store" }), fetch("/api/v1/adjustment-reasons", { cache: "no-store" }) ]); const itemsPayload = (await itemsRes.json()) as { data: StockAdjustmentListItem[] }; const lotsPayload = (await lotsRes.json()) as { data: LotListItem[] }; const reasonsPayload = (await reasonsRes.json()) as { data: AdjustmentReasonRecord[] }; if (!itemsRes.ok || !lotsRes.ok || !reasonsRes.ok) { throw new Error(dict.stockAdjustments.loadingError); } setItems(itemsPayload.data); setLots(lotsPayload.data); setReasons(reasonsPayload.data); } catch (err) { setError(err instanceof Error ? err.message : dict.stockAdjustments.loadingError); } finally { setLoading(false); } } useEffect(() => { void loadAll(); }, []); async function createAdjustment() { setSubmitting(true); setError(null); try { const response = await fetch("/api/v1/stock-adjustments", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ lot_id: form.lot_id, adjustment_reason_id: form.adjustment_reason_id, adjustment_date: form.adjustment_date, qty_change: Number(form.qty_change), notes: form.notes || null }) }); const payload = (await response.json()) as DetailResponse | ApiErrorResponse; if (!response.ok) { if ("errors" in payload && payload.errors) { const firstError = Object.values(payload.errors)[0]?.[0]; throw new Error(firstError ?? payload.message ?? dict.common.requestFailed); } throw new Error("message" in payload ? payload.message : dict.stockAdjustments.createError); } setForm(emptyForm()); await loadAll(); } catch (err) { setError(err instanceof Error ? err.message : dict.stockAdjustments.createError); } finally { setSubmitting(false); } } const activeLots = useMemo( () => lots.filter((lot) => lot.available_qty > 0), [lots] ); const selectedLot = activeLots.find((lot) => lot.id === form.lot_id) ?? null; const selectedReason = reasons.find((reason) => reason.id === form.adjustment_reason_id) ?? null; return (

{dict.stockAdjustments.overline}

{dict.stockAdjustments.createTitle}

{dict.stockAdjustments.helper}

setForm((current) => ({ ...current, lot_id: value }))} options={activeLots.map((lot) => ({ value: lot.id, label: `${lot.lot_code} · ${lot.grade} · ${lot.available_qty} ${lot.unit_code}` }))} placeholder={dict.stockAdjustments.chooseActiveLot} /> {selectedLot ? (
{selectedLot.lot_code}
{selectedLot.grade} · {dict.stockAdjustments.available}{" "} {selectedLot.available_qty} {selectedLot.unit_code}
{dict.common.warehouse}: {selectedLot.warehouse}
) : null} setForm((current) => ({ ...current, adjustment_reason_id: value })) } options={reasons.map((reason) => ({ value: reason.id, label: `${reason.code} - ${reason.name} (${adjustmentReasonCategoryLabels[reason.category]})` }))} placeholder={dict.stockAdjustments.chooseReason} /> {selectedReason ? (
{dict.stockAdjustments.category}:{" "} {adjustmentReasonCategoryLabels[selectedReason.category]}
{selectedReason.description ? (
{selectedReason.description}
) : null}
) : null}
setForm((current) => ({ ...current, adjustment_date: value })) } /> setForm((current) => ({ ...current, qty_change: value }))} placeholder={dict.stockAdjustments.adjustmentQtyPlaceholder} />