[TrendingNowPanel] Popular Show 작업중

This commit is contained in:
jiwon93.son
2024-03-29 17:13:35 +09:00
parent c710d6a1b9
commit 33f65555de
10 changed files with 747 additions and 4 deletions

View File

@@ -0,0 +1,180 @@
import React, { useCallback, useEffect, useState } from "react";
import classNames from "classnames";
import { useDispatch, useSelector } from "react-redux";
import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import { pushPanel } from "../../../actions/panelActions";
import TButton from "../../../components/TButton/TButton";
import useScrollTo from "../../../hooks/useScrollTo";
import { panel_names } from "../../../utils/Config";
import FeaturedVideoPlayer from "../../FeaturedBrandsPanel/FeaturedVideoPlayer/FeaturedVideoPlayer";
import LiveChannelsVerticalProductList from "../../FeaturedBrandsPanel/LiveChannels/LiveChannelsVerticalContents/LiveChannelsVerticalProductList/LiveChannelsVerticalProductList";
import css from "./PopularShowIndicator.module.less";
import PopularProductList from "./PopularShowVerticalContents/PopularProductList";
import PopularVideoCard from "./PopularVideoCard/PopularVideoCard";
import PopularVideoPlayer from "./PopularVideoPlayer/PopularVideoPlayer";
const Container = SpotlightContainerDecorator(
{
enterTo: "last-focused",
preserveld: true,
},
"div"
);
const ProductContainer = SpotlightContainerDecorator(
{
enterTo: "default-element",
preserveld: true,
},
"div"
);
export default function PopularShowIndicator() {
const [selectedIndex, setSelectedIndex] = useState(0);
const [cardHasFocus, setCardHasFocus] = useState(false);
// const [topInfodatas, setTopInfodatas] = useState(topInfos[0]);
const topInfos = useSelector((state) => state.main.top20ShowData.topInfos);
const dispatch = useDispatch();
const { getScrollTo, scrollTop } = useScrollTo();
// useEffect(()=>{},[])
const {
thumbnailUrl960,
showNm,
disclaimer,
expsOrd,
orderPhnNo,
productInfos,
patnrId,
selectedPatnrId,
vtctpYn,
showUrl,
catCd,
showId,
} = topInfos[selectedIndex];
const isVertical = Boolean(vtctpYn === "Y");
const handlePrevClick = useCallback(() => {
if (selectedIndex > 0) setSelectedIndex((prev) => prev - 1);
else return;
}, [selectedIndex]);
const handleNextClick = useCallback(() => {
if (selectedIndex < topInfos.length - 1)
setSelectedIndex((prev) => prev + 1);
else return;
}, [selectedIndex]);
const handleFocus = useCallback(() => {
setCardHasFocus(true);
}, []);
const handleBlur = useCallback(() => {
setCardHasFocus(false);
}, []);
useEffect(() => {
console.log("###### spot");
Spotlight.focus("popular_video");
}, []);
// 비디오 클릭
const videoClick = () => {
dispatch(
pushPanel({
name: panel_names.PLAYER_PANEL,
panelInfo: {
playInfo: {
patnrId,
showId,
lgCatCd: catCd,
type: "VOD",
showUrl,
},
},
})
);
};
// useEffect(() => {
// console.log("#cardHasFocus", cardHasFocus);
// console.log("#showUrl", showUrl);
// }, [cardHasFocus]);
const onSpotlightRight = () => {
console.log("# onSpotlightRight");
Spotlight.focus("popular-next-arrow");
};
const onSpotlightLeft = () => {
console.log("# onSpotlightLeft");
Spotlight.focus("itemCard_01");
};
return (
<Container className={css.popularContainer}>
{/* <div className={css.wrapper}> */}
<TButton
className={classNames(css.button, css.prevBtn)}
onClick={handlePrevClick}
/>
{topInfos && topInfos.length > 0 && (
<div className={css.popularContents}>
<Container>
<PopularVideoCard
thumbnailImgPath={thumbnailUrl960}
showNm={showNm}
disclaimer={disclaimer}
expsOrd={expsOrd}
orderPhnNo={orderPhnNo}
thumbnailType={isVertical ? "vertical" : "horizontal"}
onFocus={handleFocus}
onBlur={handleBlur}
isVertical={isVertical}
popularShowInfos={topInfos[selectedIndex]}
showUrl={showUrl}
onClick={videoClick}
spotlightId="popular_video"
/>
</Container>
{/* <PopularVideoPlayer
className={classNames(
css.player,
isVertical ? css.vertical : css.horizontal,
cardHasFocus && css.show
)}
src={showUrl}
shouldPlay={cardHasFocus}
width={isVertical ? 326 : 1002}
height={564}
/> */}
{/* </Container> */}
{/* <ProductContainer spotlightId="active_product"> */}
<PopularProductList
brandProductInfo={productInfos}
patnrId={patnrId}
selectedPatnrId={selectedPatnrId}
// onSpotlightLeft={onSpotlightLeft}
onSpotlightRight={onSpotlightRight}
/>
{/* </ProductContainer> */}
{/* {topInfos && topInfos.length >= 1 && (
<PopularVideoCard thumbnailImgPath={topInfos[0].thumbnailUrl} />
)} */}
</div>
)}
<TButton
className={classNames(css.button, css.nextBtn)}
onClick={handleNextClick}
onSpotlightLeft={onSpotlightLeft}
spotlightId="popular-next-arrow"
/>
</Container>
);
}

