410 lines
12 KiB
JavaScript
410 lines
12 KiB
JavaScript
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
|
|
import { useDispatch, useSelector } from "react-redux";
|
|
|
|
import { Job } from "@enact/core/util";
|
|
import Spotlight from "@enact/spotlight";
|
|
|
|
import { types } from "../../actions/actionTypes";
|
|
import { changeAppStatus } from "../../actions/commonActions";
|
|
import {
|
|
sendLogCuration,
|
|
sendLogGNB,
|
|
sendLogTotalRecommend,
|
|
} from "../../actions/logActions";
|
|
import { copyCategoryInfos, getOnSaleInfo } from "../../actions/onSaleActions";
|
|
import { popPanel, updatePanel } from "../../actions/panelActions";
|
|
import TBody from "../../components/TBody/TBody";
|
|
import TButton, { TYPES } from "../../components/TButton/TButton";
|
|
import { removeDotAndColon } from "../../components/TItemCard/TItemCard";
|
|
import TPanel from "../../components/TPanel/TPanel";
|
|
import TVerticalPagenator from "../../components/TVerticalPagenator/TVerticalPagenator";
|
|
import { LOG_MENU, LOG_TP_NO, panel_names } from "../../utils/Config";
|
|
import OnSaleContents from "./OnSaleContents/OnSaleContents";
|
|
import OnSaleNav from "./OnSaleNav/OnSaleNav";
|
|
import css from "./OnSalePanel.module.less";
|
|
import { updateHomeInfo } from "../../actions/homeActions";
|
|
|
|
const getExpsOrdByLgCatCd = (array, value) => {
|
|
const expsOrd = array.findIndex(({ lgCatCd }) => value === lgCatCd) + 1;
|
|
return expsOrd.toString();
|
|
};
|
|
|
|
export default function OnSalePanel({ panelInfo, spotlightId }) {
|
|
const dispatch = useDispatch();
|
|
|
|
const categoryInfos = useSelector(
|
|
(state) => state.onSale.onSaleData.data.categoryInfos
|
|
);
|
|
const copiedCategoryInfos = useSelector(
|
|
(state) => state.onSale.copiedCategoryInfos
|
|
);
|
|
const saleInfos = useSelector(
|
|
(state) => state.onSale.onSaleData.data.saleInfos
|
|
);
|
|
|
|
const [categories, setCategories] = useState();
|
|
const [firstFocusableTarget, setFirstFocusableTarget] = useState();
|
|
const [isInitialFocusOccurred, setIsInitialFocusOccurred] = useState(false);
|
|
const [isInitialRendered, setIsInitialRendered] = useState(true);
|
|
const [isReadyForInitialFocusTarget, setIsReadyForInitialFocusTarget] =
|
|
useState(false);
|
|
const [isTopButtonClicked, setIsTopButtonClicked] = useState(false);
|
|
const [selectedLgCatCd, setSelectedLgCatCd] = useState();
|
|
const [selectedLgCatNm, setSelectedLgCatNm] = useState();
|
|
const [spotlightDisabled, setSpotlightDisabled] = useState(true);
|
|
const [currentFocusedShelf, setCurrentFocusedShelf] = useState(null);
|
|
|
|
const enteredThroughEventPopup = Object.keys(panelInfo).length === 1;
|
|
const enteredThroughGNB = Object.keys(panelInfo).length === 0;
|
|
const previousPanelIsHome = Object.keys(panelInfo).length === 3;
|
|
const previousPanelIsDetail = Object.keys(panelInfo).length > 4;
|
|
|
|
const cbChangePageRef = useRef(null);
|
|
const focusedContainerIdRef = useRef(0);
|
|
const initialFocusTimeoutJob = useRef(new Job((func) => func(), 0));
|
|
const timerRef = useRef(null);
|
|
|
|
useEffect(() => {
|
|
dispatch(sendLogGNB(LOG_MENU.ON_SALE));
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!panelInfo?.noResetFlag) {
|
|
dispatch({ type: types.RESET_ON_SALE_STATE });
|
|
}
|
|
}, [dispatch, panelInfo?.noResetFlag]);
|
|
|
|
useEffect(() => {
|
|
if (isInitialRendered) {
|
|
if (previousPanelIsDetail) {
|
|
setIsInitialRendered(false);
|
|
return;
|
|
}
|
|
|
|
let props = { categoryIncFlag: "Y", saleInfosIncFlag: "Y" };
|
|
|
|
if (previousPanelIsHome || enteredThroughEventPopup) {
|
|
props = { ...props, lgCatCd: panelInfo?.lgCatCd };
|
|
}
|
|
|
|
dispatch(getOnSaleInfo(props));
|
|
setIsInitialRendered(false);
|
|
}
|
|
}, [
|
|
enteredThroughEventPopup,
|
|
isInitialRendered,
|
|
panelInfo?.lgCatCd,
|
|
previousPanelIsDetail,
|
|
previousPanelIsHome,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
if (!categories) {
|
|
if (previousPanelIsDetail) {
|
|
setCategories(copiedCategoryInfos);
|
|
return;
|
|
}
|
|
if (categoryInfos) {
|
|
dispatch(copyCategoryInfos(categoryInfos));
|
|
setCategories(categoryInfos);
|
|
setSelectedLgCatCd(panelInfo?.lgCatCd);
|
|
setSelectedLgCatNm(panelInfo?.lgCatNm);
|
|
}
|
|
}
|
|
}, [
|
|
categories,
|
|
categoryInfos,
|
|
copiedCategoryInfos,
|
|
previousPanelIsDetail,
|
|
selectedLgCatCd,
|
|
selectedLgCatNm,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
if (selectedLgCatCd) {
|
|
dispatch(
|
|
getOnSaleInfo({ lgCatCd: selectedLgCatCd, saleInfosIncFlag: "Y" })
|
|
);
|
|
}
|
|
}, [selectedLgCatCd]);
|
|
|
|
useEffect(() => {
|
|
if (categories && saleInfos && Object.keys(saleInfos).length > 0) {
|
|
const prdtId = saleInfos[0]?.saleProductInfos[0]?.prdtId;
|
|
|
|
if (prdtId) {
|
|
setFirstFocusableTarget("spotlightId-" + removeDotAndColon(prdtId));
|
|
setIsReadyForInitialFocusTarget(true);
|
|
}
|
|
}
|
|
}, [categories, saleInfos]);
|
|
|
|
useEffect(() => {
|
|
if (categories && isReadyForInitialFocusTarget && !isInitialFocusOccurred) {
|
|
let targetId = "spotlightId-" + categories[0]?.lgCatCd;
|
|
|
|
if (previousPanelIsDetail) {
|
|
targetId = panelInfo?.targetId;
|
|
}
|
|
|
|
if (previousPanelIsHome) {
|
|
targetId = panelInfo?.linkTpCd
|
|
? "spotlightId-" + panelInfo?.lgCatCd
|
|
: "spotlightId-" + panelInfo?.prdtId;
|
|
}
|
|
|
|
if (enteredThroughEventPopup) {
|
|
targetId = "spotlightId-" + panelInfo?.lgCatCd;
|
|
}
|
|
|
|
initialFocusTimeoutJob.current.start(() => {
|
|
const initialFocusTarget = document.querySelector(
|
|
`[data-spotlight-id="${targetId}"]`
|
|
);
|
|
|
|
setSpotlightDisabled(false);
|
|
|
|
if (initialFocusTarget) Spotlight.focus(initialFocusTarget);
|
|
else {
|
|
if (previousPanelIsHome) Spotlight.focus("sale-info-0");
|
|
}
|
|
|
|
setIsInitialFocusOccurred(true);
|
|
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
|
});
|
|
}
|
|
}, [
|
|
categories,
|
|
enteredThroughEventPopup,
|
|
isInitialFocusOccurred,
|
|
isReadyForInitialFocusTarget,
|
|
panelInfo?.lgCatCd,
|
|
panelInfo?.linkTpCd,
|
|
panelInfo?.prdtId,
|
|
panelInfo?.targetId,
|
|
previousPanelIsDetail,
|
|
previousPanelIsHome,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
if (categories && isInitialFocusOccurred && !previousPanelIsDetail) {
|
|
let params = { logTpNo: LOG_TP_NO.CURATION.ON_SALE };
|
|
|
|
if (!selectedLgCatCd) {
|
|
if (enteredThroughGNB) {
|
|
params = {
|
|
...params,
|
|
expsOrd: getExpsOrdByLgCatCd(categories, categories[0]?.lgCatCd),
|
|
lgCatCd: categories[0]?.lgCatCd,
|
|
lgCatNm: categories[0]?.lgCatNm,
|
|
};
|
|
}
|
|
|
|
if (enteredThroughEventPopup) {
|
|
params = {
|
|
...params,
|
|
expsOrd: getExpsOrdByLgCatCd(categories, panelInfo?.lgCatCd),
|
|
lgCatCd: panelInfo?.lgCatCd,
|
|
lgCatNm:
|
|
categories //
|
|
.find(({ lgCatCd }) => panelInfo?.lgCatCd === lgCatCd)
|
|
?.lgCatNm ?? "",
|
|
};
|
|
}
|
|
|
|
if (previousPanelIsHome) {
|
|
params = {
|
|
...params,
|
|
expsOrd: getExpsOrdByLgCatCd(categories, panelInfo?.lgCatCd),
|
|
lgCatCd: panelInfo?.lgCatCd,
|
|
lgCatNm: panelInfo?.lgCatNm,
|
|
};
|
|
}
|
|
} else {
|
|
params = {
|
|
...params,
|
|
expsOrd: getExpsOrdByLgCatCd(categories, selectedLgCatCd),
|
|
lgCatCd: selectedLgCatCd,
|
|
lgCatNm: selectedLgCatNm,
|
|
};
|
|
}
|
|
|
|
dispatch(sendLogCuration(params));
|
|
}
|
|
}, [
|
|
categories,
|
|
enteredThroughEventPopup,
|
|
enteredThroughGNB,
|
|
isInitialFocusOccurred,
|
|
panelInfo?.lgCatCd,
|
|
panelInfo?.lgCatNm,
|
|
previousPanelIsHome,
|
|
previousPanelIsDetail,
|
|
selectedLgCatCd,
|
|
selectedLgCatNm,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
const lastFocusedTarget = Spotlight.getCurrent();
|
|
|
|
if (lastFocusedTarget) {
|
|
const exprOrd = parseInt(
|
|
lastFocusedTarget.getAttribute("data-exposure-order")
|
|
);
|
|
const lgCatCd = lastFocusedTarget.getAttribute("data-lg-category-code");
|
|
const targetId = lastFocusedTarget.getAttribute("data-spotlight-id");
|
|
|
|
dispatch(
|
|
updatePanel({
|
|
name: panel_names.ON_SALE_PANEL,
|
|
panelInfo: {
|
|
exprOrd,
|
|
lgCatCd,
|
|
targetId,
|
|
focusedContainerId: focusedContainerIdRef.current,
|
|
noResetFlag: true,
|
|
},
|
|
})
|
|
);
|
|
}
|
|
|
|
clearTimeout(timerRef.current);
|
|
initialFocusTimeoutJob.current.stop();
|
|
};
|
|
}, []);
|
|
|
|
const handleTopButtonClick = useCallback(() => {
|
|
if (cbChangePageRef.current) {
|
|
cbChangePageRef.current(0, true, true);
|
|
}
|
|
if (!firstFocusableTarget) {
|
|
return;
|
|
}
|
|
setIsTopButtonClicked(true);
|
|
|
|
timerRef.current = setTimeout(() => {
|
|
Spotlight.focus(firstFocusableTarget);
|
|
setIsTopButtonClicked(false);
|
|
}, 200);
|
|
}, [firstFocusableTarget]);
|
|
|
|
const onFocusedContainerId = useCallback((containerId) => {
|
|
focusedContainerIdRef.current = containerId;
|
|
}, []);
|
|
|
|
const onSaleNavClicked = useCallback((ev) => {
|
|
setFirstFocusableTarget(ev);
|
|
if (cbChangePageRef.current) {
|
|
cbChangePageRef.current(0);
|
|
}
|
|
}, []);
|
|
|
|
const handleShelfFocus = useCallback(
|
|
(shelfOrder) => {
|
|
// 현재 포커스된 shelf와 다른 shelf에 포커스될 때만 true 반환
|
|
if (currentFocusedShelf !== shelfOrder) {
|
|
setCurrentFocusedShelf(shelfOrder);
|
|
return true; // dispatch 해야 함
|
|
}
|
|
return false; // dispatch 하지 않음
|
|
},
|
|
[currentFocusedShelf]
|
|
);
|
|
|
|
const handleCancel = useCallback(
|
|
(e) => {
|
|
if (panelInfo.nowShelf) {
|
|
dispatch(
|
|
updateHomeInfo({
|
|
name: panel_names.HOME_PANEL,
|
|
panelInfo: {
|
|
nowShelf: panelInfo.nowShelf,
|
|
},
|
|
})
|
|
);
|
|
}
|
|
dispatch(popPanel());
|
|
e.stopPropagation();
|
|
},
|
|
[dispatch, panelInfo.nowShelf]
|
|
);
|
|
|
|
useEffect(() => {
|
|
setTimeout(() => {
|
|
dispatch(changeAppStatus({ cursorVisible: false }));
|
|
Spotlight.setPointerMode(false);
|
|
}, 100);
|
|
}, []);
|
|
|
|
return (
|
|
<TPanel
|
|
className={css.tPanel}
|
|
spotlightId={spotlightId}
|
|
handleCancel={handleCancel}
|
|
>
|
|
{categories && (
|
|
<>
|
|
<OnSaleNav
|
|
categoryInfos={categories}
|
|
panelInfoLgCatCd={panelInfo?.lgCatCd}
|
|
previousPanelIsDetail={previousPanelIsDetail}
|
|
selectedLgCatCd={selectedLgCatCd}
|
|
setFirstFocusableTarget={onSaleNavClicked}
|
|
setSelectedLgCatCd={setSelectedLgCatCd}
|
|
setSelectedLgCatNm={setSelectedLgCatNm}
|
|
spotlightDisabled={spotlightDisabled}
|
|
/>
|
|
|
|
<TBody
|
|
className={css.tBody}
|
|
scrollable={false}
|
|
spotlightDisabled={spotlightDisabled}
|
|
>
|
|
{saleInfos && (
|
|
<TVerticalPagenator
|
|
className={css.tVerticalPagenator}
|
|
spotlightId={"onSale_verticalPagenator"}
|
|
enableFocusAction={false}
|
|
defaultContainerId={panelInfo?.focusedContainerId}
|
|
onFocusedContainerId={onFocusedContainerId}
|
|
cbChangePageRef={cbChangePageRef}
|
|
topMargin={48}
|
|
>
|
|
<>
|
|
{saleInfos.map(
|
|
({ saleNm, saleProductInfos, expsOrd }, contentsIndex) => (
|
|
<OnSaleContents
|
|
contentsIndex={contentsIndex}
|
|
isTopButtonClicked={isTopButtonClicked}
|
|
key={"sale-info-" + contentsIndex}
|
|
spotlightId={"sale-info-" + contentsIndex}
|
|
saleNm={saleNm}
|
|
shelfOrder={expsOrd}
|
|
saleProductInfos={saleProductInfos}
|
|
selectedLgCatCd={selectedLgCatCd}
|
|
selectedLgCatNm={selectedLgCatNm}
|
|
onShelfFocus={handleShelfFocus}
|
|
/>
|
|
)
|
|
)}
|
|
{saleInfos.length > 1 && (
|
|
<TButton
|
|
onClick={handleTopButtonClick}
|
|
size={null}
|
|
type={TYPES.topButton}
|
|
ariaLabel="Move to Top"
|
|
data-wheel-point
|
|
/>
|
|
)}
|
|
</>
|
|
</TVerticalPagenator>
|
|
)}
|
|
</TBody>
|
|
</>
|
|
)}
|
|
</TPanel>
|
|
);
|
|
}
|