[SHOPITME-3334] Featured Brands / Show Room / Detail Page 에서 이전키 동작 안하는 현상
Changed files: 1. ImagePanel.jsx 2. ImageOverlayContents.jsx 3. ImageSideContents.jsx 4. ListEmptyContents.jsx 5. RoomThemeList.jsx 6. ShowNowProductList.jsx Detail note: 1. refactoring and additional defensive logic
This commit is contained in:
@@ -12,7 +12,7 @@ import css from "./ImageOverlayContents.module.less";
|
||||
|
||||
const SpottableButton = Spottable("button");
|
||||
|
||||
export default memo(function ImageOverlayContents({
|
||||
const ImageOverlayContents = ({
|
||||
overlayContentsVisible,
|
||||
panelInfo,
|
||||
selectedRoomThemeInfosLength,
|
||||
@@ -23,17 +23,14 @@ export default memo(function ImageOverlayContents({
|
||||
sideContentsVisible,
|
||||
themeNm,
|
||||
...rest
|
||||
}) {
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleBackClick = useCallback(
|
||||
// eslint-disable-next-line
|
||||
(e) => {
|
||||
// e.stopPropagation();
|
||||
|
||||
if (sideContentsVisible) {
|
||||
return;
|
||||
}
|
||||
if (sideContentsVisible) return;
|
||||
|
||||
dispatch(popPanel());
|
||||
},
|
||||
@@ -44,9 +41,7 @@ export default memo(function ImageOverlayContents({
|
||||
(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (sideContentsVisible) {
|
||||
return;
|
||||
}
|
||||
if (sideContentsVisible) return;
|
||||
|
||||
const previousPageNumber =
|
||||
selectedThemeExpsOrd === 1
|
||||
@@ -67,9 +62,7 @@ export default memo(function ImageOverlayContents({
|
||||
(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (sideContentsVisible) {
|
||||
return;
|
||||
}
|
||||
if (sideContentsVisible) return;
|
||||
|
||||
const nextPageNumber =
|
||||
selectedThemeExpsOrd === selectedRoomThemeInfosLength
|
||||
@@ -181,4 +174,6 @@ export default memo(function ImageOverlayContents({
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export default memo(ImageOverlayContents);
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
import classNames from "classnames";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
@@ -6,6 +12,7 @@ import { useDispatch, useSelector } from "react-redux";
|
||||
import { Job } from "@enact/core/util";
|
||||
import Spotlight from "@enact/spotlight";
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
import { getContainerId } from "@enact/spotlight/src/container";
|
||||
|
||||
import { sendLogCuration, sendLogGNB } from "../../actions/logActions";
|
||||
import { updatePanel } from "../../actions/panelActions";
|
||||
@@ -39,7 +46,7 @@ const findSelector = (selector, maxAttempts = 5, currentAttempts = 0) => {
|
||||
}
|
||||
};
|
||||
|
||||
export default function ImagePanel({ panelInfo, spotlightId, ...rest }) {
|
||||
const ImagePanel = ({ panelInfo, spotlightId }) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const brandShowroomInfo = useSelector(
|
||||
@@ -54,32 +61,36 @@ export default function ImagePanel({ panelInfo, spotlightId, ...rest }) {
|
||||
useState(null);
|
||||
const [selectedThemeExpsOrd, setSelectedThemeExpsOrd] = useState(null);
|
||||
const [sideContentsVisible, setSideContentsVisible] = useState(true);
|
||||
const [spotlightDisabled, setSpotlightDisabled] = useState(true);
|
||||
|
||||
const initialFocusTimeoutJob = useRef(new Job((func) => func(), 100));
|
||||
const themeViewTimer = useRef(null);
|
||||
const initialFocusTimeoutJob = useRef(new Job((func) => func(), 0));
|
||||
const themeDisplayTimerRef = useRef(null);
|
||||
|
||||
const memoizedRoomThemeInfo = useMemo(
|
||||
() =>
|
||||
brandShowroomInfo?.find(({ roomId }) => roomId === panelInfo?.roomId) ||
|
||||
null,
|
||||
[brandShowroomInfo, panelInfo?.roomId]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let sideCotnentsTimer;
|
||||
|
||||
const handleAction = () => clearTimeout(sideCotnentsTimer);
|
||||
let sideContentsTimer;
|
||||
const handleAction = () => clearTimeout(sideContentsTimer);
|
||||
|
||||
window.addEventListener("click", handleAction);
|
||||
window.addEventListener("keydown", handleAction);
|
||||
|
||||
sideCotnentsTimer = setTimeout(() => setSideContentsVisible(false), 10000);
|
||||
sideContentsTimer = setTimeout(() => setSideContentsVisible(false), 10000);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("click", handleAction);
|
||||
window.removeEventListener("keydown", handleAction);
|
||||
|
||||
clearTimeout(sideCotnentsTimer);
|
||||
clearTimeout(sideContentsTimer);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
let overlayContentsTimer;
|
||||
|
||||
const handleAction = () => clearTimeout(overlayContentsTimer);
|
||||
|
||||
if (!sideContentsVisible) {
|
||||
@@ -100,112 +111,80 @@ export default function ImagePanel({ panelInfo, spotlightId, ...rest }) {
|
||||
};
|
||||
}, [sideContentsVisible]);
|
||||
|
||||
// effect: set selectedThemeExpsOrd on initial render
|
||||
useEffect(() => {
|
||||
if (panelInfo?.themeExpsOrd) {
|
||||
setSelectedThemeExpsOrd(panelInfo?.themeExpsOrd);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// effect: set selectedRoomThemeInfo and otherRoomThemeInfos based on selectedThemeExpsOrd
|
||||
useEffect(() => {
|
||||
if (memoizedRoomThemeInfo && selectedThemeExpsOrd) {
|
||||
const { roomThemeInfos } = memoizedRoomThemeInfo;
|
||||
|
||||
if (roomThemeInfos) {
|
||||
setSelectedRoomThemeInfosLength(roomThemeInfos.length);
|
||||
setSelectedRoomThemeInfo(
|
||||
roomThemeInfos.find(
|
||||
({ themeExpsOrd }) => themeExpsOrd === selectedThemeExpsOrd
|
||||
)
|
||||
);
|
||||
setOtherRoomThemeInfos(
|
||||
roomThemeInfos.filter(
|
||||
({ themeExpsOrd }) => themeExpsOrd !== selectedThemeExpsOrd
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [memoizedRoomThemeInfo, selectedThemeExpsOrd]);
|
||||
|
||||
// effect: curation log
|
||||
useEffect(() => {
|
||||
if (panelInfo && selectedRoomThemeInfo) {
|
||||
const { linkTpCd = "", patncNm, patnrId } = panelInfo;
|
||||
const params = {
|
||||
curationId: selectedRoomThemeInfo?.themeId,
|
||||
curationNm: selectedRoomThemeInfo?.themeNm,
|
||||
expsOrd: `${selectedRoomThemeInfo?.themeExpsOrd}`,
|
||||
logTpNo: LOG_TP_NO.CURATION.SHOWROOM,
|
||||
linkTpCd: panelInfo?.linkTpCd,
|
||||
patncNm: panelInfo?.patncNm,
|
||||
patnrId: panelInfo?.patnrId,
|
||||
linkTpCd,
|
||||
patncNm,
|
||||
patnrId,
|
||||
};
|
||||
|
||||
themeViewTimer.current = setTimeout(() => {
|
||||
dispatch(sendLogCuration(params));
|
||||
}, 3000);
|
||||
themeDisplayTimerRef.current = setTimeout(
|
||||
() => dispatch(sendLogCuration(params)),
|
||||
3000
|
||||
);
|
||||
|
||||
return () => clearTimeout(themeViewTimer.current);
|
||||
return () => clearTimeout(themeDisplayTimerRef.current);
|
||||
}
|
||||
}, [panelInfo, selectedRoomThemeInfo]);
|
||||
|
||||
useEffect(() => {
|
||||
if (panelInfo) {
|
||||
setOtherRoomThemeInfos(
|
||||
brandShowroomInfo
|
||||
.find(({ roomId }) => roomId === panelInfo?.roomId)
|
||||
?.roomThemeInfos //
|
||||
.filter(({ themeId }) => themeId !== panelInfo?.themeId)
|
||||
);
|
||||
|
||||
setSelectedRoomThemeInfo(
|
||||
brandShowroomInfo
|
||||
.find(({ roomId }) => roomId === panelInfo?.roomId)
|
||||
?.roomThemeInfos //
|
||||
.find(({ themeId }) => themeId === panelInfo?.themeId)
|
||||
);
|
||||
|
||||
setSelectedRoomThemeInfosLength(
|
||||
brandShowroomInfo //
|
||||
.find(({ roomId }) => roomId === panelInfo?.roomId)?.roomThemeInfos
|
||||
?.length
|
||||
);
|
||||
|
||||
setSelectedThemeExpsOrd(panelInfo?.themeExpsOrd);
|
||||
}
|
||||
}, [brandShowroomInfo, panelInfo]);
|
||||
|
||||
useEffect(() => {
|
||||
setOtherRoomThemeInfos(
|
||||
brandShowroomInfo
|
||||
.find(({ roomId }) => roomId === panelInfo?.roomId)
|
||||
?.roomThemeInfos //
|
||||
.filter(({ themeExpsOrd }) => themeExpsOrd !== selectedThemeExpsOrd)
|
||||
);
|
||||
|
||||
setSelectedRoomThemeInfo(
|
||||
brandShowroomInfo
|
||||
.find(({ roomId }) => roomId === panelInfo?.roomId)
|
||||
?.roomThemeInfos //
|
||||
.find(({ themeExpsOrd }) => themeExpsOrd === selectedThemeExpsOrd)
|
||||
);
|
||||
}, [brandShowroomInfo, panelInfo?.roomId, selectedThemeExpsOrd]);
|
||||
}, [selectedRoomThemeInfo]);
|
||||
|
||||
// effect: focus logic
|
||||
useEffect(() => {
|
||||
if (!isInitialFocusOccurred) {
|
||||
let targetId;
|
||||
|
||||
if (panelInfo?.lastFocusedTargetId) {
|
||||
targetId = panelInfo.lastFocusedTargetId;
|
||||
}
|
||||
//
|
||||
else if (panelInfo?.targetId) {
|
||||
targetId = panelInfo.targetId;
|
||||
}
|
||||
//
|
||||
else {
|
||||
targetId = "spotlightId-arrow";
|
||||
}
|
||||
const targetId =
|
||||
panelInfo?.lastFocusedTargetId ??
|
||||
panelInfo?.targetId ??
|
||||
"spotlightId-arrow";
|
||||
|
||||
initialFocusTimeoutJob.current.start(() => {
|
||||
const initialFocusTarget = findSelector(
|
||||
`[data-spotlight-id="${targetId}"]`
|
||||
);
|
||||
|
||||
setSpotlightDisabled(false);
|
||||
|
||||
if (initialFocusTarget) {
|
||||
Spotlight.focus(initialFocusTarget);
|
||||
}
|
||||
const focusTarget = findSelector(`[data-spotlight-id="${targetId}"]`);
|
||||
if (focusTarget) Spotlight.focus(focusTarget);
|
||||
|
||||
setIsInitialFocusOccurred(true);
|
||||
});
|
||||
}
|
||||
}, [
|
||||
isInitialFocusOccurred,
|
||||
panelInfo?.lastFocusedTargetId,
|
||||
panelInfo?.targetId,
|
||||
]);
|
||||
}, [isInitialFocusOccurred]);
|
||||
|
||||
// effect: unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
const lastFocusedTarget = Spotlight.getCurrent();
|
||||
|
||||
if (lastFocusedTarget) {
|
||||
const lastFocusedTargetId =
|
||||
lastFocusedTarget.getAttribute("data-spotlight-id");
|
||||
const lastFocusedTargetId = getContainerId(Spotlight.getCurrent());
|
||||
|
||||
if (lastFocusedTargetId) {
|
||||
dispatch(
|
||||
updatePanel({
|
||||
name: panel_names.IMAGE_PANEL,
|
||||
@@ -216,7 +195,7 @@ export default function ImagePanel({ panelInfo, spotlightId, ...rest }) {
|
||||
);
|
||||
}
|
||||
};
|
||||
}, [dispatch]);
|
||||
}, []);
|
||||
|
||||
const handleClick = useCallback(
|
||||
(e) => {
|
||||
@@ -224,23 +203,21 @@ export default function ImagePanel({ panelInfo, spotlightId, ...rest }) {
|
||||
if (e.target.id === "dark-gradient") {
|
||||
setSideContentsVisible(false);
|
||||
}
|
||||
} else {
|
||||
setOverlayContentsVisible((prev) => !prev);
|
||||
}
|
||||
} else setOverlayContentsVisible((prev) => !prev);
|
||||
},
|
||||
[sideContentsVisible]
|
||||
);
|
||||
|
||||
const handleSeletedTab = useCallback((nowMenu) => {
|
||||
dispatch(sendLogGNB(nowMenu));
|
||||
}, []);
|
||||
const handleSelectedTab = useCallback(
|
||||
(nowMenu) => dispatch(sendLogGNB(nowMenu)),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<TPanel
|
||||
className={css.tPanel}
|
||||
isTabActivated={false}
|
||||
spotlightId={spotlightId}
|
||||
spotlightDisabled={spotlightDisabled}
|
||||
>
|
||||
{selectedRoomThemeInfo &&
|
||||
selectedRoomThemeInfosLength &&
|
||||
@@ -271,12 +248,15 @@ export default function ImagePanel({ panelInfo, spotlightId, ...rest }) {
|
||||
{sideContentsVisible && (
|
||||
<ImageSideContents
|
||||
otherRoomThemeInfos={otherRoomThemeInfos}
|
||||
handleSeletedTab={handleSeletedTab}
|
||||
handleSelectedTab={handleSelectedTab}
|
||||
selectedRoomThemeInfo={selectedRoomThemeInfo}
|
||||
setSelectedThemeExpsOrd={setSelectedThemeExpsOrd}
|
||||
/>
|
||||
)}
|
||||
</Container>
|
||||
)}
|
||||
</TPanel>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default ImagePanel;
|
||||
|
||||
@@ -12,33 +12,30 @@ import ShopNowProductList from "./ShopNowProductList/ShopNowProductList";
|
||||
|
||||
const tabList = [$L("SHOP NOW"), $L("ROOM THEME")];
|
||||
|
||||
export default memo(function ImageSideContents({
|
||||
const ImageSideContents = ({
|
||||
otherRoomThemeInfos,
|
||||
handleSeletedTab,
|
||||
handleSelectedTab,
|
||||
selectedRoomThemeInfo,
|
||||
}) {
|
||||
setSelectedThemeExpsOrd,
|
||||
}) => {
|
||||
const [tabIndex, setTabIndex] = useState(0);
|
||||
|
||||
const { roomThemeProducts } = selectedRoomThemeInfo;
|
||||
|
||||
useEffect(() => {
|
||||
if (handleSeletedTab) {
|
||||
if (handleSelectedTab) {
|
||||
const nowMenu =
|
||||
tabIndex === 0
|
||||
? LOG_MENU.SHOW_ROOM_SHOP_NOW
|
||||
: LOG_MENU.SHOW_ROOM_ROOM_THEME;
|
||||
|
||||
handleSeletedTab(nowMenu);
|
||||
handleSelectedTab(nowMenu);
|
||||
}
|
||||
}, [tabIndex, handleSeletedTab]);
|
||||
}, [tabIndex, handleSelectedTab]);
|
||||
|
||||
const handleItemClick = useCallback(
|
||||
({ index }) => {
|
||||
if (index === tabIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTabIndex(index);
|
||||
if (index !== tabIndex) setTabIndex(index);
|
||||
},
|
||||
[tabIndex]
|
||||
);
|
||||
@@ -60,10 +57,15 @@ export default memo(function ImageSideContents({
|
||||
<ListEmptyContents tabIndex={tabIndex} />
|
||||
)
|
||||
) : otherRoomThemeInfos.length > 0 ? (
|
||||
<RoomThemeList otherRoomThemeInfos={otherRoomThemeInfos} />
|
||||
<RoomThemeList
|
||||
otherRoomThemeInfos={otherRoomThemeInfos}
|
||||
setSelectedThemeExpsOrd={setSelectedThemeExpsOrd}
|
||||
/>
|
||||
) : (
|
||||
<ListEmptyContents tabIndex={tabIndex} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export default memo(ImageSideContents);
|
||||
|
||||
@@ -9,7 +9,7 @@ const STRING_CONF = {
|
||||
THEME: "Theme",
|
||||
};
|
||||
|
||||
export default memo(function ListEmptyContents({ tabIndex = 0 }) {
|
||||
const ListEmptyContents = ({ tabIndex = 0 }) => {
|
||||
return (
|
||||
<figure className={css.container}>
|
||||
<img src={ImgContentsLoading} alt="" />
|
||||
@@ -21,4 +21,6 @@ export default memo(function ListEmptyContents({ tabIndex = 0 }) {
|
||||
</figcaption>
|
||||
</figure>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export default memo(ListEmptyContents);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useEffect } from "react";
|
||||
import React, { memo, useCallback, useEffect } from "react";
|
||||
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
@@ -9,29 +9,29 @@ import useScrollTo from "../../../../hooks/useScrollTo";
|
||||
import { panel_names } from "../../../../utils/Config";
|
||||
import css from "./RoomThemeList.module.less";
|
||||
|
||||
export default function RoomThemeList({ otherRoomThemeInfos }) {
|
||||
const RoomThemeList = ({ otherRoomThemeInfos, setSelectedThemeExpsOrd }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { getScrollTo, scrollTop } = useScrollTo();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
scrollTop({ animate: false });
|
||||
}, [scrollTop, otherRoomThemeInfos]);
|
||||
useEffect(() => scrollTop({ animate: false }), [otherRoomThemeInfos]);
|
||||
|
||||
const handleClick = useCallback(
|
||||
(themeExpsOrd, themeId) => () => {
|
||||
(themeExpsOrd, themeId, themeNm) => () => {
|
||||
if (setSelectedThemeExpsOrd) setSelectedThemeExpsOrd(themeExpsOrd);
|
||||
|
||||
dispatch(
|
||||
updatePanel({
|
||||
name: panel_names.IMAGE_PANEL,
|
||||
panelInfo: {
|
||||
themeId,
|
||||
themeExpsOrd,
|
||||
themeNm,
|
||||
y: 0,
|
||||
},
|
||||
})
|
||||
);
|
||||
},
|
||||
[dispatch]
|
||||
[setSelectedThemeExpsOrd]
|
||||
);
|
||||
|
||||
const renderItem = useCallback(
|
||||
@@ -44,7 +44,7 @@ export default function RoomThemeList({ otherRoomThemeInfos }) {
|
||||
className={css.tItemCard}
|
||||
imageAlt={themeNm}
|
||||
imageSource={themeImgUrl}
|
||||
onClick={handleClick(themeExpsOrd, themeId)}
|
||||
onClick={handleClick(themeExpsOrd, themeId, themeNm)}
|
||||
productId={themeId}
|
||||
productName={themeNm}
|
||||
type={TYPES.horizontal}
|
||||
@@ -70,4 +70,6 @@ export default function RoomThemeList({ otherRoomThemeInfos }) {
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default memo(RoomThemeList);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useEffect, useRef } from "react";
|
||||
import React, { memo, useCallback, useEffect, useRef } from "react";
|
||||
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
@@ -12,10 +12,9 @@ import { panel_names } from "../../../../utils/Config";
|
||||
import { getTranslate3dValueByDirection } from "../../../../utils/helperMethods";
|
||||
import css from "./ShopNowProductList.module.less";
|
||||
|
||||
export default function ShopNowProductList({ selectedRoomThemeInfo }) {
|
||||
const { getScrollTo, scrollTop } = useScrollTo();
|
||||
|
||||
const ShopNowProductList = ({ selectedRoomThemeInfo }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { getScrollTo, scrollTop } = useScrollTo();
|
||||
|
||||
const panelInfo = useSelector((state) => state.panels.panels[1]?.panelInfo);
|
||||
|
||||
@@ -24,9 +23,7 @@ export default function ShopNowProductList({ selectedRoomThemeInfo }) {
|
||||
const { roomThemeProducts } = selectedRoomThemeInfo;
|
||||
|
||||
useEffect(() => {
|
||||
if (!panelInfo?.y) {
|
||||
return;
|
||||
}
|
||||
if (!panelInfo?.y) return;
|
||||
|
||||
const scrollTopJobValue = scrollTopJob.current;
|
||||
const { y } = panelInfo;
|
||||
@@ -36,9 +33,7 @@ export default function ShopNowProductList({ selectedRoomThemeInfo }) {
|
||||
return () => scrollTopJobValue.stop();
|
||||
}, [panelInfo, scrollTop]);
|
||||
|
||||
useEffect(() => {
|
||||
scrollTop({ animate: false });
|
||||
}, [scrollTop, selectedRoomThemeInfo]);
|
||||
useEffect(() => scrollTop({ animate: false }), [selectedRoomThemeInfo]);
|
||||
|
||||
const handleClick = useCallback(
|
||||
(patnrId, prdtId) => (e) => {
|
||||
@@ -72,15 +67,8 @@ export default function ShopNowProductList({ selectedRoomThemeInfo }) {
|
||||
|
||||
const renderItem = useCallback(
|
||||
({ index, ...rest }) => {
|
||||
const {
|
||||
offerInfo,
|
||||
patnrId,
|
||||
// prdtExpsOrd,
|
||||
prdtId,
|
||||
prdtImgUrl,
|
||||
prdtNm,
|
||||
priceInfo,
|
||||
} = roomThemeProducts[index];
|
||||
const { offerInfo, patnrId, prdtId, prdtImgUrl, prdtNm, priceInfo } =
|
||||
roomThemeProducts[index];
|
||||
|
||||
return (
|
||||
<TItemCard
|
||||
@@ -115,4 +103,6 @@ export default function ShopNowProductList({ selectedRoomThemeInfo }) {
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default memo(ShopNowProductList);
|
||||
|
||||
Reference in New Issue
Block a user