"use client"; import { useEffect, useMemo, useState } from "react"; import { apiClient } from "@/lib/api/client"; export type CategoryLabelMap = Record; // value_code -> value_label export interface CategoryTarget { table: string; column: string; } /** * 여러 (table, column) 쌍의 카테고리 값을 한 번에 조회해서 * value_code -> value_label 통합 맵을 반환한다. */ export function useCategoryLabelMap(targets: CategoryTarget[]): CategoryLabelMap { const [map, setMap] = useState({}); const key = useMemo(() => JSON.stringify(targets), [targets]); useEffect(() => { let cancelled = false; (async () => { const merged: CategoryLabelMap = {}; for (const { table, column } of targets) { try { const res = await apiClient.get( `/table-categories/${table}/${column}/values`, ); if (res.data?.success && Array.isArray(res.data.data)) { const flatten = (vals: any[]) => { for (const v of vals) { if (v.valueCode && v.valueLabel) { merged[v.valueCode] = v.valueLabel; } if (v.children?.length) flatten(v.children); } }; flatten(res.data.data); } } catch { /* skip */ } } if (!cancelled) setMap(merged); })(); return () => { cancelled = true; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [key]); return map; } /** * remark 원문을 화면 표시용 문자열로 변환하는 파서 팩토리. * - JSON remark → 사람 읽을 수 있는 한글 (창고이동/재고조정/재고확인/공정입고) * - value_code → codeLabelMap 에서 찾은 value_label * - 매칭 없음 → 원문 그대로 (과거 한글 레코드 호환) */ export function makeParseRemark(codeLabelMap: CategoryLabelMap) { return (remark: string | null | undefined): string => { if (!remark) return ""; const trimmed = remark.trim(); if (trimmed.startsWith("{")) { try { const d = JSON.parse(trimmed); switch (d.type) { case "move": return `창고이동 (${d.from_warehouse} → ${d.to_warehouse})`; case "adjust": return `재고조정 (${d.reason || "사유 없음"}, ${d.system_qty}→${d.actual_qty}, 차이:${d.diff >= 0 ? "+" : ""}${d.diff})`; case "confirm": return `재고확인 (${d.reason || "이상없음"})`; case "process_inbound": return "공정입고"; default: return d.reason || d.memo || trimmed; } } catch { return trimmed; } } if (codeLabelMap[trimmed]) return codeLabelMap[trimmed]; return trimmed; }; }