[FeaturedBrandsPanel] section CATEGORY, scroll & focus 조정
Detail Notes : 1. 새로운 시나리오 가이드에 따른 DetailPanel 진입 이후 scroll & focus 조정
This commit is contained in:
@@ -10,7 +10,6 @@ import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
import { Job } from "@enact/core/util";
|
||||
import Spotlight from "@enact/spotlight";
|
||||
import { getContainerId } from "@enact/spotlight/src/container";
|
||||
|
||||
import {
|
||||
getBrandBestSeller,
|
||||
@@ -194,6 +193,8 @@ export default function FeaturedBrandsPanel() {
|
||||
(state) => state.brand.brandShowroomData.status
|
||||
);
|
||||
|
||||
const [firstFocusableTargetId, setFirstFocusableTargetId] = useState();
|
||||
const [spotlightDisabled, setSpotlightDisabled] = useState(true);
|
||||
const [selectedPatnrId, setSelectedPatnrId] = useState();
|
||||
const [selectedBrandInfo, setSelectedBrandInfo] = useState();
|
||||
const [selectedCatCd, setSelectedCatCd] = useState();
|
||||
@@ -201,22 +202,10 @@ export default function FeaturedBrandsPanel() {
|
||||
const [selectedSeriesId, setSelectedSeriesId] = useState();
|
||||
const [selectedCatCdLv1, setSelectedCatCdLv1] = useState();
|
||||
const [selectedCatCdLv2, setSelectedCatCdLv2] = useState();
|
||||
const [targetId, setTargetId] = useState();
|
||||
const [_, setForceUpdate] = useState({});
|
||||
const [_, forceUpdate] = useState({});
|
||||
|
||||
const firstFocusableTargetId = useRef();
|
||||
const getFirstFocusableTargetIdJob = useRef(
|
||||
new Job(() => {
|
||||
const target = document.querySelector(`[data-focusable-index="0"]`);
|
||||
|
||||
if (target) {
|
||||
firstFocusableTargetId.current = getContainerId(target);
|
||||
}
|
||||
})
|
||||
);
|
||||
const focusJob = useRef(
|
||||
new Job((targetId) => targetId && Spotlight.focus(targetId))
|
||||
);
|
||||
const forceUpdateJob = useRef(new Job(() => forceUpdate({}), 300));
|
||||
const initialFocusTimeoutJob = useRef(new Job((func) => func(), 300));
|
||||
|
||||
const isLoading = useMemo(
|
||||
() =>
|
||||
@@ -246,6 +235,18 @@ export default function FeaturedBrandsPanel() {
|
||||
]
|
||||
);
|
||||
|
||||
const previousPanelIsDetail = Object.keys(panelInfo).length >= 4;
|
||||
|
||||
useEffect(() => {
|
||||
if (panelInfo) {
|
||||
console.log(
|
||||
"%c pyh panelInfo",
|
||||
"background:blue; color:white",
|
||||
panelInfo
|
||||
);
|
||||
}
|
||||
}, [panelInfo]);
|
||||
|
||||
useEffect(() => {
|
||||
const showLoadingPanel = isLoading
|
||||
? { show: true, type: "wait" }
|
||||
@@ -255,73 +256,120 @@ export default function FeaturedBrandsPanel() {
|
||||
}, [dispatch, isLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
if (panelInfo) {
|
||||
console.log("pyh panelInfo", panelInfo);
|
||||
console.log("pyh panelInfo.length", Object.keys(panelInfo).length);
|
||||
// scrollTopBody({ animate: false });
|
||||
if (!brandInfo) {
|
||||
// console.log("%c 0 brandInfo effect", "background:blue; color:white");
|
||||
dispatch(getBrandList());
|
||||
}
|
||||
}, [dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (brandInfo && panelInfo) {
|
||||
if (previousPanelIsDetail) {
|
||||
// console.log(
|
||||
// "%c pyh 1 initial Detail effect",
|
||||
// "background:blue; color:white"
|
||||
// );
|
||||
|
||||
if (Object.keys(panelInfo).length > 1) {
|
||||
setSelectedBrandInfo(
|
||||
findItemByValue(panelInfo?.brandInfo, panelInfo?.patnrId)
|
||||
);
|
||||
setTargetId(panelInfo?.targetId);
|
||||
// pyh Todo, edit, scroll timing
|
||||
setTimeout(() => scrollTopBody({ y: panelInfo.y, animate: false }));
|
||||
|
||||
setFirstFocusableTargetId(panelInfo?.firstFocusableTargetId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// console.log(
|
||||
// "%c pyh 1 initial GNB or QuickMenu effect",
|
||||
// "background:blue; color:white"
|
||||
// );
|
||||
|
||||
scrollTopBody({ animate: false });
|
||||
setSelectedPatnrId(panelInfo?.patnrId);
|
||||
setTargetId("spotlightId-" + panelInfo?.patnrId);
|
||||
setFirstFocusableTargetId("spotlightId-" + brandInfo[0]?.patnrId);
|
||||
}
|
||||
}, [panelInfo]);
|
||||
}, [brandInfo, panelInfo]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!brandInfo) {
|
||||
dispatch(getBrandList());
|
||||
}
|
||||
}, [brandInfo, dispatch]);
|
||||
if (brandInfo && selectedPatnrId) {
|
||||
// console.log(
|
||||
// "%c pyh 2 selectedPatnrId effect",
|
||||
// "background:blue; color:white"
|
||||
// );
|
||||
|
||||
useEffect(() => {
|
||||
if (brandInfo) {
|
||||
getFirstFocusableTargetIdJob.current.start();
|
||||
dispatch(getBrandLayoutInfo({ patnrId: selectedPatnrId }));
|
||||
dispatch(getBrandLiveChannelInfo({ patnrId: selectedPatnrId }));
|
||||
dispatch(getBrandTSVInfo({ patnrId: selectedPatnrId }));
|
||||
dispatch(getBrandBestSeller({ patnrId: selectedPatnrId }));
|
||||
dispatch(getBrandRecommendedShowInfo({ patnrId: selectedPatnrId }));
|
||||
dispatch(getBrandCreatorsInfo({ patnrId: selectedPatnrId }));
|
||||
dispatch(getBrandSeriesInfo({ patnrId: selectedPatnrId }));
|
||||
dispatch(
|
||||
getBrandCategoryInfo({
|
||||
patnrId: selectedPatnrId,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
getBrandShowroom({
|
||||
patnrId: selectedPatnrId,
|
||||
})
|
||||
);
|
||||
|
||||
if (targetId) {
|
||||
focusJob.current.start(targetId);
|
||||
}
|
||||
}
|
||||
}, [brandInfo, targetId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (brandInfo) {
|
||||
if (selectedPatnrId) {
|
||||
setSelectedBrandInfo(findItemByValue(brandInfo, selectedPatnrId));
|
||||
setSelectedCatCd();
|
||||
setSelectedHstNm();
|
||||
setSelectedSeriesId();
|
||||
setSelectedCatCdLv1();
|
||||
setSelectedCatCdLv2();
|
||||
|
||||
dispatch(getBrandLayoutInfo({ patnrId: selectedPatnrId }));
|
||||
dispatch(getBrandLiveChannelInfo({ patnrId: selectedPatnrId }));
|
||||
dispatch(getBrandTSVInfo({ patnrId: selectedPatnrId }));
|
||||
dispatch(getBrandBestSeller({ patnrId: selectedPatnrId }));
|
||||
dispatch(getBrandRecommendedShowInfo({ patnrId: selectedPatnrId }));
|
||||
dispatch(getBrandCreatorsInfo({ patnrId: selectedPatnrId }));
|
||||
dispatch(getBrandSeriesInfo({ patnrId: selectedPatnrId }));
|
||||
dispatch(
|
||||
getBrandCategoryInfo({
|
||||
patnrId: selectedPatnrId,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
getBrandShowroom({
|
||||
patnrId: selectedPatnrId,
|
||||
})
|
||||
);
|
||||
}
|
||||
setSelectedBrandInfo(findItemByValue(brandInfo, selectedPatnrId));
|
||||
setSelectedCatCd();
|
||||
setSelectedHstNm();
|
||||
setSelectedSeriesId();
|
||||
setSelectedCatCdLv1();
|
||||
setSelectedCatCdLv2();
|
||||
}
|
||||
}, [brandInfo, dispatch, selectedPatnrId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedBrandInfo && firstFocusableTargetId) {
|
||||
// console.log(
|
||||
// "%c pyh *** focus effect ***",
|
||||
// "background:blue; color:white"
|
||||
// );
|
||||
|
||||
let targetId;
|
||||
|
||||
targetId = "spotlightId-" + panelInfo?.patnrId;
|
||||
|
||||
if (previousPanelIsDetail) {
|
||||
// console.log(
|
||||
// "%c pyh *** detail focus effect ***",
|
||||
// "background:blue; color:white"
|
||||
// );
|
||||
if (panelInfo?.catCdLv1) {
|
||||
setSelectedCatCdLv1(panelInfo?.catCdLv1);
|
||||
}
|
||||
|
||||
if (panelInfo?.catCdLv2) {
|
||||
setSelectedCatCdLv2(panelInfo?.catCdLv2);
|
||||
}
|
||||
|
||||
if (panelInfo?.y) {
|
||||
const { y } = panelInfo;
|
||||
scrollTopBody({ y, animate: false });
|
||||
}
|
||||
|
||||
targetId = panelInfo?.lastFocusedTargetId;
|
||||
}
|
||||
|
||||
setSpotlightDisabled(false);
|
||||
|
||||
initialFocusTimeoutJob.current.start(() => {
|
||||
const initialFocusTarget = document.querySelector(
|
||||
`[data-spotlight-id="${targetId}"]`
|
||||
);
|
||||
|
||||
// console.log("pyh initialFocusTarget?!?!\n\n", initialFocusTarget);
|
||||
|
||||
initialFocusTarget && Spotlight.focus(initialFocusTarget);
|
||||
});
|
||||
}
|
||||
}, [selectedBrandInfo, firstFocusableTargetId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedCatCd) {
|
||||
dispatch(
|
||||
@@ -356,47 +404,65 @@ export default function FeaturedBrandsPanel() {
|
||||
}, [selectedSeriesId, dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
setForceUpdate({});
|
||||
if (selectedCatCdLv1 !== undefined || selectedCatCdLv2 !== undefined) {
|
||||
forceUpdateJob.current.start();
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (selectedCatCdLv1 !== undefined || selectedCatCdLv2 !== undefined) {
|
||||
forceUpdateJob.current.stop();
|
||||
}
|
||||
};
|
||||
}, [selectedCatCdLv1, selectedCatCdLv2]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (brandInfo) {
|
||||
console.log("pyh -------------------- unmounted --------------------");
|
||||
// console.log(
|
||||
// "%c pyh ----------- unmounted -----------",
|
||||
// "background:blue; color:white"
|
||||
// );
|
||||
const marker = document.querySelector(`[data-marker="scroll-marker"]`);
|
||||
const firstFocusableTarget = document.querySelector(
|
||||
`[data-focusable-index="0"]`
|
||||
);
|
||||
const lastFocusedTarget = Spotlight.getCurrent();
|
||||
|
||||
if (marker && lastFocusedTarget) {
|
||||
const targetId = lastFocusedTarget.getAttribute("data-spotlight-id");
|
||||
|
||||
const markerRect = marker.getBoundingClientRect();
|
||||
const lastFocusedTargetRect =
|
||||
lastFocusedTarget.getBoundingClientRect();
|
||||
|
||||
const y = lastFocusedTargetRect.top - markerRect.top;
|
||||
if (marker && lastFocusedTarget && firstFocusableTarget) {
|
||||
const exprOrd = parseInt(
|
||||
lastFocusedTarget.getAttribute("data-exposure-order")
|
||||
);
|
||||
const firstFocusableTargetId =
|
||||
firstFocusableTarget.getAttribute("data-spotlight-id");
|
||||
const lastFocusedTargetId =
|
||||
lastFocusedTarget.getAttribute("data-spotlight-id");
|
||||
|
||||
dispatch(
|
||||
updatePanel({
|
||||
name: panel_names.FEATURED_BRANDS_PANEL,
|
||||
panelInfo: { ...panelInfo, brandInfo, targetId, y },
|
||||
panelInfo: {
|
||||
brandInfo,
|
||||
exprOrd,
|
||||
firstFocusableTargetId,
|
||||
lastFocusedTargetId,
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
getFirstFocusableTargetIdJob.current.stop();
|
||||
focusJob.current.stop();
|
||||
initialFocusTimeoutJob.current.stop();
|
||||
}
|
||||
};
|
||||
}, [brandInfo]);
|
||||
|
||||
const handleTopButtonClick = useCallback(() => {
|
||||
if (!firstFocusableTargetId.current) {
|
||||
if (!firstFocusableTargetId) {
|
||||
return scrollTopBody();
|
||||
}
|
||||
|
||||
focusJob.current.start(firstFocusableTargetId.current);
|
||||
Spotlight.focus(firstFocusableTargetId);
|
||||
scrollTopBody();
|
||||
}, []);
|
||||
}, [firstFocusableTargetId]);
|
||||
|
||||
// pyh Todo, test, temporary func, edited later
|
||||
const handlePopupClick = useCallback(() => {
|
||||
@@ -415,15 +481,18 @@ export default function FeaturedBrandsPanel() {
|
||||
|
||||
return (
|
||||
<TPanel className={css.tPanel}>
|
||||
<TBody className={css.tBody} cbScrollTo={getScrollToBody}>
|
||||
<TBody
|
||||
className={css.tBody}
|
||||
cbScrollTo={getScrollToBody}
|
||||
spotlightDisabled={spotlightDisabled}
|
||||
>
|
||||
<div data-marker="scroll-marker" />
|
||||
|
||||
{shouldRenderComponent(brandInfo) && (
|
||||
{shouldRenderComponent(brandInfo) && selectedBrandInfo && (
|
||||
<QuickMenu
|
||||
brandInfo={brandInfo}
|
||||
scrollTopBody={scrollTopBody}
|
||||
selectedPatnrId={selectedPatnrId}
|
||||
setSelectedPatnrId={setSelectedPatnrId}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -105,6 +105,9 @@ export default memo(function FeaturedCategory({
|
||||
isCarousel={array.length > 1}
|
||||
key={"brand-category-product-info-" + index}
|
||||
scrollTopBody={scrollTopBody}
|
||||
selectedCatCdLv1={selectedCatCdLv1}
|
||||
selectedCatCdLv2={selectedCatCdLv2}
|
||||
selectedCategoryLv2Infos={selectedCategoryLv2Infos}
|
||||
selectedPatnrId={selectedPatnrId}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -16,9 +16,12 @@ export default function FeaturedCategoryContents({
|
||||
index,
|
||||
isCarousel,
|
||||
scrollTopBody,
|
||||
selectedCatCdLv1,
|
||||
selectedCatCdLv2,
|
||||
selectedCategoryLv2Infos,
|
||||
selectedPatnrId,
|
||||
}) {
|
||||
const { brandCategoryProductDetailInfo, catNm, patnrId } =
|
||||
const { brandCategoryProductDetailInfo, catCd, catNm, patnrId } =
|
||||
brandCategoryProductDetailInfoItem;
|
||||
|
||||
return (
|
||||
@@ -27,16 +30,26 @@ export default function FeaturedCategoryContents({
|
||||
{isCarousel ? (
|
||||
<FeaturedCategoryProductList
|
||||
brandCategoryProductDetailInfo={brandCategoryProductDetailInfo}
|
||||
catCd={catCd}
|
||||
catNm={catNm}
|
||||
index={index}
|
||||
patnrId={patnrId}
|
||||
scrollTopBody={scrollTopBody}
|
||||
selectedCatCdLv1={selectedCatCdLv1}
|
||||
selectedCatCdLv2={selectedCatCdLv2}
|
||||
selectedCategoryLv2Infos={selectedCategoryLv2Infos}
|
||||
selectedPatnrId={selectedPatnrId}
|
||||
/>
|
||||
) : (
|
||||
<FeaturedCategoryProductGrid
|
||||
brandCategoryProductDetailInfo={brandCategoryProductDetailInfo}
|
||||
catCd={catCd}
|
||||
index={index}
|
||||
patnrId={patnrId}
|
||||
scrollTopBody={scrollTopBody}
|
||||
selectedCatCdLv1={selectedCatCdLv1}
|
||||
selectedCatCdLv2={selectedCatCdLv2}
|
||||
selectedCategoryLv2Infos={selectedCategoryLv2Infos}
|
||||
/>
|
||||
)}
|
||||
</Container>
|
||||
|
||||
@@ -1,20 +1,61 @@
|
||||
import React, { useCallback } from "react";
|
||||
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
import { pushPanel } from "../../../../../actions/panelActions";
|
||||
import TItemCard from "../../../../../components/TItemCard/TItemCard";
|
||||
import { pushPanel, updatePanel } from "../../../../../actions/panelActions";
|
||||
import TItemCard, {
|
||||
removeDotAndColon,
|
||||
} from "../../../../../components/TItemCard/TItemCard";
|
||||
import useScrollTopByDistance from "../../../../../hooks/useScrollTopByDistance";
|
||||
import { panel_names } from "../../../../../utils/Config";
|
||||
import { SpotlightIds } from "../../../../../utils/SpotlightIds";
|
||||
import css from "./FeaturedCategoryProductGrid.module.less";
|
||||
|
||||
export default function FeaturedCategoryProductGrid({
|
||||
brandCategoryProductDetailInfo,
|
||||
catCd,
|
||||
index,
|
||||
patnrId,
|
||||
selectedCatCdLv1,
|
||||
selectedCatCdLv2,
|
||||
selectedCategoryLv2Infos,
|
||||
scrollTopBody,
|
||||
}) {
|
||||
const { scrollTopByDistance } = useScrollTopByDistance();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const panelInfo = useSelector((state) => state.panels.panels[0]?.panelInfo);
|
||||
|
||||
const { cursorVisible } = useSelector((state) => state.common.appStatus);
|
||||
|
||||
const handleClick = useCallback(
|
||||
(prdtId) => {
|
||||
const tBody = document.querySelector(
|
||||
`[data-spotlight-id="${SpotlightIds.TBODY}"]`
|
||||
);
|
||||
|
||||
const yContainer = tBody?.children[0]?.children[0]?.children[0];
|
||||
|
||||
if (yContainer) {
|
||||
const catCdLv1 = selectedCategoryLv2Infos
|
||||
? selectedCategoryLv2Infos.length > 0
|
||||
? selectedCatCdLv1
|
||||
: catCd
|
||||
: "";
|
||||
const catCdLv2 = selectedCatCdLv2 ?? "";
|
||||
const section = "category";
|
||||
const x = 0;
|
||||
const y = yContainer.scrollTop;
|
||||
|
||||
dispatch(
|
||||
updatePanel({
|
||||
name: panel_names.FEATURED_BRANDS_PANEL,
|
||||
panelInfo: { ...panelInfo, catCdLv1, catCdLv2, section, x, y },
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
dispatch(
|
||||
pushPanel({
|
||||
name: panel_names.DETAIL_PANEL,
|
||||
@@ -22,23 +63,50 @@ export default function FeaturedCategoryProductGrid({
|
||||
})
|
||||
);
|
||||
},
|
||||
[patnrId]
|
||||
[
|
||||
catCd,
|
||||
dispatch,
|
||||
patnrId,
|
||||
selectedCatCdLv1,
|
||||
selectedCatCdLv2,
|
||||
selectedCategoryLv2Infos,
|
||||
]
|
||||
);
|
||||
|
||||
const handleFocus = useCallback(
|
||||
(itemIndex) => {
|
||||
if (cursorVisible || itemIndex > 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
scrollTopByDistance(
|
||||
`[data-marker="scroll-marker"]`,
|
||||
`[data-category-subtitle-index="${index}"]`,
|
||||
scrollTopBody,
|
||||
36
|
||||
);
|
||||
},
|
||||
[cursorVisible]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={css.container}>
|
||||
<ul>
|
||||
{brandCategoryProductDetailInfo.map(
|
||||
({ imgUrl, offerInfo, prdtId, prdtNm, priceInfo }, index) => (
|
||||
<li key={"brandCategoryProductDetailInfo-" + index}>
|
||||
({ imgUrl, offerInfo, prdtId, prdtNm, priceInfo }, itemIndex) => (
|
||||
<li key={"brand-category-product-detail-info-" + itemIndex}>
|
||||
<TItemCard
|
||||
imageAlt={prdtNm}
|
||||
imageSource={imgUrl}
|
||||
onClick={() => handleClick(prdtId)}
|
||||
onFocus={() => handleFocus(itemIndex)}
|
||||
offerInfo={offerInfo}
|
||||
priceInfo={priceInfo}
|
||||
productId={prdtId}
|
||||
productName={prdtNm}
|
||||
spotlightId={
|
||||
"category-grid-spotlightId-" + removeDotAndColon(prdtId)
|
||||
}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
|
||||
@@ -7,8 +7,13 @@
|
||||
flex-wrap: wrap;
|
||||
padding: 22px 0 0 60px;
|
||||
|
||||
li {
|
||||
margin: 0 18px 15px 0;
|
||||
> li {
|
||||
flex: none;
|
||||
|
||||
// tItemCard
|
||||
> div {
|
||||
margin: 0 18px 15px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,33 +2,73 @@ import React, { memo, useCallback, useEffect, useRef } from "react";
|
||||
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
import { Job } from "@enact/core/util";
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
import {
|
||||
getContainerId,
|
||||
setContainerLastFocusedElement,
|
||||
} from "@enact/spotlight/src/container";
|
||||
|
||||
import { pushPanel } from "../../../../../actions/panelActions";
|
||||
import TItemCard from "../../../../../components/TItemCard/TItemCard";
|
||||
import { pushPanel, updatePanel } from "../../../../../actions/panelActions";
|
||||
import TItemCard, {
|
||||
removeDotAndColon,
|
||||
} from "../../../../../components/TItemCard/TItemCard";
|
||||
import TScroller from "../../../../../components/TScroller/TScroller";
|
||||
import useScrollTo from "../../../../../hooks/useScrollTo";
|
||||
import useScrollTopByDistance from "../../../../../hooks/useScrollTopByDistance";
|
||||
import { panel_names } from "../../../../../utils/Config";
|
||||
import { SpotlightIds } from "../../../../../utils/SpotlightIds";
|
||||
import css from "./FeaturedCategoryProductList.module.less";
|
||||
|
||||
const Container = SpotlightContainerDecorator(
|
||||
{ leaveFor: { right: "" }, enterTo: "last-focused" },
|
||||
"div"
|
||||
);
|
||||
|
||||
export default memo(function FeaturedCategoryProductList({
|
||||
brandCategoryProductDetailInfo,
|
||||
catCd,
|
||||
catNm,
|
||||
index,
|
||||
patnrId,
|
||||
scrollTopBody,
|
||||
selectedCatCdLv1,
|
||||
selectedCatCdLv2,
|
||||
selectedCategoryLv2Infos,
|
||||
selectedPatnrId,
|
||||
}) {
|
||||
const { getScrollTo, scrollLeft } = useScrollTo();
|
||||
const { scrollTopByDistance } = useScrollTopByDistance();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const panelInfo = useSelector((state) => state.panels.panels[0]?.panelInfo);
|
||||
|
||||
const { cursorVisible } = useSelector((state) => state.common.appStatus);
|
||||
|
||||
const timeoutRef = useRef();
|
||||
const scrollLeftJob = useRef(new Job((func) => func(), 0));
|
||||
|
||||
useEffect(() => {
|
||||
if (panelInfo?.section !== "category") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (panelInfo?.exprOrd === index + 1) {
|
||||
const { x } = panelInfo;
|
||||
|
||||
if (x === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
scrollLeftJob.current.start(() => scrollLeft({ x }));
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (panelInfo?.exprOrd === index + 1) {
|
||||
scrollLeftJob.current.stop();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const containerId = "featured-category-product-list-id-" + catNm;
|
||||
@@ -36,39 +76,42 @@ export default memo(function FeaturedCategoryProductList({
|
||||
|
||||
if (container) {
|
||||
const childrenId = getContainerId(container?.children[0].children[0]);
|
||||
childrenId && setContainerLastFocusedElement(null, [childrenId]);
|
||||
childrenId &&
|
||||
setContainerLastFocusedElement(null, [containerId, childrenId]);
|
||||
}
|
||||
|
||||
scrollLeft();
|
||||
}, [selectedPatnrId]);
|
||||
|
||||
const setScrollTopBody = useCallback(() => {
|
||||
const marker = document.querySelector(`[data-marker="scroll-marker"]`);
|
||||
const subTitle = document.querySelector(
|
||||
`[data-category-subtitle-index="${index}"]`
|
||||
);
|
||||
|
||||
if (marker && subTitle) {
|
||||
const markerRect = marker.getBoundingClientRect();
|
||||
const subTitleRect = subTitle.getBoundingClientRect();
|
||||
const subSectionGap = 36;
|
||||
|
||||
const y = subTitleRect.top - markerRect.top - subSectionGap;
|
||||
|
||||
timeoutRef.current = setTimeout(() => scrollTopBody({ y }));
|
||||
} else {
|
||||
console.error("subTitle not found");
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleBlur = useCallback(() => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
}, []);
|
||||
}, [selectedCatCdLv1, selectedCatCdLv2, selectedPatnrId]);
|
||||
|
||||
const handleClick = useCallback(
|
||||
(prdtId) => {
|
||||
(e, prdtId) => {
|
||||
const tItemCard = e.currentTarget;
|
||||
const tBody = document.querySelector(
|
||||
`[data-spotlight-id="${SpotlightIds.TBODY}"]`
|
||||
);
|
||||
|
||||
const xContainer = tItemCard?.parentNode?.parentNode?.parentNode;
|
||||
const yContainer = tBody?.children[0]?.children[0]?.children[0];
|
||||
|
||||
if (xContainer && yContainer) {
|
||||
const catCdLv1 = selectedCategoryLv2Infos
|
||||
? selectedCategoryLv2Infos.length > 0
|
||||
? selectedCatCdLv1
|
||||
: catCd
|
||||
: "";
|
||||
const catCdLv2 = selectedCatCdLv2;
|
||||
const section = "category";
|
||||
const x = xContainer.scrollLeft;
|
||||
const y = yContainer.scrollTop;
|
||||
|
||||
dispatch(
|
||||
updatePanel({
|
||||
name: panel_names.FEATURED_BRANDS_PANEL,
|
||||
panelInfo: { ...panelInfo, catCdLv1, catCdLv2, section, x, y },
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
dispatch(
|
||||
pushPanel({
|
||||
name: panel_names.DETAIL_PANEL,
|
||||
@@ -76,7 +119,14 @@ export default memo(function FeaturedCategoryProductList({
|
||||
})
|
||||
);
|
||||
},
|
||||
[dispatch, patnrId]
|
||||
[
|
||||
catCd,
|
||||
dispatch,
|
||||
patnrId,
|
||||
selectedCatCdLv1,
|
||||
selectedCatCdLv2,
|
||||
selectedCategoryLv2Infos,
|
||||
]
|
||||
);
|
||||
|
||||
const handleFocus = useCallback(() => {
|
||||
@@ -84,13 +134,19 @@ export default memo(function FeaturedCategoryProductList({
|
||||
return;
|
||||
}
|
||||
|
||||
setScrollTopBody();
|
||||
scrollTopByDistance(
|
||||
`[data-marker="scroll-marker"]`,
|
||||
`[data-category-subtitle-index="${index}"]`,
|
||||
scrollTopBody,
|
||||
36
|
||||
);
|
||||
}, [cursorVisible]);
|
||||
|
||||
return (
|
||||
<div
|
||||
<Container
|
||||
className={css.container}
|
||||
id={"featured-category-product-list-id-" + catNm}
|
||||
spotlightId={"featured-category-product-list-id-" + catNm}
|
||||
>
|
||||
<TScroller
|
||||
cbScrollTo={getScrollTo}
|
||||
@@ -100,23 +156,26 @@ export default memo(function FeaturedCategoryProductList({
|
||||
<ul>
|
||||
{brandCategoryProductDetailInfo.map(
|
||||
({ imgUrl, offerInfo, prdtId, prdtNm, priceInfo }, itemIndex) => (
|
||||
<li key={"brand-category-product-detail-info-" + prdtId}>
|
||||
<li key={"brand-category-product-detail-info-" + itemIndex}>
|
||||
<TItemCard
|
||||
data-exposure-order={index + 1}
|
||||
imageAlt={prdtNm}
|
||||
imageSource={imgUrl}
|
||||
onBlur={handleBlur}
|
||||
onClick={() => handleClick(prdtId)}
|
||||
onClick={(e) => handleClick(e, prdtId)}
|
||||
onFocus={handleFocus}
|
||||
offerInfo={offerInfo}
|
||||
priceInfo={priceInfo}
|
||||
productId={prdtId}
|
||||
productName={prdtNm}
|
||||
spotlightId={
|
||||
"category-list-spotlightId-" + removeDotAndColon(prdtId)
|
||||
}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
</TScroller>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useEffect, useRef } from "react";
|
||||
import React, { useCallback, useEffect } from "react";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
import {
|
||||
@@ -8,10 +8,13 @@ import {
|
||||
setContainerLastFocusedElement,
|
||||
} from "@enact/spotlight/src/container";
|
||||
|
||||
import { updatePanel } from "../../../../actions/panelActions";
|
||||
import TButton, { TYPES } from "../../../../components/TButton/TButton";
|
||||
import TScroller from "../../../../components/TScroller/TScroller";
|
||||
import useScrollReset from "../../../../hooks/useScrollReset";
|
||||
import useScrollTo from "../../../../hooks/useScrollTo";
|
||||
import useScrollTopByDistance from "../../../../hooks/useScrollTopByDistance";
|
||||
import { panel_names } from "../../../../utils/Config";
|
||||
import { $L } from "../../../../utils/helperMethods";
|
||||
import css from "./FeaturedCategoryNav.module.less";
|
||||
|
||||
@@ -37,11 +40,14 @@ export default function FeaturedCategoryNav({
|
||||
scrollLeft,
|
||||
true
|
||||
);
|
||||
const { scrollTopByDistance } = useScrollTopByDistance();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const panelInfo = useSelector((state) => state.panels.panels[0]?.panelInfo);
|
||||
|
||||
const { cursorVisible } = useSelector((state) => state.common.appStatus);
|
||||
|
||||
const timeoutRef = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
const containerId = "featured-category-nav-id";
|
||||
const container = document.getElementById(containerId);
|
||||
@@ -55,39 +61,32 @@ export default function FeaturedCategoryNav({
|
||||
scrollLeft();
|
||||
}, [selectedPatnrId]);
|
||||
|
||||
const setScrollTopBody = useCallback(() => {
|
||||
const marker = document.querySelector(`[data-marker="scroll-marker"]`);
|
||||
const sectionTitle = document.querySelector(`[data-title="category"]`);
|
||||
|
||||
if (marker && sectionTitle) {
|
||||
const markerRect = marker.getBoundingClientRect();
|
||||
const sectionTitleRect = sectionTitle.getBoundingClientRect();
|
||||
const sectionGap = 58;
|
||||
|
||||
const y = sectionTitleRect.top - markerRect.top - sectionGap;
|
||||
|
||||
timeoutRef.current = setTimeout(() => scrollTopBody({ y }));
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleBlur = useCallback((index) => {
|
||||
if (index === undefined) {
|
||||
const handleBlur = useCallback((itemIndex) => {
|
||||
if (itemIndex === undefined) {
|
||||
handleStopScrolling();
|
||||
}
|
||||
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleClick = useCallback((catCdLv1) => {
|
||||
setSelectedCatCdLv1(catCdLv1);
|
||||
setSelectedCatCdLv2();
|
||||
}, []);
|
||||
const handleClick = useCallback(
|
||||
(catCdLv1) => {
|
||||
const x = 0;
|
||||
|
||||
dispatch(
|
||||
updatePanel({
|
||||
name: panel_names.FEATURED_BRANDS_PANEL,
|
||||
panelInfo: { ...panelInfo, x },
|
||||
})
|
||||
);
|
||||
|
||||
setSelectedCatCdLv1(catCdLv1);
|
||||
setSelectedCatCdLv2();
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const handleFocus = useCallback(
|
||||
(index) => {
|
||||
if (index === undefined) {
|
||||
(itemIndex) => {
|
||||
if (itemIndex === undefined) {
|
||||
handleScrollReset();
|
||||
}
|
||||
|
||||
@@ -95,7 +94,12 @@ export default function FeaturedCategoryNav({
|
||||
return;
|
||||
}
|
||||
|
||||
setScrollTopBody();
|
||||
scrollTopByDistance(
|
||||
`[data-marker="scroll-marker"]`,
|
||||
`[data-title="category"]`,
|
||||
scrollTopBody,
|
||||
58
|
||||
);
|
||||
},
|
||||
[cursorVisible]
|
||||
);
|
||||
@@ -125,7 +129,7 @@ export default function FeaturedCategoryNav({
|
||||
</TButton>
|
||||
</li>
|
||||
{brandCategoryInfo &&
|
||||
brandCategoryInfo.map(({ catCdLv1, catNmLv1 }, index) => (
|
||||
brandCategoryInfo.map(({ catCdLv1, catNmLv1 }, itemIndex) => (
|
||||
<li key={"brand-category-info-" + catCdLv1}>
|
||||
<TButton
|
||||
className={
|
||||
@@ -133,9 +137,9 @@ export default function FeaturedCategoryNav({
|
||||
selectedCatCdLv1 === catCdLv1 &&
|
||||
css.selected
|
||||
}
|
||||
onBlur={() => handleBlur(index)}
|
||||
onBlur={() => handleBlur(itemIndex)}
|
||||
onClick={() => handleClick(catCdLv1)}
|
||||
onFocus={() => handleFocus(index)}
|
||||
onFocus={() => handleFocus(itemIndex)}
|
||||
selected={selectedCatCdLv1 && selectedCatCdLv1 === catCdLv1}
|
||||
type={TYPES.oneDepthCategory}
|
||||
>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { useCallback } from "react";
|
||||
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
|
||||
import { pushPanel } from "../../../../actions/panelActions";
|
||||
import { pushPanel, updatePanel } from "../../../../actions/panelActions";
|
||||
import TButton, { TYPES } from "../../../../components/TButton/TButton";
|
||||
import TScroller from "../../../../components/TScroller/TScroller";
|
||||
import useScrollReset from "../../../../hooks/useScrollReset";
|
||||
@@ -38,13 +38,27 @@ export default function FeaturedSubCategoryNav({
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const panelInfo = useSelector((state) => state.panels.panels[0]?.panelInfo);
|
||||
|
||||
const handleBlur = useCallback(() => {
|
||||
handleStopScrolling();
|
||||
}, []);
|
||||
|
||||
const handleClick = useCallback((catCdLv2) => {
|
||||
setSelectedCatCdLv2(catCdLv2);
|
||||
}, []);
|
||||
const handleClick = useCallback(
|
||||
(catCdLv2) => {
|
||||
const x = 0;
|
||||
|
||||
dispatch(
|
||||
updatePanel({
|
||||
name: panel_names.FEATURED_BRANDS_PANEL,
|
||||
panelInfo: { ...panelInfo, x },
|
||||
})
|
||||
);
|
||||
|
||||
setSelectedCatCdLv2(catCdLv2);
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const handleFocus = useCallback(() => {
|
||||
handleScrollReset();
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useDispatch } from "react-redux";
|
||||
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
|
||||
import { updatePanel } from "../../../actions/panelActions";
|
||||
import { resetPanels, updatePanel } from "../../../actions/panelActions";
|
||||
import TScroller from "../../../components/TScroller/TScroller";
|
||||
import useScrollReset from "../../../hooks/useScrollReset";
|
||||
import useScrollTo from "../../../hooks/useScrollTo";
|
||||
@@ -21,7 +21,6 @@ export default memo(function QuickMenu({
|
||||
brandInfo,
|
||||
scrollTopBody,
|
||||
selectedPatnrId,
|
||||
setSelectedPatnrId,
|
||||
}) {
|
||||
const { getScrollTo, scrollLeft } = useScrollTo();
|
||||
const { handleScrollReset, handleStopScrolling } = useScrollReset(
|
||||
@@ -45,16 +44,13 @@ export default memo(function QuickMenu({
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(
|
||||
updatePanel({
|
||||
name: panel_names.FEATURED_BRANDS_PANEL,
|
||||
panelInfo: { brandInfo, patnrId, y: 0 },
|
||||
})
|
||||
);
|
||||
const name = panel_names.FEATURED_BRANDS_PANEL;
|
||||
const panelInfo = { patnrId };
|
||||
|
||||
setSelectedPatnrId(patnrId);
|
||||
dispatch(resetPanels([{ name }]));
|
||||
dispatch(updatePanel({ name, panelInfo }));
|
||||
},
|
||||
[brandInfo, dispatch, selectedPatnrId]
|
||||
[dispatch, selectedPatnrId]
|
||||
);
|
||||
|
||||
const handleFocus = useCallback((index) => {
|
||||
|
||||
Reference in New Issue
Block a user