Files
shoptime/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/HomeBanner.jsx
2025-06-23 09:49:13 +09:00

516 lines
17 KiB
JavaScript

// src/views/HomePanel/HomeBanner/HomeBanner.jsx
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import Spotlight from "@enact/spotlight";
import { SpotlightContainerDecorator } from "@enact/spotlight/SpotlightContainerDecorator";
import Spottable from "@enact/spotlight/Spottable";
import { $L, scaleH, scaleW } from "../../../utils/helperMethods";
import {
setDefaultFocus,
setShowPopup,
fetchCurrentUserHomeTerms,
} from "../../../actions/homeActions";
import { changeAppStatus } from "../../../actions/commonActions";
import { setMyPageTermsAgree } from "../../../actions/myPageActions";
import { pushPanel } from "../../../actions/panelActions";
import {
requestPlayControl,
releasePlayControl,
} from "../../../actions/playActions";
import CustomImage from "../../../components/CustomImage/CustomImage";
import css from "./HomeBanner.module.less";
import Random from "./RandomUnit";
import Rolling from "./RollingUnit";
import RandomUnitNew from "./RandomUnit.new";
import TNewPopUp from "../../../components/TPopUp/TNewPopUp";
// import TButtonScroller from "../../../components/TButtonScroller/TButtonScroller";
import OptionalConfirm from "../../../components/Optional/OptionalConfirm";
// import * as Config from "../../../utils/Config";
import PersistentVideoUnit from "./PersistentVideoUnit";
const SpottableComponent = Spottable("div");
const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused" },
"div",
);
const ContainerBasic = SpotlightContainerDecorator(
{ enterTo: "last-focused" },
"div",
);
export default function HomeBanner({
firstSpot,
spotlightId,
handleItemFocus,
handleShelfFocus,
}) {
const dispatch = useDispatch();
const homeTopDisplayInfo = useSelector(
(state) => state.home.homeTopDisplayInfo,
);
const bannerDataList = useSelector(
(state) => state.home.bannerData?.bannerInfos,
);
const popupVisible = useSelector((state) => state.common.popup.popupVisible);
const selectTemplate = useMemo(() => {
return homeTopDisplayInfo.shptmTmplCd;
}, [homeTopDisplayInfo]);
const _handleItemFocus = useCallback(() => {
if (handleItemFocus) {
handleItemFocus();
}
}, [handleItemFocus]);
const handleSecondBannerFocus = useCallback(() => {
const secondBannerData = bannerDataList?.[1];
if (secondBannerData) {
const randomData =
secondBannerData.bannerDetailInfos[secondBannerData.randomIndex];
const videoInfo = {
showUrl: randomData.showUrl,
patnrId: randomData.patnrId,
showId: randomData.showId,
shptmBanrTpNm: randomData.showId ? randomData.shptmBanrTpNm : "MEDIA",
lgCatCd: randomData.lgCatCd,
chanId: randomData.brdcChnlId,
modal: true,
modalContainerId: "banner1",
modalClassName: css.videoModal,
isVerticalModal: true, // Assuming second banner is horizontal, so modal is vertical
};
dispatch(requestPlayControl("banner1_preview", videoInfo));
}
if (handleItemFocus) {
handleItemFocus();
}
}, [dispatch, bannerDataList, handleItemFocus]);
const handleSecondBannerBlur = useCallback(() => {
dispatch(releasePlayControl("banner1_preview"));
}, [dispatch]);
const termsData = useSelector((state) => state.home.termsData);
const optionalTermsData = useSelector((state) =>
state.home.termsData?.data?.terms.find(
(term) => term.trmsTpCd === "MST00405",
),
);
const termsLoading = useSelector((state) => state.common.termsLoading);
const isGnbOpened = useSelector((state) => state.common.isGnbOpened);
// 선택약관 동의여부
const introTermsAgree = useSelector((state) => state.common.introTermsAgree);
//------------------------------------------------------------------------------
// 팝업표시 상태
const [isOptionalConfirmVisible, setIsOptionalConfirmVisible] =
useState(false);
const [isOptionalTermsVisible, setIsOptionalTermsVisible] = useState(false);
// 선택약관 팝업 표시 여부
const shouldShowOptionalTermsPopup = useMemo(() => {
if (termsLoading || isGnbOpened) {
return false;
}
const terms = termsData?.data?.terms;
if (!terms) {
return false;
}
const optionalTerm = terms.find((term) => term.trmsTpCd === "MST00405");
return optionalTerm
? optionalTerm.trmsPopFlag === "Y" && optionalTerm.trmsAgrFlag === "N"
: false;
}, [termsData, termsLoading, isGnbOpened]);
const handleOptionalAgree = useCallback(() => {
console.log("handleAgree Click");
// 약관 동의할 항목들 (string array)
const termsList = ["TID0000222", "TID0000223", "TID0000232"];
// 동의하지 않을 항목들 (빈 배열)
const notTermsList = [];
console.log("OptionalTermsConfirm -약관 동의 API 호출 파라미터:", {
termsList,
notTermsList,
});
const callback = (response) => {
if (response.retCode === "000" || response.retCode === 0) {
console.log("약관 동의 성공:", response);
// 약관 정보 갱신
dispatch(fetchCurrentUserHomeTerms());
} else {
console.error("약관 동의 실패:", response);
}
};
console.log("OptionalTermsConfirm - 약관 동의 API 호출 payload:", {
termsList,
notTermsList,
});
dispatch(setMyPageTermsAgree({ termsList, notTermsList }, callback));
}, [dispatch]);
const handleOptionalTermsClick = useCallback(() => {
console.log("약관 자세히 보기 클릭");
setIsOptionalConfirmVisible(false);
setIsOptionalTermsVisible(true);
// 약관 상세 팝업을 띄우는 로직 추가
}, []);
const handleOptionalAgreeClick = useCallback(() => {
handleOptionalAgree();
setIsOptionalConfirmVisible(false);
}, []);
const handleOptionalDeclineClick = useCallback(() => {
console.log("거절/다음에 하기 버튼 클릭");
setIsOptionalConfirmVisible(false);
// 거절 처리 로직 추가
}, []);
// 선택약관 팝업 Close
const handleTermsPopupClosed = useCallback(() => {
setIsOptionalTermsVisible(false);
setIsOptionalConfirmVisible(true);
Spotlight.focus("optional-confirm-popup");
}, []);
// 선택약관 팝업 Agree
const handleTermsPopupAgree = useCallback(() => {
console.log("handleTermsPopupAgree");
handleOptionalAgree();
setIsOptionalTermsVisible(false);
}, []);
//------------------------------------------------------------------------------
const _handleShelfFocus = useCallback(() => {
if (handleShelfFocus) {
handleShelfFocus();
}
}, [handleShelfFocus]);
const defaultFocus = useMemo(() => {
if (bannerDataList) {
let targetIndex = 0;
for (let i = 0; i < bannerDataList.length; i++) {
const data = bannerDataList[i];
let bannerDetailInfos = data.bannerDetailInfos;
if (data.shptmDspyTpNm === "Random") {
if (
bannerDetailInfos[data.randomIndex].shptmBanrTpNm === "LIVE" ||
bannerDetailInfos[data.randomIndex].shptmBanrTpNm === "VOD"
) {
targetIndex = i;
break;
}
} else if (
bannerDetailInfos.find(
(el) => el.shptmBanrTpNm === "LIVE" || el.shptmBanrTpNm === "VOD",
)
) {
targetIndex = i;
break;
}
}
return "banner" + targetIndex;
}
return null;
}, [bannerDataList]);
useEffect(() => {
if (firstSpot && defaultFocus && popupVisible === false) {
setTimeout(() => {
Spotlight.focus(defaultFocus);
}, 0);
}
if (defaultFocus) {
dispatch(setDefaultFocus(defaultFocus));
}
}, [defaultFocus, dispatch, popupVisible]);
// 테스트용 팝업 표시
// useEffect(() => {
// setTimeout(() => {
// console.log("App.js optionalTermsTest 팝업 표시");
// setIsOptionalConfirmVisible(true);
// // setIsOptionalTermsVisible(true);
// }, 1000);
// }, []);
// 약관 동의 및 선택 약관 팝업 처리
useEffect(() => {
if (termsLoading) {
// 약관 데이터 로딩 중에는 아무것도 하지 않음
return;
}
// 선택 약관 팝업을 띄워야 하는 경우
if (shouldShowOptionalTermsPopup) {
// 3초 후에 팝업을 띄우도록 설정
console.log("shouldShowOptionalTermsPopup", shouldShowOptionalTermsPopup);
console.log("App.js optionalTermsConfirm 팝업 표시");
const timer = setTimeout(() => {
setIsOptionalConfirmVisible(true);
// dispatch(setShowPopup({ activePopup: "optionalTermsConfirm" }));
}, 1000); // 3000 milliseconds = 3 seconds
// 컴포넌트 언마운트 시 타이머 클리어
return () => clearTimeout(timer);
}
}, [shouldShowOptionalTermsPopup, termsLoading]);
// const renderItem = useCallback(
// (index, isHorizontal) => {
// const data = bannerDataList?.[index] ?? {};
// if (index === 1) {
// return (
// <div className={!isHorizontal ? css.imgBox : undefined}>
// <RandomUnitNew
// bannerData={data}
// isHorizontal={isHorizontal}
// key={"banner" + index}
// spotlightId={"banner" + index}
// handleShelfFocus={_handleShelfFocus}
// onFocus={handleSecondBannerFocus}
// onBlur={handleSecondBannerBlur}
// randomNumber={data.randomIndex}
// />
// </div>
// );
// }
// return (
// <div className={!isHorizontal ? css.imgBox : undefined}>
// {data.shptmDspyTpNm === "Rolling" ? (
// <Rolling
// bannerData={data}
// isHorizontal={isHorizontal}
// key={"banner" + index}
// spotlightId={"banner" + index}
// handleShelfFocus={_handleShelfFocus}
// handleItemFocus={_handleItemFocus}
// />
// ) : data.shptmDspyTpNm === "Random" ? (
// <Random
// bannerData={data}
// isHorizontal={isHorizontal}
// key={"banner" + index}
// spotlightId={"banner" + index}
// handleShelfFocus={_handleShelfFocus}
// handleItemFocus={_handleItemFocus}
// randomNumber={data.randomIndex}
// />
// ) : (
// <SpottableComponent spotlightId={"banner" + index}>
// <CustomImage
// delay={0}
// src={
// isHorizontal
// ? homeTopDisplayInfo.wdthtpImgPath1
// : homeTopDisplayInfo.vtctpImgPath1
// }
// aria-label={
// isHorizontal
// ? homeTopDisplayInfo.wdthtpImgNm1
// : homeTopDisplayInfo.vtctpImgNm1
// }
// />
// </SpottableComponent>
// )}
// </div>
// );
// },
// [
// bannerDataList,
// _handleItemFocus,
// _handleShelfFocus,
// handleSecondBannerFocus,
// handleSecondBannerBlur,
// ],
// );
const renderItem = useCallback(
(index, isHorizontal) => {
const data = bannerDataList?.[index] ?? {};
return (
<div className={!isHorizontal ? css.imgBox : undefined}>
{data.shptmDspyTpNm === "Rolling" ? (
<Rolling
bannerData={data}
isHorizontal={isHorizontal}
key={"banner" + index}
spotlightId={"banner" + index}
handleShelfFocus={_handleShelfFocus}
handleItemFocus={_handleItemFocus}
/>
) : data.shptmDspyTpNm === "Random" ? (
<Random
bannerData={data}
isHorizontal={isHorizontal}
key={"banner" + index}
spotlightId={"banner" + index}
handleShelfFocus={_handleShelfFocus}
handleItemFocus={_handleItemFocus}
randomNumber={data.randomIndex}
/>
) : (
<SpottableComponent spotlightId={"banner" + index}>
<CustomImage
delay={0}
src={
isHorizontal
? homeTopDisplayInfo.wdthtpImgPath1
: homeTopDisplayInfo.vtctpImgPath1
}
aria-label={
isHorizontal
? homeTopDisplayInfo.wdthtpImgNm1
: homeTopDisplayInfo.vtctpImgNm1
}
/>
</SpottableComponent>
)}
</div>
);
},
[_handleItemFocus, _handleShelfFocus, bannerDataList]
);
const renderItemPersistentVideo = useCallback(
(index, isHorizontal) => {
const data = bannerDataList?.[index] ?? {};
return (
<div className={!isHorizontal ? css.imgBox : undefined}>
{data.shptmDspyTpNm === "Rolling" ? (
<Rolling
bannerData={data}
isHorizontal={isHorizontal}
key={"banner" + index}
spotlightId={"banner" + index}
handleShelfFocus={_handleShelfFocus}
handleItemFocus={_handleItemFocus}
/>
) : data.shptmDspyTpNm === "Random" ? (
<PersistentVideoUnit
bannerData={data}
isHorizontal={isHorizontal}
key={"banner" + index}
spotlightId={"banner" + index}
handleShelfFocus={_handleShelfFocus}
handleItemFocus={_handleItemFocus}
randomNumber={data.randomIndex}
/>
) : (
<SpottableComponent spotlightId={"banner" + index}>
<CustomImage
delay={0}
src={
isHorizontal
? homeTopDisplayInfo.wdthtpImgPath1
: homeTopDisplayInfo.vtctpImgPath1
}
aria-label={
isHorizontal
? homeTopDisplayInfo.wdthtpImgNm1
: homeTopDisplayInfo.vtctpImgNm1
}
/>
</SpottableComponent>
)}
</div>
);
},
[_handleItemFocus, _handleShelfFocus, bannerDataList, homeTopDisplayInfo],
);
const renderLayout = useCallback(() => {
switch (selectTemplate) {
case "DSP00201": {
return (
<>
<ContainerBasic className={css.smallBox}>
{/* {renderItemPersistentVideo(0, true)} */}
{renderItem(0, true)}
{renderItem(1, true)}
</ContainerBasic>
{renderItem(2, false)}
{renderItem(3, false)}
</>
);
}
case "DSP00202": {
return (
<>
{renderItem(0, false)}
<ContainerBasic className={css.smallBox}>
{renderItem(1, true)}
{renderItem(2, true)}
</ContainerBasic>
{renderItem(3, false)}
</>
);
}
case "DSP00203": {
return (
<>
{renderItem(0, false)}
{renderItem(1, false)}
<ContainerBasic className={css.smallBox}>
{renderItem(2, true)}
{renderItem(3, true)}
</ContainerBasic>
</>
);
}
}
return null;
}, [selectTemplate, renderItem, renderItemPersistentVideo]);
return (
<>
<Container
className={css.container}
spotlightId={spotlightId}
data-wheel-point={true}
>
<div className={css.homeTemplateBox}>{renderLayout()}</div>
</Container>
{/* 선택약관 동의 팝업 */}
<OptionalConfirm
open={isOptionalConfirmVisible}
spotlightId="optional-confirm-popup"
onClose={handleOptionalDeclineClick}
onOptionalTermsClick={handleOptionalTermsClick}
onOptionalAgreeClick={handleOptionalAgreeClick}
onOptionalDeclineClick={handleOptionalDeclineClick}
customPosition={true}
position={{
position: "absolute",
top: "342px", // 가운데를 기준으로 한 좌표 (1080/2) - 198
left: "0px",
bottom: "unset",
transform: "none",
}}
/>
{/* 선택약관 자세히 보기 팝업 */}
<TNewPopUp
kind="figmaTermsPopup"
open={isOptionalTermsVisible}
title={$L("Optional Terms")}
text={optionalTermsData?.trmsCntt || ""}
onClose={handleTermsPopupClosed}
onAgreeClick={handleTermsPopupAgree}
showAgreeButton={true}
/>
</>
);
}