[251101] fix: CheckOutPanel Mock-1

🕐 커밋 시간: 2025. 11. 01. 18:19:39

📊 변경 통계:
  • 총 파일: 10개
  • 추가: +68줄
  • 삭제: -33줄

📁 추가된 파일:
  + com.twin.app.shoptime/src/views/CheckOutPanel/components/BillingAddressCardMock.jsx
  + com.twin.app.shoptime/src/views/CheckOutPanel/components/PaymentCardMock.jsx
  + com.twin.app.shoptime/src/views/CheckOutPanel/components/ShippingAddressCardMock.jsx
  + com.twin.app.shoptime/src/views/CheckOutPanel/container/InformationContainerMock.jsx
  + com.twin.app.shoptime/src/views/CheckOutPanel/container/SummaryContainerMock.jsx

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/views/CheckOutPanel/CheckOutPanel.jsx
  ~ com.twin.app.shoptime/src/views/CheckOutPanel/components/OffersPromotionItemCard.jsx
  ~ com.twin.app.shoptime/src/views/CheckOutPanel/container/FixedSideBar.jsx
  ~ com.twin.app.shoptime/src/views/CheckOutPanel/container/InformationContainer.jsx
  ~ com.twin.app.shoptime/src/views/CheckOutPanel/container/OrderItemsSideBar.jsx

🔧 주요 변경 내용:
  • UI 컴포넌트 아키텍처 개선
  • 소규모 기능 개선
  • 모듈 구조 개선
This commit is contained in:
2025-11-01 18:19:41 +09:00
parent 2e2cf295dc
commit a6ffcaca22
10 changed files with 909 additions and 366 deletions

View File

