[FeaturedBrandsPanel] UpComing UI 구현
Detail Notes : 1. UpComing, UpComingList, UpComingCard, UI 구현
This commit is contained in:
@@ -15,6 +15,7 @@ import Banner from "./Banner/Banner";
|
|||||||
import css from "./FeaturedBrandsPanel.module.less";
|
import css from "./FeaturedBrandsPanel.module.less";
|
||||||
import LiveChannels from "./LiveChannels/LiveChannels";
|
import LiveChannels from "./LiveChannels/LiveChannels";
|
||||||
import QuickMenu from "./QuickMenu/QuickMenu";
|
import QuickMenu from "./QuickMenu/QuickMenu";
|
||||||
|
import UpComing from "./UpComing/UpComing";
|
||||||
|
|
||||||
const getSelectedBrandInfo = (brandInfo, selectedPatnrId) => {
|
const getSelectedBrandInfo = (brandInfo, selectedPatnrId) => {
|
||||||
return brandInfo.find((brand) => brand?.patnrId === selectedPatnrId);
|
return brandInfo.find((brand) => brand?.patnrId === selectedPatnrId);
|
||||||
@@ -34,6 +35,9 @@ export default function FeaturedBrandsPanel() {
|
|||||||
const brandChannelCnt = useSelector(
|
const brandChannelCnt = useSelector(
|
||||||
(state) => state.brand.brandLiveChannelInfoData.brandChannelCnt
|
(state) => state.brand.brandLiveChannelInfoData.brandChannelCnt
|
||||||
);
|
);
|
||||||
|
const brandLiveChannelUpcoming = useSelector(
|
||||||
|
(state) => state.brand.brandLiveChannelInfoData.brandLiveChannelUpcoming
|
||||||
|
);
|
||||||
|
|
||||||
const [selectedPatnrId, setSelectedPatnrId] = useState(String(panelInfo));
|
const [selectedPatnrId, setSelectedPatnrId] = useState(String(panelInfo));
|
||||||
const [selectedBrandInfo, setSelectedBrandInfo] = useState();
|
const [selectedBrandInfo, setSelectedBrandInfo] = useState();
|
||||||
@@ -73,7 +77,7 @@ export default function FeaturedBrandsPanel() {
|
|||||||
return (
|
return (
|
||||||
/* scenario page 98 */
|
/* scenario page 98 */
|
||||||
<TPanel className={css.container}>
|
<TPanel className={css.container}>
|
||||||
<TBody>
|
<TBody className={css.tBody}>
|
||||||
{brandInfo && brandInfo.length > 1 && (
|
{brandInfo && brandInfo.length > 1 && (
|
||||||
<QuickMenu
|
<QuickMenu
|
||||||
brandInfo={brandInfo}
|
brandInfo={brandInfo}
|
||||||
@@ -96,6 +100,10 @@ export default function FeaturedBrandsPanel() {
|
|||||||
brandChannelCnt={brandChannelCnt}
|
brandChannelCnt={brandChannelCnt}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{brandLiveChannelUpcoming && brandLiveChannelUpcoming.length > 0 && (
|
||||||
|
<UpComing brandLiveChannelUpcoming={brandLiveChannelUpcoming} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</TBody>
|
</TBody>
|
||||||
</TPanel>
|
</TPanel>
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
|
@import "../../style/CommonStyle.module.less";
|
||||||
|
@import "../../style/utils.module.less";
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
|
background-color: @BG_COLOR_01;
|
||||||
|
|
||||||
.tBody {
|
.tBody {
|
||||||
height: 1080px;
|
height: 1080px;
|
||||||
}
|
|
||||||
.sectionContainer {
|
.sectionContainer {
|
||||||
padding-left: 60px;
|
padding-left: 60px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import SectionTitle from "../../../components/SectionTitle/SectionTitle";
|
||||||
|
import { $L } from "../../../utils/helperMethods";
|
||||||
|
import css from "./UpComing.module.less";
|
||||||
|
import UpComingList from "./UpComingList/UpComingList";
|
||||||
|
|
||||||
|
const UPCOMING_STRING = "UPCOMING";
|
||||||
|
|
||||||
|
export default function UpComing({ brandLiveChannelUpcoming }) {
|
||||||
|
return (
|
||||||
|
<div className={css.container}>
|
||||||
|
<SectionTitle title={$L(UPCOMING_STRING)} />
|
||||||
|
<UpComingList brandLiveChannelUpcoming={brandLiveChannelUpcoming} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@import "../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
h2 {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import React, { memo, useCallback, useState } from "react";
|
||||||
|
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
import Spottable from "@enact/spotlight/Spottable";
|
||||||
|
|
||||||
|
import IcUpComingsNormal from "../../../../../../assets/icon/badge/ic-upcomings-nor@3x.png";
|
||||||
|
import IcUpComingsSelected from "../../../../../../assets/icon/badge/ic-upcomings-sel@3x.png";
|
||||||
|
import { $L } from "../../../../../utils/helperMethods";
|
||||||
|
import css from "./UpComingCard.module.less";
|
||||||
|
|
||||||
|
const STRING_CONF = {
|
||||||
|
REMINDER_SETTED: $L("Reminder Setted"),
|
||||||
|
REMOVE_REMINDER: $L("Remove Reminder"),
|
||||||
|
SET_REMINDER: $L("Set Reminder"),
|
||||||
|
WITH_HOST: $L("With Host"),
|
||||||
|
};
|
||||||
|
|
||||||
|
const SpottableComponent = Spottable("div");
|
||||||
|
|
||||||
|
export default memo(function UpComingCard({
|
||||||
|
hostName,
|
||||||
|
onUpComingCardBlur,
|
||||||
|
onUpComingCardClick,
|
||||||
|
onUpComingCardFocus,
|
||||||
|
showName,
|
||||||
|
startTime,
|
||||||
|
...rest
|
||||||
|
}) {
|
||||||
|
const [isFocused, setIsFocused] = useState(false);
|
||||||
|
const [isSelected, setIsSelected] = useState(false);
|
||||||
|
|
||||||
|
const handleBlur = useCallback(() => {
|
||||||
|
setIsFocused(false);
|
||||||
|
onUpComingCardBlur && onUpComingCardBlur();
|
||||||
|
}, [onUpComingCardBlur]);
|
||||||
|
|
||||||
|
const handleClick = useCallback(() => {
|
||||||
|
if (isSelected) {
|
||||||
|
setIsSelected(false);
|
||||||
|
// @@pyh, Todo toast popup and action
|
||||||
|
console.log(
|
||||||
|
"@@\nReminder Notification is turned off.\nSelect Yes to turn on reminders."
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setIsSelected(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpComingCardClick && onUpComingCardClick();
|
||||||
|
}, [isSelected, onUpComingCardClick]);
|
||||||
|
|
||||||
|
const handleFocus = useCallback(() => {
|
||||||
|
setIsFocused(true);
|
||||||
|
onUpComingCardFocus && onUpComingCardFocus();
|
||||||
|
}, [onUpComingCardFocus]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SpottableComponent
|
||||||
|
className={classNames(css.item, isSelected && css.selected)}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
onClick={handleClick}
|
||||||
|
onFocus={handleFocus}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{!isFocused && (
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
src={isSelected ? IcUpComingsSelected : IcUpComingsNormal}
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
{isSelected && <span>{STRING_CONF.REMINDER_SETTED}</span>}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<time>
|
||||||
|
{
|
||||||
|
// @@pyh, Todo 시간 변환
|
||||||
|
startTime
|
||||||
|
}
|
||||||
|
</time>
|
||||||
|
<h3>{showName}</h3>
|
||||||
|
<p>{STRING_CONF.WITH_HOST + " " + hostName}</p>
|
||||||
|
|
||||||
|
{isFocused && (
|
||||||
|
<button type="button">
|
||||||
|
{isSelected ? STRING_CONF.REMOVE_REMINDER : STRING_CONF.SET_REMINDER}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</SpottableComponent>
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
@import "../../../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.item {
|
||||||
|
/* normal */
|
||||||
|
position: relative;
|
||||||
|
.size(@w: 480px, @h: 344px);
|
||||||
|
padding: 30px;
|
||||||
|
border: solid 1px @COLOR_GRAY02;
|
||||||
|
border-radius: 12px;
|
||||||
|
background-color: @COLOR_WHITE;
|
||||||
|
|
||||||
|
> div:nth-child(1) {
|
||||||
|
.flex(@justifyCenter: flex-start);
|
||||||
|
margin-bottom: 30px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
.size(@w: 72px, @h: 72px);
|
||||||
|
margin-right: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
.font(@fontFamily: @baseFontBold, @fontSize: 36px);
|
||||||
|
color: @COLOR_WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
time {
|
||||||
|
display: inline-block;
|
||||||
|
min-height: 42px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
.font(@fontFamily: @baseFontBold, @fontSize: 36px);
|
||||||
|
color: @PRIMARY_COLOR_RED;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
.font(@fontFamily: @baseFontBold, @fontSize: 30px);
|
||||||
|
color: @COLOR_GRAY06;
|
||||||
|
.elip(@clamp:2);
|
||||||
|
word-break: break-all;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
.font(@fontFamily: @baseFont, @fontSize: 24px);
|
||||||
|
color: @COLOR_GRAY04;
|
||||||
|
.elip(@clamp:1);
|
||||||
|
word-break: break-all;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
.position(@position: absolute, @right: 30px, @bottom: 30px, @left: 30px);
|
||||||
|
.flex();
|
||||||
|
.size(@w: 420px, @h: 84px);
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: @PRIMARY_COLOR_RED;
|
||||||
|
.font(@fontFamily: @baseFontBold, @fontSize: 30px);
|
||||||
|
color: @COLOR_WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* normal focused */
|
||||||
|
&:focus-within {
|
||||||
|
&::after {
|
||||||
|
.focused(@boxShadow:50px, @borderRadius:12px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* selected */
|
||||||
|
.selected {
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
|
||||||
|
time {
|
||||||
|
color: @SELECTED_COLOR_RED;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: @COLOR_GRAY05;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* selected focused */
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"main": "UpComingCard.jsx",
|
||||||
|
"styles": [
|
||||||
|
"UpComingCard.module.less"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import React, { useCallback } from "react";
|
||||||
|
|
||||||
|
import { VirtualGridList } from "@enact/sandstone/VirtualList";
|
||||||
|
|
||||||
|
import { scaleH, scaleW } from "../../../../utils/helperMethods";
|
||||||
|
import UpComingCard from "./UpComingCard/UpComingCard";
|
||||||
|
import css from "./UpComingList.module.less";
|
||||||
|
|
||||||
|
const LIST_ITEM_CONF = {
|
||||||
|
ITEM_WIDTH: 480,
|
||||||
|
ITEM_HEIGHT: 344,
|
||||||
|
SAPCING: 18,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function UpComingList({ brandLiveChannelUpcoming }) {
|
||||||
|
const renderItem = useCallback(
|
||||||
|
({ index, ...rest }) => {
|
||||||
|
const {
|
||||||
|
hstNm: hostName,
|
||||||
|
showNm: showName,
|
||||||
|
strtDt: startTime,
|
||||||
|
} = brandLiveChannelUpcoming[index];
|
||||||
|
return (
|
||||||
|
<UpComingCard
|
||||||
|
{...rest}
|
||||||
|
hostName={hostName}
|
||||||
|
showName={showName}
|
||||||
|
startTime={startTime}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[brandLiveChannelUpcoming]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={css.container}>
|
||||||
|
{brandLiveChannelUpcoming && (
|
||||||
|
<VirtualGridList
|
||||||
|
className={css.virtualGridList}
|
||||||
|
dataSize={brandLiveChannelUpcoming.length}
|
||||||
|
direction="horizontal"
|
||||||
|
itemRenderer={renderItem}
|
||||||
|
itemSize={{
|
||||||
|
minWidth: scaleW(LIST_ITEM_CONF.ITEM_WIDTH),
|
||||||
|
minHeight: scaleH(LIST_ITEM_CONF.ITEM_HEIGHT),
|
||||||
|
}}
|
||||||
|
noScrollByWheel
|
||||||
|
scrollMode="translate"
|
||||||
|
spacing={scaleW(LIST_ITEM_CONF.SAPCING)}
|
||||||
|
verticalScrollbar="hidden"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
@import "../../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
.size(@w: 100%, @h: 344px);
|
||||||
|
|
||||||
|
.virtualGridList {
|
||||||
|
overflow: unset;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
overflow: unset !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"main": "UpComingList.jsx",
|
||||||
|
"styles": [
|
||||||
|
"UpComingList.module.less"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"main": "UpComming.jsx",
|
||||||
|
"styles": [
|
||||||
|
"UpComming.module.less"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user