|
- "use client";
-
- import { clientAuthFetch } from "@/app/utils/clientAuthFetch";
- import { NEXT_PUBLIC_API_URL } from "@/config/api";
- import { useCallback, useEffect, useState } from "react";
-
- const POLL_MS = 60_000;
-
- /** Match backend [PurchaseStockInAlertRow] JSON. */
- export type PurchaseStockInAlertItem = {
- stockInLineId: number;
- purchaseOrderId: number;
- purchaseOrderLineId: number;
- poCode: string | null;
- itemNo: string | null;
- itemName: string | null;
- status: string | null;
- lineCreated: string | null;
- receiptDate: string | null;
- lotNo: string | null;
- };
-
- function parseAlertsPayload(raw: unknown): PurchaseStockInAlertItem[] {
- if (!Array.isArray(raw)) return [];
- return raw.map((r) => {
- const o = r as Record<string, unknown>;
- return {
- stockInLineId: Number(o.stockInLineId ?? o.stockinLineId ?? 0),
- purchaseOrderId: Number(o.purchaseOrderId ?? o.purchaseorderid ?? 0),
- purchaseOrderLineId: Number(o.purchaseOrderLineId ?? o.purchaseorderlineid ?? 0),
- poCode: o.poCode != null ? String(o.poCode) : null,
- itemNo: o.itemNo != null ? String(o.itemNo) : null,
- itemName: o.itemName != null ? String(o.itemName) : null,
- status: o.status != null ? String(o.status) : null,
- lineCreated: o.lineCreated != null ? String(o.lineCreated) : null,
- receiptDate: o.receiptDate != null ? String(o.receiptDate) : null,
- lotNo: o.lotNo != null ? String(o.lotNo) : null,
- };
- });
- }
-
- /**
- * Recent PO stock-in lines in pending / receiving (backend lookback window).
- * Fetches full list for alert dialog + count for badge.
- */
- export function usePurchaseStockInAlerts(enabled: boolean, days?: number) {
- const [items, setItems] = useState<PurchaseStockInAlertItem[]>([]);
- const [count, setCount] = useState(0);
- const [loading, setLoading] = useState(false);
-
- const load = useCallback(async () => {
- if (!enabled) {
- setItems([]);
- setCount(0);
- return;
- }
- setLoading(true);
- try {
- const listParams = new URLSearchParams();
- if (days != null && Number.isFinite(days)) listParams.set("days", String(days));
- listParams.set("limit", "80");
- const listUrl = `${NEXT_PUBLIC_API_URL}/stockInLine/alerts/purchase-incomplete?${listParams}`;
-
- const countParams = new URLSearchParams();
- if (days != null && Number.isFinite(days)) countParams.set("days", String(days));
- const countSuffix = countParams.toString() ? `?${countParams}` : "";
- const countUrl = `${NEXT_PUBLIC_API_URL}/stockInLine/alerts/purchase-incomplete-count${countSuffix}`;
- const [resList, resCount] = await Promise.all([
- clientAuthFetch(listUrl),
- clientAuthFetch(countUrl),
- ]);
- if (!resList.ok) {
- setItems([]);
- } else {
- const data = await resList.json();
- setItems(parseAlertsPayload(data));
- }
- if (resCount.ok) {
- const c = (await resCount.json()) as { count?: number };
- const n = Number(c.count ?? 0);
- setCount(Number.isFinite(n) && n > 0 ? n : 0);
- } else {
- setCount(0);
- }
- } catch {
- setItems([]);
- setCount(0);
- } finally {
- setLoading(false);
- }
- }, [enabled, days]);
-
- useEffect(() => {
- if (!enabled) {
- setItems([]);
- setCount(0);
- return;
- }
- void load();
- const id = window.setInterval(() => void load(), POLL_MS);
- return () => window.clearInterval(id);
- }, [enabled, load]);
-
- return { items, count, loading, reload: load };
- }
|