[OptionCommon] popup 컨트롤 이벤트 핸들러 추가(수정 예정), Incre/Decre 버튼 추가, assets > btn 이미지 추가, 버튼 별 PopUp 연결

This commit is contained in:
jiwon93.son
2024-02-27 09:50:27 +09:00
parent ceb4aaa254
commit 19d43cc9fb
10 changed files with 404 additions and 73 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -1,14 +1,21 @@
import React, { useCallback, useEffect, useState } from "react";
import classNames from "classnames";
import { useDispatch, useSelector } from "react-redux";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import Spottable from "@enact/spotlight/Spottable";
import { setHidePopup, setShowPopup } from "../../../../actions/commonActions";
import {
getProductCouponInfo,
getProductCouponSearch,
} from "../../../../actions/couponActions";
import { getProductOption } from "../../../../actions/productActions";
import TButton from "../../../../components/TButton/TButton";
import TPopUp from "../../../../components/TPopUp/TPopUp";
import TScroller from "../../../../components/TScroller/TScroller";
import usePriceInfo from "../../../../hooks/usePriceInfo";
import { $L } from "../../../../utils/helperMethods";
import css from "./OptionCommon.module.less";
@@ -17,64 +24,121 @@ const Container = SpotlightContainerDecorator(
"div"
);
const ACTIVE_POPUP = {
options: "options",
favorite: "favorite",
coupon: "coupon",
};
export default function OptionCommon({ selectedPatnrId, selectedPardtId }) {
const dispatch = useDispatch();
const productOptionInfos = useSelector((state) => state.product.prdtOptInfo);
const [selectedIndex, setSelectedIndex] = useState(0);
const [optionPopupOpen, setOptionPopupOpen] = useState(false);
const [secondOptionOpen, setSecondOptionOpen] = useState(false);
useEffect(() => {
dispatch(
getProductOption({
patnrId: selectedPatnrId,
prdtId: selectedPardtId,
})
);
}, [dispatch]);
const handleClose = useCallback(() => {
setOptionPopupOpen(false);
}, [optionPopupOpen]);
const handleOptionClick = useCallback(
(idx) => {
idx === 0 ? setOptionPopupOpen(true) : setSecondOptionOpen(true);
},
[productOptionInfos]
const productInfos = useSelector((state) => state.main.productData);
const popupVisible = useSelector((state) => state.common.popupVisible);
const couponInfos = useSelector(
(state) => state.coupon.productCouponSearchData
);
const [selectedIndex, setSelectedIndex] = useState(0);
const [quantity, setQuantity] = useState(1);
const [activePopup, setActivePopup] = useState(null);
const [couponTypes, setCouponTypes] = useState(null);
const { priceInfo, shippingCharge, favorYn } = productInfos;
const { originalPrice, discountedPrice, discountRate } =
usePriceInfo(priceInfo) || {};
const promotions = [$L("SHOPTIME PROMOTION"), $L("SPECIAL PROMOTION")];
const promotionDesc = $L("Coupon only applicable to this product!");
useEffect(() => {
if (selectedPardtId && selectedPatnrId) {
dispatch(
getProductOption({
patnrId: selectedPatnrId,
prdtId: selectedPardtId,
})
);
dispatch(
getProductCouponSearch({
// patnrId: selectedPatnrId,
// prdtId: selectedPardtId,
patnrId: 11,
prdtId: 7280567,
})
);
dispatch(
getProductCouponInfo({
patnrId: selectedPatnrId,
prdtId: selectedPardtId,
})
);
}
}, [dispatch, selectedPardtId, selectedPatnrId]);
const handleOptionClick = useCallback(() => {}, []);
const handleIncrement = useCallback(() => {
setQuantity(quantity + 1);
}, [quantity]);
const handlDecrement = useCallback(() => {
if (quantity <= 1) setQuantity(1);
else setQuantity(quantity - 1);
}, [quantity]);
const handleFavoriteClick = useCallback(() => {
// TODO : 찜 로직
setActivePopup(ACTIVE_POPUP.favorite);
dispatch(setShowPopup());
}, [dispatch]);
const handleCouponClick = useCallback(
(idx) => {
setActivePopup(ACTIVE_POPUP.coupon);
setCouponTypes(idx);
dispatch(setShowPopup());
},
[dispatch]
);
const onClose = useCallback(() => {
dispatch(setHidePopup());
setActivePopup(null);
}, [dispatch]);
// console.log("#couponInfos", couponInfos);
return (
<Container className={css.detailContainer}>
<TScroller verticalScrollbar="auto" className={css.detailScroll}>
{productOptionInfos &&
productOptionInfos.length > 0 &&
productOptionInfos.map((option, idx) => {
const {
cntryCd,
concProdOptSno,
optNm,
patnrId,
prdtId,
prodOptSno,
prodOptTpCdCval,
prdtOptDtl,
} = option;
return (
<div key={`option: ${idx}`} className={css.optionLayer}>
<span>{$L(optNm.toUpperCase())}</span>
<TButton
className={css.optionBtn}
onClick={() => {
handleOptionClick(idx);
}}
>
<span className={css.optionValue}>
{prdtOptDtl[0].prodOptCval}
</span>
</TButton>
<TPopUp
<div className={css.detailContainer}>
<Container>
<TScroller verticalScrollbar="auto" className={css.detailScroll}>
{productOptionInfos &&
productOptionInfos.length > 0 &&
productOptionInfos.map((option, idx) => {
const {
cntryCd,
concProdOptSno,
optNm,
patnrId,
prdtId,
prodOptSno,
prodOptTpCdCval,
prdtOptDtl,
} = option;
return (
<div key={`option: ${idx}`} className={css.optionLayer}>
<span>{$L(optNm.toUpperCase())}</span>
<TButton
className={css.optionBtn}
onClick={() => {
handleOptionClick(idx);
}}
>
<span className={css.optionValue}>
{prdtOptDtl[0].prodOptCval}
</span>
</TButton>
{/* <TPopUp
kind={"optionPopup"}
options={
productOptionInfos && productOptionInfos[idx].prdtOptDtl
@@ -90,26 +154,122 @@ export default function OptionCommon({ selectedPatnrId, selectedPardtId }) {
button1Text={$L("CLOSE")}
selectedOptionIdx={selectedIndex}
setSelectedOptionIdx={setSelectedIndex}
/>
</div>
);
})}
</TScroller>
<div className={css.detailBottomLayer}>
<div className={css.leftLayer}>
<span>SHOPTIME PROMOTION</span>
<span>Coupon only applicable to this product!</span>
/> */}
</div>
);
})}
{/* QUANTITY */}
<Container className={css.quantityLayer}>
<span>{$L("QUANTITY")}</span>
<div className={css.wrapper}>
<TButton
className={classNames(
css.quantityBtn,
css.decreaseBtn,
quantity === 1 && css.decreaseDimBtn
)}
onClick={handlDecrement}
/>
<span>{quantity}</span>
<TButton
className={classNames(css.quantityBtn, css.increaseBtn)}
onClick={handleIncrement}
/>
</div>
</Container>
</TScroller>
</Container>
{/* COUPON */}
{promotions.map((promotion, idx) => {
return (
<Container className={css.detailBottomLayer} key={`coupon: ${idx}`}>
<div className={css.leftLayer}>
<span className={css.promotionName}>{promotion}</span>
<span className={css.promotionDesc}>{promotionDesc}</span>
</div>
<TButton
className={css.promotionBtn}
onClick={() => {
handleCouponClick(idx);
}}
>
{$L("COUPON")}
</TButton>
</Container>
);
})}
{/* QVC Price */}
{originalPrice && discountedPrice && (
<div
className={
originalPrice === discountedPrice
? css.notDiscountedPriceLayer
: css.discountedPriceLayer
}
>
<span>{$L("QVC Price")}</span>
<div className={css.priceWrapper}>
{discountedPrice !== originalPrice && (
<span className={css.discountRateTag}>{discountRate}</span>
)}
<span className={css.discountedPrice}>{discountedPrice}</span>
{discountedPrice !== originalPrice && (
<span className={css.originalPrice}>{originalPrice}</span>
)}
</div>
</div>
<TButton>COUPON</TButton>
</div>
<div>
<span>{$L("QVC Price")}</span>
<span></span>
</div>
<div>
<span>{$L("Shipping Free")}</span>
<span></span>
</div>
</Container>
)}
{shippingCharge && (
<div className={css.shippingLayer}>
<span>{$L("Shipping Free")}</span>
<span>{shippingCharge}</span>
</div>
)}
{/* BYU NOW & FAVORITE */}
<Container className={css.bottomBtnLayer}>
<TButton className={css.buyNowBtn}>{$L("BUY NOW")}</TButton>
<TButton className={css.favoriteBtn} onClick={handleFavoriteClick} />
</Container>
{/* COUPON POPUP */}
{activePopup && activePopup === "coupon" && (
<TPopUp
kind="couponPopup"
className={css.couponContainer}
hasText
title={
couponTypes === 0
? $L("SHOPTIME PROMOTION")
: $L("SPECIAL PROMOTION")
}
text={couponTypes === 0 ? promotions[0] : promotions[1]}
open={ACTIVE_POPUP.coupon && popupVisible}
onClose={onClose}
hasButton
button1Text={$L("CLOSE")}
button2Text={$L("DOWNLOAD ALL")}
>
<div className={css.itemContainer}>
<div className={css.couponItem}></div>
</div>
</TPopUp>
)}
{/* FAVORITE POPUP */}
{activePopup && activePopup === "favorite" && (
<TPopUp
kind="textPopup"
open={ACTIVE_POPUP.favorite && popupVisible}
onClose={onClose}
hasButton
button1Text={$L("OK")}
hasText
text={
favorYn && favorYn === "N"
? $L("Added to My Favorites List")
: $L("Canceled from My Favorites List")
}
/>
)}
</div>
);
}

View File

@@ -54,5 +54,176 @@
}
}
}
// QUANTITY
.quantityLayer {
.flex(@justifyCenter:space-between);
.font(@baseFontBold,@fontSize:24px);
color: @COLOR_GRAY05;
margin-bottom: 20px;
.wrapper {
min-width: 560px;
.flex(@justifyCenter:space-between);
}
.quantityBtn {
min-width: 90px;
background-color: @COLOR_WHITE;
color: @COLOR_GRAY03;
position: relative;
&:focus {
color: @PRIMARY_COLOR_RED;
&::after {
.focused(@boxShadow: 22px, @borderRadius: 12px);
.imgElement(42px, 42px, right 26px, center);
}
}
&.increaseBtn {
background-image: url(../../../../../assets/images/btn/btn-quantity-increase-nor@3x.png);
.imgElement(90px, 90px, center, center);
&:focus {
background-image: url(../../../../../assets/images/btn/btn-quantity-increase-foc@3x.png);
.imgElement(90px, 90px, center, center);
}
}
&.decreaseBtn {
background-image: url(../../../../../assets/images/btn/btn-quantity-decrease-nor@3x.png);
.imgElement(90px, 90px, center, center);
&:focus {
background-image: url(../../../../../assets/images/btn/btn-quantity-decrease-foc@3x.png);
.imgElement(90px, 90px, center, center);
}
}
&.decreaseDimBtn {
background-image: url(../../../../../assets/images/btn/btn-quantity-decrease-dim@3x.png);
.imgElement(90px, 90px, center, center);
opacity: 0.3;
}
}
}
}
// COUPON
.detailBottomLayer {
width: 100%;
margin-top: 27px;
.flex(@justifyCenter:space-between);
.leftLayer {
.flex(@direction:column, @justifyCenter:center,@alignCenter:flex-start);
.promotionName {
color: @COLOR_GRAY05;
.font(@baseFontBold,@fontSize:24px);
}
.promotionDesc {
color: @COLOR_GRAY03;
.font(@baseFont,@fontSize:24px);
}
}
.promotionBtn {
min-width: 144px;
height: 60px;
.font(@baseFontBold,@fontSize:24px);
line-height: 60px;
border-radius: 6px;
background: @COLOR_GRAY03;
position: relative;
&:focus {
background: @PRIMARY_COLOR_RED;
}
}
}
.discountedPriceLayer {
.flex(@justifyCenter:space-between);
.font(@baseFontBold,@fontSize:36px);
color: @COLOR_GRAY07;
margin-top: 31px;
.priceWrapper {
.flex();
}
.discountRateTag {
padding: 0 12px;
background: #f00;
color: @COLOR_WHITE;
.font(@baseFontBold,@fontSize:24px);
text-align: center;
border-radius: 6px;
height: 42px;
line-height: 42px;
}
.discountedPrice {
.font(@baseFontBold,@fontSize:44px);
line-height: 1.14;
color: @PRIMARY_COLOR_RED;
margin-left: 12px;
}
.originalPrice {
.font(@baseFont,@fontSize:24px);
color: @COLOR_GRAY03;
text-decoration: line-through;
margin-left: 9px;
}
}
.notDiscountedPriceLayer {
.flex(@justifyCenter:space-between);
.font(@baseFontBold,@fontSize:36px);
color: @COLOR_GRAY07;
margin-top: 31px;
.priceWrapper {
.flex();
}
.discountedPrice {
.font(@baseFontBold,@fontSize:44px);
line-height: 1.14;
color: @PRIMARY_COLOR_RED;
margin-left: 12px;
}
}
.shippingLayer {
width: 100%;
.flex(@justifyCenter:space-between);
margin-top: 13px;
> span {
.font(@baseFont,@fontSize:24px);
line-height: 1.33;
color: @COLOR_GRAY03;
}
}
.bottomBtnLayer {
margin-top: 24px;
position: relative;
.flex(@justifyCenter:space-between);
.buyNowBtn {
min-width: 756px;
height: 78px;
}
.favoriteBtn {
min-width: 78px;
height: 78px;
background-image: url(../../../../../assets/images/icons/ic-heart-nor@3x.png);
.imgElement(54px, 54px, center, center);
}
}
.itemContainer {
background: #f00;
width: 440px;
height: 320px;
.couponItem {
width: 440px;
height: 320px;
position: relative;
background: yellow;
}
}
}

View File

@@ -23,7 +23,7 @@ export default function ProductOption({ selectedPatnrId, selectedPardtId }) {
</div>
<div className={css.title}>{$L(prdtNm)}</div>
<div className={css.bottomLayer}>
{revwGrd && <StarRating rating={revwGrd} />}
<div>{revwGrd && <StarRating rating={revwGrd} />}</div>
<ProductTag />
</div>
</div>