View File

@@ -0,0 +1,73 @@
@import "../../../style/CommonStyle.module.less";
@import "../../../style/utils.module.less";
.popularContainer {
.size(@w:1620px,@h:564px);
position: relative;
margin: 42px auto 0;
.popularContents {
display: flex;
justify-content: space-between;
}
.button {
position: absolute;
top: 240px;
z-index: 11;
min-width: 84px;
height: 84px;
background: transparent;
box-shadow: none;
.imgElement(84px, 84px, center, center);
&.prevBtn {
left: -30px;
background-image: url("../../../../assets/images/btn/btn-left-84-nor@3x.png");
box-shadow: none;
&:focus {
background-image: url("../../../../assets/images/btn/btn-left-84-foc@3x.png");
}
}
&.nextBtn {
right: -30px;
background-image: url("../../../../assets/images/btn/btn-right-84-nor@3x.png");
&:focus {
background-image: url("../../../../assets/images/btn/btn-right-84-foc@3x.png");
}
}
}
.player {
.position(@position: absolute, @top: 22px, @left: 0);
z-index: 20;
height: 564px;
display: none;
overflow: hidden;
border-radius: 12px;
&.vertical {
width: 326px;
}
&.horizontal {
width: 1002px;
}
&::before {
// Video desc
// .position(@position: absolute, @top: 33px, @left: 18px);
// z-index: 20;
// .size(@w: 108px, @h: 48px);
// border-radius: 12px;
// background-image: url("../../../../../assets/images/tag/tag-liveshow.png");
// background-position: center center;
// background-repeat: no-repeat;
// content: "";
}
&::after {
.focused(@borderRadius: 12px);
}
.focusDropShadow();
}
}

View File

