테마전시상품 디테일페이지 구현

This commit is contained in:
고동영
2024-03-21 17:52:28 +09:00
parent a536e9b10e
commit c410234915
20 changed files with 863 additions and 854 deletions

View File

@@ -23,15 +23,17 @@ export default function ItemDetail() {
const [selectedPatnrId, setSelectedPatnrId] = useState("");
const [selectedPrdtId, setSelectedPrtdId] = useState("");
const [selectedCurationId, setSelectedCurationId] = useState("");
const [themeType, setThemeType] = useState("");
const [selectedIndex, setSelectedIndex] = useState(0);
const productData = useSelector((state) => state.main.productData);
const panels = useSelector((state) => state.panels.panels);
const hotelData = useSelector((state) => state.home.hotelData);
const productInfo = useSelector(
(state) => state.home.themeCurationDetailInfoData
);
const dispatch = useDispatch();
console.log("#hotelData", hotelData);
const getPanelInfo = () => {
if (panels) {
for (let i = 0; i < panels.length; i++) {
@@ -41,6 +43,7 @@ export default function ItemDetail() {
if (panels[0].name == "hotpickpanel") {
setSelectedPatnrId(panels[i].panelInfo.patnrId);
setSelectedCurationId(panels[i].panelInfo.curationId);
setThemeType(panels[i].panelInfo.type);
}
}
}
@@ -50,16 +53,18 @@ export default function ItemDetail() {
useEffect(() => {
getPanelInfo();
console.log("#panels ", panels);
if (selectedCurationId) {
if (themeType === "hotel") {
dispatch(
getThemeCurationDetailInfo({
getThemeHotelDetailInfo({
patnrId: selectedPatnrId,
curationId: selectedCurationId,
})
);
}
if (themeType === "theme") {
dispatch(
getThemeHotelDetailInfo({
getThemeCurationDetailInfo({
patnrId: selectedPatnrId,
curationId: selectedCurationId,
})
@@ -81,7 +86,7 @@ export default function ItemDetail() {
})
);
}
}, [dispatch, panels, selectedPatnrId, selectedPrdtId, selectedCurationId]);
}, [dispatch, selectedPatnrId]);
const onClick = () => {
dispatch(popPanel());
@@ -92,7 +97,8 @@ export default function ItemDetail() {
className={css.header}
title={
(selectedPrdtId && productData?.prdtNm) ||
(selectedCurationId && hotelData && hotelData?.hotelInfo.curationNm)
(themeType === "hotel" && hotelData?.hotelInfo.curationNm) ||
(themeType === "theme" && productInfo[selectedIndex]?.prdtNm)
}
onBackButton
onClick={onClick}
@@ -131,10 +137,11 @@ export default function ItemDetail() {
setSelectedIndex={setSelectedIndex}
selectedCurationId={selectedCurationId}
selectedPatnrId={selectedPatnrId}
themeType={themeType}
/>
)}
</TBody>
{selectedPrdtId && <YouMayLike />}
{(selectedPrdtId || themeType === "theme") && <YouMayLike />}
</TPanel>
);
}

View File

@@ -29,4 +29,6 @@
position: relative;
display: flex;
justify-content: space-between;
padding-left: 120px;
}

View File

@@ -1,38 +1,26 @@
import React, {
useCallback,
useEffect,
useState,
} from 'react';
import React, { useCallback, useEffect, useState } 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 {
setHidePopup,
setShowPopup,
} from '../../../actions/commonActions';
import { getProductCouponSearch } from '../../../actions/couponActions';
import { pushPanel } from '../../../actions/panelActions';
import { getProductOption } from '../../../actions/productActions';
import TButton from '../../../components/TButton/TButton';
import TPopUp from '../../../components/TPopUp/TPopUp';
import TScroller from '../../../components/TScroller/TScroller';
import TVirtualGridList
from '../../../components/TVirtualGridList/TVirtualGridList';
import usePriceInfo from '../../../hooks/usePriceInfo';
import * as Config from '../../../utils/Config';
import { $L } from '../../../utils/helperMethods';
import { SpotlightIds } from '../../../utils/SpotlightIds';
import FavoriteBtn from '../components/common/FavoriteBtn';
import css from './SingleOption.module.less';
import { setHidePopup, setShowPopup } from "../../../actions/commonActions";
import { getProductCouponSearch } from "../../../actions/couponActions";
import { pushPanel } from "../../../actions/panelActions";
import { getProductOption } from "../../../actions/productActions";
import TButton from "../../../components/TButton/TButton";
import TPopUp from "../../../components/TPopUp/TPopUp";
import TScroller from "../../../components/TScroller/TScroller";
import TVirtualGridList from "../../../components/TVirtualGridList/TVirtualGridList";
import usePriceInfo from "../../../hooks/usePriceInfo";
import * as Config from "../../../utils/Config";
import { $L } from "../../../utils/helperMethods";
import { SpotlightIds } from "../../../utils/SpotlightIds";
import FavoriteBtn from "../components/common/FavoriteBtn";
import css from "./SingleOption.module.less";
const Container = SpotlightContainerDecorator(
{ enterTo: "default-element", preserveId: true },
@@ -40,24 +28,59 @@ const Container = SpotlightContainerDecorator(
);
const SpottableComponent = Spottable("div");
export default function SingleOption({ selectedPatnrId, selectedPrdtId }) {
const promotionDesc = $L("Coupon only applicable to this product!");
export default function SingleOption({
selectedPatnrId,
selectedPrdtId,
productInfo,
patncNm,
}) {
const dispatch = useDispatch();
const productOptionInfos = useSelector((state) => state.product.prdtOptInfo);
const productData = useSelector((state) => state.main.productData);
const { partnerCoupon, shoptiemCoupon } = useSelector(
(state) => state.coupon.productCouponSearchData
);
const { popupVisible, activePopup } = useSelector(
(state) => state.common.popup
);
const { loginUserData } = useSelector((state) => state.common.appStatus);
const [selectedBtnOptIdx, setSelectedBtnOptIdx] = useState(0);
const [quantity, setQuantity] = useState(1);
const [selectedOptions, setSelectedOptions] = useState([]);
const [couponTypes, setCouponTypes] = useState(null);
const { priceInfo, shippingCharge } = productInfo || productData;
const { originalPrice, discountedPrice, discountRate } =
usePriceInfo(priceInfo) || {};
let promotions = [];
useEffect(() => {
if (partnerCoupon && partnerCoupon.length > 0) {
promotions.push($L("SHOPTIME PROMOTION"));
}
if (shoptiemCoupon && shoptiemCoupon.length > 0) {
promotions.push($L("SPECIAL PROMOTION"));
}
}, [partnerCoupon, shoptiemCoupon]);
console.log("#partnerCoupon", promotions);
useEffect(() => {
dispatch(
getProductOption({
patnrId: selectedPatnrId,
prdtId: selectedPrdtId,
})
);
dispatch(
getProductCouponSearch({
patnrId: selectedPatnrId,
prdtId: selectedPrdtId,
})
);
}, [dispatch, selectedPatnrId]);
const handleOptionsClick = useCallback(
(e, optionValIdx) => {
@@ -72,29 +95,6 @@ export default function SingleOption({ selectedPatnrId, selectedPrdtId }) {
[selectedBtnOptIdx]
);
const [couponTypes, setCouponTypes] = useState(null);
const { priceInfo, shippingCharge, patncNm } = productData;
const { originalPrice, discountedPrice, discountRate } =
usePriceInfo(priceInfo) || {};
const promotions = [$L("SHOPTIME PROMOTION"), $L("SPECIAL PROMOTION")];
const promotionDesc = $L("Coupon only applicable to this product!");
useEffect(() => {
dispatch(
getProductOption({
patnrId: selectedPatnrId,
prdtId: selectedPrdtId,
})
);
dispatch(
getProductCouponSearch({
patnrId: selectedPatnrId,
prdtId: selectedPrdtId,
})
);
}, [dispatch]);
const handleIncrement = useCallback(() => {
setQuantity(quantity + 1);
}, [quantity]);
@@ -230,53 +230,60 @@ export default function SingleOption({ selectedPatnrId, selectedPrdtId }) {
</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, promotion);
}}
>
{$L("COUPON")}
</TButton>
</Container>
);
})}
<div className={css.middleLayer}>
{/* COUPON */}
<div className={css.couponWrap}>
{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, promotion);
}}
>
{$L("COUPON")}
</TButton>
</Container>
);
})}
</div>
{/* Price */}
{originalPrice && discountedPrice && (
<div
className={
originalPrice === discountedPrice
? css.notDiscountedPriceLayer
: css.discountedPriceLayer
}
>
<span>{$L(`${patncNm} 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>
)}
{/* Price */}
{originalPrice && discountedPrice && (
<div
className={
originalPrice === discountedPrice
? css.notDiscountedPriceLayer
: css.discountedPriceLayer
}
>
<span>{$L(`${patncNm} 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>
</div>
)}
{shippingCharge && (
<div className={css.shippingLayer}>
<span>{$L("Shipping Free")}</span>
<span>{shippingCharge}</span>
</div>
)}
)}
{shippingCharge && (
<div className={css.shippingLayer}>
<span>{$L("Shipping Free")}</span>
<span>{shippingCharge}</span>
</div>
)}
</div>
{/* BYU NOW & FAVORITE */}
<Container className={css.bottomBtnLayer}>
<TButton className={css.buyNowBtn} onClick={handleLoginPopup}>

