SHOPTIME-1933 [Shoptime 고도화] TV 앱 테스트 (시스템 운영팀) / [SHOPTIME-2666] Reminder / 알림 팝업을 클릭 했지만 Live로 이동하지 않음

SHOPTIME-1933 [Shoptime 고도화] TV 앱 테스트 (시스템 운영팀) / [SHOPTIME-3305] Upcoming / Alert > yes로 진입 시 포커싱 이슈

changed files:
1. TabLayout.jsx
2. FeaturedBrandsPanel.jsx
3. QuickMenuItem.jsx
4. RandomUnit.jsx
5. RollingUnit.jsx
6. mainView.jsx
7. WelcomeEventPanel.jsx

detail note:
 - 원인: 해당 경로 진입 시, live channels에 대한 focus logic 부재
 - 대책: 해당 경로에 대한 focus logic 추가
This commit is contained in:
younghoon100.park
2024-10-24 18:29:12 +09:00
parent 86bb667a72
commit 0afb36618b
7 changed files with 244 additions and 147 deletions

View File

@@ -1,4 +1,10 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import classNames from "classnames";
import { useDispatch, useSelector } from "react-redux";
@@ -25,7 +31,10 @@ import css from "./RollingUnit.module.less";
const SpottableComponent = Spottable("div");
const Container = SpotlightContainerDecorator({ enterTo: "last-focused" }, "div");
const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused" },
"div"
);
const LINK_TYPES = {
FEATURED_BRANDS: "DSP00501",
@@ -52,7 +61,12 @@ const createPanelInfo = (data, categoryData = {}) => ({
focusedContainerId: null,
});
export default function RollingUnit({ bannerData, spotlightId, isHorizontal, handleItemFocus }) {
export default function RollingUnit({
bannerData,
spotlightId,
isHorizontal,
handleItemFocus,
}) {
const rollingData = bannerData.bannerDetailInfos;
const rollingDataLength = bannerData.bannerDetailInfos.length;
@@ -60,17 +74,23 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
const curationId = useSelector((state) => state.home?.bannerData?.curationId);
const curtNm = useSelector((state) => state.home?.bannerData?.curtNm);
const shptmTmplCd = useSelector((state) => state.home?.bannerData?.shptmTmplCd);
const shptmTmplCd = useSelector(
(state) => state.home?.bannerData?.shptmTmplCd
);
const nowMenu = useSelector((state) => state.common.menu.nowMenu);
const entryMenu = useSelector((state) => state.common.menu.entryMenu);
const homeCategory = useSelector((state) => state.home.menuData?.data?.homeCategory);
const homeCategory = useSelector(
(state) => state.home.menuData?.data?.homeCategory
);
const countryCode = useSelector((state) => state.common.httpHeader.cntry_cd);
const bannerId = `banner-${bannerData.banrLctnNo}`;
const savedIndex = useSelector((state) => state.home.bannerIndices[bannerId]);
const [startIndex, setStartIndex] = useState(savedIndex !== undefined ? savedIndex : 0);
const [startIndex, setStartIndex] = useState(
savedIndex !== undefined ? savedIndex : 0
);
const lastIndexRef = useRef(rollingDataLength - 1);
const doRollingRef = useRef(false);
const [unitHasFocus, setUnitHasFocus] = useState(false);
@@ -120,7 +140,11 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
return {
banrNo: `${currentRollingData?.banrDpOrd}`,
banrTpNm: currentRollingData?.vtctpYn ? (currentRollingData.vtctpYn === "Y" ? "Vertical" : "Horizontal") : "",
banrTpNm: currentRollingData?.vtctpYn
? currentRollingData.vtctpYn === "Y"
? "Vertical"
: "Horizontal"
: "",
contId,
contNm,
contTpNm: currentRollingData?.shptmBanrTpNm ?? "",
@@ -147,7 +171,9 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
const deltaTime = time - previousTimeRef.current;
if (deltaTime >= 10000 && doRollingRef.current) {
setStartIndex((prevIndex) => (prevIndex === lastIndexRef.current ? 0 : prevIndex + 1));
setStartIndex((prevIndex) =>
prevIndex === lastIndexRef.current ? 0 : prevIndex + 1
);
previousTimeRef.current = time;
}
} else {
@@ -233,7 +259,9 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
rollingData[startIndex].shptmLnkTpCd === LINK_TYPES.CATEGORY
) {
if (homeCategory && homeCategory.length > 0) {
const foundCategory = homeCategory.find((data) => data.lgCatCd === rollingData[startIndex].lgCatCd);
const foundCategory = homeCategory.find(
(data) => data.lgCatCd === rollingData[startIndex].lgCatCd
);
if (foundCategory) {
return {
lgCatNm: foundCategory.lgCatNm,
@@ -285,16 +313,23 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
switch (linkType) {
case LINK_TYPES.FEATURED_BRANDS:
handlePushPanel(panel_names.FEATURED_BRANDS_PANEL, {
from: "gnb",
patnrId: currentData.patnrId,
});
break;
case LINK_TYPES.TRENDING_NOW:
handlePushPanel(panel_names.TRENDING_NOW_PANEL, createPanelInfo(currentData));
handlePushPanel(
panel_names.TRENDING_NOW_PANEL,
createPanelInfo(currentData)
);
break;
case LINK_TYPES.HOT_PICKS:
handlePushPanel(panel_names.HOT_PICKS_PANEL, createPanelInfo(currentData));
handlePushPanel(
panel_names.HOT_PICKS_PANEL,
createPanelInfo(currentData)
);
break;
case LINK_TYPES.ON_SALE:
@@ -305,7 +340,10 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
case LINK_TYPES.CATEGORY:
if (Object.keys(categoryData).length > 0) {
handlePushPanel(panel_names.CATEGORY_PANEL, createPanelInfo(currentData, categoryData));
handlePushPanel(
panel_names.CATEGORY_PANEL,
createPanelInfo(currentData, categoryData)
);
}
break;
@@ -337,7 +375,15 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
logTpNo: LOG_TP_NO.TOP_CONTENTS.CLICK,
})
);
}, [rollingData, startIndex, bannerId, dispatch, categoryData, handlePushPanel, topContentsLogInfo]);
}, [
rollingData,
startIndex,
bannerId,
dispatch,
categoryData,
handlePushPanel,
topContentsLogInfo,
]);
const videoClick = useCallback(() => {
if (bannerId) {
@@ -365,7 +411,14 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
logTpNo: LOG_TP_NO.TOP_CONTENTS.CLICK,
})
);
}, [rollingData, startIndex, bannerId, dispatch, handleStartVideoPlayer, topContentsLogInfo]);
}, [
rollingData,
startIndex,
bannerId,
dispatch,
handleStartVideoPlayer,
topContentsLogInfo,
]);
// 10초 롤링
useEffect(() => {
@@ -415,7 +468,12 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
}, [nowMenu]);
return (
<Container className={classNames(css.rollingWrap, isHorizontal && css.isHorizontalWrap)}>
<Container
className={classNames(
css.rollingWrap,
isHorizontal && css.isHorizontalWrap
)}
>
{rollingDataLength !== 1 ? (
<SpottableComponent
className={classNames(css.arrow, css.leftBtn)}
@@ -429,7 +487,8 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
/>
) : null}
{rollingData && rollingData[startIndex].shptmBanrTpNm === "Image Banner" ? (
{rollingData &&
rollingData[startIndex].shptmBanrTpNm === "Image Banner" ? (
<SpottableComponent
className={classNames(css.itemBox, isHorizontal && css.isHorizontal)}
onClick={imageBannerClick}
@@ -438,7 +497,9 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
spotlightId={spotlightId}
spotlightDisabled={contentsFocus}
aria-label={
rollingData[startIndex].prdtNm ? rollingData[startIndex].prdtNm : rollingData[startIndex].tmnlImgNm
rollingData[startIndex].prdtNm
? rollingData[startIndex].prdtNm
: rollingData[startIndex].tmnlImgNm
}
>
<div className={css.imgBanner}>
@@ -456,14 +517,28 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
aria-label={"LIVE " + rollingData[startIndex].showNm}
>
<p className={css.liveIcon}>
<CustomImage delay={0} src={liveShow} animationSpeed="fast" ariaLabel="LIVE icon" />
<CustomImage
delay={0}
src={liveShow}
animationSpeed="fast"
ariaLabel="LIVE icon"
/>
</p>
<div className={classNames(css.itemBox, isHorizontal && css.isHorizontal)}>
<div
className={classNames(
css.itemBox,
isHorizontal && css.isHorizontal
)}
>
{rollingData[startIndex].tmnlImgPath == null ? (
<CustomImage
delay={0}
src={rollingData[startIndex].vtctpYn === "Y" ? emptyVerImage : emptyHorImage}
src={
rollingData[startIndex].vtctpYn === "Y"
? emptyVerImage
: emptyHorImage
}
ariaLabel={rollingData[startIndex].tmnlImgNm}
fallbackSrc={isHorizontal ? emptyHorImage : emptyVerImage}
/>
@@ -480,7 +555,11 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
{rollingData[startIndex].tmnlImgPath == null ? (
""
) : (
<CustomImage delay={0} src={btnPlay} ariaLabel="Play video Button" />
<CustomImage
delay={0}
src={btnPlay}
ariaLabel="Play video Button"
/>
)}
</div>
</div>
@@ -505,11 +584,20 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
spotlightDisabled={contentsFocus}
aria-label={rollingData[startIndex].showNm}
>
<div className={classNames(css.itemBox, isHorizontal && css.isHorizontal)}>
<div
className={classNames(
css.itemBox,
isHorizontal && css.isHorizontal
)}
>
{rollingData[startIndex].tmnlImgPath == null ? (
<CustomImage
delay={0}
src={rollingData[startIndex].vtctpYn === "Y" ? emptyVerImage : emptyHorImage}
src={
rollingData[startIndex].vtctpYn === "Y"
? emptyVerImage
: emptyHorImage
}
ariaLabel={rollingData[startIndex].tmnlImgNm}
/>
) : (
@@ -524,7 +612,11 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
{rollingData[startIndex].tmnlImgPath == null ? (
""
) : (
<CustomImage delay={0} src={btnPlay} ariaLabel="Play video Button" />
<CustomImage
delay={0}
src={btnPlay}
ariaLabel="Play video Button"
/>
)}
</div>
@@ -556,7 +648,9 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
spotlightId={spotlightId}
spotlightDisabled={contentsFocus}
aria-label={
rollingData[startIndex].prdtNm ? rollingData[startIndex].prdtNm : rollingData[startIndex].tmnlImgNm
rollingData[startIndex].prdtNm
? rollingData[startIndex].prdtNm
: rollingData[startIndex].tmnlImgNm
}
>
<div className={css.productInfo}>
@@ -573,9 +667,13 @@ export default function RollingUnit({ bannerData, spotlightId, isHorizontal, han
: discountRate
? discountedPrice
: originalPrice}
{discountRate && !isHorizontal && <span className={css.saleAccBox}>{originalPrice}</span>}
{discountRate && !isHorizontal && (
<span className={css.saleAccBox}>{originalPrice}</span>
)}
</div>
{isHorizontal && <span className={css.saleAccBox}>{originalPrice}</span>}
{isHorizontal && (
<span className={css.saleAccBox}>{originalPrice}</span>
)}
</div>
<div className={css.itemImgBox}>