@@ -0,0 +1,84 @@
import React, { memo, useCallback, useEffect } from "react";
import { useDispatch } from "react-redux";
import Spotlight from "@enact/spotlight";
import { SpotlightContainerDecorator } from "@enact/spotlight/SpotlightContainerDecorator";
import { pushPanel } from "../../../../actions/panelActions";
import TItemCard, { TYPES } from "../../../../components/TItemCard/TItemCard";
import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList";
import useScrollTo from "../../../../hooks/useScrollTo";
import { panel_names } from "../../../../utils/Config";
import css from "./PopularProductList.module.less";
const Container = SpotlightContainerDecorator(
{ enterTo: "default-element", preserveld: true },
"div"
);
export default function PopularProductList({
brandProductInfo,
patnrId,
selectedPatnrId,
onSpotlightRight,
}) {
const { getScrollTo, scrollTop } = useScrollTo();
const dispatch = useDispatch();
useEffect(() => {
scrollTop({ animate: false });
}, [onSpotlightRight]);
const renderItem = useCallback(
({ index, ...rest }) => {
const { offerInfo, prdtId, imgUrl, prdtNm, priceInfo, soldoutFlag } =
brandProductInfo[index];
const handleClick = () => {
dispatch(
pushPanel({
name: panel_names.DETAIL_PANEL,
panelInfo: { patnrId, prdtId },
})
);
};
return (
<TItemCard
imageAlt={prdtNm}
imageSource={imgUrl}
onClick={handleClick}
offerInfo={offerInfo}
priceInfo={priceInfo}
// productId={prdtId}
productName={prdtNm}
soldoutFlag={soldoutFlag}
className={css.itemCard}
type={TYPES.horizontal}
onSpotlightRight={onSpotlightRight}
spotlightId={`itemCard_${index}`}
{...rest}
/>
);
},
[brandProductInfo, dispatch, patnrId]
);
return (
<div className={css.container}>
{brandProductInfo && (
<TVirtualGridList
cbScrollTo={getScrollTo}
className={css.tVirtualGridList}
dataSize={brandProductInfo.length}
itemHeight={236}
itemWidth={600}
spacing={12}
renderItem={renderItem}
/>
)}
</div>
);
}

View File

@@ -0,0 +1,34 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.container {
position: relative;
overflow: hidden;
.size(@w: 636px, @h: 610px);
top: -22px;
&::after {
.position(@position: absolute, @right: 0, @bottom: 0);
z-index: 12;
background-size: 100% 100%;
.size(@w: 636px, @h: 279px);
background-image: url("../../../../../assets/images/img-topdeals-list-masking@3x.png");
content: "";
}
// tVirtualGridListContainer
// > div {
// .size(@w: 636px, @h: 564px);
// }
> div:nth-child(1) {
.size(@w: inherit, @h: 452px);
> div:nth-child(1) {
padding: 22px 18px;
}
}
}
.itemCard {
.size(@w: 600px, @h: 236px);
}

View File

@@ -0,0 +1,105 @@
import React, { useCallback, useEffect, useState } from "react";
import classNames from "classnames";
import Spottable from "@enact/spotlight/Spottable";
import ic_crown from "../../../../../assets/images/icons/ic-crown-badge@3x.png";
import ic_warning from "../../../../../assets/images/icons/ic-warning@3x.png";
import ic_call from "../../../../../assets/images/icons/ic-wh-call@3x.png";
import tag_call from "../../../../../assets/images/tag/tag-calltoorder@3x.png";
import TVideoPlayer from "../../../../components/TVideoPlayer/TVideoPlayer";
import PopularVideoPlayer from "../PopularVideoPlayer/PopularVideoPlayer";
import css from "./PopularVideoCard.module.less";
const SpottableComponent = Spottable("div");
const TYPE = {
horizontal: "horizontal",
vertical: "vertical",
};
export default function PopularVideoCard({
onBlur,
onClick,
onFocus,
showNm,
expsOrd,
orderPhnNo,
thumbnailImgPath,
disclaimer,
isVertical,
showUrl,
popularShowInfos,
spotlightId,
thumbnailType = TYPE.horizontal,
}) {
const [isFocused, setIsFocused] = useState(false);
const _onBlur = useCallback(() => {
setIsFocused(false);
onBlur && onBlur();
}, [onBlur, isFocused]);
const _onClick = useCallback(() => {
onClick && onClick();
}, [onClick]);
const _onFocus = useCallback(() => {
setIsFocused(true);
onFocus && onFocus();
}, [onFocus, isFocused]);
return (
<SpottableComponent
className={classNames(css.card, isFocused && css.focused)}
onBlur={_onBlur}
onClick={_onClick}
onFocus={_onFocus}
spotlightId={spotlightId}
>
<figure className={css[thumbnailType]}>
{thumbnailImgPath && (
<img src={thumbnailImgPath} alt="" loading="lazy" />
)}
</figure>
{/* {!isFocused && ( */}
<div className={classNames(css.videoDesc, isFocused && css.descFocused)}>
<div>
<h3>{showNm && showNm}</h3>
<div className={css.rank}>
<img src={ic_crown} alt="" />
<span>{expsOrd}</span>
</div>
</div>
{orderPhnNo && (
<div className={css.callBox}>
<img src={tag_call} alt="" />
<div className={css.callNum}>
<img src={ic_call} alt="" />
<span>{orderPhnNo}</span>
</div>
</div>
)}
<div className={css.notice}>
<img src={ic_warning} alt="" />
<span>{disclaimer}</span>
</div>
</div>
{isFocused && (
<PopularVideoPlayer
className={classNames(
css.player,
isVertical ? css.vertical : css.horizontal
)}
src={showUrl}
shouldPlay={isFocused}
// videoIsPlaying={isFocused}
width={isVertical ? 326 : 1002}
height={564}
/>
)}
</SpottableComponent>
);
}

