[장바구니] 수정#1
- cartAction 상품 옵션 받는부분이 없어 수정 - tablayout 노출관련 cartpanel추가 - cartpanel 가로값 1800으로 변경 및 노출 수정 - buyoption에 add cart 버튼클릭시 buynow와 같은 작동하도록 수정 - 상품 노출관련 수정(좀더 수정필요함) - 사이드바 수정 진행중 - 상품이 추가되지않는부분에 대해서는 현재 백엔드에서 확인중입니다.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { URLS } from "../api/apiConfig";
|
||||
import { TAxios } from "../api/TAxios";
|
||||
import { types } from "./actionTypes";
|
||||
import { URLS } from '../api/apiConfig';
|
||||
import { TAxios } from '../api/TAxios';
|
||||
import { types } from './actionTypes';
|
||||
|
||||
/**
|
||||
* 회원 장바구니 정보 조회
|
||||
@@ -55,7 +55,7 @@ export const getMyInfoCartSearch = (props) => (dispatch, getState) => {
|
||||
* @param {Object} props - 장바구니 상품 정보
|
||||
*/
|
||||
export const addToCart = (props) => (dispatch, getState) => {
|
||||
const { mbrNo, patnrId, prdtId, prodOptCdCval, prodQty } = props;
|
||||
const { mbrNo, patnrId, prdtId, prodOptCdCval, prodQty, prdtOpt } = props;
|
||||
|
||||
const onSuccess = (response) => {
|
||||
console.log("addToCart onSuccess: ", response.data);
|
||||
@@ -78,7 +78,7 @@ export const addToCart = (props) => (dispatch, getState) => {
|
||||
console.warn("ADD_TO_CART URL이 정의되지 않았습니다.");
|
||||
dispatch({
|
||||
type: types.ADD_TO_CART,
|
||||
payload: { patnrId, prdtId, prodOptCdCval, prodQty },
|
||||
payload: { patnrId, prdtId, prodOptCdCval, prodQty, prdtOpt },
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ export const addToCart = (props) => (dispatch, getState) => {
|
||||
"post",
|
||||
URLS.ADD_TO_CART,
|
||||
{},
|
||||
{ mbrNo, patnrId, prdtId, prodOptCdCval, prodQty },
|
||||
{ mbrNo, patnrId, prdtId, prodOptCdCval, prodQty, prdtOpt },
|
||||
onSuccess,
|
||||
onFail
|
||||
);
|
||||
|
||||
@@ -137,6 +137,7 @@ const PANELS_HAS_TAB = [
|
||||
panel_names.ON_SALE_PANEL,
|
||||
panel_names.SEARCH_PANEL,
|
||||
panel_names.TRENDING_NOW_PANEL,
|
||||
panel_names.CART_PANEL,
|
||||
];
|
||||
|
||||
export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import CartProductBar from './CartProductBar';
|
||||
import CartSidebar from './CartSidebar';
|
||||
|
||||
export default function CartPanel({ spotlightId, scrollOptions = [] }) {
|
||||
const cartData = useSelector((state) => state.cart.getMyinfoCartSearch);
|
||||
const cartData = useSelector((state) => state.cart.getMyinfoCartSearch.cartInfo);
|
||||
const { userNumber } = useSelector(
|
||||
(state) => state.common.appStatus.loginUserData
|
||||
);
|
||||
@@ -38,10 +38,6 @@ export default function CartPanel({ spotlightId, scrollOptions = [] }) {
|
||||
}
|
||||
}, [dispatch, userNumber]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("###cartData", cartData);
|
||||
}, [cartData]);
|
||||
|
||||
const {
|
||||
getScrollTo,
|
||||
getScrollTo: getScrollToBody,
|
||||
@@ -49,7 +45,7 @@ export default function CartPanel({ spotlightId, scrollOptions = [] }) {
|
||||
} = useScrollTo();
|
||||
|
||||
return (
|
||||
<TPanel spotlightId={spotlightId} isTabActivated={false}>
|
||||
<TPanel spotlightId={spotlightId} isTabActivated={true}>
|
||||
<TBody className={css.tbody}>
|
||||
<THeader
|
||||
className={css.theader}
|
||||
@@ -60,18 +56,21 @@ export default function CartPanel({ spotlightId, scrollOptions = [] }) {
|
||||
/>
|
||||
<div className={css.Wrap}>
|
||||
<div className={css.leftSection}>
|
||||
<CartSidebar />
|
||||
<CartSidebar cartInfo={cartData}/>
|
||||
</div>
|
||||
<div className={css.rightSection} cbScrollTo={getScrollToBody}>
|
||||
{/* 오른쪽 상품 영역 */}
|
||||
{/* <TScroller
|
||||
className={css.tScroller}
|
||||
scrollTopBody={scrollTopBody}
|
||||
{...scrollOptions}
|
||||
>
|
||||
<CartProductBar />
|
||||
</TScroller> */}
|
||||
<CartEmpty />
|
||||
{cartData && cartData?.length > 0 ? (
|
||||
<TScroller
|
||||
className={css.tScroller}
|
||||
scrollTopBody={scrollTopBody}
|
||||
{...scrollOptions}
|
||||
>
|
||||
<CartProductBar cartInfo={cartData} />
|
||||
</TScroller>
|
||||
) : (
|
||||
<CartEmpty />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</TBody>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@import "../../style/utils.module.less";
|
||||
|
||||
.tbody {
|
||||
.size(@w: 1920px, @h: 100%);
|
||||
.size(@w: 1800px, @h: 100%);
|
||||
.theader {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
|
||||
@@ -6,6 +6,7 @@ import React, {
|
||||
} from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import Spotlight from '@enact/spotlight';
|
||||
import SpotlightContainerDecorator
|
||||
@@ -20,7 +21,55 @@ import css from './CartProduct.module.less';
|
||||
|
||||
const Container = SpotlightContainerDecorator("div");
|
||||
const CartProduct = () => {
|
||||
const randomCount = useMemo(() => Math.floor(Math.random() * 3) + 1, []);
|
||||
const cartData = useSelector((state) => state.cart.getMyinfoCartSearch.cartInfo);
|
||||
|
||||
//카트 데이타 그룹화 - 수정된 부분
|
||||
const groupedCartData = useMemo(() => {
|
||||
if (!cartData || !Array.isArray(cartData)) return {};
|
||||
|
||||
return cartData.reduce((acc, item) => {
|
||||
const groupKey = item.patncNm || item.patnrId || 'unknown';
|
||||
|
||||
if (!acc[groupKey]) {
|
||||
// 객체 구조로 초기화 (수정됨)
|
||||
acc[groupKey] = {
|
||||
partnerInfo: {
|
||||
id: item.patnrId,
|
||||
name: item.patncNm,
|
||||
logo: item.patncLogPath
|
||||
},
|
||||
items: []
|
||||
};
|
||||
}
|
||||
acc[groupKey].items.push(item);
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
}, [cartData]);
|
||||
|
||||
useEffect(()=>{
|
||||
console.log("###groupedCartData",groupedCartData);
|
||||
},[groupedCartData])
|
||||
|
||||
// 파트너사별 총합 계산
|
||||
const calculatePartnerTotal = (items) => {
|
||||
const productTotal = items.reduce((sum, item) =>
|
||||
sum + (parseFloat(item.price3 || item.price2 || 0) * item.prodQty), 0
|
||||
);
|
||||
const optionTotal = items.reduce((sum, item) =>
|
||||
sum + (parseFloat(item.optPrc || 0) * item.prodQty), 0
|
||||
);
|
||||
const shippingTotal = items.reduce((sum, item) =>
|
||||
sum + parseFloat(item.shippingCharge || 0), 0
|
||||
);
|
||||
|
||||
return {
|
||||
productTotal,
|
||||
optionTotal,
|
||||
shippingTotal,
|
||||
total: productTotal + optionTotal + shippingTotal
|
||||
};
|
||||
};
|
||||
|
||||
const [pdEa, setPdEa] = useState(1);
|
||||
|
||||
@@ -29,6 +78,7 @@ const CartProduct = () => {
|
||||
setPdEa(pdEa - 1);
|
||||
}
|
||||
}, [pdEa]);
|
||||
|
||||
const handleIncreseClick = useCallback(() => {
|
||||
setPdEa(pdEa + 1);
|
||||
}, [pdEa]);
|
||||
@@ -38,97 +88,139 @@ const CartProduct = () => {
|
||||
Spotlight.focus("pd_ea_increse");
|
||||
}
|
||||
}, [pdEa]);
|
||||
|
||||
return (
|
||||
<Container className={css.productBox}>
|
||||
<div className={css.productCompany}>
|
||||
{/* 장바구니에 담긴 상품의 회사정보 */}
|
||||
<div className={css.logo}>
|
||||
<CustomImage
|
||||
className={css.img}
|
||||
src={logoImage}
|
||||
fallbackSrc={defaultImage}
|
||||
/>
|
||||
</div>
|
||||
<span className={css.company}>
|
||||
Juvelirochka
|
||||
<span className={css.productEa}>(1 ITEM)</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className={css.productPrice}>
|
||||
{/* 그 회사에 장바구니에 담긴 상품의 총합 */}
|
||||
<div className={css.leftSection}>
|
||||
Product Total $ 99,999.99 + Option $ 99,999.99 + S&H $ 99,999.9
|
||||
</div>
|
||||
<div className={css.rightSection}>
|
||||
Total
|
||||
<span className={css.total}>
|
||||
$<span className={css.totalAcc}>999,999,999</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{/* 상품 정보 반복가능 */}
|
||||
{Array.from({ length: randomCount }, (_, index) => (
|
||||
<div className={css.product}>
|
||||
<div className={css.leftBox}>
|
||||
<div className={css.checkBox}>
|
||||
<TCheckBoxSquare
|
||||
className={css.customeCheckbox}
|
||||
spotlightId="productCheckbox"
|
||||
/>
|
||||
<span className={css.productId}>ID : A565145</span>
|
||||
</div>
|
||||
<div className={css.productInfo}>
|
||||
<div className={css.leftSection}>
|
||||
<CustomImage
|
||||
className={css.productImage}
|
||||
src={defaultImage}
|
||||
fallbackSrc={defaultImage}
|
||||
/>
|
||||
</div>
|
||||
<div className={css.rightSection}>
|
||||
<div className={css.productNm}>
|
||||
Farmer Jon`s 25-ct Mini Bags Of Microwave Popcorn in Flavor
|
||||
Choice Area
|
||||
<>
|
||||
{Object.entries(groupedCartData).map(([partnerKey, group]) => {
|
||||
const totals = calculatePartnerTotal(group.items);
|
||||
|
||||
return (
|
||||
<Container className={css.productBox}>
|
||||
<div key={partnerKey} className={css.partnerSection}>
|
||||
{/* 파트너사 정보 - 한 번만 표시 */}
|
||||
<div className={css.productCompany}>
|
||||
<div className={css.logo}>
|
||||
<CustomImage
|
||||
className={css.img}
|
||||
src={group.partnerInfo.logo}
|
||||
fallbackSrc={defaultImage}
|
||||
/>
|
||||
</div>
|
||||
<div className={css.optionNm}>Sliver Metallic / XL</div>
|
||||
<div className={css.accountBox}>
|
||||
<span className={css.account}>$38.09</span>
|
||||
<div className={css.accountInfo}>
|
||||
<span className={css.originalAcc}>$41.99</span>
|
||||
<span className={css.optionAcc}>OPTION : $5.50</span>
|
||||
<span className={css.shippingAcc}>S&H: $5.50</span>
|
||||
<span className={css.company}>
|
||||
{group.partnerInfo.name}
|
||||
<span className={css.productEa}>
|
||||
({group.items.length} ITEM{group.items.length > 1 ? 'S' : ''})
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* 파트너사별 가격 총합 - 한 번만 표시 */}
|
||||
<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)}
|
||||
</div>
|
||||
<div className={css.rightSection}>
|
||||
Total
|
||||
<span className={css.total}>
|
||||
$<span className={css.totalAcc}>
|
||||
{totals.total.toLocaleString('en-US', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
})}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 해당 파트너사의 상품 리스트 - map으로 반복 */}
|
||||
{group.items.map((item) => (
|
||||
<div key={item.prodSno} className={css.product}>
|
||||
<div className={css.leftBox}>
|
||||
<div className={css.checkBox}>
|
||||
<TCheckBoxSquare
|
||||
className={css.customeCheckbox}
|
||||
spotlightId="productCheckbox"
|
||||
/>
|
||||
<span className={css.productId}>
|
||||
ID : {item.prdtId}
|
||||
</span>
|
||||
</div>
|
||||
<div className={css.productInfo}>
|
||||
<div className={css.leftSection}>
|
||||
<CustomImage
|
||||
className={css.productImage}
|
||||
src={item.imgUrl}
|
||||
fallbackSrc={defaultImage}
|
||||
/>
|
||||
</div>
|
||||
<div className={css.rightSection}>
|
||||
<div className={css.productNm}>
|
||||
{item.prdtNm}
|
||||
</div>
|
||||
{item.optNm && (
|
||||
<div className={css.optionNm}>{item.optNm}</div>
|
||||
)}
|
||||
<div className={css.accountBox}>
|
||||
<span className={css.account}>
|
||||
${parseFloat(item.price3 || item.price2 || 0).toFixed(2)}
|
||||
</span>
|
||||
<div className={css.accountInfo}>
|
||||
{item.price2 && (
|
||||
<span className={css.originalAcc}>
|
||||
${parseFloat(item.price2).toFixed(2)}
|
||||
</span>
|
||||
)}
|
||||
{item.price5 && parseFloat(item.price5) > 0 && (
|
||||
<span className={css.optionAcc}>
|
||||
OPTION : ${parseFloat(item.price5).toFixed(2)}
|
||||
</span>
|
||||
)}
|
||||
{item.shippingCharge && parseFloat(item.shippingCharge) > 0 && (
|
||||
<span className={css.shippingAcc}>
|
||||
S&H: ${parseFloat(item.shippingCharge).toFixed(2)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={css.eaBox}>
|
||||
<TButton
|
||||
className={classNames(
|
||||
css.minusBox,
|
||||
item.prodQty === 1 ? css.dimm : ""
|
||||
)}
|
||||
size="cartEa"
|
||||
onClick={() => handleDecreseClick(item.prodSno)}
|
||||
spotlightId={"pd_ea_decrese"}
|
||||
spotlightDisabled={item.prodQty === 1}
|
||||
/>
|
||||
<div className={css.ea}>{item.prodQty}</div>
|
||||
<TButton
|
||||
onClick={() => handleIncreseClick(item.prodSno)}
|
||||
className={css.plusBox}
|
||||
spotlightId={"pd_ea_increse"}
|
||||
size="cartEa"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={css.rightBox}>
|
||||
<TButton
|
||||
className={css.trashImg}
|
||||
size="cartTrash"
|
||||
// onClick={() => handleDeleteClick(item.prodSno)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={css.eaBox}>
|
||||
<TButton
|
||||
className={classNames(
|
||||
css.minusBox,
|
||||
pdEa === 1 ? css.dimm : ""
|
||||
)}
|
||||
size="cartEa"
|
||||
onClick={handleDecreseClick}
|
||||
spotlightId={"pd_ea_decrese"}
|
||||
spotlightDisabled={pdEa === 1 ? true : false}
|
||||
/>
|
||||
<div className={css.ea}>{pdEa}</div>
|
||||
<TButton
|
||||
onClick={handleIncreseClick}
|
||||
className={css.plusBox}
|
||||
spotlightId={"pd_ea_increse"}
|
||||
size="cartEa"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className={css.rightBox}>
|
||||
{/* 휴지통 */}
|
||||
<TButton className={css.trashImg} size="cartTrash" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default CartProduct;
|
||||
export default CartProduct;
|
||||
@@ -34,7 +34,7 @@
|
||||
}
|
||||
}
|
||||
.productPrice {
|
||||
width: 1198px;
|
||||
width: 1078px;
|
||||
height: 81px;
|
||||
padding: 20px 29px 20px 28px;
|
||||
background-color: #f2f2f2;
|
||||
|
||||
@@ -9,13 +9,14 @@ import css from './CartProductBar.module.less';
|
||||
const CartProductBar = ({ scrollOptions = {} }) => {
|
||||
const Container = SpotlightContainerDecorator("div");
|
||||
|
||||
const randomCount = useMemo(() => Math.floor(Math.random() * 3) + 1, []);
|
||||
// const randomCount = useMemo(() => Math.floor(Math.random() * 3) + 1, []);
|
||||
|
||||
return (
|
||||
<Container className={css.productContainer}>
|
||||
{Array.from({ length: randomCount }, (_, index) => (
|
||||
<CartProduct key={index} />
|
||||
))}
|
||||
<CartProduct />
|
||||
{/* {Array.from({ length: randomCount }, (_, index) => ( */}
|
||||
{/* <CartProduct key={index} /> */}
|
||||
{/* ))} */}
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
.productContainer {
|
||||
background-color: #f8f8f8;
|
||||
width: 1320px;
|
||||
width: 1200px;
|
||||
height: 100%;
|
||||
padding: 60px;
|
||||
.tScroller {
|
||||
|
||||
@@ -729,7 +729,8 @@ export default function ProductAllSection({
|
||||
<TButton
|
||||
spotlightId="detail-add-to-cart-button"
|
||||
className={css.addToCartButton}
|
||||
onClick={handleAddToCartClick}
|
||||
// onClick={handleAddToCartClick}
|
||||
onClick={handleBuyNowClick}
|
||||
onSpotlightUp={handleSpotlightUpFromBuyButtons}
|
||||
type="detail_small"
|
||||
>
|
||||
|
||||
@@ -462,21 +462,21 @@ const BuyOption = ({
|
||||
const discountRate = priceInfo?.split('|')[4];
|
||||
|
||||
// 로그 전송
|
||||
dispatch(
|
||||
sendLogTotalRecommend({
|
||||
nowMenu: nowMenu,
|
||||
productId: prdtId,
|
||||
productTitle: prdtNm,
|
||||
partner: patncNm,
|
||||
price: discountRate ? discountPrice : regularPrice,
|
||||
discount: discountRate,
|
||||
brand: brndNm,
|
||||
productOption: prodOptCval || '',
|
||||
category: catNm,
|
||||
contextName: Config.LOG_CONTEXT_NAME.DETAILPAGE,
|
||||
messageId: Config.LOG_MESSAGE_ID.ADD_TO_CART,
|
||||
})
|
||||
);
|
||||
// dispatch(
|
||||
// sendLogTotalRecommend({
|
||||
// nowMenu: nowMenu,
|
||||
// productId: prdtId,
|
||||
// productTitle: prdtNm,
|
||||
// partner: patncNm,
|
||||
// price: discountRate ? discountPrice : regularPrice,
|
||||
// discount: discountRate,
|
||||
// brand: brndNm,
|
||||
// productOption: prodOptCval || '',
|
||||
// category: catNm,
|
||||
// contextName: Config.LOG_CONTEXT_NAME.DETAILPAGE,
|
||||
// messageId: Config.LOG_MESSAGE_ID.ADD_TO_CART,
|
||||
// })
|
||||
// );
|
||||
|
||||
// 장바구니에 추가
|
||||
dispatch(
|
||||
@@ -484,9 +484,15 @@ const BuyOption = ({
|
||||
mbrNo: userNumber,
|
||||
patnrId: selectedPatnrId,
|
||||
prdtId: selectedPrdtId,
|
||||
prodOptCdCval: selectedOptions?.prodOptCdCval || null,
|
||||
prodQty: quantity,
|
||||
prodOptTpCdCval: productOptionInfos[0]?.prodOptTpCdCval,
|
||||
prodQty: String(quantity),
|
||||
prdtOpt: {
|
||||
prodOptCdCval: selectedOptions?.prodOptCdCval
|
||||
? selectedOptions.prodOptCdCval
|
||||
: "",
|
||||
prodOptCval:productOptionInfos[0]?.optNm,
|
||||
prodOptSno: productOptionInfos[0]?.prodOptSno,
|
||||
prodOptTpCdCval: productOptionInfos[0]?.prodOptTpCdCval,
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user