From c1cf31f57b9340349e0fd3d9eb1f2bb68b476b23 Mon Sep 17 00:00:00 2001 From: SeongHyun Kim Date: Fri, 27 Feb 2026 15:13:49 +0900 Subject: [PATCH] =?UTF-8?q?fix(pop-card-list):=20=EC=9E=A5=EB=B0=94?= =?UTF-8?q?=EA=B5=AC=EB=8B=88=20=EB=AA=A8=EB=93=9C=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?UI=20=EA=B0=9C=EC=84=A0=20+=20=EB=B2=84=EA=B7=B8=205=EA=B1=B4?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - screenApi 필드명 수정 (screenId/screenName) - 레이아웃 components Record -> Object.values() 변환 - config 키 수정 (props -> config) - SelectItem 빈 값 방어 (cartType || __comp_id) - cartType 수동입력 -> 원본 컴포넌트 Select 자동 로드 - 상태 필터 UI 제거 (in_cart 고정) - 설정 미완료 가드 완화 (sourceScreenId만 필수) --- .../pop-card-list/PopCardListComponent.tsx | 40 +++--- .../pop-card-list/PopCardListConfig.tsx | 130 +++++++++++++----- 2 files changed, 117 insertions(+), 53 deletions(-) diff --git a/frontend/lib/registry/pop-components/pop-card-list/PopCardListComponent.tsx b/frontend/lib/registry/pop-components/pop-card-list/PopCardListComponent.tsx index 0a7f4f9e..f89e44e6 100644 --- a/frontend/lib/registry/pop-components/pop-card-list/PopCardListComponent.tsx +++ b/frontend/lib/registry/pop-components/pop-card-list/PopCardListComponent.tsx @@ -498,8 +498,8 @@ export function PopCardListComponent({ if (isCartListMode) { const cartListMode = config!.cartListMode!; - // 설정 미완료 시 데이터 조회하지 않음 - if (!cartListMode.sourceScreenId || !cartListMode.cartType) { + // 원본 화면 미선택 시 데이터 조회하지 않음 + if (!cartListMode.sourceScreenId) { setLoading(false); setRows([]); return; @@ -513,27 +513,33 @@ export function PopCardListComponent({ if (cartListMode.sourceScreenId) { try { const layoutJson = await screenApi.getLayoutPop(cartListMode.sourceScreenId); - const components = layoutJson?.components || []; - const matched = components.find( - (c: any) => - c.type === "pop-card-list" && - c.props?.cartAction?.cartType === cartListMode.cartType - ); - if (matched?.props?.cardTemplate) { - setInheritedTemplate(matched.props.cardTemplate); + const componentsMap = layoutJson?.components || {}; + const componentList = Object.values(componentsMap) as any[]; + const matched = cartListMode.cartType + ? componentList.find( + (c: any) => + c.type === "pop-card-list" && + c.config?.cartAction?.cartType === cartListMode.cartType + ) + : componentList.find((c: any) => c.type === "pop-card-list"); + if (matched?.config?.cardTemplate) { + setInheritedTemplate(matched.config.cardTemplate); } } catch { // 레이아웃 로드 실패 시 config.cardTemplate 폴백 } } - // cart_items 조회 + // cart_items 조회 (cartType이 있으면 필터, 없으면 전체) + const cartFilters: Record = { + status: cartListMode.statusFilter || "in_cart", + }; + if (cartListMode.cartType) { + cartFilters.cart_type = cartListMode.cartType; + } const result = await dataApi.getTableData("cart_items", { size: 500, - filters: { - cart_type: cartListMode.cartType, - status: cartListMode.statusFilter || "in_cart", - }, + filters: cartFilters, }); const parsed = (result.data || []).map(parseCartRow); @@ -680,10 +686,10 @@ export function PopCardListComponent({ ref={containerRef} className={`flex h-full w-full flex-col ${className || ""}`} > - {isCartListMode && (!config?.cartListMode?.sourceScreenId || !config?.cartListMode?.cartType) ? ( + {isCartListMode && !config?.cartListMode?.sourceScreenId ? (

- 원본 화면과 장바구니 구분값을 설정해주세요. + 원본 화면을 선택해주세요.

) : !isCartListMode && !dataSource?.tableName ? ( diff --git a/frontend/lib/registry/pop-components/pop-card-list/PopCardListConfig.tsx b/frontend/lib/registry/pop-components/pop-card-list/PopCardListConfig.tsx index f0c09a00..eb1f565e 100644 --- a/frontend/lib/registry/pop-components/pop-card-list/PopCardListConfig.tsx +++ b/frontend/lib/registry/pop-components/pop-card-list/PopCardListConfig.tsx @@ -864,6 +864,12 @@ function CollapsibleSection({ // ===== 장바구니 목록 모드 설정 ===== +interface SourceCardListInfo { + componentId: string; + label: string; + cartType: string; +} + function CartListModeSection({ cartListMode, onUpdate, @@ -873,7 +879,10 @@ function CartListModeSection({ }) { const mode: CartListModeConfig = cartListMode || { enabled: false }; const [screens, setScreens] = useState<{ id: number; name: string }[]>([]); + const [sourceCardLists, setSourceCardLists] = useState([]); + const [loadingComponents, setLoadingComponents] = useState(false); + // 화면 목록 로드 useEffect(() => { screenApi .getScreens({ size: 500 }) @@ -890,6 +899,52 @@ function CartListModeSection({ .catch(() => {}); }, []); + // 원본 화면 선택 시 -> 해당 화면의 pop-card-list 컴포넌트 목록 로드 + useEffect(() => { + if (!mode.sourceScreenId) { + setSourceCardLists([]); + return; + } + setLoadingComponents(true); + screenApi + .getLayoutPop(mode.sourceScreenId) + .then((layoutJson: any) => { + const componentsMap = layoutJson?.components || {}; + const componentList = Object.values(componentsMap) as any[]; + const cardLists: SourceCardListInfo[] = componentList + .filter((c: any) => c.type === "pop-card-list") + .map((c: any) => ({ + componentId: c.id || "", + label: c.label || c.config?.cartAction?.cartType || "카드 목록", + cartType: c.config?.cartAction?.cartType || "", + })); + setSourceCardLists(cardLists); + }) + .catch(() => { + setSourceCardLists([]); + }) + .finally(() => setLoadingComponents(false)); + }, [mode.sourceScreenId]); + + const handleScreenChange = (val: string) => { + const screenId = val === "__none__" ? undefined : Number(val); + onUpdate({ ...mode, sourceScreenId: screenId, cartType: undefined }); + }; + + const handleComponentSelect = (val: string) => { + if (val === "__none__") { + onUpdate({ ...mode, cartType: undefined }); + return; + } + // cartType 직접 매칭 또는 componentId 매칭 (__comp_ 접두사) + const found = val.startsWith("__comp_") + ? sourceCardLists.find((c) => c.componentId === val.replace("__comp_", "")) + : sourceCardLists.find((c) => c.cartType === val); + if (found) { + onUpdate({ ...mode, cartType: found.cartType || undefined }); + } + }; + return (
@@ -912,9 +967,7 @@ function CartListModeSection({ -

- 품목을 담았던 화면을 선택하면 카드 디자인이 자동으로 적용됩니다. -

- {/* 장바구니 구분값 */} -
- - onUpdate({ ...mode, cartType: e.target.value })} - placeholder="예: purchase_inbound" - className="mt-1 h-7 text-xs" - /> -

- 원본 화면의 담기 버튼에 설정한 구분값과 동일하게 입력하세요. -

-
- - {/* 상태 필터 */} -
- - -
+ {/* 원본 컴포넌트 선택 (원본 화면에서 자동 로드) */} + {mode.sourceScreenId && ( +
+ + {loadingComponents ? ( +
+ 로딩 중... +
+ ) : sourceCardLists.length === 0 ? ( +
+ 원본 화면에 담기 설정이 있는 카드 목록이 없습니다. +
+ ) : ( + + )} +

+ 원본 화면의 카드 디자인과 장바구니 구분값이 자동으로 적용됩니다. +

+
+ )} )}