View File

@@ -0,0 +1,201 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.card {
position: relative;
z-index: 10;
overflow: hidden;
.size(@w: 1002px, @h: 564px);
border-radius: 12px;
&.focused {
.focusDropShadow();
}
&::after {
.position(@position: absolute, @top: 0, @right: 0, @left: 0);
.flex(@direction: column, @justifyCenter: space-between, @alignCenter: flex-start);
.size(@w: 1002px, @h: 564px);
background-image: linear-gradient(to top, transparent 55%, @COLOR_BLACK);
content: "";
}
> figure:nth-child(1) {
.position(@position: absolute, @top: 0, @right: 0, @left: 0);
z-index: -1;
.flex();
overflow: hidden;
&.horizontal {
> img {
.size(@w: 1002px, @h: 564px);
}
}
&.vertical {
background-color: @COLOR_BLACK;
> img {
.size(@w: 326px, @h: 564px);
}
}
}
> div:nth-child(2) {
position: absolute;
z-index: 10;
display: flex;
flex-direction: column;
width: 100%;
// padding: 18px 18px 18px 138px;
// padding: 27px 0 0 18px;
color: @COLOR_WHITE;
&:focus {
.focused(@borderRadius: 12px);
}
&::after {
.position(@position: absolute, @top: 33px, @left: 18px);
.size(@w: 108px, @h: 48px);
background-position: center center;
background-repeat: no-repeat;
content: "";
}
h3 {
min-height: 42px;
margin-bottom: 6px;
font-weight: bold;
font-size: 30px;
line-height: 1.27;
.elip(@clamp:1);
word-break: break-all;
padding: 19px 0 0 18px;
}
time {
height: 30px;
font-weight: normal;
font-size: 24px;
line-height: 1.33;
}
}
// &:focus {
// &::after {
// .focused(@borderRadius: 12px);
// }
// .focusDropShadow();
// }
}
// best seller
.videoDesc {
height: 100%;
.rank {
padding: 21px 12px;
.position(@position: absolute, @top: -1px, @right: 18px);
.flex(@direction: column);
.size(@w:78px,@h:102px);
background-color: @COLOR_GRAY07;
.font(@fontFamily: @robotoFontBold, @fontSize: 24px);
color: @COLOR_WHITE;
.border-solid(3px,@COLOR_WHITE);
border-bottom-left-radius: 79px;
border-bottom-right-radius: 79px;
&.descFocused {
background-color: red;
}
> img {
.size(@w:36px,@h:36px);
margin-bottom: 6px;
}
> span {
.font(@fontFamily: @arialFontBold, @fontSize: 42px);
font-size: 42px;
}
}
.callBox {
// width: 250px;
height: 106px;
padding: 14px;
border-radius: 10px;
border: solid 2px rgba(255, 255, 255, 0.7);
background-color: #1e1e1e;
position: absolute;
left: 60px;
bottom: 114px;
box-shadow: 5px 8.7px 15px 0 rgba(6, 0, 1, 0.5);
> span {
width: 102px;
height: 35px;
}
> img {
width: 102px;
height: 35px;
margin-bottom: 9px;
}
.callNum {
> img {
width: 34px;
height: 34px;
}
> span {
.font(@fontFamily: @baseFont, @fontSize: 29px);
font-weight: bold;
font-stretch: normal;
font-style: normal;
line-height: 1.1;
}
}
}
.notice {
width: 100%;
height: 54px;
background: #000000;
.flex(@justifyCenter:flex-start,);
padding: 6px 0 18px 18px;
position: absolute;
bottom: 0;
img {
width: 18px;
height: 18px;
margin: 6px 12px 6px 0;
object-fit: contain;
}
span {
line-height: normal;
letter-spacing: normal;
text-align: left;
.font(@fontFamily:@baseFont, @fontSize:20px);
color: @COLOR_GRAY04;
}
}
}
.player {
// .position(@position: absolute, @top: 0, @left: 0);
// z-index: 10;
height: 564px;
&.horizontal {
width: 1002px;
}
&.vertical {
width: 362px;
}
&::after {
.focused(@borderRadius: 12px);
z-index: 10;
}
}

