"use client"; import { useState, useCallback, useEffect, useMemo } from "react"; import { cn } from "@/lib/utils"; import { usePopEvent } from "@/hooks/pop"; import type { StatusBarConfig, StatusChipOption } from "./types"; import { DEFAULT_STATUS_BAR_CONFIG } from "./types"; interface PopStatusBarComponentProps { config: StatusBarConfig; label?: string; screenId?: string; componentId?: string; } export function PopStatusBarComponent({ config: rawConfig, label, screenId, componentId, }: PopStatusBarComponentProps) { const config = { ...DEFAULT_STATUS_BAR_CONFIG, ...(rawConfig || {}) }; const { publish, subscribe } = usePopEvent(screenId || ""); const [selectedValue, setSelectedValue] = useState(""); const [allRows, setAllRows] = useState[]>([]); const [autoSubStatusColumn, setAutoSubStatusColumn] = useState(null); // all_rows 이벤트 구독 useEffect(() => { if (!componentId) return; const unsub = subscribe( `__comp_input__${componentId}__all_rows`, (payload: unknown) => { const data = payload as { value?: unknown } | unknown; const inner = typeof data === "object" && data && "value" in data ? (data as { value: unknown }).value : data; if ( typeof inner === "object" && inner && !Array.isArray(inner) && "rows" in inner ) { const envelope = inner as { rows?: unknown; subStatusColumn?: string | null; }; if (Array.isArray(envelope.rows)) setAllRows(envelope.rows as Record[]); setAutoSubStatusColumn(envelope.subStatusColumn ?? null); } else if (Array.isArray(inner)) { setAllRows(inner as Record[]); setAutoSubStatusColumn(null); } } ); return unsub; }, [componentId, subscribe]); // 외부에서 값 설정 이벤트 구독 useEffect(() => { if (!componentId) return; const unsub = subscribe( `__comp_input__${componentId}__set_value`, (payload: unknown) => { const data = payload as { value?: unknown } | unknown; const incoming = typeof data === "object" && data && "value" in data ? (data as { value: unknown }).value : data; setSelectedValue(String(incoming ?? "")); } ); return unsub; }, [componentId, subscribe]); const emitFilter = useCallback( (newValue: string) => { setSelectedValue(newValue); if (!componentId) return; const baseColumn = config.filterColumn || config.countColumn || ""; const subActive = config.useSubCount && !!autoSubStatusColumn; const filterColumns = subActive ? [...new Set([baseColumn, autoSubStatusColumn!].filter(Boolean))] : [baseColumn].filter(Boolean); publish(`__comp_output__${componentId}__filter_value`, { fieldName: baseColumn, filterColumns, value: newValue, filterMode: "equals", _source: "status-bar", }); }, [componentId, publish, config.filterColumn, config.countColumn, config.useSubCount, autoSubStatusColumn] ); const chipCfg = config; const showCount = chipCfg.showCount !== false; const baseCountColumn = chipCfg.countColumn || ""; const useSubCount = chipCfg.useSubCount || false; const hideUntilSubFilter = chipCfg.hideUntilSubFilter || false; const allowAll = chipCfg.allowAll !== false; const allLabel = chipCfg.allLabel || "전체"; const chipStyle = chipCfg.chipStyle || "tab"; const options: StatusChipOption[] = chipCfg.options || []; // 하위 필터(공정) 활성 여부 const subFilterActive = useSubCount && !!autoSubStatusColumn; // hideUntilSubFilter가 켜져있으면서 아직 공정 선택이 안 된 경우 숨김 const shouldHide = hideUntilSubFilter && !subFilterActive; const effectiveCountColumn = subFilterActive ? autoSubStatusColumn : baseCountColumn; const counts = useMemo(() => { if (!showCount || !effectiveCountColumn || allRows.length === 0) return new Map(); const map = new Map(); for (const row of allRows) { if (row == null || typeof row !== "object") continue; const v = String(row[effectiveCountColumn] ?? ""); map.set(v, (map.get(v) || 0) + 1); } return map; }, [allRows, effectiveCountColumn, showCount]); const totalCount = allRows.length; const chipItems = useMemo(() => { const items: { value: string; label: string; count: number }[] = []; if (allowAll) { items.push({ value: "", label: allLabel, count: totalCount }); } for (const opt of options) { items.push({ value: opt.value, label: opt.label, count: counts.get(opt.value) || 0, }); } return items; }, [options, counts, totalCount, allowAll, allLabel]); const showLabel = !!label; if (shouldHide) { return (
{chipCfg.hiddenMessage || "조건을 선택하면 상태별 현황이 표시됩니다"}
); } if (chipStyle === "pill") { return (
{showLabel && ( {label} )}
{chipItems.map((item) => { const isActive = selectedValue === item.value; return ( ); })}
); } // tab 스타일 (기본) return (
{showLabel && ( {label} )}
{chipItems.map((item) => { const isActive = selectedValue === item.value; return ( ); })}
); }