주석제거 및 인디게이터 수정

This commit is contained in:
고동영
2024-03-21 09:51:44 +09:00
parent a7e6a41c4c
commit 76938ad211
11 changed files with 513 additions and 171 deletions

View File

@@ -61,7 +61,7 @@ export const getHomeMenu = () => (dispatch, getState) => {
);
};
// 테마 시 정보 상세 조회 IF-LGSP-060
// 테마 시 정보 상세 조회 IF-LGSP-060
export const getThemeCurationDetailInfo = (params) => (dispatch, getState) => {
const { patnrId, curationId } = params;

View File

@@ -1,4 +1,4 @@
import { types } from '../actions/actionTypes';
import { types } from "../actions/actionTypes";
const initialState = {
termsData: {},
@@ -43,10 +43,12 @@ export const homeReducer = (state = initialState, action) => {
themeCurationInfoData: action.payload,
};
case types.GET_THEME_CURATION_DETAIL_INFO: {
const themeInfo = action.payload;
const productInfo = action.payload.themeInfo[0].productInfos;
return {
...state,
themeCurationDetailInfoData: themeInfo,
themeCurationDetailInfoData: productInfo,
productData: productInfo,
};
}

View File

@@ -1,29 +1,23 @@
import React, {
useEffect,
useState,
} from 'react';
import React, { useEffect, useState } from "react";
import {
useDispatch,
useSelector,
} from 'react-redux';
import { useDispatch, useSelector } from "react-redux";
import {
getThemeCurationDetailInfo,
getThemeHotelDetailInfo,
} from '../../actions/homeActions';
import { getMainCategoryDetail } from '../../actions/mainActions';
import { popPanel } 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 css from './DetailPanel.module.less';
import GroupProduct from './GroupProduct/GroupProduct';
import SingleProduct from './SingleProduct/SingleProduct';
import ThemeProduct from './ThemeProduct/ThemeProduct';
import UnableProduct from './UnableProduct/UnableProduct';
import YouMayLike from './YouMayLike/YouMayLike';
} from "../../actions/homeActions";
import { getMainCategoryDetail } from "../../actions/mainActions";
import { popPanel } 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 css from "./DetailPanel.module.less";
import GroupProduct from "./GroupProduct/GroupProduct";
import SingleProduct from "./SingleProduct/SingleProduct";
import ThemeProduct from "./ThemeProduct/ThemeProduct";
import UnableProduct from "./UnableProduct/UnableProduct";
import YouMayLike from "./YouMayLike/YouMayLike";
export default function ItemDetail() {
const [selectedPatnrId, setSelectedPatnrId] = useState("");
@@ -33,14 +27,11 @@ export default function ItemDetail() {
const [selectedIndex, setSelectedIndex] = useState(0);
const productData = useSelector((state) => state.main.productData);
const panels = useSelector((state) => state.panels.panels);
const groupInfos = useSelector((state) => state.product.groupInfo);
const hotelInfos = useSelector(
(state) => state.home.themeCurationHotelDetailData
);
const hotelData = useSelector((state) => state.home.hotelData);
const dispatch = useDispatch();
console.log("#hotelData", hotelData);
const getPanelInfo = () => {
if (panels) {
for (let i = 0; i < panels.length; i++) {
@@ -59,6 +50,7 @@ export default function ItemDetail() {
useEffect(() => {
getPanelInfo();
console.log("#panels ", panels);
if (selectedCurationId) {
dispatch(
getThemeCurationDetailInfo({
@@ -100,7 +92,7 @@ export default function ItemDetail() {
className={css.header}
title={
(selectedPrdtId && productData?.prdtNm) ||
(selectedCurationId && hotelData?.hotelInfo.curationNm)
(selectedCurationId && hotelData && hotelData?.hotelInfo.curationNm)
}
onBackButton
onClick={onClick}

View File

@@ -1,31 +1,22 @@
import React, {
useCallback,
useEffect,
useRef,
useState,
} from 'react';
import React, { useCallback, useEffect, useRef, useState } from "react";
import {
useDispatch,
useSelector,
} from 'react-redux';
import { useDispatch, useSelector } from "react-redux";
import {
setHidePopup,
setShowPopup,
} from '../../../actions/commonActions';
import MobileSendPopUp from '../../../components/MobileSend/MobileSendPopUp';
import TButton from '../../../components/TButton/TButton';
import TQRCode from '../../../components/TQRCode/TQRCode';
import * as Config from '../../../utils/Config';
import { $L } from '../../../utils/helperMethods';
import StarRating from '../components/common/StarRating';
import css from './HotelOption.module.less';
import { setHidePopup, setShowPopup } from "../../../actions/commonActions";
import MobileSendPopUp from "../../../components/MobileSend/MobileSendPopUp";
import TButton from "../../../components/TButton/TButton";
import TQRCode from "../../../components/TQRCode/TQRCode";
import * as Config from "../../../utils/Config";
import { $L } from "../../../utils/helperMethods";
import StarRating from "../components/common/StarRating";
import css from "./HotelOption.module.less";
import ThemeIndicator from "./indicator/ThemeIndicator";
export default function HotelOption({
selectedIndex,
selectedCurationId,
selectedPatnrId,
setSelectedIndex,
}) {
const tooltipDes = $L(
` Please check for more detailed\ninformation about the product.`
@@ -77,65 +68,76 @@ export default function HotelOption({
};
return (
<div className={css.optionContainer}>
<div className={css.topLayer}>
<img src={hotelData?.hotelInfo.patncLogoPath} alt="" />
<div className={css.rating}>
<StarRating
rating={hotelInfos[selectedIndex]?.hotelDetailInfo.revwGrd}
/>
<span className={css.line} /> <div>{label}</div>
</div>
</div>
<div className={css.title}>{hotelInfos[selectedIndex]?.hotelNm}</div>
<div className={css.amenities}></div>
<div className={css.bottomLayer}>
<div>
<div className={css.today}>
{$L(
`Today, ${hotelInfos[selectedIndex]?.hotelDetailInfo.nights} Night(s) 2 Adult(s)`
)}
</div>
<div className={css.roomType}>
{hotelInfos[selectedIndex]?.hotelDetailInfo.roomType}
</div>
<div className={css.price}>
<div>{$L("Price From")}</div>
<p>
<Price />
</p>
</div>
</div>
<div className={css.qrcodeContainer}>
<TQRCode
text={hotelInfos[selectedIndex]?.qrcodeUrl}
width="160"
height="160"
/>
<div className={css.tooltip}>
<div className={css.tooltipBody}>{tooltipDes}</div>
</div>
</div>
</div>
<TButton className={css.tbutton} size="extra" onClick={handleSMSClick}>
{$L("SEE MORE")}
</TButton>
{/* MobileSendPopUp */}
{activePopup === Config.ACTIVE_POPUP.smsPopup && (
<MobileSendPopUp
open={popupVisible}
onClose={onClose}
title={hotelInfos[selectedIndex]?.hotelNm}
productImg={hotelInfos[selectedIndex]?.hotelImgUrl}
productPrice={Price()}
curationId={selectedCurationId}
patnrId={selectedPatnrId}
smsTpCd={"APP00205"}
//APP00204
<>
{hotelInfos && (
<ThemeIndicator
productInfo={hotelInfos}
selectedIndex={selectedIndex}
setSelectedIndex={setSelectedIndex}
thumbnailUrls={hotelInfos[selectedIndex]?.hotelDetailInfo.imgUrls}
/>
)}
</div>
<div className={css.optionContainer}>
<div className={css.topLayer}>
<img src={hotelData?.hotelInfo.patncLogoPath} alt="" />
<div className={css.rating}>
<StarRating
rating={hotelInfos[selectedIndex]?.hotelDetailInfo.revwGrd}
/>
<span className={css.line} /> <div>{label}</div>
</div>
</div>
<div className={css.title}>{hotelInfos[selectedIndex]?.hotelNm}</div>
<div className={css.amenities}></div>
<div className={css.bottomLayer}>
<div>
<div className={css.today}>
{$L(
`Today, ${hotelInfos[selectedIndex]?.hotelDetailInfo.nights} Night(s) 2 Adult(s)`
)}
</div>
<div className={css.roomType}>
{hotelInfos[selectedIndex]?.hotelDetailInfo.roomType}
</div>
<div className={css.price}>
<div>{$L("Price From")}</div>
<p>
<Price />
</p>
</div>
</div>
<div className={css.qrcodeContainer}>
<TQRCode
text={hotelInfos[selectedIndex]?.qrcodeUrl}
width="160"
height="160"
/>
<div className={css.tooltip}>
<div className={css.tooltipBody}>{tooltipDes}</div>
</div>
</div>
</div>
<TButton className={css.tbutton} size="extra" onClick={handleSMSClick}>
{$L("SEE MORE")}
</TButton>
{/* MobileSendPopUp */}
{activePopup === Config.ACTIVE_POPUP.smsPopup && (
<MobileSendPopUp
open={popupVisible}
onClose={onClose}
title={hotelInfos[selectedIndex]?.hotelNm}
productImg={hotelInfos[selectedIndex]?.hotelImgUrl}
productPrice={Price()}
curationId={selectedCurationId}
patnrId={selectedPatnrId}
smsTpCd={"APP00205"}
//APP00204
/>
)}
</div>
</>
);
}

View File

@@ -1,5 +1,23 @@
import React from "react";
import React, { useState } from "react";
export default function ThemeOption() {
return <>THEME OPTION</>;
import { useSelector } from "react-redux";
import ThemeIndicator from "./indicator/ThemeIndicator";
export default function ThemeOption({ selectedIndex, setSelectedIndex }) {
const productInfo = useSelector((state) => state.home.productData);
console.log("#productInfo", productInfo);
return (
<>
<ThemeIndicator
productInfo={productInfo}
selectedIndex={selectedIndex}
setSelectedIndex={setSelectedIndex}
thumbnailUrls={productInfo[selectedIndex]?.imgUrls600}
/>
<div>THEME OPTION</div>
</>
);
}

View File

@@ -1,11 +1,10 @@
import React, { useState } from 'react';
import React from "react";
import { useSelector } from 'react-redux';
import { useSelector } from "react-redux";
import ThemeHotelIndicator from '../components/indicator/ThemeHotelIndicator';
import HotelOption from './HotelOption';
import ThemeOption from './ThemeOption';
import css from './ThemeProduct.module.less';
import HotelOption from "./HotelOption";
import ThemeOption from "./ThemeOption";
import css from "./ThemeProduct.module.less";
export default function ThemeProduct({
selectedIndex,
@@ -16,21 +15,28 @@ export default function ThemeProduct({
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}>
<ThemeHotelIndicator
selectedIndex={selectedIndex}
setSelectedIndex={setSelectedIndex}
/>
{productInfos.themeInfo?.length > 0 ? (
<ThemeOption />
<ThemeOption
selectedIndex={selectedIndex}
selectedCurationId={selectedCurationId}
selectedPatnrId={selectedPatnrId}
setSelectedIndex={setSelectedIndex}
/>
) : (
<HotelOption
selectedIndex={selectedIndex}
selectedCurationId={selectedCurationId}
selectedPatnrId={selectedPatnrId}
setSelectedIndex={setSelectedIndex}
/>
)}
</div>

View File

@@ -1,23 +1,15 @@
import React, {
useCallback,
useEffect,
useRef,
useState,
} from 'react';
import React, { useCallback, useEffect, useRef, useState } from "react";
import classNames from 'classnames';
import { useSelector } from 'react-redux';
import classNames from "classnames";
import { useSelector } from "react-redux";
import Image from '@enact/sandstone/Image';
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator
from '@enact/spotlight/SpotlightContainerDecorator';
import Spottable from '@enact/spotlight/Spottable';
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 './ThemeHotelIndicator.module.less';
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 },
@@ -27,10 +19,7 @@ const SpottableComponent = Spottable("div");
const SpottableImage = Spottable(Image);
const IMAGE_WIDTH = 152;
export default function ThemeHotelIndicator({
selectedIndex,
setSelectedIndex,
}) {
export default function HotelIndicator({ selectedIndex, setSelectedIndex }) {
const [selectedImage, setSelectedImage] = useState(null);
const [imageSelectedIndex, setImageSelectedIndex] = useState(0);

View File

@@ -0,0 +1,189 @@
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 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;
const { getScrollTo, scrollTop } = useScrollTo();
let imagePosition = IMAGE_WIDTH * selectedIndex - IMAGE_WIDTH;
useEffect(() => {
if (thumbnailUrls) {
const image = thumbnailUrls[imageSelectedIndex];
setSelectedImage(image);
}
}, [thumbnailUrls, imageSelectedIndex]);
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 (productInfo.length - 1 !== selectedIndex) {
scrollTop({ y: imagePosition - IMAGE_WIDTH, animate: true });
}
}, [selectedIndex]);
const handleDownClick = useCallback(() => {
if (productInfo.length - 1 === selectedIndex) {
return;
}
setSelectedIndex((prev) => prev + 1);
if (selectedIndex > 1) {
scrollTop({
y: imagePosition,
animate: true,
});
}
}, [selectedIndex]);
const renderItem = useCallback(
({ index, ...rest }) => {
const { thumbnailUrl } = productInfo[index];
const { hotelImgUrl } = productInfo[index];
const handleItemClick = () => {
setSelectedIndex(index);
setImageSelectedIndex(0);
};
return (
<>
<SpottableImage
src={thumbnailUrl || 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>
<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>
</div>
</Container>
);
}

View File

@@ -0,0 +1,155 @@
@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;
}
}
}
.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

@@ -1,30 +1,21 @@
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 { Job } from '@enact/core/util';
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator
from '@enact/spotlight/SpotlightContainerDecorator';
import Spottable from '@enact/spotlight/Spottable';
import { Job } from "@enact/core/util";
import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import Spottable from "@enact/spotlight/Spottable";
import { getMainYouMayLike } from '../../../actions/mainActions';
import { pushPanel } from '../../../actions/panelActions';
import TItemCard from '../../../components/TItemCard/TItemCard';
import TVirtualGridList
from '../../../components/TVirtualGridList/TVirtualGridList';
import { panel_names } from '../../../utils/Config';
import { $L } from '../../../utils/helperMethods';
import { SpotlightIds } from '../../../utils/SpotlightIds';
import css from './YouMayLike.module.less';
import { getMainYouMayLike } from "../../../actions/mainActions";
import { pushPanel } from "../../../actions/panelActions";
import TItemCard from "../../../components/TItemCard/TItemCard";
import TVirtualGridList from "../../../components/TVirtualGridList/TVirtualGridList";
import { panel_names } from "../../../utils/Config";
import { $L } from "../../../utils/helperMethods";
import { SpotlightIds } from "../../../utils/SpotlightIds";
import css from "./YouMayLike.module.less";
const Container = SpotlightContainerDecorator(
{ enterTo: "default-element", preserveId: true },
@@ -40,8 +31,6 @@ export default function YouMayLike() {
const youmaylikeData = useSelector((state) => state.main.youmaylikeData);
const data = useSelector((state) => state.main.productData);
console.log("#youmaylike", youmaylikeData);
useEffect(() => {
dispatch(
getMainYouMayLike({