[구매 및 장바구니 관련수정]

- buyoption : ,로 인해서 잘리는 부분수정.
 - mock데이터 말고 정식 상품이 바로 구매로 넘어올떄 관련 부분 수정.
 - 장바구니 금액 노출부분 수정 및 스타일 수정
 - 구매 과정중 금액 노출및 정상적이지 않는 스타일에 대한수정
 - 갯수 관련 수정
This commit is contained in:
junghoon86.park
2025-11-04 14:27:50 +09:00
parent ee6d6301da
commit e4cabc9f7e
16 changed files with 369 additions and 164 deletions

View File

@@ -31,7 +31,7 @@ export const getSafeProductPrice = (product) => {
}
// priceInfo가 있으면 파싱하여 사용 (BuyOption에서 전달된 원본 상품 데이터)
if (product.priceInfo) {
if (product?.priceInfo) {
const priceParts = product.priceInfo.split('|');
if (priceParts.length >= 5) {
const originalPrice = parseFloat(priceParts[0]) || 0;
@@ -48,6 +48,21 @@ export const getSafeProductPrice = (product) => {
currSignLoc: 'left', // 기본값
};
}
} else {
const originalPrice = parseFloat(product?.price2) || 0;
const price = parseFloat(product?.price3) || originalPrice; // 할인가격
const discountRate = 0;
const discountAmount = 0;
const currSign = '$';
return {
price,
originalPrice,
discount: discountAmount > 0 ? discountAmount : Math.max(0, originalPrice - price),
currSign,
currSignLoc: 'left', // 기본값
};
}
// fallback: finalPrice, discountPrice 등 기존 방식
@@ -188,6 +203,7 @@ export const isAuctionProduct = (product) => {
*/
export const normalizeProductDataForDisplay = (product) => {
// Mock Mode: product가 없어도 기본값으로 진행
console.log("###product 확인용", product)
if (!product) {
console.log('[mockDataSafetyUtils] normalizeProductDataForDisplay - product is null/undefined, using defaults');
return {
@@ -276,7 +292,7 @@ const extractPrice = (value) => {
export const calculateOrderSummaryFromProductInfo = (productInfo) => {
console.log('[BuyOption][CheckOutPanel] calculateOrderSummaryFromProductInfo - Input productInfo:', productInfo);
console.log('[BuyOption][CheckOutPanel] calculateOrderSummaryFromProductInfo - Available price fields:', {
price2: productInfo?.price2,
price2: productInfo?.price3 === productInfo?.price2 ? productInfo?.price3 : productInfo?.price2,
price5: productInfo?.price5,
finalPrice: productInfo?.finalPrice,
discountPrice: productInfo?.discountPrice,
@@ -299,6 +315,7 @@ export const calculateOrderSummaryFromProductInfo = (productInfo) => {
// 1. Items (상품 가격) - 최우선순위 Fallback 체인
const itemsPrice = extractPrice(
productInfo.price3 ||
productInfo.price2 ||
productInfo.finalPrice ||
productInfo.discountPrice ||

View File

@@ -6,9 +6,35 @@ import React, {
} from 'react';
import classNames from 'classnames';
import { useSelector, useDispatch } from 'react-redux';
import {
useDispatch,
useSelector,
} from 'react-redux';
import { updateSelectedItems } from '../../actions/mockCartActions';
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator
from '@enact/spotlight/SpotlightContainerDecorator';
import logoImage from '../../../assets/images/ic-partners-qvc@3x.png';
import defaultImage from '../../../assets/images/img-thumb-empty-144@3x.png';
import {
removeFromCart,
updateCartItem,
} from '../../actions/cartActions';
import {
removeFromMockCart,
setMockCartItemQuantity,
updateSelectedItems,
} from '../../actions/mockCartActions';
import CustomImage from '../../components/CustomImage/CustomImage';
import TButton from '../../components/TButton/TButton';
import TCheckBoxSquare from '../../components/TCheckBox/TCheckBoxSquare';
import store from '../../store/store';
import { BUYNOW_CONFIG } from '../../utils/BuyNowConfig';
import {
normalizeProductDataForDisplay,
} from '../../utils/mockDataSafetyUtils';
import css from './CartProduct.module.less';
// Debounce 유틸리티 함수
const debounce = (func, wait) => {
@@ -56,22 +82,6 @@ const OptimizedImage = ({ src, alt, className, fallbackSrc }) => {
);
};
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator
from '@enact/spotlight/SpotlightContainerDecorator';
import logoImage from '../../../assets/images/ic-partners-qvc@3x.png';
import defaultImage from '../../../assets/images/img-thumb-empty-144@3x.png';
import CustomImage from '../../components/CustomImage/CustomImage';
import TButton from '../../components/TButton/TButton';
import TCheckBoxSquare from '../../components/TCheckBox/TCheckBoxSquare';
import { removeFromCart, updateCartItem } from '../../actions/cartActions';
import { removeFromMockCart, setMockCartItemQuantity } from '../../actions/mockCartActions';
import store from '../../store/store';
import { BUYNOW_CONFIG } from '../../utils/BuyNowConfig';
import { normalizeProductDataForDisplay } from '../../utils/mockDataSafetyUtils';
import css from './CartProduct.module.less';
const Container = SpotlightContainerDecorator("div");
const CartProduct = ({ cartInfo }) => {
const dispatch = useDispatch();
@@ -250,9 +260,18 @@ const CartProduct = ({ cartInfo }) => {
{/* 파트너사별 가격 총합 - 한 번만 표시 */}
<div className={css.productPrice}>
<div className={css.leftSection}>
Product Total ${totals.productTotal.toFixed(2)} +
Option ${totals.optionTotal.toFixed(2)} +
S&H ${totals.shippingTotal.toFixed(2)}
Product Total ${totals.productTotal.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})} +
Option ${totals.optionTotal.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})} +
S&H ${totals.shippingTotal.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})}
</div>
<div className={css.rightSection}>
Total
@@ -315,22 +334,34 @@ const CartProduct = ({ cartInfo }) => {
)}
<div className={css.accountBox}>
<span className={css.account}>
${parseFloat(item.price3 || item.price2 || 0).toFixed(2)}
${parseFloat(item.price3 || item.price2 || 0).toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})}
</span>
<div className={css.accountInfo}>
{item.price2 && (
<span className={css.originalAcc}>
${parseFloat(item.price2).toFixed(2)}
${parseFloat(item.price2).toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})}
</span>
)}
{item.price5 && parseFloat(item.price5) > 0 && (
<span className={css.optionAcc}>
OPTION : ${parseFloat(item.price5).toFixed(2)}
OPTION : ${parseFloat(item.price5).toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})}
</span>
)}
{item.shippingCharge && parseFloat(item.shippingCharge) > 0 && (
<span className={css.shippingAcc}>
S&H: ${parseFloat(item.shippingCharge).toFixed(2)}
S&H: ${parseFloat(item.shippingCharge).toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})}
</span>
)}
</div>

