From 5d587dbdebcad5b12bbfdad168dbc929445e193a Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Fri, 14 Nov 2025 14:41:56 +0900 Subject: [PATCH] =?UTF-8?q?[=EC=B9=B4=ED=8A=B8,=20=EC=B2=B4=ED=81=AC?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EC=88=98=EC=A0=95]#1=20=20-=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=EB=85=B8=EC=B6=9C=20=EB=B0=8F=20=EB=82=98=EC=98=A4?= =?UTF-8?q?=EB=8A=94=20=EA=B0=92=20=EC=88=98=EC=A0=95=EC=A4=91.=20=20-=20?= =?UTF-8?q?=EC=B2=B4=ED=81=AC=EB=B0=95=EC=8A=A4=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=ED=95=B4=EC=84=9C=20=EC=A3=BC=EB=AC=B8=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=20-=20=EC=B2=B4=ED=81=AC=EB=B0=95=EC=8A=A4=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=EC=8B=9C=20=EA=B8=88=EC=95=A1=20=EB=85=B8=EC=B6=9C=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/actions/actionTypes.js | 2 + .../src/actions/cartActions.js | 16 + .../src/actions/checkoutActions.js | 14 +- .../src/reducers/cartReducer.js | 41 +- .../src/utils/mockDataSafetyUtils.js | 3 +- .../src/views/CartPanel/CartPanel.jsx | 63 +- .../src/views/CartPanel/CartProduct.jsx | 288 ++++----- .../src/views/CartPanel/CartSidebar.jsx | 565 ++++++++---------- .../src/views/CheckOutPanel/CheckOutPanel.jsx | 6 +- .../container/OrderItemsSideBar.jsx | 2 +- .../container/SummaryCotainer.jsx | 2 +- 11 files changed, 527 insertions(+), 475 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/actionTypes.js b/com.twin.app.shoptime/src/actions/actionTypes.js index cffa6b8b..30f5f742 100644 --- a/com.twin.app.shoptime/src/actions/actionTypes.js +++ b/com.twin.app.shoptime/src/actions/actionTypes.js @@ -86,6 +86,8 @@ export const types = { DELETE_MY_INFO_CART : "DELETE_MY_INFO_CART", DELETE_ALL_MY_INFO_CART : "DELETE_ALL_MY_INFO_CART", UPDATE_MY_INFO_CART : "UPDATE_MY_INFO_CART", + //cart checkbox toggle action + TOGGLE_CHECK_CART : "TOGGLE_CHECK_CART", // appData actions ADD_MAIN_INDEX: 'ADD_MAIN_INDEX', diff --git a/com.twin.app.shoptime/src/actions/cartActions.js b/com.twin.app.shoptime/src/actions/cartActions.js index 70258e5e..dd1d2386 100644 --- a/com.twin.app.shoptime/src/actions/cartActions.js +++ b/com.twin.app.shoptime/src/actions/cartActions.js @@ -171,6 +171,22 @@ export const deleteAllMyinfoCart = (props) => (dispatch, getState) => { ); }; +/** + * 장바구니 상품 체크박스 토글 + * @param {Object} item - 선택된 상품 정보 + * @param {Boolean} isChecked - 선택 여부 + */ +export const toggleCheckCart = (item, isChecked) => (dispatch) => { + dispatch({ + type: types.TOGGLE_CHECK_CART, + payload: { + item: item, + isChecked: isChecked, + timestamp: Date.now(), + }, + }); +}; + /** * 장바구니 상품 수정 */ diff --git a/com.twin.app.shoptime/src/actions/checkoutActions.js b/com.twin.app.shoptime/src/actions/checkoutActions.js index e94a999b..8705f22d 100644 --- a/com.twin.app.shoptime/src/actions/checkoutActions.js +++ b/com.twin.app.shoptime/src/actions/checkoutActions.js @@ -1,7 +1,10 @@ -import { URLS } from "../api/apiConfig"; -import { TAxios } from "../api/TAxios"; -import { types } from "./actionTypes"; -import { changeAppStatus, showError } from "./commonActions"; +import { URLS } from '../api/apiConfig'; +import { TAxios } from '../api/TAxios'; +import { types } from './actionTypes'; +import { + changeAppStatus, + showError, +} from './commonActions'; // 회원 체크아웃 정보 조회 IF-LGSP-345 export const getMyInfoCheckoutInfo = @@ -150,6 +153,7 @@ export const getCheckoutTotalAmt = dirPurcSelYn, bilAddrSno, dlvrAddrSno, + isPageLoading, orderProductCoupontUse, } = params; @@ -195,7 +199,7 @@ export const getCheckoutTotalAmt = "post", URLS.GET_CHECKOUT_TOTAL_AMT, {}, - { mbrNo, dirPurcSelYn, bilAddrSno, dlvrAddrSno, orderProductCoupontUse }, + { mbrNo, dirPurcSelYn, bilAddrSno, dlvrAddrSno, isPageLoading, orderProductCoupontUse }, onSuccess, onFail ); diff --git a/com.twin.app.shoptime/src/reducers/cartReducer.js b/com.twin.app.shoptime/src/reducers/cartReducer.js index a4a7143c..8b7c97a1 100644 --- a/com.twin.app.shoptime/src/reducers/cartReducer.js +++ b/com.twin.app.shoptime/src/reducers/cartReducer.js @@ -9,6 +9,11 @@ const initialState = { cartList: [], totalCount: 0, }, + selectCart : { + cartList: [], + checkedItems: [], // ✅ 체크된 상품 정보 저장 + totalCount: 0, + }, // 추가/수정/삭제 결과 lastAction: null, error: null, @@ -35,13 +40,43 @@ export const cartReducer = (state = initialState, action) => { case types.INSERT_MY_INFO_CART: return { ...state, - getMyinfoCartSearch: { - ...state.getMyinfoCartSearch, - cartList: [...state.getMyinfoCartSearch.cartList, action.payload], + selectCart: { + ...state.selectCart, + cartList: [...state.selectCart.cartList, action.payload], totalCount: (state.getMyinfoCartSearch.totalCount || 0) + 1, }, }; + //체크박스 토글시 상품 처리 + case types.TOGGLE_CHECK_CART: { + const checkedItem = action.payload.item; + const isChecked = action.payload.isChecked; + + let updatedCheckedList = state.selectCart?.checkedItems || []; + + if (isChecked) { + const itemExists = updatedCheckedList.some( + item => item.prodSno === checkedItem.prodSno + ); + if (!itemExists) { + updatedCheckedList = [...updatedCheckedList, checkedItem]; + } + } else { + updatedCheckedList = updatedCheckedList.filter( + item => item.prodSno !== checkedItem.prodSno + ); + } + + return { + ...state, + selectCart: { + ...state.selectCart, + checkedItems: updatedCheckedList, + totalCount: updatedCheckedList.length, + }, + }; + } + // 장바구니에서 상품 삭제 case types.DELETE_MY_INFO_CART: return { diff --git a/com.twin.app.shoptime/src/utils/mockDataSafetyUtils.js b/com.twin.app.shoptime/src/utils/mockDataSafetyUtils.js index bddc5237..f4b6b487 100644 --- a/com.twin.app.shoptime/src/utils/mockDataSafetyUtils.js +++ b/com.twin.app.shoptime/src/utils/mockDataSafetyUtils.js @@ -202,8 +202,7 @@ export const isAuctionProduct = (product) => { * @returns {Object} 정규화된 상품 객체 */ export const normalizeProductDataForDisplay = (product) => { - // Mock Mode: product가 없어도 기본값으로 진행 - console.log("###product 확인용", product) + // Mock Mode: product가 없어도 기본값으로 진행 if (!product) { console.log('[mockDataSafetyUtils] normalizeProductDataForDisplay - product is null/undefined, using defaults'); return { diff --git a/com.twin.app.shoptime/src/views/CartPanel/CartPanel.jsx b/com.twin.app.shoptime/src/views/CartPanel/CartPanel.jsx index a835bbd5..6209aec9 100644 --- a/com.twin.app.shoptime/src/views/CartPanel/CartPanel.jsx +++ b/com.twin.app.shoptime/src/views/CartPanel/CartPanel.jsx @@ -10,6 +10,10 @@ import { } from 'react-redux'; import { getMyInfoCartSearch } from '../../actions/cartActions'; +import { + setHidePopup, + setShowPopup, +} from '../../actions/commonActions'; import { initializeMockCart, resetMockCart, @@ -21,10 +25,12 @@ import { import TBody from '../../components/TBody/TBody'; import THeader from '../../components/THeader/THeader'; import TPanel from '../../components/TPanel/TPanel'; +import TPopUp from '../../components/TPopUp/TPopUp'; import TScroller from '../../components/TScroller/TScroller'; import useScrollTo from '../../hooks/useScrollTo'; -import { BUYNOW_CONFIG } from '../../utils/BuyNowConfig'; +import { launchMembershipApp } from '../../lunaSend'; import * as Config from '../../utils/Config'; +import { $L } from '../../utils/helperMethods'; import CartEmpty from './CartEmpty'; import css from './CartPanel.module.less'; import CartProductBar from './CartProductBar'; @@ -44,13 +50,19 @@ export default function CartPanel({ spotlightId, scrollOptions = [], panelInfo } const { userNumber } = useSelector( (state) => state.common.appStatus.loginUserData ); + const { popupVisible, activePopup } = useSelector( + (state) => state.common.popup + ); + const webOSVersion = useSelector( + (state) => state.common.appStatus.webOSVersion + ); // Mock Mode 여부 확인 및 적절한 데이터 선택 // const isMockMode = BUYNOW_CONFIG.isMockMode(); const isMockMode = false; const displayCartData = useMemo(() => { return isMockMode ? mockCartData : cartData; - }, [isMockMode, mockCartData, cartData]); + }, [isMockMode, mockCartData, cartData]); // PlayerPanel/MediaPanel 충돌 방지 로직 (CheckOutPanel 전환 시에만 활성화) useEffect(() => { @@ -166,6 +178,35 @@ export default function CartPanel({ spotlightId, scrollOptions = [], panelInfo } const { getScrollTo, scrollTop } = useScrollTo(); + // 로그인 팝업 텍스트 로직 (SingleOption과 동일) + const loginPopupText = useMemo(() => { + return $L('Would you like to sign in?'); + }, [userNumber]); + + // 로그인 팝업 열기 핸들러 (SingleOption과 동일) + const handleLoginPopUpOpen = useCallback(() => { + if (!userNumber) { + if (webOSVersion >= '6.0') { + dispatch(setHidePopup()); + dispatch(launchMembershipApp()); // 필요시 추가 + } + return; + } + }, [dispatch, webOSVersion, userNumber]); + + // 팝업 닫기 핸들러 (SingleOption과 동일) + const onClose = useCallback(() => { + dispatch(setHidePopup()); + }, + [dispatch] + ); + + useEffect(()=>{ + if(!userNumber || userNumber === ''){ + dispatch(setShowPopup(Config.ACTIVE_POPUP.loginPopup)); + } + },[userNumber, dispatch]) + return ( @@ -182,7 +223,7 @@ export default function CartPanel({ spotlightId, scrollOptions = [], panelInfo }
{/* 오른쪽 상품 영역 */} - {displayCartData && displayCartData?.length > 0 ? ( + {userNumber && displayCartData && displayCartData?.length > 0 ? ( ) : ( + + + )} + {/* LOGIN POPUP */} + {(!userNumber || userNumber === '') && activePopup === Config.ACTIVE_POPUP.loginPopup && ( + )}
diff --git a/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx b/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx index 8280d01e..dcc34fd5 100644 --- a/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx +++ b/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx @@ -18,6 +18,7 @@ import defaultImage from '../../../assets/images/img-thumb-empty-144@3x.png'; import { deleteMyinfoCart, removeFromCart, + toggleCheckCart, updateMyinfoCart, } from '../../actions/cartActions'; import { @@ -94,6 +95,7 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { // 항상 호출되어야 하는 Hook들 const fallbackCartData = useSelector((state) => state.cart.getMyinfoCartSearch.cartInfo); + const checkedItems = useSelector((state) => state.cart.selectCart.checkedItems || []); // ✅ Redux에서 체크된 아이템 가져오기 const selectedItems = useSelector((state) => state.mockCart.selectedItems || []); const userNumber = useSelector((state) => state.common.appStatus.loginUserData.userNumber); @@ -103,7 +105,6 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { // Mock Mode 확인 const isMockMode = BUYNOW_CONFIG.isMockMode(); - //카트 데이타 그룹화 - 수정된 부분 const groupedCartData = useMemo(() => { if (!cartData || !Array.isArray(cartData)) return {}; @@ -111,7 +112,6 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { const groupKey = item.patncNm || item.patnrId || 'unknown'; if (!acc[groupKey]) { - // 객체 구조로 초기화 (수정됨) acc[groupKey] = { partnerInfo: { id: item.patnrId, @@ -137,14 +137,15 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { // 파트너사별 총합 계산 const calculatePartnerTotal = (items) => { const productTotal = items.reduce((sum, item) => - sum + (parseFloat(Number(item.price3) !== 0 ? Number(item.price3) : Number(item.price2) !== 0 ? Number(item.price2) : 0) * item.prodQty), 0 + sum + (Number(item.price3) !== 0 ? Number(item.price3) : Number(item.price2) !== 0 ? Number(item.price2) : 0) * item.prodQty, 0 ); const optionTotal = items.reduce((sum, item) => - sum + (parseFloat(Number(item.price5) !== 0 ? Number(item.price5) : Number(item.optPrc) !== 0 ? Number(item.optPrc) : 0) * item.prodQty), 0 + //sum + (parseFloat(Number(item.price5) !== 0 ? Number(item.price5) : Number(item.optPrc) !== 0 ? Number(item.optPrc) : 0) * item.prodQty), 0 + sum + (Number(item.optPrc) !== 0 && item.optPrc !== undefined) ? Number(item.optPrc) : 0 * item.prodQty, 0 ); const shippingTotal = items.reduce((sum, item) => - sum + parseFloat((item.shippingCharge) * item.prodQty || 0), 0 + sum + parseFloat(item.shippingCharge || 0), 0 ); return { @@ -176,7 +177,7 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { } } } - }, [dispatch, isMockMode]); + }, [dispatch, isMockMode, userNumber]); const handleIncreseClick = useCallback((prodSno, patnrId, prdtId, currentQty) => { const newQty = currentQty + 1; @@ -190,7 +191,7 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { dispatch(updateMyinfoCart({ mbrNo: userNumber, patnrId, prdtId, prodSno, prodQty: newQty })); } } - }, [dispatch, isMockMode]); + }, [dispatch, isMockMode, userNumber]); // 상품 삭제 핸들러 const handleDeleteClick = useCallback((prodSno) => { @@ -205,46 +206,29 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { } }, [dispatch, isMockMode]); - // 체크박스 선택 핸들러 (TCheckBoxSquare onToggle 형식에 맞춤) - debounce 적용 - const debouncedUpdateSelectedItems = useCallback( - debounce((newSelectedItems) => { - dispatch(updateSelectedItems(newSelectedItems)); - }, 100), // 100ms debounce - [dispatch] - ); - - const handleCheckboxToggle = useCallback((prodSno) => { + // 체크박스 선택 핸들러 - ✅ Redux 상태만 사용하도록 수정 + const handleCheckboxToggle = useCallback((prodSno, fullItemData) => { return ({ selected: isChecked }) => { - const DEBUG_LOG = false; // 수동 설정: false로 비활성화 - - if (DEBUG_LOG) { - console.log('[CartProduct] handleCheckboxToggle called - prodSno:', prodSno, 'selected:', isChecked); - } - - if (isMockMode) { - let newSelectedItems; - if (isChecked) { - // 상품 선택 - newSelectedItems = [...selectedItems, prodSno]; - } else { - // 상품 선택 해제 - newSelectedItems = selectedItems.filter(id => id !== prodSno); - } - - // debounced 호출 사용 - debouncedUpdateSelectedItems(newSelectedItems); - - if (DEBUG_LOG) { - console.log('[CartProduct] Checkbox toggled - prodSno:', prodSno, 'isChecked:', isChecked, 'selectedItems:', newSelectedItems); - } - } + // Redux 상태에만 저장 + dispatch(toggleCheckCart(fullItemData, isChecked)); }; - }, [dispatch, isMockMode, selectedItems, debouncedUpdateSelectedItems]); + }, [dispatch]); + + // 장바구니 삭제 + const deleteCart = useCallback((patnrId, prdtId, prodSno, item) => { + dispatch(toggleCheckCart(item, false)); + dispatch(deleteMyinfoCart({ + mbrNo : userNumber, + patnrId: String(patnrId), + prdtId : String(prdtId), + prodSno : String(prodSno) + })) + },[dispatch, userNumber]) // 상품이 선택되었는지 확인 - const isItemSelected = useCallback((prodSno) => { - return selectedItems.includes(prodSno); - }, [selectedItems]); + const isItemSelected = useCallback((prodSno) => { + return checkedItems.some(item => item.prodSno === prodSno); + }, [checkedItems]); const handleFocus = useCallback((index, groupIndex) => { if(index === 0 && groupIndex === 0){ @@ -259,9 +243,7 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { andThen(() => document.getElementById(sectionId)), when(isNil, () => null), andThen((targetElement) => { - // offsetTop: 부모 컨테이너 기준 절대 위치 사용 - // const y = targetElement.offsetTop; - const y = 0; //0으로 들어가는것이 깔끔. + const y = 0; return scrollTop({ y, animate: true }); }) )(sectionId) @@ -269,22 +251,14 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { [scrollTop] ); - //장바구니 삭제 - const deleteCart = useCallback((patnrId, prdtId, prodSno) => { - dispatch(deleteMyinfoCart({ - mbrNo : userNumber, - patnrId: String(patnrId), - prdtId : String(prdtId), - prodSno : String(prodSno) - })) - },[dispatch]) + return ( - <> - {Object.entries(groupedCartData).map(([partnerKey, group], index) => { - const totals = calculatePartnerTotal(group.items); - return ( - + <> + {Object.entries(groupedCartData).map(([partnerKey, group], index) => { + const totals = calculatePartnerTotal(group.items); + return ( + {index === 0 && (
)} @@ -310,9 +284,9 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => {
Product Total ${totals.productTotal.toLocaleString('en-US', { - minimumFractionDigits: 2, - maximumFractionDigits: 2 - })} + + minimumFractionDigits: 2, + maximumFractionDigits: 2 + })} + {totals.optionTotal > 0 && ( <> Option ${totals.optionTotal.toLocaleString('en-US', { @@ -322,9 +296,9 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { )} S&H ${totals.shippingTotal.toLocaleString('en-US', { - minimumFractionDigits: 2, - maximumFractionDigits: 2 - })} + minimumFractionDigits: 2, + maximumFractionDigits: 2 + })}
Total @@ -345,8 +319,8 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { const normalizedItem = normalizeProductDataForDisplay(item); // ✅ 이미지 우선순위: ProductAllSection 고품질 이미지 → 기타 모든 이미지 필드 - const imageSrc = (item.imgUrls600 && item.imgUrls600[0]) || // ✅ ProductAllSection의 고품질 이미지 - (item.thumbnailUrl960) || // ✅ 960px 썸네일 + const imageSrc = (item.imgUrls600 && item.imgUrls600[0]) || + (item.thumbnailUrl960) || (normalizedItem.imgUrls && normalizedItem.imgUrls[0]?.imgUrl) || (item.imgUrls && item.imgUrls[0]?.imgUrl) || (item.imgList && item.imgList[0]?.imgUrl) || @@ -356,109 +330,109 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { defaultImage; return ( -
-
-
- {handleFocus(index, groupIndex)}} - /> - - ID : {item.prdtId} - -
-
-
- +
+
+ {handleFocus(index, groupIndex)}} /> + + ID : {item.prdtId} +
-
-
- {item.prdtNm} +
+
+
- {item.optNm && ( -
{item.optNm}
- )} -
- - ${parseFloat(Number(item.price3) > 0 ? Number(item.price3) : Number(item.price2) > 0 ? Number(item.price2) : 0).toLocaleString('en-US', { - minimumFractionDigits: 2, - maximumFractionDigits: 2 - })} - -
+
+
+ {item.prdtNm} +
+ {item.optNm && ( +
{item.optNm}
+ )} +
+ + ${parseFloat(Number(item.price3) > 0 ? Number(item.price3) : Number(item.price2) > 0 ? Number(item.price2) : 0).toLocaleString('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + })} + +
- {item.price2 && (parseFloat(item.price2) > 0 && parseFloat(item.price3) > 0 && parseFloat(item.price2) !== parseFloat(item.price3)) && ( - <> - ${parseFloat(item.price2).toLocaleString('en-US', { - minimumFractionDigits: 2, - maximumFractionDigits: 2 - })} - - )} + {item.price2 && (parseFloat(item.price2) > 0 && parseFloat(item.price3) > 0 && parseFloat(item.price2) !== parseFloat(item.price3)) && ( + <> + ${parseFloat(item.price2).toLocaleString('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + })} + + )} - {item.price5 && parseFloat(item.price5) > 0 && ( - - OPTION : ${parseFloat(item.price5).toLocaleString('en-US', { - minimumFractionDigits: 2, - maximumFractionDigits: 2 - })} - - )} - {item.shippingCharge && parseFloat(item.shippingCharge) > 0 && ( - - S&H: ${parseFloat(item.shippingCharge).toLocaleString('en-US', { - minimumFractionDigits: 2, - maximumFractionDigits: 2 - })} - - )} + {item.optPrc && parseFloat(item.optPrc) > 0 && parseFloat(item.optPrc) !== parseFloat(item.price2) && parseFloat(item.optPrc) !== parseFloat(item.price3) && ( + + OPTION : ${parseFloat(item.optPrc).toLocaleString('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + })} + + )} + {item.shippingCharge && parseFloat(item.shippingCharge) > 0 && ( + + S&H: ${parseFloat(item.shippingCharge).toLocaleString('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + })} + + )} +
+
+
+ handleDecreseClick(item.prodSno, item.patnrId, item.prdtId, item.prodQty)} + spotlightId={"pd_ea_decrese"} + spotlightDisabled={item.prodQty === 1} + /> +
{item.prodQty}
+ handleIncreseClick(item.prodSno, item.patnrId, item.prdtId, item.prodQty)} + className={css.plusBox} + spotlightId={"pd_ea_increse"} + size="cartEa" + />
-
- handleDecreseClick(item.prodSno, item.patnrId, item.prdtId, item.prodQty)} - spotlightId={"pd_ea_decrese"} - spotlightDisabled={item.prodQty === 1} - /> -
{item.prodQty}
- handleIncreseClick(item.prodSno, item.patnrId, item.prdtId, item.prodQty)} - className={css.plusBox} - spotlightId={"pd_ea_increse"} - size="cartEa" - /> -
+
+ deleteCart(item.patnrId, item.prdtId, item.prodSno, item)} + /> +
-
- deleteCart(item.patnrId, item.prdtId, item.prodSno)} - /> -
-
); })}
- ); - })} - + ); + })} + ); }; diff --git a/com.twin.app.shoptime/src/views/CartPanel/CartSidebar.jsx b/com.twin.app.shoptime/src/views/CartPanel/CartSidebar.jsx index b850ac53..3ed00e78 100644 --- a/com.twin.app.shoptime/src/views/CartPanel/CartSidebar.jsx +++ b/com.twin.app.shoptime/src/views/CartPanel/CartSidebar.jsx @@ -9,7 +9,16 @@ import { useSelector, } from 'react-redux'; -import { pushPanel } from '../../actions/panelActions'; +import { getMyInfoCheckoutInfo } from '../../actions/checkoutActions'; +import { + changeAppStatus, + setShowPopup, + showError, +} from '../../actions/commonActions'; +import { + popPanel, + pushPanel, +} from '../../actions/panelActions'; import TButton from '../../components/TButton/TButton'; import { BUYNOW_CONFIG } from '../../utils/BuyNowConfig'; import * as Config from '../../utils/Config'; @@ -26,175 +35,174 @@ const CartSidebar = ({ cartInfo }) => { // 실제 장바구니 데이터 (API 모드일 때만 사용) const fallbackCartInfo = useSelector((state) => state.cart.getMyinfoCartSearch.cartInfo); - const selectedItems = useSelector((state) => state.mockCart.selectedItems || []); + // ✅ Redux에서 체크된 상품 정보 가져오기 + const checkedItems = useSelector((state) => state.cart.selectCart.checkedItems || []); + + const { userNumber } = useSelector( + (state) => state.common.appStatus.loginUserData + ); // 사용할 장바구니 데이터 결정 const displayCartInfo = cartInfo || (isMockMode ? null : fallbackCartInfo); - // 선택된 상품들만 필터링 - 항상 선택된 상품들만 반환 - const getSelectedItems = useCallback((items) => { - const DEBUG_LOG = false; // 수동 설정: false로 비활성화 - - if (DEBUG_LOG) { - console.log('[CartSidebar] getSelectedItems called - isMockMode:', isMockMode, 'selectedItems:', selectedItems); + // ✅ 계산할 상품 결정 (체크된 상품이 있으면 체크된 상품, 없으면 전체 상품) + const itemsToCalculate = useMemo(() => { + if (checkedItems && checkedItems.length > 0) { + // 체크된 상품이 있으면 체크된 상품만 사용 + console.log('[CartSidebar] Using checked items for calculation:', checkedItems.length); + return checkedItems; + } else if (displayCartInfo && Array.isArray(displayCartInfo)) { + // 체크된 상품이 없으면 전체 장바구니 상품 사용 + console.log('[CartSidebar] No checked items, using all cart items:', displayCartInfo.length); + return displayCartInfo; } + return []; + }, [checkedItems, displayCartInfo]); - if (!items || !Array.isArray(items)) { - if (DEBUG_LOG) { - console.log('[CartSidebar] No items provided, returning empty array'); + // checkOutValidate 콜백 함수 (SingleOption과 동일한 로직) + function checkOutValidate(response) { + console.log('%c[BuyOption] 🔴 checkOutValidate CALLED', 'background: red; color: white; font-weight: bold; padding: 5px;', { + hasResponse: !!response, + retCode: response?.retCode, + retMsg: response?.retMsg, + hasCardInfo: !!response?.data?.cardInfo, + hasBillingAddress: response?.data?.billingAddressList?.length > 0, + hasShippingAddress: response?.data?.shippingAddressList?.length > 0, + hasProductList: response?.data?.productList?.length > 0, + }); + + if (response) { + if (response.retCode === 0) { + // 🔍 조건 체크 + const isCardInfoNull = response.data.cardInfo === null; + const isBillingAddressEmpty = response.data.billingAddressList.length === 0; + const isShippingAddressEmpty = response.data.shippingAddressList.length === 0; + + console.log('%c[BuyOption] 🔍 Address & Card Validation:', 'background: blue; color: white; font-weight: bold; padding: 5px;', { + isCardInfoNull, + isBillingAddressEmpty, + isShippingAddressEmpty, + needsQRPopup: isCardInfoNull || isBillingAddressEmpty || isShippingAddressEmpty, + }); + + if ( + isCardInfoNull || + isBillingAddressEmpty || + isShippingAddressEmpty + ) { + console.log('%c[BuyOption] 🟡 Missing card/address - Showing QR Popup', 'background: orange; color: white; font-weight: bold; padding: 5px;'); + dispatch(setShowPopup(Config.ACTIVE_POPUP.qrPopup)); + dispatch(changeAppStatus({ isLoading: false })); + return; + } else { + console.log('%c[BuyOption] ✅ All address & card data present - Proceeding to CheckOutPanel', 'background: green; color: white; font-weight: bold; padding: 5px;'); + const { mbrId, prdtId, prodSno } = response.data.productList[0]; + const cartTpSno = `${mbrId}_${prdtId}_${prodSno}`; + + + // 🔴 CRITICAL: 기존 CheckOutPanel 있으면 제거 후 새로 push (API Mode) + dispatch((dispatchFn, getState) => { + const panels = getState().panels?.panels || []; + const checkoutPanelExists = panels.some(p => p.name === Config.panel_names.CHECKOUT_PANEL); + + console.log('[BuyOption] 📊 API Mode - Current panels:', panels.map(p => p.name)); + + // 1️⃣ DetailPanel 제거 (STANDALONE_PANEL이므로 다른 패널 제거 필수) + console.log('[BuyOption] 🗑️ API Mode - Removing DetailPanel'); + dispatchFn(popPanel(Config.panel_names.DETAIL_PANEL)); + + // 2️⃣ 기존 CheckOutPanel 제거 (있으면) + if (checkoutPanelExists) { + console.log('[BuyOption] 🗑️ API Mode - Removing existing CheckOutPanel'); + dispatchFn(popPanel(Config.panel_names.CHECKOUT_PANEL)); + } + + // 3️⃣ 새로운 CheckOutPanel push + console.log('[BuyOption] ➕ API Mode - Pushing new CheckOutPanel'); + dispatchFn(pushPanel({ + name: Config.panel_names.CHECKOUT_PANEL, + // panelInfo: { logInfo: { ...logInfo, cartTpSno } }, + })); + + }); + + } + } else if (response.retCode === 1001) { + dispatch(setShowPopup(Config.ACTIVE_POPUP.qrPopup)); + dispatch(changeAppStatus({ isLoading: false })); + } else { + dispatch( + showError( + response.retCode, + response.retMsg, + false, + response.retDetailCode, + response.returnBindStrings + ) + ); + dispatch(changeAppStatus({ isLoading: false })); + return; + } } - return []; } - if (!isMockMode) { - if (DEBUG_LOG) { - console.log('[CartSidebar] API Mode - returning all items'); - } - return items; - } + // ✅ Mock 데이터 또는 실제 데이터 계산 - 최적화 버전 + const calculatedData = useMemo(() => { + const DEBUG_LOG = false; - if (selectedItems.length === 0) { - if (DEBUG_LOG) { - console.log('[CartSidebar] No items selected, returning empty array'); - } - return []; // 선택된 상품이 없으면 빈 배열 반환 - } + if (itemsToCalculate && itemsToCalculate.length > 0) { + let totalItems = 0; + let totalOption = 0; + let totalShipping = 0; + let totalQuantity = 0; - const filtered = items.filter(item => { - const itemId = item.prodSno || item.cartId; - const isSelected = selectedItems.includes(itemId); - if (DEBUG_LOG) { - console.log('[CartSidebar] Item filter:', { - itemName: item.prdtNm, - itemId, - isSelected - }); - } - return isSelected; - }); + itemsToCalculate.forEach((item) => { + // API 모드: 실제 가격 필드 사용 + const productPrice = parseFloat(Number(item.price3) !== 0 ? Number(item.price3) : Number(item.price2) !== 0 ? Number(item.price2) : 0); + const optionPrice = parseFloat(Number(item.price3) !== Number(item.optPrc) && (Number(item.price3) !== Number(item.optPrc)) ? Number(item.optPrc) : 0 || 0); + const shippingPrice = parseFloat(Number(item.shippingCharge) || 0); - if (DEBUG_LOG) { - console.log('[CartSidebar] Filtered selected items:', filtered.length, 'out of', items.length); - } - return filtered; - }, [isMockMode, selectedItems]); + const qty = item.prodQty || item.qty || 1; + totalItems += productPrice * qty; + totalOption += optionPrice * qty; + totalShipping += shippingPrice; + totalQuantity += qty; - // 개별 상품 가격 캐싱 (성능 최적화) - const itemPriceCache = useMemo(() => { - const cache = new Map(); - - if (isMockMode && displayCartInfo) { - displayCartInfo.forEach(item => { - if (!cache.has(item.prodSno || item.cartId)) { - - const orderSummary = calculateOrderSummaryFromProductInfo(item); - cache.set(item.prodSno || item.cartId, { - price: orderSummary.items, - coupon: 0, - shipping: orderSummary.shipping + if (DEBUG_LOG) { + console.log('[CartSidebar] Item calculation:', { + name: item.prdtNm, + qty, + itemPrice: productPrice, + itemOption: optionPrice, + itemShipping: shippingPrice, + runningTotal: totalItems }); } }); - } - return cache; - }, [isMockMode, displayCartInfo]); + const subtotal = Math.max(0, totalItems + totalOption + totalShipping); - // Mock 데이터 또는 실제 데이터 계산 (선택된 상품만) - 최적화 버전 - const calculatedData = useMemo(() => { - const DEBUG_LOG = false; // 수동 설정: false로 비활성화 - - if (isMockMode) { - // Mock Mode: 선택된 상품들로 개별 가격 계산 (캐시 사용) - if (displayCartInfo && Array.isArray(displayCartInfo) && displayCartInfo.length > 0) { - const selectedCartItems = getSelectedItems(displayCartInfo); - - if (DEBUG_LOG) { - console.log('[CartSidebar] Selected items for calculation:', selectedCartItems); - } - - // 캐시된 가격 정보 사용 - let totalItems = 0; - let totalCoupon = 0; - let totalShipping = 0; - let totalQuantity = 0; - - selectedCartItems.forEach((item) => { - const itemId = item.prodSno || item.cartId; - const cachedPrice = itemPriceCache.get(itemId); - - if (cachedPrice) { - const qty = item.prodQty || item.qty || 1; - totalItems += cachedPrice.price * qty; - totalCoupon += cachedPrice.coupon * qty; - totalShipping += cachedPrice.shipping * qty; - totalQuantity += qty; - - if (DEBUG_LOG) { - console.log('[CartSidebar] Item calculation (cached):', { - name: item.prdtNm, - qty, - itemPrice: cachedPrice.price, - itemCoupon: cachedPrice.coupon, - itemShipping: cachedPrice.shipping, - runningTotal: totalItems - }); - } - } + if (DEBUG_LOG) { + console.log('[CartSidebar] Final calculation:', { + isCheckedMode: checkedItems && checkedItems.length > 0, + itemCount: itemsToCalculate.length, + totalQuantity, + totalItems, + totalOption, + totalShipping, + subtotal, }); - - const subtotal = Math.max(0, totalItems - totalCoupon + totalShipping); - if (DEBUG_LOG) { - console.log('[CartSidebar] Final calculation for selected items:', { - totalQuantity, - totalItems, - totalCoupon, - totalShipping, - subtotal, - }); - } - - return { - itemCount: totalQuantity, - subtotal: totalItems, - optionTotal: totalCoupon, - shippingHandling: totalShipping, - orderTotalBeforeTax: subtotal, - }; - } else { - // Mock Mode에 데이터가 없는 경우 - return { - itemCount: 0, - subtotal: 0, - optionTotal: 0, - shippingHandling: 0, - orderTotalBeforeTax: 0, - }; } - } else if (displayCartInfo && Array.isArray(displayCartInfo) && displayCartInfo.length > 0) { - // API Mode: 실제 장바구니 데이터로 계산 - const itemCount = displayCartInfo.reduce((sum, item) => sum + (item.prodQty || 1), 0); - const subtotal = displayCartInfo.reduce((sum, item) => { - const price = parseFloat(Number(item.price3) !== 0 ? Number(item.price3) : Number(item.price2) !== 0 ? Number(item.price2) : 0); - return sum + (price * (item.prodQty || 1)); - }, 0); - const optionTotal = displayCartInfo.reduce((sum, item) => { - const optionPrice = parseFloat(Number(item.price5) || Number(item.optPrc) || 0); - return sum + (optionPrice * (item.prodQty || 1)); - }, 0); - const shippingHandling = displayCartInfo.reduce((sum, item) => { - return sum + parseFloat(Number(item.shippingCharge) * (item.prodQty || 1)) - }, 0); return { - itemCount, - subtotal, - optionTotal, - shippingHandling, - orderTotalBeforeTax: subtotal + optionTotal + shippingHandling, + itemCount: totalQuantity, + subtotal: totalItems, + optionTotal: totalOption, + shippingHandling: totalShipping, + orderTotalBeforeTax: subtotal, }; } else { - // 데이터가 없는 경우 + // 상품이 없는 경우 return { itemCount: 0, subtotal: 0, @@ -203,175 +211,129 @@ const CartSidebar = ({ cartInfo }) => { orderTotalBeforeTax: 0, }; } - }, [isMockMode, displayCartInfo, getSelectedItems, itemPriceCache]); + }, [itemsToCalculate, checkedItems]); - // 체크아웃 버튼 클릭 핸들러 - 완전한 데이터 전송 + // 체크아웃 버튼 클릭 핸들러 const handleCheckoutClick = useCallback(() => { const DEBUG_LOG = true; // 수동 설정: true로 활성화 (디버깅용) console.log('[CartSidebar] 🎯 Checkout button clicked! Starting checkout process...'); console.log('[CartSidebar] 📊 Current state:', { isMockMode, - totalItems: cartInfo?.length || 0, - selectedItemsCount: selectedItems.length + checkedItemsCount: checkedItems.length, + itemsToCalculateCount: itemsToCalculate.length }); - if (isMockMode) { - // Mock Mode: 선택된 상품들로 CheckOutPanel로 이동 - if (DEBUG_LOG) { - console.log('[CartSidebar] Mock Mode - Going to Checkout'); - console.log('[CartSidebar] Mock Mode - cartInfo:', JSON.stringify(cartInfo)); - } - - // ✅ 선택된 상품들만 필터링 (체크박스 선택된 상품) - const allCartItems = cartInfo && Array.isArray(cartInfo) ? cartInfo : []; - const selectedCartItems = getSelectedItems(allCartItems); - - if (DEBUG_LOG) { - console.log('[CartSidebar] Mock Mode - All cart items:', allCartItems.length); - console.log('[CartSidebar] Mock Mode - Selected cart items:', selectedCartItems.length); - console.log('[CartSidebar] Mock Mode - Selected items:', JSON.stringify(selectedCartItems)); - } - - // 선택된 상품이 없는 경우 - if (selectedCartItems.length === 0) { - if (DEBUG_LOG) { - console.log('[CartSidebar] Mock Mode - No items selected, cannot proceed to checkout'); - } - return; // 아무것도 하지 않음 - } - - // ✅ CheckOutPanel 전송용 데이터 구성 (CheckOutPanel 기대 구조에 맞춤) - const checkoutData = { - // 하위 호환성: 첫 번째 상품을 productInfo로 - productInfo: selectedCartItems[0], - - // ✅ CheckOutPanel이 기대하는 cartItems 필드 (isFromCart=true일 때 사용) - cartItems: selectedCartItems.map(item => ({ - prdtId: item.prdtId, - prdtNm: item.prdtNm, - patnrId: item.patnrId, - patncNm: item.patncNm, - price2: item.price2, // 원가 - price3: item.price3, // 할인가 - price5: item.price5, // 쿠폰 - prodQty: item.prodQty || item.qty || 1, - optNm: item.optNm, - shippingCharge: item.shippingCharge || '0', - // 추가 필드들 - finalPrice: item.finalPrice, - discountPrice: item.discountPrice, - origPrice: item.origPrice, - priceInfo: item.priceInfo, - // 이미지 정보 - imgUrl: item.imgUrl, - thumbnailUrl: item.thumbnailUrl, - imgUrls600: item.imgUrls600 - })), - - // 메타데이터 - isFromCart: true, - fromCartPanel: true, // 추가 확인용 - cartTotal: orderTotalBeforeTax, - itemCount: itemCount, - subtotal: subtotal, - optionTotal: optionTotal, - shippingHandling: shippingHandling - }; - - if (DEBUG_LOG) { - console.log('%c🚨🚨🚨 CART SIDEBAR CHECKOUT DATA ANALYSIS 🚨🚨🚨', 'background: yellow; color: black; font-weight: bold; font-size: 14px; padding: 5px;'); - console.log('%cOriginal cartInfo:', 'background: yellow; color: black; padding: 3px;', cartInfo); - console.log('%c🔍 ORIGINAL CART ITEM 1 PRICE FIELDS:', 'background: magenta; color: white; padding: 3px;'); - console.log('price2:', cartInfo?.[0]?.price2); - console.log('price3:', cartInfo?.[0]?.price3); - console.log('price5:', cartInfo?.[0]?.price5); - console.log('optPrc:', cartInfo?.[0]?.optPrc); - console.log('finalPrice:', cartInfo?.[0]?.finalPrice); - console.log('discountPrice:', cartInfo?.[0]?.discountPrice); - console.log('price:', cartInfo?.[0]?.price); - console.log('origPrice:', cartInfo?.[0]?.origPrice); - console.log('Full first item:', cartInfo?.[0]); - console.log('%cSelected items array:', 'background: yellow; color: black; padding: 3px;', selectedItems); - console.log('%cSelected cart items (filtered):', 'background: yellow; color: black; padding: 3px;', selectedCartItems); - console.log('%cCheckout data prepared:', 'background: yellow; color: black; padding: 3px;', checkoutData); - console.log('%cCartItems count:', 'background: yellow; color: black; padding: 3px;', checkoutData.cartItems.length); - console.log('%cCartItems details:', 'background: yellow; color: black; padding: 3px;', checkoutData.cartItems); - console.log('%cisFromCart value:', 'background: yellow; color: black; padding: 3px;', checkoutData.isFromCart); - console.log('%cAbout to pushPanel to CHECKOUT_PANEL', 'background: yellow; color: black; padding: 3px;'); - } - - // ✅ CheckOutPanel로 이동 - console.log('[CartSidebar] 🚀 Executing pushPanel to CHECKOUT_PANEL'); - console.log('[CartSidebar] 📦 Checkout data summary:', { - itemCount: checkoutData.cartItems?.length || 0, - cartTotal: checkoutData.cartTotal, - hasProductInfo: !!checkoutData.productInfo, - isFromCart: checkoutData.isFromCart, - panelName: Config.panel_names.CHECKOUT_PANEL - }); - - try { - dispatch(pushPanel({ - name: Config.panel_names.CHECKOUT_PANEL, - panelInfo: checkoutData - })); - console.log('[CartSidebar] ✅ pushPanel executed successfully'); - } catch (error) { - console.error('[CartSidebar] ❌ pushPanel failed:', error); - } - - } else { - // API Mode: 실제 API 데이터로 처리 - if (DEBUG_LOG) { - console.log('[CartSidebar] API Mode - Checkout (to be implemented)'); - } - - // API Mode에서도 동일한 로직 적용 - const allCartItems = cartInfo && Array.isArray(cartInfo) ? cartInfo : []; - const selectedCartItems = getSelectedItems(allCartItems); - - if (selectedCartItems.length === 0) { - if (DEBUG_LOG) { - console.log('[CartSidebar] API Mode - No items selected, cannot proceed to checkout'); - } - return; - } - - const checkoutData = { - productInfo: selectedCartItems[0], - cartItems: selectedCartItems.map(item => ({ - prdtId: item.prdtId, - prdtNm: item.prdtNm, - patnrId: item.patnrId, - patncNm: item.patncNm, - price2: item.price2, - price3: item.price3, - price5: item.price5, - prodQty: item.prodQty || item.qty || 1, - optNm: item.optNm, - shippingCharge: item.shippingCharge || '0' - })), - isFromCart: true, - fromCartPanel: true, // 추가 확인용 - cartTotal: orderTotalBeforeTax, - itemCount: itemCount - }; - - dispatch(pushPanel({ - name: Config.panel_names.CHECKOUT_PANEL, - panelInfo: checkoutData - })); + // ✅ 계산할 상품이 없는 경우 + if (itemsToCalculate.length === 0) { + console.log('[CartSidebar] ❌ No items to checkout'); + return; } - }, [dispatch, isMockMode, cartInfo, getSelectedItems, orderTotalBeforeTax, itemCount, subtotal, optionTotal, shippingHandling]); + + if (DEBUG_LOG) { + console.log('[CartSidebar] Items to checkout:', JSON.stringify(itemsToCalculate)); + } + + // ✅ CheckOutPanel 전송용 데이터 구성 + const { itemCount, subtotal, optionTotal, shippingHandling, orderTotalBeforeTax } = calculatedData; + + const checkoutData = { + // 하위 호환성: 첫 번째 상품을 productInfo로 + productInfo: itemsToCalculate[0], + + // ✅ CheckOutPanel이 기대하는 cartItems 필드 + cartItems: itemsToCalculate.map(item => ({ + prdtId: item.prdtId, + prdtNm: item.prdtNm, + patnrId: item.patnrId, + patncNm: item.patncNm, + price2: item.price2, // 원가 + price3: item.price3, // 할인가 + price5: item.price5, // 옵션가 + prodQty: item.prodQty || item.qty || 1, + optNm: item.optNm, + shippingCharge: item.shippingCharge || '0', + // 추가 필드들 + finalPrice: item.finalPrice, + discountPrice: item.discountPrice, + origPrice: item.origPrice, + priceInfo: item.priceInfo, + // 이미지 정보 + imgUrl: item.imgUrl, + thumbnailUrl: item.thumbnailUrl, + imgUrls600: item.imgUrls600, + prodSno: item.prodSno, + })), + + // 메타데이터 + isFromCart: true, + fromCartPanel: true, + isCheckedMode: checkedItems && checkedItems.length > 0, // ✅ 체크 모드 여부 + cartTotal: orderTotalBeforeTax, + itemCount: itemCount, + subtotal: subtotal, + optionTotal: optionTotal, + shippingHandling: shippingHandling + + + }; + + if (DEBUG_LOG) { + console.log('%c🚨🚨🚨 CART SIDEBAR CHECKOUT DATA 🚨🚨🚨', 'background: yellow; color: black; font-weight: bold; font-size: 14px; padding: 5px;'); + console.log('%cMode:', 'background: yellow; color: black; padding: 3px;', checkedItems.length > 0 ? 'CHECKED ITEMS MODE' : 'ALL ITEMS MODE'); + console.log('%cItems to checkout:', 'background: yellow; color: black; padding: 3px;', itemsToCalculate); + console.log('%cCheckout data prepared:', 'background: yellow; color: black; padding: 3px;', checkoutData); + console.log('%cCartItems count:', 'background: yellow; color: black; padding: 3px;', checkoutData.cartItems.length); + console.log('%cCalculated totals:', 'background: yellow; color: black; padding: 3px;', { + itemCount, + subtotal, + optionTotal, + shippingHandling, + orderTotalBeforeTax + }); + } + + // ✅ CheckOutPanel로 이동 + console.log('[CartSidebar] 🚀 Executing pushPanel to CHECKOUT_PANEL'); + + try { + dispatch( + getMyInfoCheckoutInfo( + { + mbrNo: userNumber, + dirPurcSelYn: 'Y', + cartList: + checkedItems && checkedItems.map((item) => ({ + patnrId: item.patnrId, + prdtId: item.prdtId, + prodOptCdCval: item.prodOptCdCval ? item.prodOptCdCval : null, + prodQty: String(item.prodQty), + prodOptTpCdCval: item.prodOptTpCdCval, + })) + + }, + checkOutValidate + ) + ); + + // dispatch(pushPanel({ + // name: Config.panel_names.CHECKOUT_PANEL, + // panelInfo: checkoutData + // })); + console.log('[CartSidebar] ✅ pushPanel executed successfully'); + } catch (error) { + console.error('[CartSidebar] ❌ pushPanel failed:', error); + } + + }, [dispatch, checkedItems, itemsToCalculate, calculatedData]); const { itemCount, subtotal, optionTotal, shippingHandling, orderTotalBeforeTax } = calculatedData; const formatPrice = (price) => { return `$${price.toLocaleString('en-US', { - minimumFractionDigits: 2, - maximumFractionDigits: 2 - })}`; + minimumFractionDigits: 2, + maximumFractionDigits: 2 + })}`; }; return ( @@ -429,6 +391,7 @@ const CartSidebar = ({ cartInfo }) => { className={css.checkoutButton} spotlightId="cart-checkout-button" onClick={handleCheckoutClick} + disabled={itemsToCalculate.length === 0} > Checkout @@ -437,4 +400,4 @@ const CartSidebar = ({ cartInfo }) => { ); }; -export default CartSidebar; +export default CartSidebar; \ No newline at end of file diff --git a/com.twin.app.shoptime/src/views/CheckOutPanel/CheckOutPanel.jsx b/com.twin.app.shoptime/src/views/CheckOutPanel/CheckOutPanel.jsx index 361a73eb..4d534bb8 100644 --- a/com.twin.app.shoptime/src/views/CheckOutPanel/CheckOutPanel.jsx +++ b/com.twin.app.shoptime/src/views/CheckOutPanel/CheckOutPanel.jsx @@ -138,6 +138,7 @@ export default function CheckOutPanel({ panelInfo }) { const empTermsData = useSelector((state) => state.emp.empTermsData.terms); const { popupVisible, activePopup } = useSelector((state) => state.common.popup); const popup = useSelector((state) => state.common.popup); + const cartSelectInfo = useSelector((state) => state.cart.selectCart.checkedItems); // Mock Mode: panelInfo.productInfo 또는 Redux에서 상품 데이터 사용 const productData = BUYNOW_CONFIG.isMockMode() @@ -360,9 +361,10 @@ export default function CheckOutPanel({ panelInfo }) { getCheckoutTotalAmt( { mbrNo: userNumber, - dirPurcSelYn: 'Y', + dirPurcSelYn: cartSelectInfo.length > 0 ? 'N' : 'Y', bilAddrSno: infoForCheckoutData.bilAddrSno, dlvrAddrSno: infoForCheckoutData.dlvrAddrSno, + isPageLoading: "Y", orderProductCoupontUse, }, totalAmtValidate @@ -667,7 +669,7 @@ export default function CheckOutPanel({ panelInfo }) { closeSideBar={toggleOrderSideBar} productData={safeProductData} rawProductData={productData} - productInfo={panelInfo?.productInfo} + productInfo={reduxProductData} fromCartPanel={panelInfo?.fromCartPanel} /> )} diff --git a/com.twin.app.shoptime/src/views/CheckOutPanel/container/OrderItemsSideBar.jsx b/com.twin.app.shoptime/src/views/CheckOutPanel/container/OrderItemsSideBar.jsx index 35700b0e..e8057b38 100644 --- a/com.twin.app.shoptime/src/views/CheckOutPanel/container/OrderItemsSideBar.jsx +++ b/com.twin.app.shoptime/src/views/CheckOutPanel/container/OrderItemsSideBar.jsx @@ -165,7 +165,7 @@ export default function OrderItemsSideBar({ patncLogPath={item.patncLogPath} prdtId={item.prdtId} expsPrdtNo={item.expsPrdtNo} - price={item.price2 >= item.price3 ? item.price3 : item.price2} + price={(item.price2 >= item.price3 && item.price3 !== 0) ? item.price3 : item.price2} currSign={item.currSign} currSignLoc={item.currSignLoc} shippingCharge={item.shippingCharge} diff --git a/com.twin.app.shoptime/src/views/CheckOutPanel/container/SummaryCotainer.jsx b/com.twin.app.shoptime/src/views/CheckOutPanel/container/SummaryCotainer.jsx index c803ac1c..137d19fb 100644 --- a/com.twin.app.shoptime/src/views/CheckOutPanel/container/SummaryCotainer.jsx +++ b/com.twin.app.shoptime/src/views/CheckOutPanel/container/SummaryCotainer.jsx @@ -59,7 +59,7 @@ export default function SummaryContainer({ // Check if priceTotalData has actual data (ordPmtReqAmt is the key field) const hasValidPriceTotalData = priceTotalData && Object.keys(priceTotalData).length > 0 && priceTotalData.ordPmtReqAmt; - + console.log("###hasValidPriceTotalData",hasValidPriceTotalData) // Mock Mode: priceTotalData가 없으면 가짜 데이터 제공 const effectivePriceTotalData = hasValidPriceTotalData ? priceTotalData : { totProdPrc: 0.00,