Files
shoptime/com.twin.app.shoptime/src/views/OnSalePanel/OnSalePanel.jsx

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>
);
}