@@ -1,44 +1,43 @@
import React, { useCallback, useEffect, useRef, useState } from "react";
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useDispatch, useSelector } from "react-redux";
import { useDispatch, useSelector } from 'react-redux';
import { Job } from "@enact/core/util";
import Spotlight from "@enact/spotlight";
import { Job } from '@enact/core/util';
import Spotlight from '@enact/spotlight';
import {
getCheckoutTotalAmt,
resetCheckoutData,
} from "../../actions/checkoutActions";
import { setHidePopup, setShowPopup } from "../../actions/commonActions";
import { getShoptimeTerms } from "../../actions/empActions";
import { getCheckoutTotalAmt, resetCheckoutData } from '../../actions/checkoutActions';
import { setHidePopup, setShowPopup } from '../../actions/commonActions';
import { getShoptimeTerms } from '../../actions/empActions';
import {
sendLogCheckOutBtnClick,
sendLogGNB,
sendLogMyInfoEdit,
sendLogPaymentEntry,
sendLogTotalRecommend,
} from "../../actions/logActions";
import { popPanel } from "../../actions/panelActions";
import TBody from "../../components/TBody/TBody";
import TButton from "../../components/TButton/TButton";
import TButtonScroller from "../../components/TButtonScroller/TButtonScroller";
import TButtonTab from "../../components/TButtonTab/TButtonTab";
import TFullPopup from "../../components/TFullPopup/TFullPopup";
import THeader from "../../components/THeader/THeader";
import TPanel from "../../components/TPanel/TPanel";
import TPopUp from "../../components/TPopUp/TPopUp";
import TQRCode from "../../components/TQRCode/TQRCode";
import useScrollTo from "../../hooks/useScrollTo";
import * as Config from "../../utils/Config";
import { $L, scaleH, scaleW } from "../../utils/helperMethods";
import { SpotlightIds } from "../../utils/SpotlightIds";
import { BUYNOW_CONFIG } from "../../utils/BuyNowConfig";
import css from "./CheckOutPanel.module.less";
import PinCodeInput from "./components/PinCodeInput";
import FixedSideBar from "./container/FixedSideBar";
import InformationContainer from "./container/InformationContainer";
import OrderItemsSideBar from "./container/OrderItemsSideBar";
import SummaryContainer from "./container/SummaryCotainer";
} from '../../actions/logActions';
import { popPanel } from '../../actions/panelActions';
import TBody from '../../components/TBody/TBody';
import TButton from '../../components/TButton/TButton';
import TButtonScroller from '../../components/TButtonScroller/TButtonScroller';
import TButtonTab from '../../components/TButtonTab/TButtonTab';
import TFullPopup from '../../components/TFullPopup/TFullPopup';
import THeader from '../../components/THeader/THeader';
import TPanel from '../../components/TPanel/TPanel';
import TPopUp from '../../components/TPopUp/TPopUp';
import TQRCode from '../../components/TQRCode/TQRCode';
import useScrollTo from '../../hooks/useScrollTo';
import * as Config from '../../utils/Config';
import { $L, scaleH, scaleW } from '../../utils/helperMethods';
import { SpotlightIds } from '../../utils/SpotlightIds';
import { BUYNOW_CONFIG } from '../../utils/BuyNowConfig';
import css from './CheckOutPanel.module.less';
import PinCodeInput from './components/PinCodeInput';
import FixedSideBar from './container/FixedSideBar';
import InformationContainer from './container/InformationContainer';
import OrderItemsSideBar from './container/OrderItemsSideBar';
import SummaryContainer from './container/SummaryCotainer';
import SummaryContainerMock from './container/SummaryContainerMock';
import InformationContainerMock from './container/InformationContainerMock';
export default function CheckOutPanel({ panelInfo }) {
console.log('[CheckOutPanel] Component mounted');
@@ -46,23 +45,16 @@ export default function CheckOutPanel({ panelInfo }) {
console.log('[CheckOutPanel] panelInfo.logInfo:', panelInfo?.logInfo);
const dispatch = useDispatch();
const panels = useSelector((state) => state.panels.panels);
console.log('[CheckOutPanel] panels:', panels?.map(p => p.name));
const { userNumber } = useSelector(
(state) => state.common.appStatus.loginUserData
);
const reduxProductData = useSelector(
(state) => state.checkout?.checkoutData.productList
);
const infoForCheckoutData = useSelector(
(state) => state.checkout?.infoForCheckoutData
);
const selectedCoupons = useSelector(
(state) => state.checkout.selectedCoupons
console.log(
'[CheckOutPanel] panels:',
panels?.map((p) => p.name)
);
const { userNumber } = useSelector((state) => state.common.appStatus.loginUserData);
const reduxProductData = useSelector((state) => state.checkout?.checkoutData.productList);
const infoForCheckoutData = useSelector((state) => state.checkout?.infoForCheckoutData);
const selectedCoupons = useSelector((state) => state.checkout.selectedCoupons);
const empTermsData = useSelector((state) => state.emp.empTermsData.terms);
const { popupVisible, activePopup } = useSelector(
(state) => state.common.popup
);
const { popupVisible, activePopup } = useSelector((state) => state.common.popup);
const popup = useSelector((state) => state.common.popup);
// Mock Mode: 가짜 상품 데이터 생성
@@ -80,7 +72,7 @@ export default function CheckOutPanel({ panelInfo }) {
discountPrice: 99999,
currSign: '$',
currSignLoc: 'left',
}
},
]
: reduxProductData;
@@ -103,8 +95,7 @@ export default function CheckOutPanel({ panelInfo }) {
const isMounted = useRef(true);
const { getScrollTo: getScrollToBody, scrollTop: scrollTopBody } =
useScrollTo();
const { getScrollTo: getScrollToBody, scrollTop: scrollTopBody } = useScrollTo();
const spotJob = useRef(new Job((func) => func(), 0));
@@ -172,20 +163,18 @@ export default function CheckOutPanel({ panelInfo }) {
console.log('[CheckOutPanel] API Mode - calling getCheckoutTotalAmt');
// API Mode: 기존 로직 유지
if (infoForCheckoutData && productData) {
const orderProductCoupontUse = Object.keys(selectedCoupons).map(
(productId) => {
const { cpnCdSeq, cpnSno, prdtId } = selectedCoupons[productId];
const product = productData.find((prod) => prod.prdtId === prdtId);
const orderProductCoupontUse = Object.keys(selectedCoupons).map((productId) => {
const { cpnCdSeq, cpnSno, prdtId } = selectedCoupons[productId];
const product = productData.find((prod) => prod.prdtId === prdtId);
return {
cpnCdSeq,
cpnSno,
prdtId,
prodSno: product?.prodSno,
patnrId: product?.patnrId,
};
}
);
return {
cpnCdSeq,
cpnSno,
prdtId,
prodSno: product?.prodSno,
patnrId: product?.patnrId,
};
});
if (
infoForCheckoutData &&
@@ -196,7 +185,7 @@ export default function CheckOutPanel({ panelInfo }) {
getCheckoutTotalAmt(
{
mbrNo: userNumber,
dirPurcSelYn: "Y",
dirPurcSelYn: 'Y',
bilAddrSno: infoForCheckoutData.bilAddrSno,
dlvrAddrSno: infoForCheckoutData.dlvrAddrSno,
orderProductCoupontUse,
@@ -209,7 +198,10 @@ export default function CheckOutPanel({ panelInfo }) {
}, [dispatch, infoForCheckoutData, productData, userNumber, selectedCoupons]);
useEffect(() => {
console.log('[CheckOutPanel] empTermsData useEffect - empTermsData length:', empTermsData?.length);
console.log(
'[CheckOutPanel] empTermsData useEffect - empTermsData length:',
empTermsData?.length
);
const newTabList = [];
if (empTermsData) {
@@ -235,7 +227,7 @@ export default function CheckOutPanel({ panelInfo }) {
spotJobValue.start(() => {
if (!activePopup) {
Spotlight.focus("spotlightId_placeOrderBtn");
Spotlight.focus('spotlightId_placeOrderBtn');
} else if (activePopup === Config.ACTIVE_POPUP.errorPopup) {
Spotlight.focus(SpotlightIds.TPOPUP);
}
@@ -254,11 +246,11 @@ export default function CheckOutPanel({ panelInfo }) {
const toggleOrderSideBar = useCallback(() => {
console.log('[CheckOutPanel] toggleOrderSideBar called - current state:', orderSideBarOpen);
if (!orderSideBarOpen) {
dispatch(sendLogCheckOutBtnClick({ btnNm: "ORDER ITEMS" }));
dispatch(sendLogCheckOutBtnClick({ btnNm: 'ORDER ITEMS' }));
dispatch(
sendLogTotalRecommend({
buttonTitle: "ORDER ITEMS",
buttonId: "checkout_order_items_view",
buttonTitle: 'ORDER ITEMS',
buttonId: 'checkout_order_items_view',
contextName: Config.LOG_CONTEXT_NAME.CHECKOUT,
messageId: Config.LOG_MESSAGE_ID.BUTTONCLICK,
})
@@ -272,11 +264,11 @@ export default function CheckOutPanel({ panelInfo }) {
const toggleOfferSideBar = useCallback(() => {
console.log('[CheckOutPanel] toggleOfferSideBar called - current state:', offerSideBarOpen);
if (!offerSideBarOpen) {
dispatch(sendLogCheckOutBtnClick({ btnNm: "OFFERS & PROMOTION" }));
dispatch(sendLogCheckOutBtnClick({ btnNm: 'OFFERS & PROMOTION' }));
dispatch(
sendLogTotalRecommend({
buttonTitle: "OFFERS & PROMOTION",
buttonId: "checkout_offers_promotion_view",
buttonTitle: 'OFFERS & PROMOTION',
buttonId: 'checkout_offers_promotion_view',
contextName: Config.LOG_CONTEXT_NAME.CHECKOUT,
messageId: Config.LOG_MESSAGE_ID.BUTTONCLICK,
})
@@ -308,9 +300,7 @@ export default function CheckOutPanel({ panelInfo }) {
(termsID) => {
console.log('[CheckOutPanel] handleTermsClick called with termsID:', termsID);
if (empTermsData) {
const selectedTerms = empTermsData.find(
(term) => term.termsID === termsID
);
const selectedTerms = empTermsData.find((term) => term.termsID === termsID);
console.log('[CheckOutPanel] Selected terms:', selectedTerms?.termsTypeName);
dispatch(
@@ -318,17 +308,15 @@ export default function CheckOutPanel({ panelInfo }) {
buttonTitle: selectedTerms.termsTypeName,
buttonId: `checkout_terms_${selectedTerms.termsTypeName
.toLowerCase()
.replace(/\s+/g, "_")}`,
.replace(/\s+/g, '_')}`,
contextName: Config.LOG_CONTEXT_NAME.CHECKOUT,
messageId: Config.LOG_MESSAGE_ID.BUTTONCLICK,
})
);
setCurrentTerms(selectedTerms);
dispatch(setShowPopup(Config.ACTIVE_POPUP.termsPopup));
Spotlight.focus("spotlightId_TbuttonScrollerDown");
const selectedIndex = empTermsData.findIndex(
(term) => term.termsID === termsID
);
Spotlight.focus('spotlightId_TbuttonScrollerDown');
const selectedIndex = empTermsData.findIndex((term) => term.termsID === termsID);
setSelectedTabIndex(selectedIndex);
setResetScroll(true);
@@ -393,52 +381,84 @@ export default function CheckOutPanel({ panelInfo }) {
dispatch(sendLogMyInfoEdit({ btnNm }));
}, []);
console.log('[CheckOutPanel] Rendering - orderSideBarOpen:', orderSideBarOpen, 'offerSideBarOpen:', offerSideBarOpen, 'placeOrderPopup:', placeOrderPopup);
console.log('[CheckOutPanel] Rendering - productData exists:', !!productData, 'length:', productData?.length);
console.log(
'[CheckOutPanel] Rendering - orderSideBarOpen:',
orderSideBarOpen,
'offerSideBarOpen:',
offerSideBarOpen,
'placeOrderPopup:',
placeOrderPopup
);
console.log(
'[CheckOutPanel] Rendering - productData exists:',
!!productData,
'length:',
productData?.length
);
return (
<>
<TPanel
isTabActivated={false}
spotlightDisabled={
orderSideBarOpen || offerSideBarOpen || placeOrderPopup
}
spotlightDisabled={orderSideBarOpen || offerSideBarOpen || placeOrderPopup}
handleCancel={onCancelCheckoutPanel}
>
<TBody className={css.tbody} cbScrollTo={getScrollToBody}>
<THeader
className={css.theader}
title="CHECKOUT"
onBackButton
onClick={onBackClick}
/>
<THeader className={css.theader} title="CHECKOUT" onBackButton onClick={onBackClick} />
<div className={css.Wrap}>
<SummaryContainer
setPlaceOrderPopup={setPlaceOrderPopup}
empTermsData={empTermsData}
handleTermsClick={handleTermsClick}
currSign={currSign}
currSignLoc={currSignLoc}
doSendLogPaymentEntry={doSendLogPaymentEntry}
/>
<InformationContainer
toggleOrderSideBar={toggleOrderSideBar}
toggleOfferSideBar={toggleOfferSideBar}
scrollTopBody={scrollTopBody}
doSendLogMyInfoEdit={doSendLogMyInfoEdit}
/>
{BUYNOW_CONFIG.isMockMode() ? (
<SummaryContainerMock
setPlaceOrderPopup={setPlaceOrderPopup}
empTermsData={empTermsData}
handleTermsClick={handleTermsClick}
currSign={currSign}
currSignLoc={currSignLoc}
doSendLogPaymentEntry={doSendLogPaymentEntry}
/>
) : (
<SummaryContainer
setPlaceOrderPopup={setPlaceOrderPopup}
empTermsData={empTermsData}
handleTermsClick={handleTermsClick}
currSign={currSign}
currSignLoc={currSignLoc}
doSendLogPaymentEntry={doSendLogPaymentEntry}
/>
)}
{(() => {
console.log(
'[CheckOutPanel] Before conditional - isMockMode:',
BUYNOW_CONFIG.isMockMode()
);
if (BUYNOW_CONFIG.isMockMode()) {
console.log('[CheckOutPanel] Rendering InformationContainerMock');
return (
<InformationContainerMock
toggleOrderSideBar={toggleOrderSideBar}
toggleOfferSideBar={toggleOfferSideBar}
scrollTopBody={scrollTopBody}
doSendLogMyInfoEdit={doSendLogMyInfoEdit}
/>
);
} else {
console.log('[CheckOutPanel] Rendering InformationContainer');
return (
<InformationContainer
toggleOrderSideBar={toggleOrderSideBar}
toggleOfferSideBar={toggleOfferSideBar}
scrollTopBody={scrollTopBody}
doSendLogMyInfoEdit={doSendLogMyInfoEdit}
/>
);
}
})()}
</div>
</TBody>
</TPanel>
{orderSideBarOpen && (
<OrderItemsSideBar closeSideBar={toggleOrderSideBar} />
)}
{orderSideBarOpen && <OrderItemsSideBar closeSideBar={toggleOrderSideBar} />}
{offerSideBarOpen && (
<FixedSideBar
closeSideBar={toggleOfferSideBar}
offerSideBarOpen={offerSideBarOpen}
/>
<FixedSideBar closeSideBar={toggleOfferSideBar} offerSideBarOpen={offerSideBarOpen} />
)}
{activePopup === Config.ACTIVE_POPUP.termsPopup && (
@@ -447,7 +467,7 @@ export default function CheckOutPanel({ panelInfo }) {
open={popupVisible}
onClose={onCloseTermsPopup}
hasButton
button1Text={$L("OK")}
button1Text={$L('OK')}
>
{currentTerms && (
<div className={css.termsConts}>

View File

@@ -0,0 +1,81 @@
import React, { useCallback } from 'react';
import TCheckBox from '../../../components/TCheckBox/TCheckBox';
import TScroller from '../../../components/TScroller/TScroller';
import CheckOutContainer from './CheckOutContainer';
import css from './BillingAddressCard.module.less';
export default function BillingAddressCardMock({ list, onFocus }) {
console.log('[CheckOutPanel] BillingAddressCardMock - Mounted, list length:', list?.length);
const [selected, setSelected] = React.useState(list?.[0]?.bilAddrSno);
console.log('[CheckOutPanel] BillingAddressCardMock - selected:', selected);
const handleSelectAddress = useCallback((bilAddrSno) => {
console.log('[CheckOutPanel] BillingAddressCardMock - handleSelectAddress:', bilAddrSno);
setSelected(bilAddrSno);
}, []);
const _onFocus = useCallback(() => {
if (onFocus) {
onFocus();
}
}, [onFocus]);
return (
<CheckOutContainer className={css.shippingBox}>
<TScroller className={css.shipping} direction="horizontal" noScrollByWheel>
<ul>
{list &&
list.map(
(
{
bilOdrFnm,
bilOdrLnm,
bilZpcd,
bilStatNm,
bilCityNm,
bilDtlAddr,
bilCtpt,
bilEmalAddr,
bilAddrSno,
},
index
) => {
return (
<li key={index} className={css.itemContainer}>
<TCheckBox
className={css.checkBox}
selected={selected === bilAddrSno}
onToggle={() => handleSelectAddress(bilAddrSno)}
onFocus={_onFocus}
spotlightId={'billing-checkbox-' + index}
/>
<h2 className={css.title}>
{bilOdrFnm} {bilOdrLnm}
</h2>
<div className={css.addressWrap}>
<p>
{bilZpcd} {bilStatNm}, <br />
{bilCityNm} <br />
{bilDtlAddr}
</p>
</div>
<div className={css.cardFooter}>
<p className={css.callNumber}>
<span />
{bilCtpt?.replace(/^(\d{2,3})(\d{3,4})(\d{4})$/, `$1-$2-$3`)}
</p>
<p className={css.email}>
<span />
{bilEmalAddr}
</p>
</div>
</li>
);
}
)}
</ul>
</TScroller>
</CheckOutContainer>
);
}

View File

@@ -1,22 +1,22 @@
import React, { memo, useCallback, useEffect, useMemo, useState } from "react";
import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
import classNames from "classnames";
import { useDispatch, useSelector } from "react-redux";
import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux';
import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
import { updateSelectedCoupon } from "../../../actions/checkoutActions";
import CustomImage from "../../../components/CustomImage/CustomImage";
import TDropDown from "../../../components/TDropDown/TDropDown";
import { $L, formatCurrencyValue } from "../../../utils/helperMethods";
import css from "./OffersPromotionItemCard.module.less";
import { updateSelectedCoupon } from '../../../actions/checkoutActions';
import CustomImage from '../../../components/CustomImage/CustomImage';
import TDropDown from '../../../components/TDropDown/TDropDown';
import { $L, formatCurrencyValue } from '../../../utils/helperMethods';
import css from './OffersPromotionItemCard.module.less';
const OffersPromotionItemContainer = SpotlightContainerDecorator(
{ leaveFor: { left: "", right: "" } },
"div"
{ leaveFor: { left: '', right: '' } },
'div'
);
const DropDownBox = SpotlightContainerDecorator("div");
const DropDownBox = SpotlightContainerDecorator('div');
export const SIZES = {
itemWidth: 660,
itemHeight: 433,
@@ -41,39 +41,35 @@ export default memo(function OffersPromotionItemCard({
expsPrdtNo,
...rest
}) {
const priceTotalData = useSelector(
(state) => state.checkout?.checkoutTotalData
);
const selectedCoupon = useSelector(
(state) => state.checkout?.selectedCoupons?.[prdtId]
);
const priceTotalData = useSelector((state) => state.checkout?.checkoutTotalData);
const selectedCoupon = useSelector((state) => state.checkout?.selectedCoupons?.[prdtId]);
const dispatch = useDispatch();
const [openChk, setOpenChk] = useState(false);
const selectedIndex = useMemo(() => {
if (!selectedCoupon) return -1;
return prdtCoupon.findIndex(
(coupon) => coupon.cpnNo === selectedCoupon.cpnNo
);
if (!selectedCoupon || !prdtCoupon || !Array.isArray(prdtCoupon)) return -1;
return prdtCoupon.findIndex((coupon) => coupon.cpnNo === selectedCoupon.cpnNo);
}, [selectedCoupon, prdtCoupon]);
const formattedPrices = useMemo(() => {
return {
discounted: priceTotalData?.totProdPrc
? formatCurrencyValue(priceTotalData?.totProdPrc, currSign, currSignLoc)
: "-",
: '-',
shipping: priceTotalData?.totDlvrAmt
? formatCurrencyValue(priceTotalData?.totDlvrAmt, currSign, currSignLoc)
: "-",
: '-',
};
}, [priceTotalData, currSign, currSignLoc]);
const handleCouponSelect = (e) => {
const selectedIdx = e.selected;
const selected = prdtCoupon[selectedIdx];
dispatch(updateSelectedCoupon(prdtId, selected));
if (prdtCoupon && Array.isArray(prdtCoupon) && prdtCoupon[selectedIdx]) {
const selected = prdtCoupon[selectedIdx];
dispatch(updateSelectedCoupon(prdtId, selected));
}
};
const dropDownOpen = useCallback(() => {
@@ -84,15 +80,15 @@ export default memo(function OffersPromotionItemCard({
}, []);
useEffect(() => {
const c = document.getElementById("floatLayer");
c.classList.add("checkout_dropdown");
const c = document.getElementById('floatLayer');
c.classList.add('checkout_dropdown');
return () => {
c.classList.remove("checkout_dropdown");
c.classList.remove('checkout_dropdown');
};
}, []);
useEffect(() => {
if (offerSideBarOpen) {
Spotlight.focus("fixed_dropdown");
Spotlight.focus('fixed_dropdown');
}
}, [offerSideBarOpen]);
@@ -104,19 +100,13 @@ export default memo(function OffersPromotionItemCard({
</div>
<div className={css.itemContents}>
<div className={css.leftContents}>
<CustomImage
src={imgUrls[0].imgUrl}
alt=""
className={css.itemImage}
/>
<CustomImage src={imgUrls[0].imgUrl} alt="" className={css.itemImage} />
</div>
<div className={css.rightContents}>
<p className={css.prdtNm}>{prdtNm}</p>
<p className={css.priceWrap}>
<span className={css.itemPrice}>
<span className={css.discountedPrice}>
{formattedPrices.discounted}
</span>
<span className={css.discountedPrice}>{formattedPrices.discounted}</span>
{/* {originalPrice && originalPrice !== discountedPrice && (
<span className={css.originalPrice}>
{formattedPrices.original}
@@ -124,12 +114,12 @@ export default memo(function OffersPromotionItemCard({
)} */}
</span>
<span className={css.shippingPrice}>
{`${$L("S&H")}: `}
{`${$L('S&H')}: `}
{formattedPrices.shipping}
</span>
{auctProdYn === "Y" && !auctFinalPriceChgDt && (
{auctProdYn === 'Y' && !auctFinalPriceChgDt && (
<div className={css.noticeBox}>
{$L("Purchased products will be paid at the final price.")}
{$L('Purchased products will be paid at the final price.')}
</div>
)}
</p>
@@ -137,17 +127,16 @@ export default memo(function OffersPromotionItemCard({
</div>
<DropDownBox className={css.dropDownWrap} spotlightId="fixed_dropdown">
<TDropDown
className={classNames(
css.dropDown,
openChk === true ? css.selected : null
)}
className={classNames(css.dropDown, openChk === true ? css.selected : null)}
width="x-large"
selectedIndex={selectedIndex}
onSelect={handleCouponSelect}
onOpen={dropDownOpen}
onClose={dropDownClose}
>
{prdtCoupon.map((item) => item.cpnTtl)}
{prdtCoupon && Array.isArray(prdtCoupon) && prdtCoupon.length > 0
? prdtCoupon.map((item) => item.cpnTtl)
: []}
</TDropDown>
</DropDownBox>
</OffersPromotionItemContainer>

View File

@@ -0,0 +1,56 @@
import React, { useCallback } from 'react';
import TCheckBox from '../../../components/TCheckBox/TCheckBox';
import TScroller from '../../../components/TScroller/TScroller';
import CheckOutContainer from './CheckOutContainer';
import css from './PaymentCard.module.less';
export default function PaymentCardMock({ list, onFocus }) {
console.log('[CheckOutPanel] PaymentCardMock - Mounted, list length:', list?.length);
const [selected, setSelected] = React.useState(list?.[0]?.cardSno);
console.log('[CheckOutPanel] PaymentCardMock - selected:', selected);
const handleSelectCard = useCallback((cardSno) => {
console.log('[CheckOutPanel] PaymentCardMock - handleSelectCard:', cardSno);
setSelected(cardSno);
}, []);
const _onFocus = useCallback(() => {
if (onFocus) {
onFocus();
}
}, [onFocus]);
return (
<CheckOutContainer className={css.paymentBox}>
<TScroller className={css.payment} direction="horizontal" noScrollByWheel>
<ul>
{list &&
list.map(({ cardSno, cardNm, cardNo, cardType }, index) => {
return (
<li key={index} className={css.itemContainer}>
<TCheckBox
className={css.checkBox}
selected={selected === cardSno}
onToggle={() => handleSelectCard(cardSno)}
onFocus={_onFocus}
spotlightId={'payment-checkbox-' + index}
/>
<h2 className={css.title}>{cardNm}</h2>
<div className={css.cardWrap}>
<p>{cardNo}</p>
</div>
<div className={css.cardFooter}>
<p className={css.cardType}>
<span />
{cardType}
</p>
</div>
</li>
);
})}
</ul>
</TScroller>
</CheckOutContainer>
);
}

View File

@@ -0,0 +1,81 @@
import React, { useCallback } from 'react';
import TCheckBox from '../../../components/TCheckBox/TCheckBox';
import TScroller from '../../../components/TScroller/TScroller';
import CheckOutContainer from './CheckOutContainer';
import css from './ShippingAddressCard.module.less';
export default function ShippingAddressCardMock({ list, onFocus }) {
console.log('[CheckOutPanel] ShippingAddressCardMock - Mounted, list length:', list?.length);
const [selected, setSelected] = React.useState(list?.[0]?.dlvrAddrSno);
console.log('[CheckOutPanel] ShippingAddressCardMock - selected:', selected);
const handleSelectAddress = useCallback((dlvrAddrSno) => {
console.log('[CheckOutPanel] ShippingAddressCardMock - handleSelectAddress:', dlvrAddrSno);
setSelected(dlvrAddrSno);
}, []);
const _onFocus = useCallback(() => {
if (onFocus) {
onFocus();
}
}, [onFocus]);
return (
<CheckOutContainer className={css.shippingBox}>
<TScroller className={css.shipping} direction="horizontal" noScrollByWheel>
<ul>
{list &&
list.map(
(
{
dlvrOdrFnm,
dlvrOdrLnm,
dlvrZpcd,
dlvrStatNm,
dlvrCityNm,
dlvrDtlAddr,
dlvrCtpt,
dlvrEmalAddr,
dlvrAddrSno,
},
index
) => {
return (
<li key={index} className={css.itemContainer}>
<TCheckBox
className={css.checkBox}
selected={selected === dlvrAddrSno}
onToggle={() => handleSelectAddress(dlvrAddrSno)}
onFocus={_onFocus}
spotlightId={'shipping-checkbox-' + index}
/>
<h2 className={css.title}>
{dlvrOdrFnm} {dlvrOdrLnm}
</h2>
<div className={css.addressWrap}>
<p>
{dlvrZpcd} {dlvrStatNm}, <br />
{dlvrCityNm} <br />
{dlvrDtlAddr}
</p>
</div>
<div className={css.cardFooter}>
<p className={css.callNumber}>
<span />
{dlvrCtpt?.replace(/^(\d{2,3})(\d{3,4})(\d{4})$/, `$1-$2-$3`)}
</p>
<p className={css.email}>
<span />
{dlvrEmalAddr}
</p>
</div>
</li>
);
}
)}
</ul>
</TScroller>
</CheckOutContainer>
);
}

View File

@@ -1,57 +1,55 @@
import React, { useCallback } from "react";
import React, { useCallback } from 'react';
import classNames from "classnames";
import { useSelector } from "react-redux";
import classNames from 'classnames';
import { useSelector } from 'react-redux';
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
import noCouponImg from "../../../../assets/images/img-checkout-coupon@3x.png";
import TIconButton from "../../../components/TIconButton/TIconButton";
import TVirtualGridList from "../../../components/TVirtualGridList/TVirtualGridList";
import { $L } from "../../../utils/helperMethods";
import OffersPromotionItemCard, {
SIZES,
} from "../components/OffersPromotionItemCard";
import { BUYNOW_CONFIG } from "../../../utils/BuyNowConfig";
import css from "./FixedSideBar.module.less";
import noCouponImg from '../../../../assets/images/img-checkout-coupon@3x.png';
import TIconButton from '../../../components/TIconButton/TIconButton';
import TVirtualGridList from '../../../components/TVirtualGridList/TVirtualGridList';
import { $L } from '../../../utils/helperMethods';
import OffersPromotionItemCard, { SIZES } from '../components/OffersPromotionItemCard';
import { BUYNOW_CONFIG } from '../../../utils/BuyNowConfig';
import css from './FixedSideBar.module.less';
const SideBarContainer = SpotlightContainerDecorator("div");
const SideBarContainer = SpotlightContainerDecorator('div');
export default function FixedSideBar({ closeSideBar, offerSideBarOpen }) {
console.log('[CheckOutPanel] FixedSideBar mounted');
const reduxOrderItemList = useSelector(
(state) => state.checkout?.checkoutData?.productList
);
const reduxOrderItemList = useSelector((state) => state.checkout?.checkoutData?.productList);
console.log('[CheckOutPanel] FixedSideBar reduxOrderItemList:', reduxOrderItemList);
// Check if reduxOrderItemList has actual data
const hasValidOrderItemList = Array.isArray(reduxOrderItemList) && reduxOrderItemList.length > 0;
console.log('[CheckOutPanel] FixedSideBar hasValidOrderItemList:', hasValidOrderItemList);
const orderItemList = hasValidOrderItemList ? reduxOrderItemList : (BUYNOW_CONFIG.isMockMode() ? [
{
prdtId: 'MOCK_PRODUCT_1',
prdtNm: 'Mock Product',
prodQty: 1,
prdtOpt: [{ prodOptCdCval: 'MOCK_OPT_1' }],
patncLogPath: '/mock/image.jpg',
expsPrdtNo: 'MOCK_EXP_1',
currSign: '$',
currSignLoc: 'left',
shippingCharge: 0,
auctProdYn: 'N',
auctFinalPriceChgDt: null,
imgUrls: ['/mock/image.jpg'],
prdtCoupon: [],
}
] : null);
const orderItemList = hasValidOrderItemList
? reduxOrderItemList
: BUYNOW_CONFIG.isMockMode()
? [
{
prdtId: 'MOCK_PRODUCT_1',
prdtNm: 'Mock Product',
prodQty: 1,
prdtOpt: [{ prodOptCdCval: 'MOCK_OPT_1', optNm: 'Mock Option' }],
patncLogPath: '/mock/image.jpg',
expsPrdtNo: 'MOCK_EXP_1',
currSign: '$',
currSignLoc: 'left',
shippingCharge: 0,
auctProdYn: 'N',
auctFinalPriceChgDt: null,
imgUrls: [{ imgUrl: '/mock/image.jpg' }],
prdtCoupon: [],
},
]
: null;
console.log('[CheckOutPanel] FixedSideBar effectiveOrderItemList:', orderItemList);
const selectedCoupons = useSelector(
(state) => state.checkout.selectedCoupons
); // 선택된 쿠폰 정보
const selectedCoupons = useSelector((state) => state.checkout.selectedCoupons); // 선택된 쿠폰 정보
console.log('[CheckOutPanel] FixedSideBar selectedCoupons:', selectedCoupons);
const renderItem = useCallback(
@@ -88,13 +86,10 @@ export default function FixedSideBar({ closeSideBar, offerSideBarOpen }) {
return (
<>
<div className={classNames(css.bgLayer)} onClick={closeSideBar} />
<SideBarContainer
className={classNames(css.fixedSideBar)}
spotlightRestrict="self-only"
>
<SideBarContainer className={classNames(css.fixedSideBar)} spotlightRestrict="self-only">
<div className={css.sideMainTitle}>
<TIconButton className={css.backButton} onClick={closeSideBar} />
<h2 className={css.title}>{$L("OFFERS & PROMOTION")}</h2>
<h2 className={css.title}>{$L('OFFERS & PROMOTION')}</h2>
</div>
<div className={css.sideCoupon}>
<div className={css.right}>COUPON</div>

View File

@@ -1,45 +1,42 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector } from "react-redux";
import { useDispatch, useSelector } from 'react-redux';
import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import Spottable from "@enact/spotlight/Spottable";
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
import Spottable from '@enact/spotlight/Spottable';
import { setHidePopup, setShowPopup } from "../../../actions/commonActions";
import { popPanel } from "../../../actions/panelActions";
import TButton from "../../../components/TButton/TButton";
import TPopUp from "../../../components/TPopUp/TPopUp";
import TQRCode from "../../../components/TQRCode/TQRCode";
import useScrollTo from "../../../hooks/useScrollTo";
import useScrollTopByDistance from "../../../hooks/useScrollTopByDistance";
import * as Config from "../../../utils/Config";
import { $L, getQRCodeUrl } from "../../../utils/helperMethods";
import BillingAddressCard from "../components/BillingAddressCard";
import PaymentCard from "../components/PaymentCard";
import ShippingAddressCard from "../components/ShippingAddressCard";
import Subject from "../components/Subject";
import css from "./InformationContainer.module.less";
import { sendLogTotalRecommend } from "../../../actions/logActions";
import { BUYNOW_CONFIG } from "../../../utils/BuyNowConfig";
import { setHidePopup, setShowPopup } from '../../../actions/commonActions';
import { popPanel } from '../../../actions/panelActions';
import TButton from '../../../components/TButton/TButton';
import TPopUp from '../../../components/TPopUp/TPopUp';
import TQRCode from '../../../components/TQRCode/TQRCode';
import useScrollTo from '../../../hooks/useScrollTo';
import useScrollTopByDistance from '../../../hooks/useScrollTopByDistance';
import * as Config from '../../../utils/Config';
import { $L, getQRCodeUrl } from '../../../utils/helperMethods';
import BillingAddressCard from '../components/BillingAddressCard';
import PaymentCard from '../components/PaymentCard';
import ShippingAddressCard from '../components/ShippingAddressCard';
import Subject from '../components/Subject';
import css from './InformationContainer.module.less';
import { sendLogTotalRecommend } from '../../../actions/logActions';
import { BUYNOW_CONFIG } from '../../../utils/BuyNowConfig';
const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused" },
"div"
);
const Container = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
const BtnSpot = Spottable("p");
const BtnSpot = Spottable('p');
const getBtnNmByIndex = (index) => {
switch (index) {
case 0:
return "SHIPPING ADDRESS";
return 'SHIPPING ADDRESS';
case 1:
return "BILLING ADDRESS";
return 'BILLING ADDRESS';
case 2:
return "PATMENT METHOD";
return 'PATMENT METHOD';
default:
return "";
return '';
}
};
@@ -54,19 +51,14 @@ export default function InformationContainer({
// All useSelector calls must be at the top - before any conditional logic
const reduxCheckoutData = useSelector((state) => state.checkout?.checkoutData);
const { cursorVisible } = useSelector((state) => state.common.appStatus);
const { popupVisible, activePopup } = useSelector(
(state) => state.common.popup
);
const { popupVisible, activePopup } = useSelector((state) => state.common.popup);
const auctProdYn = useSelector(
(state) => state.checkout?.checkoutData?.productList?.[0].auctProdYn
);
const auctFinalPriceChgDt = useSelector(
(state) =>
state.checkout?.checkoutData?.productList?.[0].auctFinalPriceChgDt
);
const totDcAmt = useSelector(
(state) => state.checkout?.checkoutTotalData?.orderTotalAmtInfo?.totDcAmt
(state) => state.checkout?.checkoutData?.productList?.[0].auctFinalPriceChgDt
);
const totDcAmt = useSelector((state) => state.checkout?.checkoutTotalData?.totDcAmt);
const reduxServerHOST = useSelector((state) => state.common.appStatus.serverHOST);
const reduxServerType = useSelector((state) => state.localSettings.serverType);
const reduxNowMenu = useSelector((state) => state.common.menu.nowMenu);
@@ -75,69 +67,74 @@ export default function InformationContainer({
// Mock Mode: Provide fallback values for Redux selectors
const serverHOST = BUYNOW_CONFIG.isMockMode()
? (reduxServerHOST || 'sdp-us.shoptime.com')
? reduxServerHOST || 'sdp-us.shoptime.com'
: reduxServerHOST;
const serverType = BUYNOW_CONFIG.isMockMode()
? (reduxServerType || 'system')
: reduxServerType;
const nowMenu = BUYNOW_CONFIG.isMockMode()
? (reduxNowMenu || 'MOCK_NOW_MENU')
: reduxNowMenu;
const serverType = BUYNOW_CONFIG.isMockMode() ? reduxServerType || 'system' : reduxServerType;
const nowMenu = BUYNOW_CONFIG.isMockMode() ? reduxNowMenu || 'MOCK_NOW_MENU' : reduxNowMenu;
const entryMenu = BUYNOW_CONFIG.isMockMode()
? (reduxEntryMenu || 'MOCK_ENTRY_MENU')
? reduxEntryMenu || 'MOCK_ENTRY_MENU'
: reduxEntryMenu;
const deviceInfo = BUYNOW_CONFIG.isMockMode()
? (reduxDeviceInfo || { dvcIndex: 1 })
? reduxDeviceInfo || { dvcIndex: 1 }
: reduxDeviceInfo;
// Check if reduxCheckoutData has actual data (productList)
const hasValidCheckoutData = reduxCheckoutData?.productList && Array.isArray(reduxCheckoutData.productList) && reduxCheckoutData.productList.length > 0;
const hasValidCheckoutData =
reduxCheckoutData?.productList &&
Array.isArray(reduxCheckoutData.productList) &&
reduxCheckoutData.productList.length > 0;
const checkoutData = hasValidCheckoutData ? reduxCheckoutData : (BUYNOW_CONFIG.isMockMode() ? {
productList: [{
prdtId: 'MOCK_PRODUCT_1',
prdtNm: 'Mock Product',
patnrId: '1',
prodQty: 1,
prdtOpt: [{ prodOptCdCval: 'MOCK_OPT_1' }],
auctProdYn: 'N',
auctFinalPriceChgDt: null,
}],
shippingAddressList: [
{
dlvrAddrSno: 'MOCK_ADDR_1',
dlvrOdrFnm: 'Mock',
dlvrOdrLnm: 'Receiver',
dlvrZpcd: '12345',
dlvrStatNm: 'CA',
dlvrCityNm: 'Los Angeles',
dlvrDtlAddr: '123 Mock Street, Suite 100',
dlvrCtpt: '555-1234',
dlvrEmalAddr: 'mock@example.com',
}
],
billingAddressList: [
{
bilAddrSno: 'MOCK_ADDR_2',
payerFnm: 'Mock',
payerLnm: 'Payer',
bilAddrZpcd: '12346',
bilAddrStatNm: 'CA',
bilAddrCityNm: 'Los Angeles',
bilAddrDtlAddr: '456 Mock Avenue, Suite 200',
bilAddrCtpt: '555-5678',
bilAddrEmalAddr: 'payer@example.com',
}
],
cardInfo: [
{
cardSno: 'MOCK_CARD_1',
cardNm: 'Mock Card',
cardNo: '****-****-****-1234',
cardType: 'CREDIT',
}
],
} : null);
const checkoutData = hasValidCheckoutData
? reduxCheckoutData
: BUYNOW_CONFIG.isMockMode()
? {
productList: [
{
prdtId: 'MOCK_PRODUCT_1',
prdtNm: 'Mock Product',
patnrId: '1',
prodQty: 1,
prdtOpt: [{ prodOptCdCval: 'MOCK_OPT_1' }],
auctProdYn: 'N',
auctFinalPriceChgDt: null,
},
],
shippingAddressList: [
{
dlvrAddrSno: 'MOCK_ADDR_1',
dlvrOdrFnm: 'Mock',
dlvrOdrLnm: 'Receiver',
dlvrZpcd: '12345',
dlvrStatNm: 'CA',
dlvrCityNm: 'Los Angeles',
dlvrDtlAddr: '123 Mock Street, Suite 100',
dlvrCtpt: '555-1234',
dlvrEmalAddr: 'mock@example.com',
},
],
billingAddressList: [
{
bilAddrSno: 'MOCK_ADDR_2',
bilOdrFnm: 'Mock',
bilOdrLnm: 'Payer',
bilZpcd: '12346',
bilStatNm: 'CA',
bilCityNm: 'Los Angeles',
bilDtlAddr: '456 Mock Avenue, Suite 200',
bilCtpt: '5555678',
bilEmalAddr: 'payer@example.com',
},
],
cardInfo: [
{
cardSno: 'MOCK_CARD_1',
cardNm: 'Mock Card',
cardNo: '****-****-****-1234',
cardType: 'CREDIT',
},
],
}
: null;
const [_, setTab] = useState(0);
const [prdtData, setPrdtData] = useState({});
@@ -158,14 +155,12 @@ export default function InformationContainer({
const { patnrId, prdtId, prodQty } = checkoutData.productList[0];
const prdtOpt = checkoutData.productList[0].prdtOpt;
const prodOptCdCval =
Array.isArray(prdtOpt) && prdtOpt.length > 0
? prdtOpt[0].prodOptCdCval
: "";
Array.isArray(prdtOpt) && prdtOpt.length > 0 ? prdtOpt[0].prodOptCdCval : '';
const params = {
patnrId: patnrId,
prdtId: prdtId,
prodOptCdCval: prodOptCdCval || "",
prodOptCdCval: prodOptCdCval || '',
prodQty: prodQty,
};
@@ -200,31 +195,20 @@ export default function InformationContainer({
console.error('[CheckOutPanel] InformationContainer checkoutUrl useMemo - ERROR:', error);
return null;
}
}, [
serverHOST,
serverType,
entryMenu,
nowMenu,
deviceInfo,
]);
}, [serverHOST, serverType, entryMenu, nowMenu, deviceInfo]);
// Extract the actual URL string from the URL object
const checkoutUrl = checkoutUrlObj?.checkoutUrl || null;
const handleFocus = useCallback(() => {
const c = Spotlight.getCurrent();
const target = c.getAttribute("data-spotlight-id");
const target = c.getAttribute('data-spotlight-id');
const targetValue = '[data-spotlight-id="' + target + '"]';
if (cursorVisible) {
return;
}
scrollTopByDistance(
`[data-marker="scroll-marker"]`,
targetValue,
scrollTopBody,
100
);
scrollTopByDistance(`[data-marker="scroll-marker"]`, targetValue, scrollTopBody, 100);
}, []);
const handleButtonClick = useCallback(
@@ -240,7 +224,7 @@ export default function InformationContainer({
dispatch(
sendLogTotalRecommend({
buttonTitle: `${btnNm} ADD/EDIT`,
buttonId: `checkout_info_${btnNm.toLowerCase().replace(/\s+/g, "_")}`,
buttonId: `checkout_info_${btnNm.toLowerCase().replace(/\s+/g, '_')}`,
contextName: Config.LOG_CONTEXT_NAME.CHECKOUT,
messageId: Config.LOG_MESSAGE_ID.BUTTONCLICK,
})
@@ -284,10 +268,7 @@ export default function InformationContainer({
ADD/EDIT
</TButton>
{checkoutData?.shippingAddressList && (
<ShippingAddressCard
list={checkoutData.shippingAddressList}
onFocus={handleFocus}
/>
<ShippingAddressCard list={checkoutData.shippingAddressList} onFocus={handleFocus} />
)}
</div>
<div className={css.listBox}>
@@ -300,8 +281,10 @@ export default function InformationContainer({
>
ADD/EDIT
</TButton>
{/* BillingAddressCard disabled due to infinite render */}
<div style={{padding: '10px', textAlign: 'center', color: '#999'}}>Mock Billing Address</div>
{/* BillingAddressCard disabled due to infinite render loop in Mock Mode */}
<div style={{ padding: '10px', textAlign: 'center', color: '#999' }}>
Mock Billing Address
</div>
</div>
<div className={css.listBox}>
<Subject title="PATMENT METHOD" />
@@ -313,9 +296,7 @@ export default function InformationContainer({
>
ADD/EDIT
</TButton>
{checkoutData?.cardInfo && (
<PaymentCard list={checkoutData.cardInfo} />
)}
{checkoutData?.cardInfo && <PaymentCard list={checkoutData.cardInfo} />}
</div>
<div className={css.listBox}>
<Subject title="OFFERS & PROMOTION" />
@@ -326,7 +307,7 @@ export default function InformationContainer({
spotlightId="checkout-btn-fifth"
onFocus={handleFocus}
>
{auctProdYn === "Y" && !auctFinalPriceChgDt ? " - " : totDcAmt}
{auctProdYn === 'Y' && !auctFinalPriceChgDt ? ' - ' : totDcAmt ? totDcAmt : '-'}
</BtnSpot>
</div>
</div>
@@ -342,27 +323,22 @@ export default function InformationContainer({
>
<div className={css.popupContainer}>
<div className={css.header}>
<h3>{$L("QR CODE")}</h3>
<h3>{$L('QR CODE')}</h3>
</div>
<div className={css.qrcodeContainer}>
{checkoutUrl && (
<div className={css.qrcode}>
<TQRCode
text={checkoutUrl}
isBillingProductVisible
width="360"
height="360"
/>
<TQRCode text={checkoutUrl} isBillingProductVisible width="360" height="360" />
</div>
)}
<h3>
{$L(
"Please update your information and complete the payment on your mobile. By clicking the OK button, you will be redirected to the product details page"
'Please update your information and complete the payment on your mobile. By clicking the OK button, you will be redirected to the product details page'
)}
</h3>
<TButton className={css.popupBtn} onClick={handleDone}>
{$L("OK")}
{$L('OK')}
</TButton>
</div>
</div>

View File

@@ -0,0 +1,201 @@
import React, { useCallback } from 'react';
import Spottable from '@enact/spotlight/Spottable';
import TButton from '../../../components/TButton/TButton';
import { $L } from '../../../utils/helperMethods';
import Subject from '../components/Subject';
import ShippingAddressCardMock from '../components/ShippingAddressCardMock';
import BillingAddressCardMock from '../components/BillingAddressCardMock';
import PaymentCardMock from '../components/PaymentCardMock';
import css from './InformationContainer.module.less';
const BtnSpot = Spottable('p');
// Mock 데이터 - API 응답 시뮬레이션
const mockCheckoutData = {
productList: [
{
prdtId: 'MOCK_PRODUCT_1',
prdtNm: 'Mock Product',
patnrId: '1',
prodQty: 1,
prdtOpt: [{ prodOptCdCval: 'MOCK_OPT_1' }],
auctProdYn: 'N',
auctFinalPriceChgDt: null,
},
],
shippingAddressList: [
{
dlvrAddrSno: 'SHIPPING_ADDR_1',
dlvrOdrFnm: 'Chocho',
dlvrOdrLnm: 'Silverstar',
dlvrZpcd: '80249',
dlvrStatNm: 'COLORADO',
dlvrCityNm: 'DENVE',
dlvrDtlAddr: 'The Westin Denver Internation Airport, 8300 Pena',
dlvrCtpt: '3101234567',
dlvrEmalAddr: 'chocho.silverstar@example.com',
},
],
billingAddressList: [
{
bilAddrSno: 'BILLING_ADDR_1',
bilOdrFnm: 'ggg',
bilOdrLnm: 'hh',
bilZpcd: '78728',
bilStatNm: 'TEXAS',
bilCityNm: 'AUSTIN',
bilDtlAddr: 'Shop LC 100 Michael Angelo Way',
bilCtpt: '1111',
bilEmalAddr: 'test@1234.com',
},
{
bilAddrSno: 'BILLING_ADDR_2',
bilOdrFnm: 'Chocho',
bilOdrLnm: 'Silverstar',
bilZpcd: '80249',
bilStatNm: 'COLORADO',
bilCityNm: 'DENVER',
bilDtlAddr: 'The Westin Denver International Airport, 8300 Pena',
bilCtpt: '010-9922-8311',
bilEmalAddr: 'test.hj.usa@yopmail.com',
},
{
bilAddrSno: 'BILLING_ADDR_3',
bilOdrFnm: 'Chocho',
bilOdrLnm: 'Silverstar',
bilZpcd: '78728',
bilStatNm: 'TEXAS',
bilCityNm: 'AUSTIN',
bilDtlAddr: 'Shop LC 100 Michael Angelo W',
bilCtpt: '010-9922-8311',
bilEmalAddr: 'test.hj.usa@yopmail.com',
},
],
cardInfo: [
{
cardSno: 'CARD_1',
cardNm: 'Visa Card',
cardNo: '****-****-****-1234',
cardType: 'CREDIT',
},
],
};
export default function InformationContainerMock({
toggleOfferSideBar,
toggleOrderSideBar,
scrollTopBody,
doSendLogMyInfoEdit,
}) {
console.log('[CheckOutPanel] InformationContainerMock - Mounted');
console.log('[CheckOutPanel] InformationContainerMock - mockCheckoutData:', mockCheckoutData);
console.log(
'[CheckOutPanel] InformationContainerMock - shippingAddressList length:',
mockCheckoutData?.shippingAddressList?.length
);
console.log(
'[CheckOutPanel] InformationContainerMock - billingAddressList length:',
mockCheckoutData?.billingAddressList?.length
);
console.log(
'[CheckOutPanel] InformationContainerMock - cardInfo length:',
mockCheckoutData?.cardInfo?.length
);
const handleFocus = useCallback(() => {
console.log('[CheckOutPanel] InformationContainerMock - handleFocus called');
}, []);
const handleButtonClick = useCallback(
(index) => {
const btnNames = ['SHIPPING ADDRESS', 'BILLING ADDRESS', 'PATMENT METHOD'];
const btnNm = btnNames[index];
console.log(
'[CheckOutPanel] InformationContainerMock - handleButtonClick index:',
index,
'btnNm:',
btnNm
);
if (btnNm && doSendLogMyInfoEdit) {
doSendLogMyInfoEdit(btnNm);
}
},
[doSendLogMyInfoEdit]
);
return (
<>
<div className={css.container}>
<div data-marker="scroll-marker" />
<Subject title="ORDER ITEMS" />
<div className={css.markBtn}>
<BtnSpot
onClick={toggleOrderSideBar}
scrollTopBody={scrollTopBody}
spotlightId="checkout-btn-first"
onFocus={handleFocus}
>
1 ITEMS
</BtnSpot>
</div>
<div className={css.listBox}>
<Subject title="SHIPPING ADDRESS" />
<TButton
className={css.editBtn}
spotlightId="shipping-add-btn"
onFocus={handleFocus}
onClick={() => handleButtonClick(0)}
>
ADD/EDIT
</TButton>
<ShippingAddressCardMock
list={mockCheckoutData.shippingAddressList}
onFocus={handleFocus}
/>
</div>
<div className={css.listBox}>
<Subject title="BILLING ADDRESS" />
<TButton
className={css.editBtn}
spotlightId="billing-add-btn"
onFocus={handleFocus}
onClick={() => handleButtonClick(1)}
>
ADD/EDIT
</TButton>
<BillingAddressCardMock
list={mockCheckoutData.billingAddressList}
onFocus={handleFocus}
/>
</div>
<div className={css.listBox}>
<Subject title="PATMENT METHOD" />
<TButton
className={css.editBtn}
spotlightId="payment-add-btn"
onFocus={handleFocus}
onClick={() => handleButtonClick(2)}
>
ADD/EDIT
</TButton>
<PaymentCardMock list={mockCheckoutData.cardInfo} onFocus={handleFocus} />
</div>
<div className={css.listBox}>
<Subject title="OFFERS & PROMOTION" />
<div className={css.markBtn}>
<BtnSpot
onClick={toggleOfferSideBar}
scrollTopBody={scrollTopBody}
spotlightId="checkout-btn-fifth"
onFocus={handleFocus}
>
-
</BtnSpot>
</div>
</div>
</div>
</>
);
}

View File

@@ -1,54 +1,56 @@
import React, { useCallback, useEffect } from "react";
import React, { useCallback, useEffect } from 'react';
import { useSelector } from "react-redux";
import { useSelector } from 'react-redux';
import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
import TIConButton from "../../../components/TIconButton/TIconButton";
import TVirtualGridList from "../../../components/TVirtualGridList/TVirtualGridList";
import usePriceInfo from "../../../hooks/usePriceInfo";
import { $L } from "../../../utils/helperMethods";
import OrderItemCard, { SIZES } from "../components/OrderItemCard";
import { BUYNOW_CONFIG } from "../../../utils/BuyNowConfig";
import css from "./OrderItemsSideBar.module.less";
import TIConButton from '../../../components/TIconButton/TIconButton';
import TVirtualGridList from '../../../components/TVirtualGridList/TVirtualGridList';
import usePriceInfo from '../../../hooks/usePriceInfo';
import { $L } from '../../../utils/helperMethods';
import OrderItemCard, { SIZES } from '../components/OrderItemCard';
import { BUYNOW_CONFIG } from '../../../utils/BuyNowConfig';
import css from './OrderItemsSideBar.module.less';
const SideBarContainer = SpotlightContainerDecorator("div");
const SideBarContainer = SpotlightContainerDecorator('div');
export default function OrderItemsSideBar({ closeSideBar }) {
console.log('[CheckOutPanel] OrderItemsSideBar mounted');
const reduxOrderItemList = useSelector(
(state) => state.checkout?.checkoutData?.productList
);
const reduxOrderItemList = useSelector((state) => state.checkout?.checkoutData?.productList);
console.log('[CheckOutPanel] OrderItemsSideBar reduxOrderItemList:', reduxOrderItemList);
// Check if reduxOrderItemList has actual data
const hasValidOrderItemList = Array.isArray(reduxOrderItemList) && reduxOrderItemList.length > 0;
console.log('[CheckOutPanel] OrderItemsSideBar hasValidOrderItemList:', hasValidOrderItemList);
const orderItemList = hasValidOrderItemList ? reduxOrderItemList : (BUYNOW_CONFIG.isMockMode() ? [
{
prdtId: 'MOCK_PRODUCT_1',
prdtNm: 'Mock Product',
prodQty: 1,
prdtOpt: [{ prodOptCdCval: 'MOCK_OPT_1' }],
patncLogPath: '/mock/image.jpg',
expsPrdtNo: 'MOCK_EXP_1',
currSign: '$',
currSignLoc: 'left',
shippingCharge: 0,
auctProdYn: 'N',
auctFinalPriceChgDt: null,
imgUrls: ['/mock/image.jpg'],
}
] : null);
const orderItemList = hasValidOrderItemList
? reduxOrderItemList
: BUYNOW_CONFIG.isMockMode()
? [
{
prdtId: 'MOCK_PRODUCT_1',
prdtNm: 'Mock Product',
prodQty: 1,
prdtOpt: [{ prodOptCdCval: 'MOCK_OPT_1', optNm: 'Mock Option' }],
patncLogPath: '/mock/image.jpg',
expsPrdtNo: 'MOCK_EXP_1',
currSign: '$',
currSignLoc: 'left',
shippingCharge: 0,
auctProdYn: 'N',
auctFinalPriceChgDt: null,
imgUrls: [{ imgUrl: '/mock/image.jpg' }],
},
]
: null;
console.log('[CheckOutPanel] OrderItemsSideBar effectiveOrderItemList:', orderItemList);
useEffect(() => {
console.log('[CheckOutPanel] OrderItemsSideBar focus effect');
Spotlight.focus("orderItemSideBar_backButton");
Spotlight.focus('orderItemSideBar_backButton');
}, []);
const renderItem = useCallback(
@@ -90,7 +92,7 @@ export default function OrderItemsSideBar({ closeSideBar }) {
onClick={closeSideBar}
spotlightId="orderItemSideBar_backButton"
/>
<h2 className={css.title}>{$L("ORDER ITEMS")}</h2>
<h2 className={css.title}>{$L('ORDER ITEMS')}</h2>
</div>
<div className={css.orderItemListsWrap}>
{orderItemList && orderItemList.length > 0 ? (

View File

@@ -0,0 +1,142 @@
import React, { useCallback, useEffect, useMemo } from 'react';
import TButton from '../../../components/TButton/TButton';
import * as Config from '../../../utils/Config';
import { $L, formatCurrencyValue } from '../../../utils/helperMethods';
import css from './SummaryContainer.module.less';
export default function SummaryContainerMock({
setPlaceOrderPopup,
empTermsData,
handleTermsClick,
currSign,
currSignLoc,
doSendLogPaymentEntry,
}) {
console.log('[CheckOutPanel] SummaryContainerMock - START render');
console.log('[CheckOutPanel] SummaryContainerMock - empTermsData:', empTermsData);
console.log('[CheckOutPanel] SummaryContainerMock - currSign:', currSign);
// Mock Mode: 하드코딩된 가격 데이터
const effectivePriceTotalData = {
totProdPrc: 521.66,
totDcAmt: 0,
totDlvrAmt: 0,
ordPmtNoTaxAmt: 521.66,
ordTotTaxAmt: 50,
ordPmtReqAmt: 571.66,
};
// Mock Mode: 기본 상품 정보
const productList = {
auctProdYn: 'N',
auctFinalPriceChgDt: null,
};
const items = useMemo(
() => [
{
name: 'Items',
value: formatCurrencyValue(effectivePriceTotalData.totProdPrc, currSign, currSignLoc),
},
{
name: 'Your Coupon Savings',
value: effectivePriceTotalData.totDcAmt
? formatCurrencyValue(effectivePriceTotalData.totDcAmt, currSign, currSignLoc, true)
: '-',
},
{
name: 'Shipping & Handling',
value: formatCurrencyValue(effectivePriceTotalData.totDlvrAmt, currSign, currSignLoc),
},
{
name: 'TOTAL (before Tax)',
value: formatCurrencyValue(effectivePriceTotalData.ordPmtNoTaxAmt, currSign, currSignLoc),
},
{
name: 'Estimated Sales Tax',
value: formatCurrencyValue(effectivePriceTotalData.ordTotTaxAmt, currSign, currSignLoc),
},
],
[effectivePriceTotalData, currSign, currSignLoc]
);
const handleClickOrder = useCallback(() => {
console.log('[SummaryContainerMock] Place order clicked');
if (doSendLogPaymentEntry) {
doSendLogPaymentEntry();
}
setPlaceOrderPopup(true);
}, [doSendLogPaymentEntry, setPlaceOrderPopup]);
const renderItemList = useCallback(
() =>
items.map((item, index) => (
<div key={index} className={css.item}>
<span className={css.summaryDesc}>{item.name}</span>
<span className={css.summaryCnt}>{item.value}</span>
</div>
)),
[items]
);
const renderTermsList = useCallback(
() =>
empTermsData &&
empTermsData.length > 0 &&
empTermsData.map((term) => {
const { termsID, termsTypeName } = term;
return (
<li key={termsID} className={css.termsList}>
<span className={css.termsTypeName}>{termsTypeName}</span>
<TButton className={css.viewAllButton} onClick={() => handleTermsClick(termsID)}>
{$L('View All')}
</TButton>
</li>
);
}),
[empTermsData, handleTermsClick]
);
const estimatedTotal = useMemo(() => {
console.log('[CheckOutPanel] SummaryContainerMock - estimatedTotal useMemo');
return formatCurrencyValue(effectivePriceTotalData.ordPmtReqAmt, currSign, currSignLoc);
}, [effectivePriceTotalData, currSign, currSignLoc]);
const showAuctionNotice = productList?.auctProdYn === 'Y' && !productList.auctFinalPriceChgDt;
console.log('[CheckOutPanel] SummaryContainerMock - about to return JSX');
return (
<>
<div className={css.container}>
<div className={css.order}>
<h3>{$L('ORDER SUMMARY')}</h3>
<span className={css.line} />
<div className={css.itemWrap}>{renderItemList()}</div>
</div>
<div className={css.total}>
<div className={css.totalBox}>
<div className={css.totalTitle}>{$L('Estimated Total')}</div>
<div className={css.price}>{estimatedTotal}</div>
</div>
{showAuctionNotice && (
<div className={css.noticeBox}>
{$L('Purchased products will be paid at the final price.')}
</div>
)}
</div>
<div className={css.bottom}>
<ul className={css.termsWrap}>{renderTermsList()}</ul>
<TButton
className={css.tButton}
onClick={handleClickOrder}
spotlightId="spotlightId_placeOrderBtn"
>
{$L('PLACE ORDER')}
</TButton>
</div>
</div>
</>
);
}