View File

@@ -0,0 +1,62 @@
import React, { memo, useCallback } from "react";
import ReactPlayer from "react-player";
import VideoPlayer from "../../../../components/VideoPlayer/VideoPlayer";
import { scaleH, scaleW } from "../../../../utils/helperMethods";
export default memo(function PopularVideoPlayer({
className,
readyCb,
src,
shouldPlay,
width,
height,
}) {
const handleReady = useCallback(() => {
readyCb && readyCb(true);
}, [readyCb]);
const mediainfoHandler = useCallback((e) => {
const type = e.type;
if (type !== "timeupdate") {
console.log("@@ [mediaInfoHandler].....", type);
}
switch (type) {
case "loadeddata":
console.log("@@ [mediaInfoHandler] loaded data");
break;
case "durationchange":
console.log("@@ [mediaInfoHandler] duration", e.currentTarget.duration);
break;
}
}, []);
return (
<div>
{typeof window === window.PalmSystem ? (
<VideoPlayer
className={className}
noAutoShowMediaControls
// onLoadedData={handleReady}
onLoadedData={mediainfoHandler}
onDurationChange={mediainfoHandler}
spotlightDisabled
>
{shouldPlay && <source src={src} type="application/mpegurl" />}
</VideoPlayer>
) : (
<ReactPlayer
className={className}
onReady={handleReady}
playing={shouldPlay}
url={shouldPlay ? src : ""}
width={scaleW(width)}
height={scaleH(height)}
/>
)}
</div>
);
});

View File

@@ -15,6 +15,7 @@ import useScrollReset from "../../hooks/useScrollReset";
import useScrollTo from "../../hooks/useScrollTo";
import { panel_names } from "../../utils/Config";
import { $L } from "../../utils/helperMethods";
import PopularShowIndicator from "./PopularShow/PopularShowIndicator";
import css from "./TrendingNowPanel.module.less";
const Container = SpotlightContainerDecorator(
@@ -71,12 +72,12 @@ export default function TrendingNowPanel({ panelInfo }) {
};
}, []);
const [isVideoErrorOccurred, setIsVideoErrorOccurred] = useState(false);
return (
<TPanel>
<TBody className={css.trendingNow} cbScrollTo={getScrollTo}>
<Container className={css.popularContainer}>
<SectionTitle title={STRING_CONF.POPULAR_SHOW} />
<PopularShowIndicator />
</Container>
<Container className={css.bestContainer}>
<SectionTitle title={STRING_CONF.BEST_SELLER} />

View File

@@ -6,11 +6,14 @@
height: 100%;
.popularContainer {
width: 100%;
padding: 64px 60px 60px 60px;
height: 762px;
padding: 64px 0;
height: 766px;
background-image: url("../../../assets/images/img-topdeals-bg@3x.png");
background-size: contain;
background-size: cover;
background-repeat: no-repeat;
> h2 {
padding-left: 60px;
}
}
.bestContainer {