[DetailPanel] 결제가능상품 옵션 선택 시나리오 수정

This commit is contained in:
고동영
2024-06-07 16:39:59 +09:00
parent 990ab6a0ce
commit b333168c7c
6 changed files with 101 additions and 44 deletions

View File

@@ -204,5 +204,7 @@
"Excellent": "Excellent", "Excellent": "Excellent",
"TSV": "TSV", "TSV": "TSV",
"Free S&H": "Free S&H", "Free S&H": "Free S&H",
"Big Sale": "Big Sale" "Big Sale": "Big Sale",
"SELECT": "SELECT",
"Please select Option": "Please select Option"
} }

View File

@@ -44,6 +44,7 @@ function TButtonBase({
ariaLabel, ariaLabel,
children, children,
spotlightId, spotlightId,
spotlightDisabled = false,
className, className,
onClick, onClick,
onBlur, onBlur,
@@ -112,6 +113,7 @@ function TButtonBase({
onClick={_onClick} onClick={_onClick}
role="button" role="button"
aria-label={ariaLabel} aria-label={ariaLabel}
spotlightDisabled={spotlightDisabled}
> >
{withMarquee ? ( {withMarquee ? (
<Marquee className={css.marquee} marqueeOn="focus"> <Marquee className={css.marquee} marqueeOn="focus">

View File

@@ -56,6 +56,7 @@ export default function TPopUp({
onClose, onClose,
hasButton, hasButton,
hasText, hasText,
hasOnClose = false,
hasIndicator, hasIndicator,
hasLogo, hasLogo,
hasThumbnail, hasThumbnail,
@@ -279,7 +280,7 @@ export default function TPopUp({
{button1Text} {button1Text}
</TButton> </TButton>
)} )}
{button2Text && ( {button2Text && !hasOnClose && (
<TButton spotlightId="tPopupBtn2" onClick={onClose} role="button"> <TButton spotlightId="tPopupBtn2" onClick={onClose} role="button">
{button2Text} {button2Text}
</TButton> </TButton>

View File

@@ -1,4 +1,10 @@
import React, { useCallback, useEffect, useRef, useState } from "react"; import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import classNames from "classnames"; import classNames from "classnames";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
@@ -24,7 +30,6 @@ import TPopUp from "../../../components/TPopUp/TPopUp";
import TQRCode from "../../../components/TQRCode/TQRCode"; import TQRCode from "../../../components/TQRCode/TQRCode";
import TScroller from "../../../components/TScroller/TScroller"; import TScroller from "../../../components/TScroller/TScroller";
import TVirtualGridList from "../../../components/TVirtualGridList/TVirtualGridList"; import TVirtualGridList from "../../../components/TVirtualGridList/TVirtualGridList";
import usePriceInfo from "../../../hooks/usePriceInfo"; import usePriceInfo from "../../../hooks/usePriceInfo";
import * as Config from "../../../utils/Config"; import * as Config from "../../../utils/Config";
import { $L } from "../../../utils/helperMethods"; import { $L } from "../../../utils/helperMethods";
@@ -44,6 +49,8 @@ export default function SingleOption({
isSpotlight, isSpotlight,
selectedPatnrId, selectedPatnrId,
selectedPrdtId, selectedPrdtId,
selectedIndex,
type,
}) { }) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const productOptionInfos = useSelector((state) => state.product.prdtOptInfo); const productOptionInfos = useSelector((state) => state.product.prdtOptInfo);
@@ -64,8 +71,10 @@ export default function SingleOption({
const [quantity, setQuantity] = useState(1); const [quantity, setQuantity] = useState(1);
const [selectedCouponIndex, setSelectedCouponIndex] = useState(0); const [selectedCouponIndex, setSelectedCouponIndex] = useState(0);
const [selectedCoupon, setSelectedCoupon] = useState(); const [selectedCoupon, setSelectedCoupon] = useState();
const [isOptionValue, setIsOptionValue] = useState(false);
const [isOptionSelect, setIsOptionSelect] = useState(false);
const [selectedOptionItemIndex, setSelectedOptionItemIndex] = useState(0); const [selectedOptionItemIndex, setSelectedOptionItemIndex] = useState(0);
const [selectedOptions, setSelectedOptions] = useState([]); const [selectedOptions, setSelectedOptions] = useState();
const [couponTypes, setCouponTypes] = useState(null); const [couponTypes, setCouponTypes] = useState(null);
const [couponCodes, setCouponCodes] = useState(""); const [couponCodes, setCouponCodes] = useState("");
const [selectedOptionInfo, setSelectedOptionInfo] = useState(); const [selectedOptionInfo, setSelectedOptionInfo] = useState();
@@ -109,33 +118,49 @@ export default function SingleOption({
); );
}, [dispatch, selectedPatnrId, selectedPrdtId, productData]); }, [dispatch, selectedPatnrId, selectedPrdtId, productData]);
useEffect(() => {
if (type !== "theme") {
return;
}
if (selectedOptions) {
setSelectedBtnOptIdx(0);
}
setSelectedOptions();
setIsOptionValue(false);
setSelectedOptionItemIndex(0);
setIsOptionSelect(false);
}, [selectedIndex, type]);
const handleOptionClick = useCallback( const handleOptionClick = useCallback(
(optionValIdx) => { (optionValIdx) => {
setSelectedBtnOptIdx(optionValIdx); setSelectedBtnOptIdx(optionValIdx);
setSelectedOptionItemIndex(0); setSelectedOptionItemIndex(0);
setSelectedOptions(productOptionInfos[optionValIdx].prdtOptDtl[0]);
setIsOptionValue(false);
setIsOptionSelect(true);
onClose(); onClose();
}, },
[selectedBtnOptIdx] [productOptionInfos, selectedOptionItemIndex]
); );
const handleOptionItemClick = useCallback( const handleOptionItemClick = useCallback(
(index) => { (index) => {
setSelectedOptionItemIndex(index); setSelectedOptionItemIndex(index);
setSelectedOptions(
productOptionInfos[selectedBtnOptIdx].prdtOptDtl[index]
);
setIsOptionValue(true);
onClose(); onClose();
}, },
[selectedOptionItemIndex] [productOptionInfos, selectedBtnOptIdx]
); );
useEffect(() => { const loginPopupText = useMemo(() => {
if (productOptionInfos && productOptionInfos.length > 0) { if (!selectedOptions || (!isOptionValue && isOptionSelect)) {
setSelectedOptions( return $L("Please select Option");
productOptionInfos[selectedBtnOptIdx].prdtOptDtl[
selectedOptionItemIndex
]
);
} }
}, [selectedBtnOptIdx, selectedOptionItemIndex, productOptionInfos]); return $L("Would you like to sign in?");
}, [selectedOptions]);
const handleIncrement = useCallback(() => { const handleIncrement = useCallback(() => {
setQuantity(quantity + 1); setQuantity(quantity + 1);
}, [quantity]); }, [quantity]);
@@ -146,12 +171,26 @@ export default function SingleOption({
}, [quantity]); }, [quantity]);
const handleOptionPopUpOpen = useCallback( const handleOptionPopUpOpen = useCallback(
(OptionInfo, isProductOptionInfoArray) => { (optionInfo, isProductOptionInfoArray) => {
setSelectedOptionInfo(OptionInfo); if (
productOptionInfos.length !== 1 &&
!isOptionSelect &&
!isProductOptionInfoArray
) {
return dispatch(setShowPopup(Config.ACTIVE_POPUP.loginPopup));
}
setSelectedOptionInfo(optionInfo);
setHasProductOptionArray(isProductOptionInfoArray); setHasProductOptionArray(isProductOptionInfoArray);
dispatch(setShowPopup(Config.ACTIVE_POPUP.optionPopup)); dispatch(setShowPopup(Config.ACTIVE_POPUP.optionPopup));
}, },
[dispatch, activePopup, selectedOptionItemIndex] [
dispatch,
isOptionSelect,
activePopup,
productOptionInfos,
selectedOptionItemIndex,
]
); );
const handleQRCodePopUpOpen = useCallback(() => { const handleQRCodePopUpOpen = useCallback(() => {
@@ -180,6 +219,14 @@ export default function SingleOption({
}, [activePopup, selectedBtnOptIdx, selectedOptionItemIndex]); }, [activePopup, selectedBtnOptIdx, selectedOptionItemIndex]);
const handleLoginPopup = useCallback(() => { const handleLoginPopup = useCallback(() => {
console.log("#selectedOptions", productOptionInfos);
if (productOptionInfos && !isOptionValue && isOptionSelect) {
return dispatch(setShowPopup(Config.ACTIVE_POPUP.loginPopup));
}
if (productOptionInfos && !selectedOptions) {
dispatch(setShowPopup(Config.ACTIVE_POPUP.loginPopup));
return;
}
if (!loginUserData.userNumber) { if (!loginUserData.userNumber) {
dispatch(setShowPopup(Config.ACTIVE_POPUP.loginPopup)); dispatch(setShowPopup(Config.ACTIVE_POPUP.loginPopup));
} else { } else {
@@ -190,14 +237,22 @@ export default function SingleOption({
cartList: { cartList: {
patnrId: selectedPatnrId, patnrId: selectedPatnrId,
prdtId: selectedPrdtId, prdtId: selectedPrdtId,
prodOptCdCval: selectedOptions.prodOptCdCval, prodOptCdCval: selectedOptions?.prodOptCdCval,
prodQty: quantity, prodQty: quantity,
}, },
}, },
}) })
); );
} }
}, [dispatch, quantity, discountedPrice, selectedBtnOptIdx, selectedOptions]); }, [
dispatch,
isOptionValue,
isOptionSelect,
quantity,
discountedPrice,
selectedBtnOptIdx,
selectedOptions,
]);
const handleCouponClick = useCallback( const handleCouponClick = useCallback(
(idx, promotion) => { (idx, promotion) => {
@@ -260,17 +315,6 @@ export default function SingleOption({
} }
}, [productOptionInfos, productData]); }, [productOptionInfos, productData]);
//옵션이 있을 경우 selectedOption에 첫번째 옵션을 강제로 담음 ( 들어오자마자 BUYNOW 클릭시 체크아웃으로 상품 넘어감 )
useEffect(() => {
if (productOptionInfos && productOptionInfos.length > 0) {
setSelectedOptions(
productOptionInfos[selectedBtnOptIdx].prdtOptDtl[
selectedOptionItemIndex
]
);
}
}, [productOptionInfos]);
const getCouponCode = () => { const getCouponCode = () => {
const snoArray = []; const snoArray = [];
@@ -281,24 +325,29 @@ export default function SingleOption({
setCouponCodes(snoArray.join(", ")); setCouponCodes(snoArray.join(", "));
}; };
const renderOptionName = (optionInfo) => { const renderOptionName = useCallback(() => {
return optionInfo?.optNm || null; if (selectedOptions) {
}; return productOptionInfos[selectedBtnOptIdx]?.optNm || null;
}
return $L("SELECT");
}, [productOptionInfos, selectedOptions, selectedBtnOptIdx]);
const renderOptionValue = useCallback( const renderOptionValue = useCallback(
(optionInfo) => { (optionInfo) => {
if ( if (
optionInfo && optionInfo &&
optionInfo.prdtOptDtl && optionInfo.prdtOptDtl &&
optionInfo.prdtOptDtl.length > 0 optionInfo.prdtOptDtl.length > 0 &&
isOptionValue
) { ) {
return ( return (
optionInfo.prdtOptDtl[selectedOptionItemIndex]?.prodOptCval || null optionInfo.prdtOptDtl[selectedOptionItemIndex]?.prodOptCval || null
); );
} }
return null; return $L("SELECT");
}, },
[selectedOptionItemIndex] [selectedOptions, isOptionValue, selectedOptionItemIndex]
); );
const renderItem = useCallback( const renderItem = useCallback(
@@ -406,7 +455,7 @@ export default function SingleOption({
spotlightId={"selectedOptionBox-0"} spotlightId={"selectedOptionBox-0"}
> >
<span className={css.optionValue}> <span className={css.optionValue}>
{renderOptionName(productOptionInfos[selectedBtnOptIdx])} {renderOptionName()}
</span> </span>
</TButton> </TButton>
</div> </div>
@@ -424,6 +473,7 @@ export default function SingleOption({
) )
} }
spotlightId={"selectedOptionBox-1"} spotlightId={"selectedOptionBox-1"}
spotlightDisabled={productOptionInfos.length === 1}
> >
<span className={css.optionValue}> <span className={css.optionValue}>
{renderOptionValue(productOptionInfos[selectedBtnOptIdx])} {renderOptionValue(productOptionInfos[selectedBtnOptIdx])}
@@ -532,15 +582,15 @@ export default function SingleOption({
kind="textPopup" kind="textPopup"
hasText hasText
open={popupVisible} open={popupVisible}
text={$L("Would you like to sign in?")} text={loginPopupText}
hasButton hasButton
hasOnClose={!selectedOptions || (!isOptionValue && isOptionSelect)}
button1Text={$L("OK")} button1Text={$L("OK")}
button2Text={$L("CANCEL")} button2Text={$L("CANCEL")}
onClick={handleQRCodePopUpOpen} onClick={handleQRCodePopUpOpen}
onClose={onClose} onClose={onClose}
></TPopUp> ></TPopUp>
)} )}
{/* SHOPTIME OPTION POPUP */} {/* SHOPTIME OPTION POPUP */}
{activePopup === Config.ACTIVE_POPUP.optionPopup && ( {activePopup === Config.ACTIVE_POPUP.optionPopup && (
<TPopUp <TPopUp

View File

@@ -4,14 +4,14 @@ import { useSelector } from "react-redux";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator"; import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import useLogService from "../../../hooks/useLogService";
import { LOG_MENU, LOG_TP_NO } from "../../../utils/Config";
import { formatGMTString } from "../../../utils/helperMethods";
import Indicator from "../components/indicator/Indicator"; import Indicator from "../components/indicator/Indicator";
import IndicatorOptions from "../components/indicator/IndicatorOptions"; import IndicatorOptions from "../components/indicator/IndicatorOptions";
import ProductOption from "../components/ProductOption"; import ProductOption from "../components/ProductOption";
import SingleOption from "./SingleOption"; import SingleOption from "./SingleOption";
import css from "./SingleProduct.module.less"; import css from "./SingleProduct.module.less";
import useLogService from "../../../hooks/useLogService";
import { LOG_MENU, LOG_TP_NO } from "../../../utils/Config";
import { formatGMTString } from "../../../utils/helperMethods";
const Container = SpotlightContainerDecorator( const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused", preserveld: true }, { enterTo: "last-focused", preserveld: true },
@@ -152,6 +152,7 @@ export default function SingleProduct({
productInfo={productData} productInfo={productData}
selectedPatnrId={selectedPatnrId} selectedPatnrId={selectedPatnrId}
selectedPrdtId={selectedPrdtId} selectedPrdtId={selectedPrdtId}
selectedIndex={selectedIndex}
soldoutFlag={isProductSoldOut} soldoutFlag={isProductSoldOut}
/> />
</ProductOption> </ProductOption>

View File

@@ -16,6 +16,7 @@ export default function ThemeSingleOption({
thumbnailUrls={productInfo?.thumbnailUrl} thumbnailUrls={productInfo?.thumbnailUrl}
> >
<SingleOption <SingleOption
type="theme"
selectedPatnrId={productData?.themeInfo[0]?.patnrId} selectedPatnrId={productData?.themeInfo[0]?.patnrId}
selectedPrdtId={productInfo[selectedIndex]?.prdtId} selectedPrdtId={productInfo[selectedIndex]?.prdtId}
productInfo={productInfo[selectedIndex]} productInfo={productInfo[selectedIndex]}