View File

@@ -116,109 +116,114 @@
}
}
}
.middleLayer {
height: 329px;
// COUPON
.couponWrap {
width: 100%;
height: 180px;
}
.detailBottomLayer {
width: 100%;
// COUPON
.detailBottomLayer {
width: 100%;
margin-top: 27px;
.flex(@justifyCenter:space-between);
.leftLayer {
.flex(@direction:column, @justifyCenter:center,@alignCenter:flex-start);
.promotionName {
color: @COLOR_GRAY05;
margin-top: 27px;
.flex(@justifyCenter:space-between);
.leftLayer {
.flex(@direction:column, @justifyCenter:center,@alignCenter:flex-start);
.promotionName {
color: @COLOR_GRAY05;
font-weight: bold;
font-size: 24px;
}
.promotionDesc {
color: @COLOR_GRAY03;
font-size: 24px;
}
}
.promotionBtn {
min-width: 144px;
height: 60px;
font-weight: bold;
font-size: 24px;
line-height: 60px;
border-radius: 6px;
background: @COLOR_GRAY03;
position: relative;
&:focus {
background: @PRIMARY_COLOR_RED;
}
}
.promotionDesc {
color: @COLOR_GRAY03;
}
.discountedPriceLayer {
.flex(@justifyCenter:space-between);
font-weight: bold;
font-size: 36px;
color: @COLOR_GRAY07;
margin-top: 31px;
.priceWrapper {
.flex();
}
.discountRateTag {
padding: 0 12px;
background: #f00;
color: @COLOR_WHITE;
font-weight: bold;
font-size: 24px;
text-align: center;
border-radius: 6px;
height: 42px;
line-height: 42px;
}
.discountedPrice {
font-weight: bold;
font-size: 24px;
line-height: 1.14;
color: @PRIMARY_COLOR_RED;
margin-left: 12px;
}
.originalPrice {
font-size: 24px;
color: @COLOR_GRAY03;
text-decoration: line-through;
margin-left: 9px;
}
}
.promotionBtn {
min-width: 144px;
height: 60px;
.notDiscountedPriceLayer {
.flex(@justifyCenter:space-between);
font-weight: bold;
font-size: 24px;
line-height: 60px;
border-radius: 6px;
background: @COLOR_GRAY03;
position: relative;
&:focus {
background: @PRIMARY_COLOR_RED;
font-size: 36px;
color: @COLOR_GRAY07;
margin-top: 31px;
.priceWrapper {
.flex();
}
.discountedPrice {
font-weight: bold;
font-size: 44px;
line-height: 1.14;
color: @PRIMARY_COLOR_RED;
margin-left: 12px;
}
}
}
.discountedPriceLayer {
.flex(@justifyCenter:space-between);
font-weight: bold;
font-size: 36px;
color: @COLOR_GRAY07;
margin-top: 31px;
.priceWrapper {
.flex();
}
.discountRateTag {
padding: 0 12px;
background: #f00;
color: @COLOR_WHITE;
font-weight: bold;
font-size: 24px;
text-align: center;
border-radius: 6px;
height: 42px;
line-height: 42px;
}
.discountedPrice {
font-weight: bold;
font-size: 24px;
line-height: 1.14;
color: @PRIMARY_COLOR_RED;
margin-left: 12px;
}
.originalPrice {
font-size: 24px;
color: @COLOR_GRAY03;
text-decoration: line-through;
margin-left: 9px;
}
}
.notDiscountedPriceLayer {
.flex(@justifyCenter:space-between);
font-weight: bold;
font-size: 36px;
color: @COLOR_GRAY07;
margin-top: 31px;
.priceWrapper {
.flex();
}
.discountedPrice {
font-weight: bold;
font-size: 44px;
line-height: 1.14;
color: @PRIMARY_COLOR_RED;
margin-left: 12px;
}
}
.shippingLayer {
width: 100%;
.flex(@justifyCenter:space-between);
margin-top: 13px;
> span {
font-size: 24px;
line-height: 1.33;
color: @COLOR_GRAY03;
.shippingLayer {
width: 100%;
.flex(@justifyCenter:space-between);
margin-top: 13px;
> span {
font-size: 24px;
line-height: 1.33;
color: @COLOR_GRAY03;
}
}
}
.bottomBtnLayer {
margin-top: 24px;
position: relative;
.flex(@justifyCenter:space-between);
.buyNowBtn {

View File

@@ -10,6 +10,7 @@ import * as Config from "../../../utils/Config";
import { $L } from "../../../utils/helperMethods";
import StarRating from "../components/common/StarRating";
import css from "./HotelOption.module.less";
import IndicatorOptions from "./indicator/IndicatorOptions";
import ThemeIndicator from "./indicator/ThemeIndicator";
export default function HotelOption({
@@ -69,15 +70,19 @@ export default function HotelOption({
return (
<>
{hotelInfos && (
<ThemeIndicator
productInfo={hotelInfos}
selectedIndex={selectedIndex}
setSelectedIndex={setSelectedIndex}
thumbnailUrls={hotelInfos[selectedIndex]?.hotelDetailInfo.imgUrls}
<div>
{hotelInfos && (
<ThemeIndicator
productInfo={hotelInfos}
selectedIndex={selectedIndex}
setSelectedIndex={setSelectedIndex}
thumbnailUrls={hotelInfos[selectedIndex]?.hotelDetailInfo.imgUrls}
/>
)}
<IndicatorOptions
address={hotelInfos[selectedIndex]?.hotelDetailInfo.hotelAddr}
/>
)}
</div>
<div className={css.optionContainer}>
<div className={css.topLayer}>
<img src={hotelData?.hotelInfo.patncLogoPath} alt="" />

View File

@@ -2,22 +2,45 @@ import React, { useState } from "react";
import { useSelector } from "react-redux";
import ProductOption from "../components/ProductOption";
import SingleOption from "../SingleProduct/SingleOption";
import IndicatorOptions from "./indicator/IndicatorOptions";
import ThemeIndicator from "./indicator/ThemeIndicator";
import css from "./ThemeOption.module.less";
export default function ThemeOption({ selectedIndex, setSelectedIndex }) {
const productInfo = useSelector((state) => state.home.productData);
const productInfo = useSelector(
(state) => state.home.themeCurationDetailInfoData
);
const productData = useSelector((state) => state.home.productData);
console.log("#productInfo", productInfo);
console.log("#productData", productData);
return (
<>
<ThemeIndicator
productInfo={productInfo}
selectedIndex={selectedIndex}
setSelectedIndex={setSelectedIndex}
thumbnailUrls={productInfo[selectedIndex]?.imgUrls600}
/>
<div>THEME OPTION</div>
<div className={css.indicatorContainer}>
<ThemeIndicator
productInfo={productInfo}
selectedIndex={selectedIndex}
setSelectedIndex={setSelectedIndex}
thumbnailUrls={productInfo[selectedIndex]?.imgUrls600}
/>
<IndicatorOptions
isFullOption
productInfo={productInfo[selectedIndex]}
/>
</div>
<div>
<ProductOption productInfo={productInfo[selectedIndex]}>
<SingleOption
selectedPatnrId={productData?.themeInfo[0]?.patnrId}
selectedPrdtId={productInfo[selectedIndex]?.prdtId}
productInfo={productInfo[selectedIndex]}
patncNm={productData?.themeInfo[0]?.patncNm}
/>
</ProductOption>
</div>
</>
);
}

View File

@@ -1,46 +1,6 @@
@import "../../../style/CommonStyle.module.less";
@import "../../../style/utils.module.less";
.optionContainer {
.flex(@direction:column ,@justifyCenter:flex-start,@alignCenter:flex-start);
.size(@w: 1026px, @h: 930px);
background-color: @BG_COLOR_01;
padding: 30px 120px 120px 60px;
.topLayer {
width: 100%;
.flex(@direction:row ,@justifyCenter:flex-start);
text-align: left;
color: @COLOR_GRAY03;
font-weight: bold;
font-size: 30px;
img {
width: 42px;
height: 42px;
margin-right: 11px;
}
}
.bottomLayer {
width: 846px;
.flex(@justifyCenter:space-between,@alignCenter:center);
height: 42px;
margin-top: 14px;
> div {
height: 36px;
}
}
.title {
font-weight: bold;
font-size: 36px;
color: @COLOR_GRAY08;
width: 739px;
.elip(@clamp:2);
margin-top: 24px;
font-stretch: normal;
font-style: normal;
line-height: 1.17;
letter-spacing: normal;
text-align: left;
}
.indicatorContainer {
.size(@w: 834px, @h: 930px);
}

View File

@@ -11,27 +11,19 @@ export default function ThemeProduct({
setSelectedIndex,
selectedCurationId,
selectedPatnrId,
themeType,
}) {
const productInfos = useSelector(
(state) => state.home.themeCurationDetailInfoData
);
const hotelInfos = useSelector(
(state) => state.home.themeCurationHotelDetailData
);
console.log("#productInfos", productInfos);
console.log("#hotelInfos", hotelInfos);
return (
<div className={css.container}>
{productInfos.themeInfo?.length > 0 ? (
{themeType === "theme" && (
<ThemeOption
selectedIndex={selectedIndex}
selectedCurationId={selectedCurationId}
selectedPatnrId={selectedPatnrId}
setSelectedIndex={setSelectedIndex}
/>
) : (
)}
{themeType === "hotel" && (
<HotelOption
selectedIndex={selectedIndex}
selectedCurationId={selectedCurationId}

View File

@@ -1,182 +0,0 @@
import React, { useCallback, useEffect, useRef, useState } from "react";
import classNames from "classnames";
import { useSelector } from "react-redux";
import Image from "@enact/sandstone/Image";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import Spottable from "@enact/spotlight/Spottable";
import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList";
import useScrollTo from "../../../../hooks/useScrollTo";
import css from "./HotelIndicator.module.less";
const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused", preserveld: true },
"div"
);
const SpottableComponent = Spottable("div");
const SpottableImage = Spottable(Image);
const IMAGE_WIDTH = 152;
export default function HotelIndicator({ selectedIndex, setSelectedIndex }) {
const [selectedImage, setSelectedImage] = useState(null);
const [imageSelectedIndex, setImageSelectedIndex] = useState(0);
const hotelInfos = useSelector(
(state) => state.home.themeCurationHotelDetailData
);
const { cursorVisible } = useSelector((state) => state.common.appStatus);
const imageLength = hotelInfos[selectedIndex]?.hotelDetailInfo.imgUrls.length;
const { getScrollTo, scrollTop } = useScrollTo();
let imagePosition = IMAGE_WIDTH * selectedIndex - IMAGE_WIDTH;
useEffect(() => {
const image =
hotelInfos[selectedIndex]?.hotelDetailInfo.imgUrls[imageSelectedIndex];
setSelectedImage(image || hotelInfos[0]?.hotelDetailInfo.imgUrls[0]);
}, [selectedIndex, imageSelectedIndex, hotelInfos]);
const handlePrevClick = () => {
if (imageSelectedIndex > 0) {
setImageSelectedIndex((prev) => prev - 1);
}
};
const handleNextClick = () => {
if (imageSelectedIndex + 1 < imageLength) {
setImageSelectedIndex((prev) => prev + 1);
}
};
const handleUpClick = useCallback(() => {
if (selectedIndex === 0) {
return;
}
setSelectedIndex((prev) => prev - 1);
if (hotelInfos.length - 1 !== selectedIndex) {
scrollTop({ y: imagePosition - IMAGE_WIDTH, animate: true });
}
}, [selectedIndex]);
const handleDownClick = useCallback(() => {
if (hotelInfos.length - 1 === selectedIndex) {
return;
}
setSelectedIndex((prev) => prev + 1);
if (selectedIndex > 1) {
scrollTop({
y: imagePosition,
animate: true,
});
}
}, [selectedIndex]);
const renderItem = useCallback(
({ index, ...rest }) => {
const { hotelImgUrl } = hotelInfos[index];
const handleItemClick = () => {
setSelectedIndex(index);
setImageSelectedIndex(0);
};
return (
<>
<SpottableImage
src={hotelImgUrl}
alt=""
className={classNames(
css.image,
selectedIndex === index && css.selected
)}
onClick={handleItemClick}
spotlightId={`indicator-image-${index}`}
{...rest}
>
<span
className={
selectedIndex === index && css.selected && css.checkIcon
}
/>
</SpottableImage>
</>
);
},
[hotelInfos, selectedIndex]
);
return (
<Container className={css.Wrap}>
<div className={css.indicatorContainer}>
<div>
{hotelInfos && (
<SpottableImage
src={selectedImage}
alt=""
className={css.thumbnail}
>
<Container className={css.thumbnailIndicator}>
<SpottableComponent
className={classNames(
css.prevButton,
imageSelectedIndex === 0 && css.disable
)}
onClick={handlePrevClick}
spotlightDisabled={imageSelectedIndex === 0}
/>
<span>
{imageSelectedIndex + 1} / {imageLength}
</span>
<SpottableComponent
className={classNames(
css.nextButton,
imageLength - 1 === imageSelectedIndex && css.disable
)}
onClick={handleNextClick}
spotlightDisabled={imageLength - 1 === imageSelectedIndex}
/>
</Container>
</SpottableImage>
)}
<div className={css.address}>
<span className={css.location} />
<div>{hotelInfos[selectedIndex]?.hotelDetailInfo.hotelAddr}</div>
</div>
</div>
<div>
<SpottableComponent
onClick={handleUpClick}
spotlightDisabled={!cursorVisible}
className={classNames(
css.upButton,
selectedIndex === 0 && css.disable
)}
/>
<Container className={css.tVirtualGridListContainer}>
{hotelInfos && hotelInfos.length > 0 && (
<TVirtualGridList
cbScrollTo={getScrollTo}
className={css.tVirtualGridList}
dataSize={hotelInfos.length}
itemWidth={144}
itemHeight={144}
spacing={8}
renderItem={renderItem}
/>
)}
</Container>
<SpottableComponent
onClick={handleDownClick}
spotlightDisabled={!cursorVisible}
className={classNames(
css.downButton,
hotelInfos.length - 1 === selectedIndex && css.disable
)}
/>
</div>
</div>
</Container>
);
}

View File

@@ -1,173 +0,0 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.Wrap {
padding-left: 120px;
.size(@w: 894px, @h: 930px);
.indicatorContainer {
margin: 30px 0 0 10px;
width: 714px;
height: 560px;
display: flex;
.thumbnail {
.size(@w: 560px, @h: 560px);
border: solid 1px #dadada;
background-color: #fff;
margin: 0 10px 10px 0;
position: relative;
display: flex;
justify-content: center;
&:focus {
&::after {
.focused(@boxShadow: 22px, @borderRadius:0px);
}
}
.thumbnailIndicator {
margin-top: auto;
position: relative;
margin-bottom: 30px;
z-index: 10;
.prevButton {
.size(@w:42px, @h: 42px);
.position(@position: absolute, @right: 70px, @bottom: 0 , @top: 0);
background-image: url("../../../../../assets/images/btn/btn-prev-thumb-nor.svg");
background-position: center;
background-size: cover;
&:focus {
background-image: url("../../../../../assets/images/btn/btn-prev-thumb-foc.svg");
}
&.disable {
opacity: 0.1;
background-image: url("../../../../../assets/images/btn/btn-prev-thumb-nor.svg");
}
}
.nextButton {
.size(@w:42px, @h: 42px);
.position(@position: absolute, @left: 70px, @bottom: 0 , @top: 0);
background-image: url("../../../../../assets/images/btn/btn-next-thumb-nor.svg");
background-position: center;
background-size: cover;
&:focus {
background-image: url("../../../../../assets/images/btn/btn-next-thumb-foc.svg");
}
&.disable {
opacity: 0.1;
background-image: url("../../../../../assets/images/btn/btn-next-thumb-nor.svg");
}
}
> span {
// .size(@w: 51px , @h: 21px);
-webkit-text-stroke: 1px rgba(255, 255, 255, 0.7);
color: #222222;
font-size: 24px;
font-weight: bold;
line-height: 1.33;
}
}
}
.address {
font-size: 24px;
color: #808080;
position: relative;
.location {
.size(@w:36px, @h: 36px);
position: absolute;
background-image: url("../../../../../assets/images/icons/ic-location.svg");
background-position: center;
background-size: cover;
}
> div {
padding-left: 36px;
}
}
.tVirtualGridListContainer {
overflow: hidden;
.size(@w: 144px , @h: 447px);
> div:nth-child(1) {
.size(@w: inherit, @h: 447px);
}
}
.upButton {
.size(@w: 144px , @h: 48px);
border: none;
margin-bottom: 10px;
background-position: center;
background-size: cover;
background-image: url("../../../../../assets/images/btn/btn-bk-up-nor.svg");
&:focus {
background-image: url("../../../../../assets/images/btn/btn-bk-up-foc.svg");
}
&.disable {
opacity: 0.1;
background-image: url("../../../../../assets/images/btn/btn-bk-up-nor.svg");
}
}
.downButton {
.size(@w: 144px , @h: 48px);
border: none;
margin-top: 10px;
background-position: center;
background-size: cover;
background-image: url("../../../../../assets/images/btn/btn-bk-down-nor.svg");
&:focus {
background-image: url("../../../../../assets/images/btn/btn-bk-down-foc.svg");
}
&.disable {
opacity: 0.1;
background-image: url("../../../../../assets/images/btn/btn-bk-down-nor.svg");
}
}
.image {
.size(@w: 144px , @h: 144px);
margin: 0 0 6px 0;
border: solid 1px #dadada;
position: relative;
&:focus {
&::after {
.focused(@boxShadow: 22px, @borderRadius:0px);
}
}
&.selected {
&:before {
.size(@w: 142px , @h: 142px);
content: "";
position: absolute;
left: 0;
top: 0;
background-color: #7a808d;
opacity: 0.7;
}
}
}
.checkIcon {
.position(@position: absolute, @top: auto, @right: 44px, @bottom: 48px, @left: auto);
.size(@w: 49px , @h: 49px);
background-image: url("../../../../../assets/images/icons/ic-check-thumb.svg");
background-position: center;
background-size: cover;
z-index: 20;
}
}
}

View File

@@ -0,0 +1,176 @@
import React, { useCallback, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import Spottable from "@enact/spotlight/Spottable";
import { setHidePopup, setShowPopup } from "../../../../actions/commonActions";
import MobileSendPopUp from "../../../../components/MobileSend/MobileSendPopUp";
import TButtonTab from "../../../../components/TButtonTab/TButtonTab";
import TPopUp from "../../../../components/TPopUp/TPopUp";
import TQRCode from "../../../../components/TQRCode/TQRCode";
import TScroller from "../../../../components/TScroller/TScroller";
import useScrollTo from "../../../../hooks/useScrollTo";
import * as Config from "../../../../utils/Config";
import { $L } from "../../../../utils/helperMethods";
import ProductTag from "../../components/common/ProductTag";
import StarRating from "../../components/common/StarRating";
import css from "./IndicatorOptions.module.less";
const SpottableComponent = Spottable("div");
export default function IndicatorOptions({
isFullOption,
address,
productInfo,
}) {
const [opened, setOpened] = useState(false);
const [tabLabel, setTabLabel] = useState("");
const { getScrollTo, scrollTop } = useScrollTo();
const { popupVisible, activePopup } = useSelector(
(state) => state.common.popup
);
const dispatch = useDispatch();
const handlePopUpClick = (label) => {
setOpened((prev) => !prev);
setTabLabel([label]);
};
const handleUpClick = () => {
scrollTop({ y: 500 });
};
const handleDownClick = () => {
scrollTop({
y: 500,
});
};
const handleSMSonClose = () => {
dispatch(setHidePopup());
};
const handleSMSClick = useCallback(() => {
dispatch(setShowPopup(Config.ACTIVE_POPUP.smsPopup));
}, [popupVisible]);
const renderPopUp = () => {
return (
<TPopUp
kind="productDetail"
onClose={handlePopUpClick}
open={opened}
hasButton
button1Text={"CLOSE"}
>
<div className={css.popUpContainer}>
<div className={css.popUpHeader}>
<img src={productInfo?.thumbnailUrl} />
<div className={css.path}>
<div>
<img src={productInfo?.patncLogoPath} alt="" />
<span>{`ID:` + productInfo?.prdtId}</span>
</div>
<h3>{productInfo?.prdtNm}</h3>
<div className={css.tagWrap}>
<StarRating
rating={productInfo?.revwGrd}
className={css.starRating}
/>
<ProductTag productInfo={productInfo} />
</div>
</div>
</div>
<div className={css.line} />
<div className={css.tButtonTab}>
<TButtonTab
selectedIndex={0}
contents={tabLabel}
className={css.tab}
spotlightDisabled={true}
/>
<div className={css.content}>
<button className={css.upButton} onClick={handleUpClick} />
<TScroller
className={css.scrollContainer}
verticalScrollbar="auto"
cbScrollTo={getScrollTo}
>
<p className={css.description}> {productInfo?.prdtDesc}</p>
</TScroller>
<button className={css.downButton} onClick={handleDownClick} />
</div>
</div>
</div>
</TPopUp>
);
};
return (
<>
<div className={css.indicatorOptionContainer}>
{opened && renderPopUp()}
{address && (
<div className={css.address}>
<span className={css.location} />
<div>{address}</div>
</div>
)}
{isFullOption && (
<>
<div className={css.order}>
<div>{$L("Call to Order")}</div>
<div className={css.icon}>
<span />
<div>{productInfo?.orderPhnNo}</div>
</div>
</div>
<div className={css.buttonWrap}>
<div className={css.tButton}>
<SpottableComponent
onClick={() => handlePopUpClick("DESCRIPTION")}
>
{$L("DESCRIPTION")}
</SpottableComponent>
<SpottableComponent
onClick={() => handlePopUpClick("RETURN & EXCHANGES")}
>
{$L("RETURN & EXCHANGES")}
</SpottableComponent>
<SpottableComponent onClick={handleSMSClick}>
{$L("SHOP BY MOBILE")}
</SpottableComponent>
</div>
<div className={css.qrcode}>
{productInfo?.qrImgUrl ? (
productInfo?.qrImgUrl
) : (
<TQRCode
text={productInfo?.qrcodeUrl}
width="160"
height="160"
/>
)}
</div>
</div>
</>
)}
{/* MobileSendPopUp */}
{activePopup === Config.ACTIVE_POPUP.smsPopup && (
<MobileSendPopUp
open={popupVisible}
onClose={handleSMSonClose}
title={productInfo?.prdtNm}
productImg={productInfo?.thumbnailUrl}
// productPrice={Price()}
// patnrId={selectedPatnrId}
// smsTpCd={"APP00205"}
/>
)}
</div>
</>
);
}

View File

@@ -0,0 +1,197 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.indicatorOptionContainer {
.address {
margin-top: 18px;
width: 560px;
font-size: 24px;
color: #808080;
position: relative;
.location {
.size(@w:36px, @h: 36px);
position: absolute;
background-image: url("../../../../../assets/images/icons/ic-location.svg");
background-position: center;
background-size: cover;
}
> div {
padding-left: 36px;
}
}
.order {
font-weight: bold;
font-size: 30px;
.size(@w: 560px, @h: 68px);
display: flex;
justify-content: space-between;
line-height: 68px;
background-color: #f2f2f2;
margin-top: 10px;
> div {
padding: 0 33px 0 30px;
}
}
.icon {
display: flex;
> span {
.size(@w: 42px, @h: 42px);
background-image: url("../../../../../assets/images/icons/ic-gr-call.svg");
background-size: cover;
background-position: center;
margin: 13px 0 0 4px;
}
}
.buttonWrap {
display: flex;
}
.tButton {
.size(@w: 362px, @h: 192px);
margin-top: 10px;
text-align: center;
> div {
font-weight: normal;
font-size: 24px;
.size(@w: 362px, @h: 60px);
box-shadow: 0px 3px 6px 0 rgba(2, 3, 3, 0.1);
border-radius: 6px;
border: solid 1px var(--white);
background-image: linear-gradient(to top, #f5f5f5, #fff);
margin-bottom: 6px;
color: #808080;
line-height: 60px;
&:focus {
.focusDropShadow();
box-shadow: 0 0 22px 0 rgba(0, 0, 0, 0.5);
background-image: linear-gradient(to top, #c70850, #c70850);
color: #fff;
}
}
}
.qrcode {
.size(@w: 192px, @h: 192px);
box-shadow: 0 3px 6px 0 rgba(2, 3, 3, 0.1);
border-radius: 6px;
border: solid 1px #fff;
background-image: linear-gradient(to top, #f5f5f5, #fff);
margin-top: 10px;
padding: 16px 16px 0 16px;
}
}
.popUpHeader {
display: flex;
> img {
.size(@w: 200px , @h: 200px);
border: solid 1px #dadada;
}
.path {
padding-left: 20px;
display: flex;
flex-direction: column;
// 브랜드 아이콘
> div > img {
.size(@w: 42px , @h: 42px);
background-color: #f8f8f8;
margin: 0 12px 0 0;
}
// 상품 ID
> div > span {
font-weight: bold;
font-size: 30px;
color: #808080;
}
// 상품명
> h3 {
.elip(2);
color: #1a1a1a;
font-weight: bold;
font-size: 36px;
margin: 24px 22px 0 0;
}
}
.tagWrap {
width: 770px;
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: row;
margin-top: auto;
}
}
.line {
.size(@w: 990px , @h: 1px);
margin: 30px 0 30px 0;
background-color: #dadada;
}
.tab {
width: 980px;
}
.content {
.size(@w: 980px , @h: 300px);
padding: 28px 0 0 30px;
background-color: #fff;
border: solid 1px #dadada;
position: relative;
.scrollContainer {
height: 250px;
//스크롤 바
> div > div:nth-child(2) > div:nth-child(1) > div {
.size(@w: 8px , @h: 100px);
background-color: #7a808d;
border-radius: 0px;
}
//스크롤 바 백그라운드
> div > div:nth-child(2) > div:nth-child(1) {
width: 8px;
height: 182px;
background-color: #e7e7e7;
border-radius: 0px;
}
//스크롤이 내려가는 총 길이
> div > div:nth-child(2) {
width: 48px;
height: 105px;
margin-top: 15px;
padding-left: 14.5px;
}
}
.upButton {
position: absolute;
top: 0px;
left: 930px;
.size(@w: 48px , @h: 48px);
background-image: url("../../../../../assets/images/btn/btn-scroll-up-dim.svg");
background-position: center;
background-size: cover;
}
.downButton {
position: absolute;
top: 250px;
left: 930px;
.size(@w: 48px , @h: 48px);
background-image: url("../../../../../assets/images/btn/btn-scroll-down-dim.svg");
background-position: center;
background-size: cover;
}
.description {
font-weight: normal;
font-size: 24px;
line-height: 1.33;
color: #808080;
padding-right: 75px;
}
}

View File

@@ -9,7 +9,7 @@ import Spottable from "@enact/spotlight/Spottable";
import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList";
import useScrollTo from "../../../../hooks/useScrollTo";
import css from "./HotelIndicator.module.less";
import css from "./ThemeIndicator.module.less";
const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused", preserveld: true },
@@ -23,16 +23,13 @@ const IMAGE_WIDTH = 152;
export default function ThemeIndicator({
selectedIndex,
setSelectedIndex,
//상품정보
productInfo,
thumbnailUrls,
}) {
const [selectedImage, setSelectedImage] = useState(null);
const [imageSelectedIndex, setImageSelectedIndex] = useState(0);
const hotelInfos = useSelector(
(state) => state.home.themeCurationHotelDetailData
);
const { cursorVisible } = useSelector((state) => state.common.appStatus);
const imageLength = thumbnailUrls && thumbnailUrls.length;
@@ -116,73 +113,70 @@ export default function ThemeIndicator({
</>
);
},
[hotelInfos, selectedIndex]
[productInfo, selectedIndex]
);
return (
<Container className={css.Wrap}>
<div className={css.indicatorContainer}>
<div>
{hotelInfos && (
<SpottableImage
src={selectedImage}
alt=""
className={css.thumbnail}
>
<Container className={css.thumbnailIndicator}>
<SpottableComponent
className={classNames(
css.prevButton,
imageSelectedIndex === 0 && css.disable
)}
onClick={handlePrevClick}
spotlightDisabled={imageSelectedIndex === 0}
/>
<span>
{imageSelectedIndex + 1} / {imageLength}
</span>
<SpottableComponent
className={classNames(
css.nextButton,
imageLength - 1 === imageSelectedIndex && css.disable
)}
onClick={handleNextClick}
spotlightDisabled={imageLength - 1 === imageSelectedIndex}
/>
</Container>
</SpottableImage>
)}
</div>
<div>
<SpottableComponent
onClick={handleUpClick}
spotlightDisabled={!cursorVisible}
className={classNames(
css.upButton,
selectedIndex === 0 && css.disable
)}
/>
<Container className={css.tVirtualGridListContainer}>
{productInfo && productInfo.length > 0 && (
<TVirtualGridList
cbScrollTo={getScrollTo}
className={css.tVirtualGridList}
dataSize={productInfo.length}
itemWidth={144}
itemHeight={144}
spacing={8}
renderItem={renderItem}
<Container className={css.indicatorContainer}>
<div>
{productInfo && (
<SpottableImage src={selectedImage} alt="" className={css.thumbnail}>
<Container className={css.thumbnailIndicator}>
<SpottableComponent
className={classNames(
css.prevButton,
imageSelectedIndex === 0 && css.disable
)}
onClick={handlePrevClick}
spotlightDisabled={imageSelectedIndex === 0}
/>
)}
</Container>
<SpottableComponent
onClick={handleDownClick}
spotlightDisabled={!cursorVisible}
className={classNames(
css.downButton,
productInfo.length - 1 === selectedIndex && css.disable
)}
/>
</div>
<span>
{imageSelectedIndex + 1} / {imageLength}
</span>
<SpottableComponent
className={classNames(
css.nextButton,
imageLength - 1 === imageSelectedIndex && css.disable
)}
onClick={handleNextClick}
spotlightDisabled={imageLength - 1 === imageSelectedIndex}
/>
</Container>
</SpottableImage>
)}
{/* <IndicatorOptions /> */}
</div>
<div>
<SpottableComponent
onClick={handleUpClick}
spotlightDisabled={!cursorVisible}
className={classNames(
css.upButton,
selectedIndex === 0 && css.disable
)}
/>
<Container className={css.tVirtualGridListContainer}>
{productInfo && productInfo.length > 0 && (
<TVirtualGridList
cbScrollTo={getScrollTo}
className={css.tVirtualGridList}
dataSize={productInfo.length}
itemWidth={144}
itemHeight={144}
spacing={8}
renderItem={renderItem}
/>
)}
</Container>
<SpottableComponent
onClick={handleDownClick}
spotlightDisabled={!cursorVisible}
className={classNames(
css.downButton,
productInfo.length - 1 === selectedIndex && css.disable
)}
/>
</div>
</Container>
);

View File

@@ -1,155 +1,152 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.Wrap {
padding-left: 120px;
.size(@w: 894px, @h: 930px);
.indicatorContainer {
margin-top: 30px;
width: 714px;
height: 560px;
display: flex;
.indicatorContainer {
margin: 30px 0 0 10px;
width: 714px;
height: 560px;
.thumbnail {
.size(@w: 560px, @h: 560px);
border: solid 1px #dadada;
background-color: #fff;
margin: 0 10px 10px 0;
position: relative;
display: flex;
justify-content: center;
.thumbnail {
.size(@w: 560px, @h: 560px);
border: solid 1px #dadada;
background-color: #fff;
margin: 0 10px 10px 0;
position: relative;
display: flex;
justify-content: center;
&:focus {
&::after {
.focused(@boxShadow: 22px, @borderRadius:0px);
}
&:focus {
&::after {
.focused(@boxShadow: 22px, @borderRadius:0px);
}
}
.thumbnailIndicator {
margin-top: auto;
position: relative;
margin-bottom: 30px;
z-index: 10;
.thumbnailIndicator {
margin-top: auto;
position: relative;
margin-bottom: 30px;
z-index: 1;
.prevButton {
.size(@w:42px, @h: 42px);
.position(@position: absolute, @right: 70px, @bottom: 0 , @top: 0);
.prevButton {
.size(@w:42px, @h: 42px);
.position(@position: absolute, @right: 70px, @bottom: 0 , @top: 0);
background-image: url("../../../../../assets/images/btn/btn-prev-thumb-nor.svg");
background-position: center;
background-size: cover;
&:focus {
background-image: url("../../../../../assets/images/btn/btn-prev-thumb-foc.svg");
}
&.disable {
opacity: 0.1;
background-image: url("../../../../../assets/images/btn/btn-prev-thumb-nor.svg");
background-position: center;
background-size: cover;
&:focus {
background-image: url("../../../../../assets/images/btn/btn-prev-thumb-foc.svg");
}
&.disable {
opacity: 0.1;
background-image: url("../../../../../assets/images/btn/btn-prev-thumb-nor.svg");
}
}
.nextButton {
.size(@w:42px, @h: 42px);
.position(@position: absolute, @left: 70px, @bottom: 0 , @top: 0);
}
.nextButton {
.size(@w:42px, @h: 42px);
.position(@position: absolute, @left: 70px, @bottom: 0 , @top: 0);
background-image: url("../../../../../assets/images/btn/btn-next-thumb-nor.svg");
background-position: center;
background-size: cover;
&:focus {
background-image: url("../../../../../assets/images/btn/btn-next-thumb-foc.svg");
}
&.disable {
opacity: 0.1;
background-image: url("../../../../../assets/images/btn/btn-next-thumb-nor.svg");
background-position: center;
background-size: cover;
&:focus {
background-image: url("../../../../../assets/images/btn/btn-next-thumb-foc.svg");
}
&.disable {
opacity: 0.1;
background-image: url("../../../../../assets/images/btn/btn-next-thumb-nor.svg");
}
}
> span {
// .size(@w: 51px , @h: 21px);
-webkit-text-stroke: 1px rgba(255, 255, 255, 0.7);
color: #222222;
font-size: 24px;
font-weight: bold;
line-height: 1.33;
}
}
}
.tVirtualGridListContainer {
overflow: hidden;
.size(@w: 144px , @h: 447px);
> div:nth-child(1) {
.size(@w: inherit, @h: 447px);
> span {
// .size(@w: 51px , @h: 21px);
-webkit-text-stroke: 1px rgba(255, 255, 255, 0.7);
color: #222222;
font-size: 24px;
font-weight: bold;
line-height: 1.33;
}
}
.upButton {
.size(@w: 144px , @h: 48px);
border: none;
margin-bottom: 10px;
background-position: center;
background-size: cover;
background-image: url("../../../../../assets/images/btn/btn-bk-up-nor.svg");
&:focus {
background-image: url("../../../../../assets/images/btn/btn-bk-up-foc.svg");
}
&.disable {
opacity: 0.1;
background-image: url("../../../../../assets/images/btn/btn-bk-up-nor.svg");
}
}
.downButton {
.size(@w: 144px , @h: 48px);
border: none;
margin-top: 10px;
background-position: center;
background-size: cover;
background-image: url("../../../../../assets/images/btn/btn-bk-down-nor.svg");
&:focus {
background-image: url("../../../../../assets/images/btn/btn-bk-down-foc.svg");
}
&.disable {
opacity: 0.1;
background-image: url("../../../../../assets/images/btn/btn-bk-down-nor.svg");
}
}
.image {
.size(@w: 144px , @h: 144px);
margin: 0 0 6px 0;
border: solid 1px #dadada;
position: relative;
&:focus {
&::after {
.focused(@boxShadow: 22px, @borderRadius:0px);
}
}
&.selected {
&:before {
.size(@w: 142px , @h: 142px);
content: "";
position: absolute;
left: 0;
top: 0;
background-color: #7a808d;
opacity: 0.7;
}
}
}
.checkIcon {
.position(@position: absolute, @top: auto, @right: 44px, @bottom: 48px, @left: auto);
.size(@w: 49px , @h: 49px);
background-image: url("../../../../../assets/images/icons/ic-check-thumb.svg");
background-position: center;
background-size: cover;
z-index: 20;
}
}
.tVirtualGridListContainer {
overflow: hidden;
.size(@w: 144px , @h: 447px);
> div:nth-child(1) {
.size(@w: inherit, @h: 447px);
}
}
.upButton {
.size(@w: 144px , @h: 48px);
border: none;
margin-bottom: 10px;
background-position: center;
background-size: cover;
background-image: url("../../../../../assets/images/btn/btn-bk-up-nor.svg");
&:focus {
background-image: url("../../../../../assets/images/btn/btn-bk-up-foc.svg");
}
&.disable {
opacity: 0.1;
background-image: url("../../../../../assets/images/btn/btn-bk-up-nor.svg");
}
}
.downButton {
.size(@w: 144px , @h: 48px);
border: none;
margin-top: 10px;
background-position: center;
background-size: cover;
background-image: url("../../../../../assets/images/btn/btn-bk-down-nor.svg");
&:focus {
background-image: url("../../../../../assets/images/btn/btn-bk-down-foc.svg");
}
&.disable {
opacity: 0.1;
background-image: url("../../../../../assets/images/btn/btn-bk-down-nor.svg");
}
}
.image {
.size(@w: 144px , @h: 144px);
margin: 0 0 6px 0;
border: solid 1px #dadada;
position: relative;
&:focus {
&::after {
.focused(@boxShadow: 22px, @borderRadius:0px);
}
}
&.selected {
&:before {
.size(@w: 142px , @h: 142px);
content: "";
position: absolute;
left: 0;
top: 0;
background-color: #7a808d;
opacity: 0.7;
}
}
}
.checkIcon {
.position(@position: absolute, @top: auto, @right: 44px, @bottom: 48px, @left: auto);
.size(@w: 49px , @h: 49px);
background-image: url("../../../../../assets/images/icons/ic-check-thumb.svg");
background-position: center;
background-size: cover;
z-index: 20;
}
//isOptions
}

View File

@@ -1,14 +1,14 @@
import React, { useCallback } from 'react';
import React, { useCallback } from "react";
import classNames from 'classnames';
import { useSelector } from 'react-redux';
import classNames from "classnames";
import { useSelector } from "react-redux";
import TButton from '../../../components/TButton/TButton';
import TQRCode from '../../../components/TQRCode/TQRCode';
import usePriceInfo from '../../../hooks/usePriceInfo';
import { $L } from '../../../utils/helperMethods';
import FavoriteBtn from '../components/common/FavoriteBtn';
import css from './UnableOption.module.less';
import TButton from "../../../components/TButton/TButton";
import TQRCode from "../../../components/TQRCode/TQRCode";
import usePriceInfo from "../../../hooks/usePriceInfo";
import { $L } from "../../../utils/helperMethods";
import FavoriteBtn from "../components/common/FavoriteBtn";
import css from "./UnableOption.module.less";
export default function OptionPartnerPrice({
selectedPatnrId,
@@ -30,8 +30,6 @@ export default function OptionPartnerPrice({
installmentMonths,
} = productInfos;
console.log("#offerInfo", offerInfo);
const { discountRate } = usePriceInfo(priceInfo) || {};
const TYPE_CASE = {
case1: price2 && !price3 && !price5 && !offerInfo,

View File

@@ -8,7 +8,7 @@
left: 0;
border-top: 4px solid #7a808d;
box-shadow: 0 0 22px 0 rgba(0, 0, 0, 0.5);
z-index: 3;
z-index: 2;
&.focused {
.focusDropShadow();

View File

@@ -7,14 +7,14 @@ import ProductTag from "../components/common/ProductTag";
import StarRating from "../components/common/StarRating";
import css from "./ProductOption.module.less";
export default function ProductOption({ children }) {
export default function ProductOption({ children, productInfo }) {
const productDataInfos = useSelector((state) => state.main.productData);
const { patncLogoPath, prdtId, prdtNm, revwGrd, pmtSuptYn } =
productDataInfos;
productInfo || productDataInfos;
return (
<div className={css.optionContainer}>
{productDataInfos && (
{(productDataInfos || productInfo) && (
<div className={css.contentHeader}>
<div className={css.topLayer}>
<img src={patncLogoPath && patncLogoPath} alt="patncLogoPath" />
@@ -23,7 +23,7 @@ export default function ProductOption({ children }) {
<div className={css.title}>{$L(prdtNm)}</div>
<div className={css.bottomLayer}>
<div>{revwGrd && <StarRating rating={revwGrd} />}</div>
<ProductTag />
<ProductTag productInfo={productInfo} />
</div>
</div>
)}

View File

@@ -5,7 +5,7 @@
.flex(@direction:column ,@justifyCenter:flex-start,@alignCenter:flex-start);
.size(@w: 1026px, @h: 930px);
background-color: @BG_COLOR_01;
padding: 30px 120px 120px 60px;
padding: 30px 120px 60px 60px;
.topLayer {
width: 100%;
@@ -31,6 +31,7 @@
}
}
.title {
height: 84px;
font-weight: bold;
font-size: 36px;
color: @COLOR_GRAY08;

View File

@@ -2,8 +2,7 @@
@import "../../../style/utils.module.less";
.Wrap {
padding-left: 120px;
.size(@w: 894px, @h: 930px);
.size(@w: 834px, @h: 930px);
.order {
font-weight: bold;
font-size: 30px;

View File

@@ -5,13 +5,14 @@ import { useSelector } from "react-redux";
import usePriceInfo from "../../../../hooks/usePriceInfo";
import css from "./ProductTag.module.less";
export default function ProductTag() {
export default function ProductTag({ productInfo }) {
const productDataInfos = useSelector((state) => state.main.productData);
const couponInfos = useSelector(
(state) => state.coupon.productCouponSearchData.couponInfo
);
const { todaySpclFlag, freeShippingFlag, priceInfo, rewd } = productDataInfos;
const { todaySpclFlag, freeShippingFlag, priceInfo, rewd } =
productInfo || productDataInfos;
const { originalPrice, discountedPrice } = usePriceInfo(priceInfo) || {};
const isBigSale =