View File

@@ -140,6 +140,7 @@
&:first-child {
border-left: none;
padding-left: 6px;
text-decoration: line-through;
}
}
// 동일 코드로 인한 상위에서 공통 처리.

View File

@@ -1,12 +1,21 @@
import React, { useMemo, useCallback } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { memo } from 'react';
import React, {
memo,
useCallback,
useMemo,
} from 'react';
import {
useDispatch,
useSelector,
} from 'react-redux';
import { pushPanel } from '../../actions/panelActions';
import TButton from '../../components/TButton/TButton';
import { BUYNOW_CONFIG } from '../../utils/BuyNowConfig';
import { pushPanel } from '../../actions/panelActions';
import * as Config from '../../utils/Config';
import { calculateOrderSummaryFromProductInfo } from '../../utils/mockDataSafetyUtils';
import {
calculateOrderSummaryFromProductInfo,
} from '../../utils/mockDataSafetyUtils';
import css from './CartSidebar.module.less';
const CartSidebar = ({ cartInfo }) => {
@@ -77,6 +86,7 @@ const CartSidebar = ({ cartInfo }) => {
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,
@@ -359,7 +369,10 @@ const CartSidebar = ({ cartInfo }) => {
const { itemCount, subtotal, optionTotal, shippingHandling, orderTotalBeforeTax } = calculatedData;
const formatPrice = (price) => {
return `$${price.toFixed(2)}`;
return `$${price.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})}`;
};
return (

View File

@@ -36,7 +36,7 @@
}
.itemCount {
width: 114px;
width: 150px;
height: 22px;
font-family: LGSmartUI;
font-size: 30.5px;

View File

@@ -1,12 +1,27 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import React, {
useCallback,
useEffect,
useMemo,
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 { getCheckoutTotalAmt, resetCheckoutData } from '../../actions/checkoutActions';
import { setHidePopup, setShowPopup } from '../../actions/commonActions';
import {
getCheckoutTotalAmt,
resetCheckoutData,
} from '../../actions/checkoutActions';
import {
setHidePopup,
setShowPopup,
} from '../../actions/commonActions';
import { getShoptimeTerms } from '../../actions/empActions';
import {
sendLogCheckOutBtnClick,
@@ -26,23 +41,27 @@ 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 * as Config from '../../utils/Config';
import {
$L,
scaleH,
scaleW,
} from '../../utils/helperMethods';
import {
normalizeProductDataForDisplay,
getSafeFirstProduct,
getSafeCurrencyInfo,
getSafeFirstProduct,
normalizeProductDataForDisplay,
} from '../../utils/mockDataSafetyUtils';
import { SpotlightIds } from '../../utils/SpotlightIds';
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';
import OrderItemsSideBar from './container/OrderItemsSideBar';
import SummaryContainerMock from './container/SummaryContainerMock';
import SummaryContainer from './container/SummaryCotainer';
export default function CheckOutPanel({ panelInfo }) {
// DEBUG_LOG 설정 - 이 값이 true일 때만 console.log가 실행됨
@@ -542,6 +561,10 @@ export default function CheckOutPanel({ panelInfo }) {
dispatch(sendLogMyInfoEdit({ btnNm }));
}, []);
const checkOutPanelInfo = panels.find(
(panel) => panel.name === "checkoutpanel"
)?.panelInfo;
console.log(
'[CheckOutPanel] Rendering - orderSideBarOpen:',
orderSideBarOpen,
@@ -597,7 +620,7 @@ export default function CheckOutPanel({ panelInfo }) {
toggleOfferSideBar={toggleOfferSideBar}
scrollTopBody={scrollTopBody}
doSendLogMyInfoEdit={doSendLogMyInfoEdit}
orderItemsCount={orderItemsCount}
orderItemsCount={orderItemsCount}
/>
) : (
<InformationContainer
@@ -684,6 +707,7 @@ export default function CheckOutPanel({ panelInfo }) {
<PinCodeInput
setPlaceOrderPopup={setPlaceOrderPopup}
setIsOrderSuccessful={setIsOrderSuccessful}
lastTotalPrice={checkOutPanelInfo?.estimatedTotal}
/>
</TFullPopup>
<div style={{display: 'none'}}>

View File

@@ -1,12 +1,18 @@
import React, { memo, useMemo } from "react";
import React, {
memo,
useMemo,
} from 'react';
import { useSelector } from "react-redux";
import { useSelector } from 'react-redux';
import Spottable from "@enact/spotlight/Spottable";
import Spottable from '@enact/spotlight/Spottable';
import CustomImage from "../../../components/CustomImage/CustomImage";
import { $L, formatCurrencyValue } from "../../../utils/helperMethods";
import css from "./OrderItemCard.module.less";
import CustomImage from '../../../components/CustomImage/CustomImage';
import {
$L,
formatCurrencyValue,
} from '../../../utils/helperMethods';
import css from './OrderItemCard.module.less';
const OrderItemContainer = Spottable("div");
@@ -29,11 +35,13 @@ export default memo(function OrderItemCard({
auctProdYn,
auctFinalPriceChgDt,
expsPrdtNo,
price,
...rest
}) {
const priceTotalData = useSelector(
(state) => state.checkout?.checkoutTotalData
);
console.log("###priceTotalData",priceTotalData);
const formattedPrices = useMemo(() => {
return {
@@ -75,7 +83,10 @@ export default memo(function OrderItemCard({
<p className={css.priceWrap}>
<span className={css.itemPrice}>
<span className={css.discountedPrice}>
{formattedPrices.discounted}
$ {(price * prodQty).toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})}
</span>
{/* {originalPrice && originalPrice !== discountedPrice && (
<span className={css.originalPrice}>
@@ -83,10 +94,12 @@ export default memo(function OrderItemCard({
</span>
)} */}
</span>
<span className={css.shippingPrice}>
{`${$L("S&H")}: `}
{formattedPrices.shipping}
</span>
<span className={css.shippingPrice}>
{`${$L("S&H")}: `}
{shippingCharge}
</span>
{auctProdYn === "Y" && !auctFinalPriceChgDt && (
<div className={css.noticeBox}>
{$L("Purchased products will be paid at the final price.")}

View File

@@ -98,7 +98,7 @@
height: 18px;
background-color: @COLOR_GRAY03;
}
}
}
.noticeBox {
width: 100%;

View File

@@ -4,3 +4,33 @@
.paymentBox {
min-height: 305px;
}
.itemContainer {
width: 444px;
height: 348px;
background-color: #fcfcfc;
border-radius: 12px;
padding: 32px 30px;
position: relative;
margin-right: 12px;
flex: none;
.checkBox{
position: absolute;
right: 20px;
top: 20px;
}
.title {
color: #333333;
font-weight: bold;
font-size: 36px;
margin-bottom: 19px;
}
.cardWrap {
color: #808080;
line-height: 1.33;
font-size: 24px;
margin-top: 230px;
}
}

View File

@@ -40,12 +40,12 @@ export default function PaymentCardMock({ list, onFocus }) {
<div className={css.cardWrap}>
<p>{cardNo}</p>
</div>
<div className={css.cardFooter}>
{/* <div className={css.cardFooter}>
<p className={css.cardType}>
<span />
{cardType}
</p>
</div>
</div> */}
</li>
);
})}

View File

@@ -4,34 +4,44 @@ import React, {
useMemo,
useRef,
useState,
} from "react";
} 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 Spottable from "@enact/spotlight/Spottable";
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator
from '@enact/spotlight/SpotlightContainerDecorator';
import Spottable from '@enact/spotlight/Spottable';
import { insertMyInfoCheckoutOrder } from "../../../actions/checkoutActions";
import { setHidePopup, setShowPopup } from "../../../actions/commonActions";
import { insertMyInfoCheckoutOrder } from '../../../actions/checkoutActions';
import {
setHidePopup,
setShowPopup,
} from '../../../actions/commonActions';
import { sendLogTotalRecommend } from '../../../actions/logActions';
import {
popPanel,
pushPanel,
resetPanels,
} from "../../../actions/panelActions";
import { getMyInfoCardPincodeCheck } from "../../../actions/pinCodeActions";
import CustomImage from "../../../components/CustomImage/CustomImage";
import TButton from "../../../components/TButton/TButton";
import TPopUp from "../../../components/TPopUp/TPopUp";
import TQRCode from "../../../components/TQRCode/TQRCode";
import * as Config from "../../../utils/Config";
import { $L, getQRCodeUrl } from "../../../utils/helperMethods";
import { sha256 } from "../../../utils/sha256";
import { SpotlightIds } from "../../../utils/SpotlightIds";
import { BUYNOW_CONFIG } from "../../../utils/BuyNowConfig";
import css from "./PinCodeInput.module.less";
import { sendLogTotalRecommend } from "../../../actions/logActions";
} from '../../../actions/panelActions';
import { getMyInfoCardPincodeCheck } from '../../../actions/pinCodeActions';
import CustomImage from '../../../components/CustomImage/CustomImage';
import TButton from '../../../components/TButton/TButton';
import TPopUp from '../../../components/TPopUp/TPopUp';
import TQRCode from '../../../components/TQRCode/TQRCode';
import { BUYNOW_CONFIG } from '../../../utils/BuyNowConfig';
import * as Config from '../../../utils/Config';
import {
$L,
getQRCodeUrl,
} from '../../../utils/helperMethods';
import { sha256 } from '../../../utils/sha256';
import { SpotlightIds } from '../../../utils/SpotlightIds';
import css from './PinCodeInput.module.less';
const PinCodeContainer = SpotlightContainerDecorator("div");
const PinCodeDigitsContainer = SpotlightContainerDecorator(
@@ -44,7 +54,10 @@ const SpottableButton = Spottable("div");
export default function PinCodeInput({
setPlaceOrderPopup,
setIsOrderSuccessful,
productData,
lastTotalPrice,
}) {
console.log("###lastTotalPrice",lastTotalPrice);
const dispatch = useDispatch();
const { activePopup, popupVisible } = useSelector(
@@ -207,26 +220,26 @@ export default function PinCodeInput({
data: {
retCode: 0,
data: {
ordNo: `MOCK_ORDER_${Date.now()}`,
expsOrdNo: `MOCK_EXPS_${Date.now()}`,
bilCityNm: "Mock City",
bilCtpt: "Mock Phone",
bilDtlAddr: "Mock Detail Address",
bilEmalAddr: "mock@example.com",
bilOdrFnm: "Mock",
bilOdrLnm: "User",
bilStatNm: "Mock State",
bilZpcd: "12345",
cardKnd: "MOCK_CARD",
dlvrCityNm: "Mock City",
dlvrCtpt: "Mock Phone",
ordNo: `ORDER_${Date.now()}`,
expsOrdNo: `EXPS_${Date.now()}`,
bilCityNm: "AUSTIN",
bilCtpt: "1111",
bilDtlAddr: "Shop LC 100 Michael Angelo Way",
bilEmalAddr: "test@1234.com",
bilOdrFnm: "ggg",
bilOdrLnm: "hh",
bilStatNm: "TEXAS",
bilZpcd: "78728",
cardKnd: "Visa Card",
dlvrCityNm: "DENVE",
dlvrCtpt: "3101234567",
dlvrDate: new Date().toISOString().split('T')[0],
dlvrDtlAddr: "Mock Detail Address",
dlvrEmalAddr: "mock@example.com",
dlvrOdrFnm: "Mock",
dlvrOdrLnm: "User",
dlvrZpcd: "12345",
realTotAmt: productList?.finalPrice || 99999,
dlvrDtlAddr: "The Westin Denver Internation Airport, 8300 Pena",
dlvrEmalAddr: "chocho.silverstar@example.com",
dlvrOdrFnm: "Chocho",
dlvrOdrLnm: "Silverstar",
dlvrZpcd: "80249",
realTotAmt: productList?.finalPrice || lastTotalPrice || 0,
totDlvrAmt: 0,
}
}
@@ -328,7 +341,7 @@ export default function PinCodeInput({
panelInfo: {
orderInfo: response.data.data,
auctProdYn: auctProdYn,
auctFinalPriceChgDt: auctFinalPriceChgDt,
auctFinalPriceChgDt: auctFinalPriceChgDt ? auctFinalPriceChgDt : discountRate ? discountPrice : regularPrice,
currSign: productList.currSign,
currSignLoc: productList.currSignLoc,
logInfo: logInfo,

View File

@@ -1,13 +1,16 @@
import React, { useCallback, useMemo } from 'react';
import React, {
useCallback,
useMemo,
} 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 ShippingAddressCardMock from '../components/ShippingAddressCardMock';
import Subject from '../components/Subject';
import css from './InformationContainer.module.less';
const BtnSpot = Spottable('p');
@@ -50,28 +53,6 @@ const mockCheckoutData = {
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: [
{
@@ -89,6 +70,7 @@ export default function InformationContainerMock({
scrollTopBody,
doSendLogMyInfoEdit,
orderItemsCount = 0,
productData,
}) {
console.log('[CheckOutPanel] InformationContainerMock - Mounted');
console.log('[CheckOutPanel] InformationContainerMock - mockCheckoutData:', mockCheckoutData);
@@ -189,7 +171,7 @@ export default function InformationContainerMock({
</TButton>
<PaymentCardMock list={mockCheckoutData.cardInfo} onFocus={handleFocus} />
</div>
<div className={css.listBox}>
{/* <div className={css.listBox}>
<Subject title="OFFERS & PROMOTION" />
<div className={css.markBtn}>
<BtnSpot
@@ -201,7 +183,7 @@ export default function InformationContainerMock({
-
</BtnSpot>
</div>
</div>
</div> */}
</div>
</>
);

View File

@@ -1,20 +1,25 @@
import React, { useCallback, useEffect } from 'react';
import React, {
useCallback,
useEffect,
} from 'react';
import { useSelector } from 'react-redux';
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
import SpotlightContainerDecorator
from '@enact/spotlight/SpotlightContainerDecorator';
import TIConButton from '../../../components/TIconButton/TIconButton';
import TVirtualGridList from '../../../components/TVirtualGridList/TVirtualGridList';
import TVirtualGridList
from '../../../components/TVirtualGridList/TVirtualGridList';
import usePriceInfo from '../../../hooks/usePriceInfo';
import { BUYNOW_CONFIG } from '../../../utils/BuyNowConfig';
import { $L } from '../../../utils/helperMethods';
import {
normalizeProductDataForDisplay,
getSafeFirstProduct,
normalizeProductDataForDisplay,
} from '../../../utils/mockDataSafetyUtils';
import OrderItemCard, { SIZES } from '../components/OrderItemCard';
import { BUYNOW_CONFIG } from '../../../utils/BuyNowConfig';
import css from './OrderItemsSideBar.module.less';
const SideBarContainer = SpotlightContainerDecorator('div');
@@ -36,10 +41,13 @@ export default function OrderItemsSideBar({
console.log('[CheckOutPanel] OrderItemsSideBar fromCartPanel:', fromCartPanel);
// Check if reduxOrderItemList has actual data
const hasValidOrderItemList = Array.isArray(reduxOrderItemList) && reduxOrderItemList.length > 0;
console.log('[CheckOutPanel] OrderItemsSideBar hasValidOrderItemList:', hasValidOrderItemList);
const hasValidOrderItemList = Array.isArray(reduxOrderItemList) && reduxOrderItemList?.length > 0;
console.log('[CheckOutPanel] OrderItemsSideBar1 hasValidOrderItemList:', hasValidOrderItemList);
console.log('[CheckOutPanel] OrderItemsSideBar1 Array.isArray(reduxOrderItemList):', Array.isArray(reduxOrderItemList));
console.log('[CheckOutPanel] OrderItemsSideBar1 reduxOrderItemList?.length:', reduxOrderItemList?.length);
const mapToOrderItem = (product, index) => {
const normalized =
product && product.isValid ? product : normalizeProductDataForDisplay(product);
@@ -144,7 +152,8 @@ export default function OrderItemsSideBar({
({ index, ...rest }) => {
console.log('[CheckOutPanel] OrderItemsSideBar renderItem - index:', index);
const item = orderItemList[index];
console.log('[CheckOutPanel] OrderItemsSideBar renderItem - item:', item);
return (
<OrderItemCard
{...rest}
@@ -156,6 +165,7 @@ export default function OrderItemsSideBar({
patncLogPath={item.patncLogPath}
prdtId={item.prdtId}
expsPrdtNo={item.expsPrdtNo}
price={item.price >= item.originalPrice ? item.originalPrice : item.price}
currSign={item.currSign}
currSignLoc={item.currSignLoc}
shippingCharge={item.shippingCharge}

View File

@@ -1,9 +1,25 @@
import React, { useCallback, useEffect, useMemo } from 'react';
import React, {
useCallback,
useEffect,
useMemo,
} from 'react';
import {
useDispatch,
useSelector,
} from 'react-redux';
import { updatePanel } from '../../../actions/panelActions';
import TButton from '../../../components/TButton/TButton';
import * as Config from '../../../utils/Config';
import { $L, formatCurrencyValue } from '../../../utils/helperMethods';
import { getSafeFirstProduct, calculateOrderSummaryFromProductInfo } from '../../../utils/mockDataSafetyUtils';
import {
$L,
formatCurrencyValue,
} from '../../../utils/helperMethods';
import {
calculateOrderSummaryFromProductInfo,
getSafeFirstProduct,
} from '../../../utils/mockDataSafetyUtils';
import css from './SummaryContainer.module.less';
export default function SummaryContainerMock({
@@ -30,6 +46,9 @@ export default function SummaryContainerMock({
console.log('%cproductInfo:', 'background: yellow; color: black; padding: 3px;', productInfo);
console.log('%cproductInfo.price2:', 'background: yellow; color: black; padding: 3px;', productInfo?.price2);
console.log('%cproductInfo.price5:', 'background: yellow; color: black; padding: 3px;', productInfo?.price5);
console.log('%cproductInfo.prodQty:', 'background: yellow; color: black; padding: 3px;', productInfo?.prodQty);
const dispatch = useDispatch();
const cartSummarySource = useMemo(() => {
if (!fromCartPanel) {
@@ -66,9 +85,9 @@ export default function SummaryContainerMock({
const productSummary = calculateOrderSummaryFromProductInfo(product);
console.log('Product summary result:', productSummary);
totalItems += productSummary.items;
totalCoupon += productSummary.couponSavings;
totalShipping += productSummary.shipping;
totalItems += productSummary.items * product.prodQty;
totalCoupon += (productSummary.couponSavings * product.prodQty);
totalShipping += productSummary.shipping * product.prodQty;
});
const subtotal = Math.max(0, totalItems - totalCoupon + totalShipping);
@@ -95,7 +114,28 @@ export default function SummaryContainerMock({
// 2순위: productInfo (단일 상품)
if (productInfo) {
console.log('[BuyOption][CheckOutPanel] SummaryContainerMock - Using calculateOrderSummaryFromProductInfo (single product)');
return calculateOrderSummaryFromProductInfo(productInfo);
const productSummary = calculateOrderSummaryFromProductInfo(productInfo);
let totalItems = 0;
let totalCoupon = 0;
let totalShipping = 0;
totalItems += productSummary.items * productInfo?.prodQty;
totalCoupon += (productSummary.couponSavings * productInfo?.prodQty);
totalShipping += productSummary.shipping * productInfo?.prodQty;
const subtotal = Math.max(0, totalItems - totalCoupon + totalShipping);
const tax = Math.round((subtotal * 0.1) * 100) / 100;
return {
items: totalItems,
couponSavings: totalCoupon,
shipping: totalShipping,
subtotal: subtotal,
tax: tax,
total: subtotal + tax,
currency: { currSign, currSignLoc }
}
}
// 3순위: 기존 방식으로 fallback
@@ -227,6 +267,31 @@ export default function SummaryContainerMock({
console.log('[BuyOption][CheckOutPanel] SummaryContainerMock - about to return JSX');
const panels = useSelector((state) => state.panels?.panels);
useEffect(() => {
if (!Array.isArray(panels)) return;
const modalCheckOutPanel = panels.find(
(panel) => panel?.name === Config.panel_names.CHECKOUT_PANEL
);
if (
modalCheckOutPanel &&
modalCheckOutPanel.panelInfo?.estimatedTotal !== estimatedTotal
) {
dispatch(
updatePanel({
name: Config.panel_names.CHECKOUT_PANEL,
panelInfo: {
...modalCheckOutPanel.panelInfo,
estimatedTotal: estimatedTotal,
},
})
);
}
}, [dispatch, estimatedTotal]);
return (
<>
<div className={css.container}>

View File

@@ -36,8 +36,8 @@ export default function ConfirmPanel({ spotlightId }) {
const myPageTabs = useSelector((state) => state.home.menuData.data.mypage);
const myOrder =
myPageTabs.find((item) => item.menuId === Config.MYPAGE_TABS.MY_ORDERS) ||
{};
{};
const panelInfo = panels.find(
(panel) => panel.name === "confirmpanel"
)?.panelInfo;
@@ -162,8 +162,7 @@ export default function ConfirmPanel({ spotlightId }) {
<div className={css.bottomContents}>
<p className={css.bottomContentsTitle}>{$L("ESTIMATED TOTAL")}</p>
<span className={css.bottomContentsDesc}>
{formatCurrencyValue(realTotAmt, currSign, currSignLoc)} (
{cardKnd})
{realTotAmt} ({cardKnd})
{auctProdYn && auctProdYn === "Y" && !auctFinalPriceChgDt && (
<span className={css.noticeBox}>
{$L("Purchased products will be paid at the final price.")}

View File

@@ -2,8 +2,8 @@ import React, {
useCallback,
useEffect,
useMemo,
useState,
useRef,
useState,
} from 'react';
import {
@@ -16,7 +16,6 @@ import SpotlightContainerDecorator
from '@enact/spotlight/SpotlightContainerDecorator';
import { addToCart } from '../../../actions/cartActions';
import { addToMockCart } from '../../../actions/mockCartActions';
import { getMyInfoCheckoutInfo } from '../../../actions/checkoutActions';
import {
changeAppStatus,
@@ -25,12 +24,12 @@ import {
showError,
} from '../../../actions/commonActions';
import { getProductCouponSearch } from '../../../actions/couponActions';
import { getSafeProductPrice } from '../../../utils/mockDataSafetyUtils';
import {
sendLogPaymentEntry,
sendLogTotalRecommend,
} from '../../../actions/logActions';
import { finishMediaPreview } from '../../../actions/mediaActions';
import { addToMockCart } from '../../../actions/mockCartActions';
import {
popPanel,
pushPanel,
@@ -43,10 +42,13 @@ import {
import { clearAllToasts } from '../../../actions/toastActions';
import TButton from '../../../components/TButton/TButton';
import TPopUp from '../../../components/TPopUp/TPopUp';
import { BUYNOW_CONFIG } from '../../../utils/BuyNowConfig';
import {
createMockProductOptionData,
} from '../../../utils/BuyNowDataManipulator';
import * as Config from '../../../utils/Config';
import { $L } from '../../../utils/helperMethods';
import { BUYNOW_CONFIG } from '../../../utils/BuyNowConfig';
import { createMockProductOptionData } from '../../../utils/BuyNowDataManipulator';
import { getSafeProductPrice } from '../../../utils/mockDataSafetyUtils';
import FavoriteBtn from '../components/FavoriteBtn';
import styles from './BuyOption.module.less';
import BuyOptionPriceBlock from './BuyOptionPriceBlock';
@@ -556,23 +558,24 @@ const BuyOption = ({
const extractNumericPrice = (priceStr) => {
if (typeof priceStr === 'number') return priceStr;
if (typeof priceStr === 'string') {
const numMatch = priceStr.match(/[\d.]+/);
const cleanedValue = priceStr.replace(/,/g, '');
const numMatch = cleanedValue.match(/[\d.]+/);
return numMatch ? parseFloat(numMatch[0]) : 0;
}
return 0;
};
const price2Value = extractNumericPrice(productInfo?.price2);
const price3Value = extractNumericPrice(productInfo?.price3 ? productInfo?.price3 : productInfo?.price2);
const price5Value = extractNumericPrice(productInfo?.price5);
console.log('[BuyOption] handleClickOrder - productInfo.price2:', productInfo?.price2, '-> extracted:', price2Value);
console.log('[BuyOption] handleClickOrder - productInfo.price2:', productInfo?.price3, '-> extracted:', price3Value);
console.log('[BuyOption] handleClickOrder - productInfo.price5:', productInfo?.price5, '-> extracted:', price5Value);
// 가격 계산:
// discountPrice = price2 (상품 가격)
// regularPrice = price2 + price5 (상품 가격 + 할인액 = 원래 가격)
let discountPrice = price2Value > 0 ? price2Value : 0;
let regularPrice = price2Value + price5Value; // price2 + price5 = 원래 가격
let discountPrice = price3Value > 0 ? price3Value : 0;
let regularPrice = price3Value + price5Value; // price2 + price5 = 원래 가격
const discountRate = priceInfo?.split('|')[4];
@@ -688,12 +691,13 @@ const BuyOption = ({
patncNm: patncNm || 'Mock Partner',
// calculateOrderSummaryFromProductInfo 함수가 필요한 필드들
// productInfo에서 직접 추출한 값을 전달
price2: price2Value, // Items (상품 가격)
price2: price3Value, // Items (상품 가격)
price5: price5Value, // Coupon Savings (할인액)
finalPrice: discountPrice,
discount: price5Value,
origPrice: regularPrice,
discountPrice: discountPrice,
prodQty:quantity,
// 추가 가격 필드들 (fallback용)
price: discountPrice,
originalPrice: regularPrice,
@@ -701,7 +705,8 @@ const BuyOption = ({
...(productInfo.imgList && { imgList: productInfo.imgList }),
...(productInfo.thumbnailUrl && { thumbnailUrl: productInfo.thumbnailUrl }),
...(productInfo.imgUrls && { imgUrls: productInfo.imgUrls }),
shippingCharge: 0, // 배송비
shippingCharge: productInfo?.shippingFee || '12.99', // 배송비
shippingFee: productInfo?.shippingFee || '12.99',
currSign: '$',
currSignLoc: 'left',
},
@@ -709,7 +714,7 @@ const BuyOption = ({
};
console.log('[BuyOption] Mock Mode - checkoutPanelInfo.productInfo price fields:', {
price2: price2Value,
price2: price3Value,
price5: price5Value,
finalPrice: discountPrice,
origPrice: regularPrice,
@@ -884,12 +889,13 @@ const BuyOption = ({
const extractNumericPrice = (value) => {
if (typeof value === 'number') return value;
if (typeof value === 'string') {
const numMatch = value.match(/[\d.]+/);
const cleanedValue = value.replace(/,/g, '');
const numMatch = cleanedValue.match(/[\d.]+/);
return numMatch ? parseFloat(numMatch[0]) : 0;
}
return 0;
};
const price2Value = extractNumericPrice(productInfo?.price2);
const price5Value = extractNumericPrice(productInfo?.price5);
@@ -1001,7 +1007,8 @@ const BuyOption = ({
const extractNumericPrice = (value) => {
if (typeof value === 'number') return value;
if (typeof value === 'string') {
const numMatch = value.match(/[\d.]+/);
const cleanedValue = value.replace(/,/g, '');
const numMatch = cleanedValue.match(/[\d.]+/);
return numMatch ? parseFloat(numMatch[0]) : 0;
}
return 0;