feat(pop): 후속 액션 화면 이동 구현 + 입고확정 버튼 선택 상태 피드백
- PopViewerWithModals에 __pop_navigate__ 이벤트 구독 추가 - targetScreenId가 있으면 해당 POP 화면으로 이동 - "back"이면 router.back(), params는 쿼리스트링 전달 - 입고확정 버튼에 카드리스트 선택 상태 시각 피드백 - 미선택: 기본 아이콘/색상 - 선택됨: emerald-600 배경 + 선택 개수 뱃지 - selected_items connectionMeta category를 "event"로 변경하여 자동 매칭 대상 포함
This commit is contained in:
parent
f12fca46be
commit
2e8300bbf5
|
|
@ -12,6 +12,7 @@
|
|||
"use client";
|
||||
|
||||
import { useState, useCallback, useEffect, useMemo } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
|
|
@ -61,6 +62,7 @@ export default function PopViewerWithModals({
|
|||
overrideGap,
|
||||
overridePadding,
|
||||
}: PopViewerWithModalsProps) {
|
||||
const router = useRouter();
|
||||
const [modalStack, setModalStack] = useState<OpenModal[]>([]);
|
||||
const { subscribe, publish } = usePopEvent(screenId);
|
||||
|
||||
|
|
@ -126,11 +128,30 @@ export default function PopViewerWithModals({
|
|||
});
|
||||
});
|
||||
|
||||
const unsubNavigate = subscribe("__pop_navigate__", (payload: unknown) => {
|
||||
const data = payload as {
|
||||
screenId?: string;
|
||||
params?: Record<string, string>;
|
||||
};
|
||||
|
||||
if (!data?.screenId) return;
|
||||
|
||||
if (data.screenId === "back") {
|
||||
router.back();
|
||||
} else {
|
||||
const query = data.params
|
||||
? "?" + new URLSearchParams(data.params).toString()
|
||||
: "";
|
||||
window.location.href = `/pop/screens/${data.screenId}${query}`;
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubOpen();
|
||||
unsubClose();
|
||||
unsubNavigate();
|
||||
};
|
||||
}, [subscribe, publish, layout.modals]);
|
||||
}, [subscribe, publish, layout.modals, router]);
|
||||
|
||||
// 최상위 모달만 닫기 (X 버튼, overlay 클릭, ESC)
|
||||
const handleCloseTopModal = useCallback(() => {
|
||||
|
|
|
|||
|
|
@ -420,6 +420,21 @@ export function PopButtonComponent({
|
|||
const [showCartConfirm, setShowCartConfirm] = useState(false);
|
||||
const [confirmProcessing, setConfirmProcessing] = useState(false);
|
||||
const [showInboundConfirm, setShowInboundConfirm] = useState(false);
|
||||
const [inboundSelectedCount, setInboundSelectedCount] = useState(0);
|
||||
|
||||
// 입고 확정 모드: 선택 항목 수 수신
|
||||
useEffect(() => {
|
||||
if (!isInboundConfirmMode || !componentId) return;
|
||||
const unsub = subscribe(
|
||||
`__comp_input__${componentId}__selected_items`,
|
||||
(payload: unknown) => {
|
||||
const data = payload as { value?: unknown[] } | undefined;
|
||||
const items = Array.isArray(data?.value) ? data.value : [];
|
||||
setInboundSelectedCount(items.length);
|
||||
}
|
||||
);
|
||||
return unsub;
|
||||
}, [isInboundConfirmMode, componentId, subscribe]);
|
||||
|
||||
// 장바구니 상태 수신 (카드 목록에서 count/isDirty 전달)
|
||||
useEffect(() => {
|
||||
|
|
@ -673,6 +688,20 @@ export function PopButtonComponent({
|
|||
return "";
|
||||
}, [isCartMode, cartCount, cartIsDirty]);
|
||||
|
||||
// 입고 확정 2상태 아이콘: 미선택(기본 아이콘) / 선택됨(체크 아이콘)
|
||||
const inboundIconName = useMemo(() => {
|
||||
if (!isInboundConfirmMode) return iconName;
|
||||
return inboundSelectedCount > 0 ? (config?.icon || "PackageCheck") : (config?.icon || "PackageCheck");
|
||||
}, [isInboundConfirmMode, inboundSelectedCount, config?.icon, iconName]);
|
||||
|
||||
// 입고 확정 2상태 버튼 색상: 미선택(기본) / 선택됨(초록)
|
||||
const inboundButtonClass = useMemo(() => {
|
||||
if (!isInboundConfirmMode) return "";
|
||||
return inboundSelectedCount > 0
|
||||
? "bg-emerald-600 hover:bg-emerald-700 text-white border-emerald-600"
|
||||
: "";
|
||||
}, [isInboundConfirmMode, inboundSelectedCount]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
|
|
@ -685,11 +714,12 @@ export function PopButtonComponent({
|
|||
"transition-transform active:scale-95",
|
||||
isIconOnly && "px-2",
|
||||
cartButtonClass,
|
||||
inboundButtonClass,
|
||||
)}
|
||||
>
|
||||
{(isCartMode ? cartIconName : iconName) && (
|
||||
{(isCartMode ? cartIconName : isInboundConfirmMode ? inboundIconName : iconName) && (
|
||||
<DynamicLucideIcon
|
||||
name={isCartMode ? cartIconName : iconName}
|
||||
name={isCartMode ? cartIconName : isInboundConfirmMode ? inboundIconName : iconName}
|
||||
size={16}
|
||||
className={isIconOnly ? "" : "mr-1.5"}
|
||||
/>
|
||||
|
|
@ -711,6 +741,16 @@ export function PopButtonComponent({
|
|||
{cartCount}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 입고 확정 선택 개수 배지 */}
|
||||
{isInboundConfirmMode && inboundSelectedCount > 0 && (
|
||||
<div
|
||||
className="absolute -top-2 -right-2 flex items-center justify-center rounded-full bg-emerald-600 text-white text-[10px] font-bold"
|
||||
style={{ minWidth: 18, height: 18, padding: "0 4px" }}
|
||||
>
|
||||
{inboundSelectedCount}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -1990,6 +2030,7 @@ PopComponentRegistry.registerComponent({
|
|||
{ key: "cart_updated", label: "장바구니 상태", type: "event", category: "event", description: "카드 목록에서 장바구니 변경 시 count/isDirty 수신" },
|
||||
{ key: "cart_save_completed", label: "저장 완료", type: "event", category: "event", description: "카드 목록에서 DB 저장 완료 시 수신" },
|
||||
{ key: "collected_data", label: "수집된 데이터", type: "event", category: "event", description: "컴포넌트에서 수집한 데이터+매핑 응답" },
|
||||
{ key: "selected_items", label: "선택된 항목", type: "event", category: "event", description: "카드 목록에서 체크박스로 선택된 항목 수 수신" },
|
||||
],
|
||||
},
|
||||
touchOptimized: true,
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ PopComponentRegistry.registerComponent({
|
|||
{ key: "selected_row", label: "선택된 행", type: "selected_row", category: "data", description: "사용자가 선택한 카드의 행 데이터를 전달" },
|
||||
{ key: "cart_updated", label: "장바구니 상태", type: "event", category: "event", description: "장바구니 변경 시 count/isDirty 전달" },
|
||||
{ key: "cart_save_completed", label: "저장 완료", type: "event", category: "event", description: "장바구니 DB 저장 완료 후 결과 전달" },
|
||||
{ key: "selected_items", label: "선택된 항목", type: "value", category: "data", description: "장바구니 모드에서 체크박스로 선택된 항목 배열" },
|
||||
{ key: "selected_items", label: "선택된 항목", type: "event", category: "event", description: "장바구니 모드에서 체크박스로 선택된 항목 배열" },
|
||||
{ key: "collected_data", label: "수집 응답", type: "event", category: "event", description: "데이터 수집 요청에 대한 응답 (선택 항목 + 매핑)" },
|
||||
],
|
||||
receivable: [
|
||||
|
|
|
|||
Loading…
Reference in New Issue