일반상품 옵션이 있을경우 로직 구현

This commit is contained in:
고동영
2024-04-18 18:32:43 +09:00
parent cd9396c26e
commit 0e761559e4
7 changed files with 167 additions and 129 deletions

View File

@@ -1,25 +1,17 @@
import React, {
memo,
useCallback,
useEffect,
useState,
} from 'react';
import React, { memo, useCallback, useEffect, useState } from "react";
import classNames from 'classnames';
import classNames from "classnames";
import Spottable from '@enact/spotlight/Spottable';
import Spottable from "@enact/spotlight/Spottable";
import defaultimgHorizontal
from '../../../assets/images/img-thumb-empty-hor@3x.png';
import defaultImageItem
from '../../../assets/images/img-thumb-empty-product@3x.png';
import defaultimgVertical
from '../../../assets/images/img-thumb-empty-ver@3x.png';
import IcLiveShow from '../../../assets/images/tag/tag-liveshow.png';
import usePriceInfo from '../../hooks/usePriceInfo';
import { $L } from '../../utils/helperMethods';
import CustomImage from '../CustomImage/CustomImage';
import css from './TItemCard.module.less';
import defaultimgHorizontal from "../../../assets/images/img-thumb-empty-hor@3x.png";
import defaultImageItem from "../../../assets/images/img-thumb-empty-product@3x.png";
import defaultimgVertical from "../../../assets/images/img-thumb-empty-ver@3x.png";
import IcLiveShow from "../../../assets/images/tag/tag-liveshow.png";
import usePriceInfo from "../../hooks/usePriceInfo";
import { $L } from "../../utils/helperMethods";
import CustomImage from "../CustomImage/CustomImage";
import css from "./TItemCard.module.less";
const SpottableComponent = Spottable("div");
@@ -67,6 +59,7 @@ export default memo(function TItemCard({
rank,
soldoutFlag,
spotlightId,
isSpotlightDisable,
nonPosition = false,
type = TYPES.vertical,
...rest
@@ -132,6 +125,7 @@ export default memo(function TItemCard({
onClick={_onClick}
onFocus={_onFocus}
spotlightId={spotlightId ?? "spotlightId-" + removeDotAndColon(productId)}
spotlightDisable={isSpotlightDisable}
{...rest}
>
<div className={css.imageWrap}>

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useEffect } from "react";
import React, { useCallback, useEffect, useState } from "react";
import classNames from "classnames";
@@ -59,7 +59,7 @@ export default function TPopUp({
text,
options,
optionClick,
selectedOptIdx,
selectedIndex,
...rest
}) {
useEffect(() => {
@@ -88,6 +88,7 @@ export default function TPopUp({
const _optionClick = useCallback(
(e, idx) => {
if (optionClick) {
console.log("#optionClick", optionClick);
optionClick(e, idx);
}
},
@@ -113,7 +114,7 @@ export default function TPopUp({
);
const selectedOptClick = useCallback(
(index) => (e) => {
_optionClick(e, index);
_optionClick(index);
},
[_optionClick]
);
@@ -165,7 +166,8 @@ export default function TPopUp({
)}
>
{options.map((option, index) => {
const { prodOptCval, optImgUrl, optPrc, optStkQty } = option;
const { prodOptCval, optImgUrl, optPrc, optStkQty, optNm } =
option;
const optStock = Number(optStkQty);
return (
@@ -173,20 +175,20 @@ export default function TPopUp({
{...rest}
className={classNames(
css.option,
index === selectedOptIdx && css.selectedOption,
index === selectedIndex && css.selectedOption,
index == selectedIndex && css.focused,
optStock <= 0 && css.optionSoldOut
)}
spotlightId={
index === selectedOptIdx ? "selectedOptionBtn" : null
}
onClick={optStock >= 1 && selectedOptClick(index)}
spotlightId={`selectedOptionBtn-${index}`}
onClick={selectedOptClick(index)}
key={`option: ${index}`}
spotlightDisabled={optStock && optStock <= 0}
// spotlightDisabled={optStock && optStock <= 0}
>
{optImgUrl && (
<img src={optImgUrl} alt="" className={css.img} />
)}
<span>{prodOptCval}</span>
<span>{optNm ? optNm : prodOptCval}</span>
{optPrc && optStock !== 0 && `($${optPrc})`}
</SpottableComponent>
);

View File

@@ -9,11 +9,12 @@ import {
getThemeHotelDetailInfo,
} from "../../actions/homeActions";
import { getMainCategoryDetail } from "../../actions/mainActions";
import { popPanel } from "../../actions/panelActions";
import { popPanel, resetPanels } from "../../actions/panelActions";
import { getProductGroup } from "../../actions/productActions";
import TBody from "../../components/TBody/TBody";
import THeader from "../../components/THeader/THeader";
import TPanel from "../../components/TPanel/TPanel";
import { panel_names } from "../../utils/Config";
import css from "./DetailPanel.module.less";
import GroupProduct from "./GroupProduct/GroupProduct";
import SingleProduct from "./SingleProduct/SingleProduct";
@@ -47,7 +48,9 @@ export default function ItemDetail() {
if (panels[i].name === "detailpanel") {
setSelectedPatnrId(panels[i].panelInfo.patnrId);
setSelectedPrtdId(panels[i].panelInfo.prdtId);
if (panels[0].name == "hotpickpanel") {
setSelectedCurationId(panels[i].panelInfo.curationId);
setThemeType(panels[i].panelInfo.type);
if (panels[0].name === "hotpickpanel") {
setSelectedPatnrId(panels[i].panelInfo.patnrId);
setSelectedCurationId(panels[i].panelInfo.curationId);
setThemeType(panels[i].panelInfo.type);
@@ -89,10 +92,6 @@ export default function ItemDetail() {
}, [dispatch, selectedPatnrId, selectedPrdtId, panels]);
const onClick = useCallback(() => {
setSelectedPrtdId("");
setSelectedPatnrId("");
setSelectedCurationId("");
setCategoryId("");
dispatch(popPanel());
}, [dispatch]);

View File

@@ -52,15 +52,19 @@ export default function SingleOption({
(state) => state.common.appStatus.loginUserData
);
const { loginUserData } = useSelector((state) => state.common.appStatus);
const [hasProductOptionArray, setHasProductOptionArray] = useState(true);
const [isOption, setIsOption] = useState(false);
const [promotions, setPromotions] = useState([]);
const [selectedBtnOptIdx, setSelectedBtnOptIdx] = useState(0);
const [quantity, setQuantity] = useState(1);
const [selectedCoupon, setSelectedCoupon] = useState();
const [selectedOptionIdx, setSelectedOptionsIdx] = useState([]);
const [selectedOptions, setsSelectedOptions] = useState([]);
const [selectedOptionItemIndex, setSelectedOptionItemIndex] = useState(0);
const [selectedOptions, setSelectedOptions] = useState([]);
const [couponTypes, setCouponTypes] = useState(null);
const [couponCodes, setCouponCodes] = useState("");
const [selectedOptionInfo, setSelectedOptionInfo] = useState();
const [downloadCouponArr, setDownloadCouponArr] = useState([]);
const [focusIndex, setFocusIndex] = useState(0);
const { priceInfo, shippingCharge } = productInfo || productData;
const { originalPrice, discountedPrice, discountRate } =
usePriceInfo(priceInfo) || {};
@@ -85,50 +89,43 @@ export default function SingleOption({
prdtId: selectedPrdtId,
})
);
dispatch(
getProductCouponSearch({
patnrId: selectedPatnrId,
prdtId: selectedPrdtId,
mbrNo: userInfo,
})
);
}
dispatch(
getProductCouponSearch({
patnrId: selectedPatnrId,
prdtId: selectedPrdtId,
mbrNo: userInfo,
})
);
}, [dispatch, selectedPatnrId]);
console.log("#productData", productData);
console.log("#productOptionInfos", productOptionInfos);
const handleOptionsClick = useCallback(
(e, optionValIdx) => {
setsSelectedOptions((prevOptions) => {
const updatedOptions = [...prevOptions];
updatedOptions[selectedBtnOptIdx] =
productOptionInfos[selectedBtnOptIdx].prdtOptDtl[optionValIdx];
return updatedOptions;
});
setSelectedOptionsIdx((prevOptions) => {
const updatedOptions = [...prevOptions];
updatedOptions[selectedBtnOptIdx] = optionValIdx;
return updatedOptions;
});
Spotlight.focus(`optionBtn-${selectedBtnOptIdx}`);
const handleOptionClick = useCallback(
(optionValIdx) => {
console.log("#optionValIdx", optionValIdx);
setSelectedBtnOptIdx(optionValIdx);
onClose();
},
[selectedBtnOptIdx, productOptionInfos]
[selectedBtnOptIdx]
);
const handleOptionItemClick = useCallback(
(index) => {
setSelectedOptionItemIndex(index);
onClose();
},
[selectedOptionItemIndex]
);
useEffect(() => {
if (!selectedOptionIdx || selectedOptionIdx.length < 0) {
setsSelectedOptions((prevOptions) => {
const updatedOptions = [...prevOptions];
updatedOptions[selectedBtnOptIdx] =
productOptionInfos[selectedBtnOptIdx].prdtOptDtl[0];
return updatedOptions;
});
if (productOptionInfos && productOptionInfos.length > 0) {
setSelectedOptions(
productOptionInfos[selectedBtnOptIdx].prdtOptDtl[
selectedOptionItemIndex
]
);
}
}, [selectedOptions]);
}, [selectedBtnOptIdx, selectedOptionItemIndex]);
const handleIncrement = useCallback(() => {
setQuantity(quantity + 1);
@@ -139,14 +136,17 @@ export default function SingleOption({
else setQuantity(quantity - 1);
}, [quantity]);
const handleOptionBtnClick = useCallback(
(idx) => {
const handleOptionPopUpOpen = useCallback(
(OptionInfo, isProductOptionInfoArray) => {
setSelectedOptionInfo(OptionInfo);
setHasProductOptionArray(isProductOptionInfoArray);
dispatch(setShowPopup(Config.ACTIVE_POPUP.optionPopup));
setSelectedBtnOptIdx(idx);
},
[dispatch, selectedBtnOptIdx]
);
console.log("#selectedOptionItemIndex", selectedOptionItemIndex);
// Spotlight.focus(`selectedOptionBtn-2`);
},
[dispatch, selectedOptionItemIndex, activePopup]
);
const handleLoginPopup = useCallback(() => {
if (!loginUserData.userInfo) {
dispatch(setShowPopup(Config.ACTIVE_POPUP.loginPopup));
@@ -155,20 +155,12 @@ export default function SingleOption({
pushPanel({
name: Config.panel_names.CHECKOUT_PANEL,
panelInfo: {
cartList: [
{
patnrId: selectedPatnrId,
prdtId: selectedPrdtId,
prodOptCdCval:
selectedOptions[selectedBtnOptIdx]?.prodOptCdCval,
prodQty: quantity,
},
],
// quantity: quantity,
// patnrId: selectedPatnrId,
// prdtId: selectedPrdtId,
// price: discountedPrice ? discountedPrice : originalPrice,
// selectedOption: selectedOptions,
cartList: {
patnrId: selectedPatnrId,
prdtId: selectedPrdtId,
prodOptCdCval: selectedOptions.prodOptCdCval,
prodQty: quantity,
},
},
})
);
@@ -198,25 +190,58 @@ export default function SingleOption({
}, [selectedCoupon, userInfo, couponCodes]);
const onClose = useCallback(() => {
console.log(
"########################CLOSE!!!!!!!!!!",
hasProductOptionArray
);
if (hasProductOptionArray) {
Spotlight.focus("selectedOptionBox-1");
} else {
Spotlight.focus("selectedOptionBox-0");
}
dispatch(setHidePopup());
}, [dispatch]);
}, [dispatch, productOptionInfos]);
useEffect(() => {
if (selectedCoupon) {
getCouponCode();
}
}, [selectedCoupon]);
//디테일패널 최초 진입시 옵션이 있으면 포커스 없으면 백버튼 포커스
useEffect(() => {
if (!isSpotlight) {
return;
}
if (productOptionInfos && productOptionInfos.length > 0) {
Spotlight.focus("optionBtn-0");
Spotlight.focus("selectedOptionBox-0");
if (productOptionInfos.length === 1) {
Spotlight.focus("selectedOptionBox-1");
}
} else if (productData && productData.soldoutFlag === "Y") {
Spotlight.focus("spotlightId_backBtn");
}
}, [productOptionInfos, productData]);
//옵션이 있을 경우 selectedOption에 첫번째 옵션을 강제로 담음 ( 들어오자마자 BUYNOW 클릭시 체크아웃으로 상품 넘어감 )
useEffect(() => {
if (productOptionInfos && productOptionInfos.length > 0) {
setSelectedOptions(
productOptionInfos[selectedBtnOptIdx].prdtOptDtl[
selectedOptionItemIndex
]
);
}
}, [productOptionInfos]);
useEffect(() => {
if (!isSpotlight) {
return;
}
Spotlight.focus(`selectedOptionBox-${selectedBtnOptIdx}`);
}, [selectedBtnOptIdx]);
const getCouponCode = () => {
const snoArray = [];
@@ -227,19 +252,19 @@ export default function SingleOption({
setCouponCodes(snoArray.join(", "));
};
// Option Name을 렌더링하는 함수
const renderOptionName = (optionInfo) => {
return optionInfo?.optNm || null;
};
// Option Value를 렌더링하는 함수
const renderOptionValue = (optionInfo) => {
if (
optionInfo &&
optionInfo.prdtOptDtl &&
optionInfo.prdtOptDtl.length > 0
) {
return optionInfo.prdtOptDtl[0]?.prodOptCval || null;
return (
optionInfo.prdtOptDtl[selectedOptionItemIndex]?.prodOptCval || null
);
}
return null;
};
@@ -323,24 +348,46 @@ export default function SingleOption({
<div className={css.detailContainer}>
<Container>
<TScroller verticalScrollbar="auto" className={css.detailScroll}>
<div className={css.optionLayer}>
{/* OPTION */}
<span>{$L("OPTION")}</span>
<TButton
className={css.optionBtn}
onClick={() => {
handleOptionBtnClick();
}}
>
<span className={css.optionValue}>
{productOptionInfos &&
productOptionInfos.length > 0 &&
(productOptionInfos.length > 1
? renderOptionName(productOptionInfos[0])
: renderOptionValue(productOptionInfos[0]))}
</span>
</TButton>
</div>
{productOptionInfos && productOptionInfos.length > 0 && (
<>
{productOptionInfos.length !== 1 && (
<div className={css.optionLayer}>
{/* OPTION 1 */}
<span>{$L("OPTION")}</span>
<TButton
className={css.optionBtn}
onClick={() =>
handleOptionPopUpOpen(productOptionInfos, true)
}
spotlightId={"selectedOptionBox-0"}
>
<span className={css.optionValue}>
{renderOptionName(productOptionInfos[selectedBtnOptIdx])}
</span>
</TButton>
</div>
)}
<div className={css.optionLayer}>
{/* OPTION 2 */}
<span>{$L("OPTION")}</span>
<TButton
className={css.optionBtn}
onClick={() =>
handleOptionPopUpOpen(
productOptionInfos[selectedBtnOptIdx]?.prdtOptDtl,
false
)
}
spotlightId={"selectedOptionBox-1"}
>
<span className={css.optionValue}>
{renderOptionValue(productOptionInfos[selectedBtnOptIdx])}
</span>
</TButton>
</div>
</>
)}
{/* QUANTITY */}
<Container className={css.quantityLayer}>
@@ -454,23 +501,19 @@ export default function SingleOption({
{activePopup === Config.ACTIVE_POPUP.optionPopup && (
<TPopUp
kind="optionPopup"
options={
productOptionInfos &&
productOptionInfos[selectedBtnOptIdx].prdtOptDtl
}
options={selectedOptionInfo}
onClose={onClose}
open={popupVisible}
optionClick={handleOptionsClick}
optionClick={
hasProductOptionArray ? handleOptionClick : handleOptionItemClick
}
hasButton
hasText
title={$L(productOptionInfos[selectedBtnOptIdx].optNm.toUpperCase())}
title={$L("OPTION")}
button1Text={$L("CLOSE")}
className={css.productOptionPopup}
selectedOptIdx={
selectedOptions[selectedBtnOptIdx] === null ||
selectedOptions[selectedBtnOptIdx] === undefined
? 0
: selectedOptions[selectedBtnOptIdx]
selectedIndex={
hasProductOptionArray ? selectedBtnOptIdx : selectedOptionItemIndex
}
/>
)}

View File

@@ -46,6 +46,7 @@ export default function SingleProduct({
<SingleOption
selectedPatnrId={selectedPatnrId}
selectedPrdtId={selectedPrdtId}
isSpotlight
/>
</ProductOption>
</div>

View File

@@ -96,6 +96,7 @@ export default function YouMayLike({ isUnable, lgCatCd }) {
offerInfo={offerInfo}
productName={prdtNm}
onClick={handleItemClick}
isSpotlightDisable
/>
);
},

View File

@@ -172,8 +172,6 @@ export default function ThemeIndicator({
);
}, [dispatch, productInfo, selectedIndex]);
console.log("#productInfo", productInfo[selectedIndex]);
console.log("#selectedIndex", selectedIndex);
const renderThumbnail = useCallback(() => {
const hasMediaUrl = getProductMediaUrlStatus();
return (