Files
shoptime/com.twin.app.shoptime/src/views/MainView/MainView.jsx
optrader 99ea3e6595 [251216] fix: TrendingNowPanel 3-layer add
🕐 커밋 시간: 2025. 12. 16. 10:26:10

📊 변경 통계:
  • 총 파일: 1개
  • 추가: +13줄
  • 삭제: -2줄

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/views/MainView/MainView.jsx
2025-12-16 10:26:10 +09:00

935 lines
31 KiB
JavaScript

import React, { use, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import classNames from 'classnames';
import { indexOf } from 'ilib/lib/JSUtils';
import { useDispatch, useSelector } from 'react-redux';
import platform from '@enact/core/platform';
import Spotlight from '@enact/spotlight';
import defaultWatchItem from '../../../assets/images/img-alert-banner-st@3x.png';
// 테스트용 - TODO: 메인 홈 화면에 나와야 하는 이미지들 추가 후 preloadImages에 추가
// import testImage from '../../../assets/images/img-banner-myinfo-login@3x.png';
// import defaultImageItem from '../../../assets/images/img-thumb-empty-product@3x.png';
import LoadingPreloadImage from '../../../assets/images/intro/splash_02_stop.webp';
import LoadingAnimation from '../../../assets/images/intro/splash_03_end.webp';
import LoadingCompleteImage from '../../../assets/images/intro/splash_04_end.webp';
import LoadingShopOnTvImage from '../../../assets/images/intro/splash_end.jpg';
import {
alertToast,
changeAppStatus,
changeLocalSettings,
clearErrorMessage,
setExitApp,
setHidePopup,
setShowPopup,
} from '../../actions/commonActions';
import { getHomeMenu, getHomeTerms, updateHomeInfo } from '../../actions/homeActions';
import {
sendLogAlarmClick,
sendLogAlarmPop,
sendLogLive,
sendLogVOD,
} from '../../actions/logActions';
import { getMyUpcomingAlertShow, setMyTermsWithdraw } from '../../actions/myPageActions';
import { popPanel, pushPanel, resetPanels, updatePanel } from '../../actions/panelActions';
import EndOfServicePopUp from '../../components/EndOfServicePopUp/EndOfServicePopUp';
import Loader from '../../components/Loader/Loader';
import { convertUtcToLocal } from '../../components/MediaPlayer/util';
import OptionalTermsConfirm from '../../components/Optional/OptionalTermsConfirm';
import OptionalTermsConfirmBottom from '../../components/Optional/OptionalTermsConfirmBottom';
import PreloadImage from '../../components/PreloadImage/PreloadImage';
import SystemNotification from '../../components/SystemNotification/SystemNotification';
import TabLayout from '../../components/TabLayout/TabLayout';
import TButton from '../../components/TButton/TButton';
import TNewPopUp from '../../components/TPopUp/TNewPopUp';
import TPopUp from '../../components/TPopUp/TPopUp';
import usePrevious from '../../hooks/usePrevious';
import * as Config from '../../utils/Config';
import { panel_names, STANDALONE_PANELS, isStandalonePanel } from '../../utils/Config';
import { $L, getErrorMessage, getSpottableDescendants } from '../../utils/helperMethods';
import { BUYNOW_CONFIG } from '../../utils/BuyNowConfig';
import { SpotlightIds } from '../../utils/SpotlightIds';
import CartPanel from '../CartPanel/CartPanel';
import CategoryPanel from '../CategoryPanel/CategoryPanel';
import CheckOutPanel from '../CheckOutPanel/CheckOutPanel';
import ConfirmPanel from '../ConfirmPanel/ConfirmPanel';
import DebugPanel from '../DebugPanel/DebugPanel';
import DetailPanel from '../DetailPanel/DetailPanel';
import ErrorPanel from '../ErrorPanel/ErrorPanel';
import FeaturedBrandsPanel from '../FeaturedBrandsPanel/FeaturedBrandsPanel';
import HomePanel from '../HomePanel/HomePanel';
import HotPicksPanel from '../HotPicksPanel/HotPicksPanel';
import ImagePanel from '../ImagePanel/ImagePanel';
import IntroPanel from '../IntroPanel/IntroPanel.new';
import JustForYouPanel from '../JustForYouPanel/JustForYouPanel';
import JustForYouTestPanel from '../JustForYouTestPanel/JustForYouTestPanel';
import LoadingPanel from '../LoadingPanel/LoadingPanel';
import MediaPanel from '../MediaPanel/MediaPanel.v3';
import MyPagePanel from '../MyPagePanel/MyPagePanel';
import OnSalePanel from '../OnSalePanel/OnSalePanel';
import PlayerPanel from '../PlayerPanel/PlayerPanel';
import SearchPanel from '../SearchPanel/SearchPanel.new.v2';
/* VUI_DISABLE_START - VoicePanel import 비활성화 */
// import VoicePanel from '../VoicePanel/VoicePanel';
/* VUI_DISABLE_END */
import ThemeCurationPanel from '../ThemeCurationPanel/ThemeCurationPanel';
import TrendingNowPanel from '../TrendingNowPanel/TrendingNowPanel';
import UserReviewPanel from '../UserReview/UserReviewPanel';
import WelcomeEventPanel from '../WelcomeEventPanel/WelcomeEventPanel';
import css from './MainView.module.less';
// DEBUG_MODE 상수 - true일 때만 console.log 출력
const DEBUG_MODE = false;
const preloadImages = [
LoadingPreloadImage,
LoadingAnimation,
LoadingCompleteImage,
LoadingShopOnTvImage,
];
const panelMap = {
[Config.panel_names.INTRO_PANEL]: IntroPanel,
[Config.panel_names.HOME_PANEL]: HomePanel,
[Config.panel_names.MY_PAGE_PANEL]: MyPagePanel,
[Config.panel_names.CATEGORY_PANEL]: CategoryPanel,
[Config.panel_names.SEARCH_PANEL]: SearchPanel,
/* VUI_DISABLE_START - VoicePanel panelMap 비활성화 */
// [Config.panel_names.VOICE_PANEL]: VoicePanel,
/* VUI_DISABLE_END */
[Config.panel_names.ON_SALE_PANEL]: OnSalePanel,
[Config.panel_names.TRENDING_NOW_PANEL]: TrendingNowPanel,
[Config.panel_names.HOT_PICKS_PANEL]: HotPicksPanel,
[Config.panel_names.FEATURED_BRANDS_PANEL]: FeaturedBrandsPanel,
[Config.panel_names.CART_PANEL]: CartPanel,
[Config.panel_names.ERROR_PANEL]: ErrorPanel,
[Config.panel_names.DEBUG_PANEL]: DebugPanel,
[Config.panel_names.DETAIL_PANEL]: DetailPanel,
[Config.panel_names.PLAYER_PANEL]: PlayerPanel,
[Config.panel_names.MEDIA_PANEL]: MediaPanel,
[Config.panel_names.CHECKOUT_PANEL]: CheckOutPanel,
[Config.panel_names.WELCOME_EVENT_PANEL]: WelcomeEventPanel,
[Config.panel_names.THEME_CURATION_PANEL]: ThemeCurationPanel,
[Config.panel_names.IMAGE_PANEL]: ImagePanel,
[Config.panel_names.CONFIRM_PANEL]: ConfirmPanel,
[Config.panel_names.USER_REVIEW_PANEL]: UserReviewPanel,
[Config.panel_names.JUST_FOR_YOU_PANEL]: JustForYouPanel,
[Config.panel_names.JUST_FOR_YOU_TEST_PANEL]: JustForYouTestPanel,
// [Config.panel_names.OPTIONAL_TERMS_PANEL]: TermsOfOptional,
};
const logTpNoLiveSet = new Set([
Config.LOG_TP_NO.LIVE.HOME,
Config.LOG_TP_NO.LIVE.FEATURED_BRANDS,
Config.LOG_TP_NO.LIVE.FULL,
Config.LOG_TP_NO.LIVE.ITEM_DETAIL,
]);
const STRING_CONF = {
YES: 'YES',
NO: 'NO',
EXIT: 'EXIT',
THIS_IS_AN_UNSUPPORTED_COUNTRY: 'This is an unsupported country.',
CHANGE_COUNTRY:
'If you have changed your LG service country setting, the usage information in Shop Time during your previous country setting will be deleted. Do you want to proceed?',
};
export default function MainView({ className, initService }) {
const dispatch = useDispatch();
const httpHeader = useSelector((state) => state.common.httpHeader);
const mainIndex = useSelector((state) => state.appData.mainIndex);
const panels = useSelector((state) => state.panels.panels);
const lastPanelAction = useSelector((state) => state.panels.lastPanelAction);
const loadingComplete = useSelector((state) => state.common?.loadingComplete);
const menuData = useSelector((state) => state.home.menuData?.data);
const {
popupVisible,
activePopup,
data: errorCode,
data: popupData,
} = useSelector((state) => state.common.popup);
const { showLoadingPanel, toast, toastText, isLoading, webOSVersion, deviceId } = useSelector(
(state) => state.common.appStatus
);
const homeInfo = useSelector((state) => state.home.homeInfo);
const skipEndOfServicePopup = useSelector((state) => state.localSettings.skipEndOfServicePopup);
const isInternetConnected = useSelector((state) => state.common.appStatus.isInternetConnected);
const deviceCountryCode = httpHeader?.['X-Device-Country'] || '';
const isLogSentRef = useRef(false);
const watchRecord = useSelector((state) => state.localSettings?.watchRecord);
const watchRecordRef = usePrevious(watchRecord);
const [tabActivated, setTabActivated] = useState(false);
const [imagePreloaded, setImagePreloaded] = useState(false);
const [ariaHidden, setAriaHidden] = useState(false);
const [showEndOfServicePopup, setShowEndOfServicePopup] = useState(false);
const topPanel = panels[panels.length - 1];
// BUYNOW_CONFIG 초기화 (마운트 시 한 번만 실행)
useEffect(() => {
// TV 배포용: Mock Mode 하드코딩 활성화
// 모든 상품에서 BUY NOW 버튼이 표시됨
const mockMode = false;
// 모듈 변수에 저장 (이후 ProductAllSection 등에서 메모리에서만 읽음)
BUYNOW_CONFIG.init(mockMode);
}, []);
// useEffect(() => {
// console.log('🔍 MainView 팝업 상태 변경:', {
// popupVisible,
// activePopup,
// });
// }, [popupVisible, activePopup]);
const isHomeOnTop = useMemo(() => {
return !mainIndex && (panels.length <= 0 || (panels.length === 1 && panels[0].panelInfo.modal));
}, [mainIndex, panels]);
const hasDetailPanel = useMemo(
() => panels.some((panel) => panel?.name === Config.panel_names.DETAIL_PANEL),
[panels]
);
const onPreImageLoadComplete = useCallback(() => {
// console.log('MainView onPreImageLoadComplete');
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
setImagePreloaded(true);
}, [dispatch]);
const currentTabLayoutPanelInfo = useMemo(() => {
return panels[panels.length - 1]?.panelInfo;
}, [panels]);
const renderTopPanel = useCallback(() => {
if (panels && panels.length > 0) {
let renderingPanels = [];
const topPanel = panels[panels.length - 1];
const hasFeaturedBrandsPanel = panels.some(
(panel) => panel?.name === Config.panel_names.FEATURED_BRANDS_PANEL
);
const hasTrendingNowPanel = panels.some(
(panel) => panel?.name === Config.panel_names.TRENDING_NOW_PANEL
);
// 단독 패널 체크 - CheckOutPanel, CartPanel 등 단독으로 렌더링되어야 하는 패널들
if (DEBUG_MODE) {
console.log(`[PANEL_MainView] 🔍 Top panel name: ${topPanel?.name}`);
console.log(
`[PANEL_MainView] 🔍 isStandalonePanel check:`,
isStandalonePanel(topPanel?.name)
);
console.log(`[PANEL_MainView] 🔍 STANDALONE_PANELS:`, STANDALONE_PANELS);
console.log(
`[PANEL_MainView] 🔍 All panels:`,
panels.map((p) => ({ name: p.name, hasModal: !!p.panelInfo?.modal }))
);
}
if (isStandalonePanel(topPanel?.name)) {
if (DEBUG_MODE) {
console.log(
`[MainView] ✅ Standalone panel detected: ${topPanel?.name} - rendering independently`
);
}
renderingPanels = [topPanel]; // 단독 패널만 단독으로 렌더링
}
// 기존 3-layer 구조 체크: PlayerPanel + DetailPanel + MediaPanel(modal)
else {
const hasThreeLayerStructure =
panels.length >= 3 &&
// PlayerPanel이 맨 아래
(panels[panels.length - 3]?.name === Config.panel_names.PLAYER_PANEL ||
panels[panels.length - 3]?.name === Config.panel_names.PLAYER_PANEL_NEW) &&
// DetailPanel이 중간
panels[panels.length - 2]?.name === Config.panel_names.DETAIL_PANEL &&
// MediaPanel modal이 맨 위
panels[panels.length - 1]?.name === Config.panel_names.MEDIA_PANEL &&
panels[panels.length - 1]?.panelInfo?.modal === true;
if (hasThreeLayerStructure) {
if (DEBUG_MODE) {
console.log(
'[MainView] Rendering 3-layer structure: PlayerPanel + DetailPanel + MediaPanel'
);
}
if (hasFeaturedBrandsPanel || hasTrendingNowPanel) {
renderingPanels = panels.slice(-4);
} else {
renderingPanels = panels.slice(-3);
}
} else if (
panels[panels.length - 1]?.name === Config.panel_names.PLAYER_PANEL ||
panels[panels.length - 1]?.name === Config.panel_names.PLAYER_PANEL_NEW ||
panels[panels.length - 1]?.name === Config.panel_names.MEDIA_PANEL ||
panels[panels.length - 2]?.name === Config.panel_names.PLAYER_PANEL ||
panels[panels.length - 2]?.name === Config.panel_names.MEDIA_PANEL
) {
if (hasFeaturedBrandsPanel || hasTrendingNowPanel) {
renderingPanels = panels.slice(-3);
} else {
renderingPanels = panels.slice(-2);
}
} else {
renderingPanels = panels.slice(-1);
}
}
// DetailPanel 위치 확인 (있으면 항상 onTop 처리)
const detailPanelIndex = renderingPanels.findIndex(
(panel) => panel.name === Config.panel_names.DETAIL_PANEL
);
return (
<>
{(isHomeOnTop ||
hasDetailPanel ||
(panels.length === 1 &&
(panels[0]?.name === Config.panel_names.PLAYER_PANEL ||
panels[0]?.name === Config.panel_names.PLAYER_PANEL_NEW ||
panels[0]?.name === Config.panel_names.MEDIA_PANEL))) && (
<HomePanel
key={Config.panel_names.HOME_PANEL}
isOnTop={isHomeOnTop}
showGradientBackground={homeInfo?.panelInfo?.showGradientBackground || false}
/>
)}
{renderingPanels.map((panel, index) => {
const Component = panelMap[panel.name];
let isPanelOnTop = false;
// 단독 패널은 항상 onTop
if (isStandalonePanel(panel.name)) {
isPanelOnTop = true;
if (DEBUG_MODE) {
console.log(`[MainView] Standalone panel ${panel.name} is always onTop`);
}
}
// DetailPanel이 포함되어 있으면 항상 onTop
else if (detailPanelIndex >= 0) {
isPanelOnTop = index === detailPanelIndex;
if (DEBUG_MODE && isPanelOnTop) {
console.log('[MainView] DetailPanel set to onTop');
}
}
// 2-layer 케이스: modal이면 첫 번째가 onTop
else if (
index === 0 &&
renderingPanels.length === 2 &&
(renderingPanels[1].name === Config.panel_names.PLAYER_PANEL ||
renderingPanels[1].name === Config.panel_names.PLAYER_PANEL_NEW ||
renderingPanels[1].name === Config.panel_names.MEDIA_PANEL) &&
renderingPanels[1].panelInfo.modal
) {
isPanelOnTop = true;
}
// 일반 케이스: 마지막 패널이 onTop
else if (index === renderingPanels.length - 1) {
isPanelOnTop = true;
}
return (
<Component
key={panel.name + panels.indexOf(panel)} //to maintain react virtual dom
panelInfo={panel.panelInfo}
spotlightId={panel.name}
isTabActivated={tabActivated}
isOnTop={isPanelOnTop}
/>
);
})}
</>
);
} else if (isHomeOnTop) {
return (
<HomePanel
key={Config.panel_names.HOME_PANEL}
isOnTop={isHomeOnTop}
showGradientBackground={homeInfo?.panelInfo?.showGradientBackground || false}
/>
);
}
return null;
}, [panels, tabActivated, isHomeOnTop, homeInfo]);
const onTabActivated = useCallback((activated) => {
setTabActivated(activated);
}, []);
const topPanelName = useMemo(() => {
if (panels && panels.length > 0) {
let targetName = panels[panels.length - 1].name;
if (
(panels[panels.length - 1].name === Config.panel_names.PLAYER_PANEL ||
panels[panels.length - 1].name === Config.panel_names.MEDIA_PANEL) &&
panels[panels.length - 1].panelInfo.modal
) {
targetName = panels[panels.length - 2]?.name;
}
return targetName;
}
return null;
}, [panels]);
function reload(response) {
if (response) {
if (response.retCode === 0 && typeof window === 'object') {
window.location.reload();
} else {
if (DEBUG_MODE) {
console.error('unknown error', response.retCode);
}
}
}
}
const handlePopupClick = useCallback(() => {
// 602 지원하지 않는 국가
if (activePopup === Config.ACTIVE_POPUP.unSupportedCountryPopup) {
dispatch(setExitApp());
return;
}
// 603 국가 변경
if (activePopup === Config.ACTIVE_POPUP.changeCountyPopup) {
dispatch(
setMyTermsWithdraw(
{
mandatoryIncludeYn: 'Y',
termsList: ['MST00401', 'MST00402'],
},
reload
)
);
}
}, [dispatch, activePopup]);
const handlePopupClose = useCallback(() => {
dispatch(setExitApp());
}, [dispatch]);
const getMessageByPopupType = (type) => {
switch (type) {
case Config.ACTIVE_POPUP.unSupportedCountryPopup:
return $L(STRING_CONF.THIS_IS_AN_UNSUPPORTED_COUNTRY);
case Config.ACTIVE_POPUP.changeCountyPopup:
return $L(STRING_CONF.CHANGE_COUNTRY);
default:
return;
}
};
useEffect(() => {
if (panels && panels.length > 0) {
let panel = panels[panels.length - 1];
// 3-layer 구조 체크: PlayerPanel + DetailPanel + MediaPanel(modal)
if (
panels.length >= 3 &&
panels[panels.length - 1]?.name === Config.panel_names.MEDIA_PANEL &&
panels[panels.length - 1]?.panelInfo?.modal &&
panels[panels.length - 2]?.name === Config.panel_names.DETAIL_PANEL
) {
panel = panels[panels.length - 2]; // DetailPanel로 포커스
if (DEBUG_MODE) {
console.log('[MainView] 3-layer: Focus on DetailPanel');
}
}
// 2-layer modal 구조
else if (
(panels[panels.length - 1].name === Config.panel_names.PLAYER_PANEL ||
panels[panels.length - 1].name === Config.panel_names.MEDIA_PANEL) &&
panels[panels.length - 1].panelInfo.modal
) {
panel = panels[panels.length - 2];
}
if (panel?.name) {
const timeoutId = setTimeout(() => {
// focus to panel if it's not preview video status changing case
if (
!lastPanelAction ||
(lastPanelAction.indexOf('preview') !== 0 && lastPanelAction !== 'update')
) {
//do focus itself if has focusedContainerId
Spotlight.focus(panel?.name);
}
}, 0);
return () => clearTimeout(timeoutId);
}
}
}, [panels, lastPanelAction]);
const cursorStateChange = useCallback(
(ev) => {
dispatch(
changeAppStatus({
cursorVisible: ev.visibility || ev.detail.visibility,
})
);
},
[dispatch]
);
useEffect(() => {
document.addEventListener('cursorStateChange', cursorStateChange, false);
if (platform.platformName !== 'webos') {
//for debug
dispatch(changeAppStatus({ cursorVisible: !platform.touchscreen }));
} else {
dispatch(
changeAppStatus({
cursorVisible: window.cursorEvent && window.cursorEvent.visibility,
})
);
}
return () => {
document.removeEventListener('cursorStateChange', cursorStateChange);
};
}, []);
const [intervalActive, setIntervalActive] = useState(true);
const [alertItems, setAlertItems] = useState([]);
const popupTimerRef = useRef(null); // 타이머 ID를 저장할 상태 변수
const { upComingAlertShow } = useSelector((state) => state.myPage.upComingData);
const upComingAlertShowRef = useRef(upComingAlertShow);
const firstAlertItem = useMemo(() => alertItems[0], [alertItems]);
useEffect(() => {
upComingAlertShowRef.current = upComingAlertShow;
}, [upComingAlertShow]);
useEffect(() => {
if (activePopup === Config.ACTIVE_POPUP.watchPopup && firstAlertItem && popupVisible) {
const {
hstNm,
lgCatCd,
lgCatNm,
patncNm,
patnrId,
showId,
showNm,
strtDt: alarmDt,
} = firstAlertItem;
dispatch(
sendLogAlarmPop({
alarmDt,
alarmType: 'Upcoming',
cnt: '0',
hstNm,
lgCatCd,
lgCatNm,
patncNm,
patnrId: patnrId.toString(),
showId,
showNm,
})
);
}
}, [activePopup, firstAlertItem, popupVisible, dispatch]);
// 팝업 30초 후 종료
useEffect(() => {
// 이전 타이머 정리
if (popupTimerRef.current) {
clearTimeout(popupTimerRef.current);
popupTimerRef.current = null;
}
if (popupVisible && activePopup === Config.ACTIVE_POPUP.watchPopup) {
const timerId = setTimeout(() => {
dispatch(setHidePopup());
setIntervalActive((prev) => !prev);
}, 30000);
// 타이머 ID를 상태 변수에 저장
popupTimerRef.current = timerId;
}
return () => {
if (popupTimerRef.current) {
clearTimeout(popupTimerRef.current);
popupTimerRef.current = null;
}
};
}, [popupVisible, activePopup, dispatch]);
// 알림 팝업
const checkForAlerts = useCallback(() => {
const currentUpComingAlertShow = upComingAlertShowRef.current;
if (
currentUpComingAlertShow?.upcomAlamUseFlag === 'Y' &&
currentUpComingAlertShow.alertShows?.length > 0
) {
const alertList = currentUpComingAlertShow.alertShows.filter((show) =>
isSameDateTime(show.strtDt)
);
if (alertList.length > 0) {
setAlertItems(alertList);
dispatch(setShowPopup(Config.ACTIVE_POPUP.watchPopup));
setIntervalActive((prev) => !prev);
}
}
}, [dispatch]);
// 알람 체크 - 50초 마다 시간 체크(분까지만 체크)
useEffect(() => {
const interval = setInterval(() => {
if (intervalActive) {
checkForAlerts();
}
}, 50000);
return () => clearInterval(interval);
}, [intervalActive, checkForAlerts]);
// 날짜 같은지 확인 하는 함수
const isSameDateTime = (dateString) => {
const today = new Date();
const targetDate = convertUtcToLocal(dateString);
return (
today.getFullYear() === targetDate.getFullYear() &&
today.getMonth() === targetDate.getMonth() &&
today.getDate() === targetDate.getDate() &&
today.getHours() === targetDate.getHours() &&
today.getMinutes() === targetDate.getMinutes()
);
};
// 알림 확인 FEATURED_BRANDS_PANEL 이동
const handleClick = useCallback(() => {
if (!firstAlertItem) return;
const {
hstNm,
lgCatCd,
lgCatNm,
patncNm,
patnrId,
showId,
showNm,
strtDt: alarmDt,
} = firstAlertItem;
dispatch(
sendLogAlarmClick({
alarmDt,
alarmType: 'Upcoming',
clickFlag: 'Ok',
cnt: '0',
hstNm,
keywordList: '',
lgCatCd,
lgCatNm,
logTpNo: Config.LOG_TP_NO.ALARM_CLICK.BROADCAST,
patncNm,
patnrId: patnrId.toString(),
showId,
showNm,
})
);
dispatch(resetPanels());
dispatch(
pushPanel({
name: panel_names.FEATURED_BRANDS_PANEL,
panelInfo: { from: 'upcoming', patnrId: patnrId.toString() },
})
);
dispatch(setHidePopup());
setIntervalActive((prev) => !prev);
if (popupTimerRef.current) {
clearTimeout(popupTimerRef.current); // 버튼 클릭 시 타이머 제거
popupTimerRef.current = null;
}
}, [dispatch, firstAlertItem]);
const onClickNetworkError = useCallback(() => {
if (initService) {
initService();
}
dispatch(setHidePopup());
}, [dispatch, initService]);
const onExitNetworkError = useCallback(() => {
dispatch(setExitApp());
}, [dispatch]);
const onWatchClose = useCallback(() => {
if (!firstAlertItem) return;
const {
hstNm,
lgCatCd,
lgCatNm,
patncNm,
patnrId,
showId,
showNm,
strtDt: alarmDt,
} = firstAlertItem;
dispatch(
sendLogAlarmClick({
alarmDt,
alarmType: 'Upcoming',
clickFlag: 'No',
cnt: '0',
hstNm,
keywordList: '',
lgCatCd,
lgCatNm,
logTpNo: Config.LOG_TP_NO.ALARM_CLICK.BROADCAST,
patncNm,
patnrId: patnrId.toString(),
showId,
showNm,
})
);
setIntervalActive((prev) => !prev);
dispatch(setHidePopup());
}, [firstAlertItem, dispatch]);
const sendLogIfNeeded = useCallback(() => {
if (!watchRecordRef.current || Object.keys(watchRecordRef.current).length === 0) {
return;
}
const { logTpNo } = watchRecordRef.current;
const sendLog = logTpNoLiveSet.has(logTpNo) ? sendLogLive : sendLogVOD;
const resetWatchRecord = () => dispatch(changeLocalSettings({ watchRecord: {} }));
dispatch(sendLog({ ...watchRecordRef.current }, resetWatchRecord));
}, [dispatch]);
useEffect(() => {
if (deviceId && httpHeader && !isLogSentRef.current) {
sendLogIfNeeded();
isLogSentRef.current = true;
}
}, [deviceId, httpHeader, sendLogIfNeeded]);
useEffect(() => {
if (loadingComplete && !menuData) {
dispatch(getHomeMenu());
}
}, [loadingComplete]);
useEffect(() => {
if (
activePopup === Config.ACTIVE_POPUP.changeCountyPopup ||
activePopup === Config.ACTIVE_POPUP.unSupportedCountryPopup
) {
const timeoutId = setTimeout(() => {
Spotlight.focus('tPopupBtn1');
}, 0);
return () => clearTimeout(timeoutId);
}
}, [activePopup]);
useEffect(() => {
if (deviceCountryCode === 'US') {
setAriaHidden(false);
} else {
setAriaHidden(true);
}
}, [deviceCountryCode]);
useEffect(() => {
if (webOSVersion && Number(webOSVersion) < 4 && !skipEndOfServicePopup) {
setShowEndOfServicePopup(true);
dispatch(setShowPopup(Config.ACTIVE_POPUP.endOfServicePopup));
}
}, [webOSVersion]);
const handleErrorPopupClose = useCallback(() => {
if (DEBUG_MODE) {
console.log(
'handleErrorPopupClose 호출됨! activePopup:',
activePopup,
'popupData:',
popupData
);
}
if (popupData?.shouldPopPanel) {
dispatch(popPanel());
}
dispatch(clearErrorMessage());
dispatch(setHidePopup());
if (topPanel?.name === panel_names.DETAIL_PANEL) {
setTimeout(() => {
Spotlight.focus(SpotlightIds.DETAIL_BUYNOW);
});
}
}, [dispatch, popupData, activePopup, topPanel?.name]);
// 딥링크 확인 테스트
const contentTarget = useSelector((state) => state.common.deepLinkInfo.contentTarget);
return (
<div className={classNames(css.mainViewWrap, className)} aria-hidden={ariaHidden}>
{!imagePreloaded && (
<PreloadImage preloadImages={preloadImages} onLoadComplete={onPreImageLoadComplete} />
)}
<LoadingPanel showLoadingPanel={showLoadingPanel} />
{errorCode !== 502 && errorCode !== 602 && errorCode !== 603 && loadingComplete && (
<div className={classNames(css.container)}>
<div className={classNames(css.mainlayout)}>{renderTopPanel()}</div>
<TabLayout
topPanelName={topPanelName}
onTabActivated={onTabActivated}
panelInfo={currentTabLayoutPanelInfo}
/>
</div>
)}
{isLoading && <Loader />}
{/* 시청예약 알림 팝업 */}
{activePopup === Config.ACTIVE_POPUP.watchPopup && firstAlertItem && (
<TPopUp
kind="watchPopup"
open={popupVisible}
onClose={onWatchClose}
onClick={handleClick}
hasText
hasButton
hasLogo
logo={firstAlertItem?.patncLogoPath}
hasThumbnail
thumbnail={
firstAlertItem?.thumbnailUrl == null || firstAlertItem?.thumbnailUrl == ''
? defaultWatchItem
: firstAlertItem?.thumbnailUrl
}
button1Text={$L('YES')}
button2Text={$L('NO')}
title={$L('Watch Now!')}
text={firstAlertItem?.showNm}
/>
)}
{activePopup === Config.ACTIVE_POPUP.errorPopup && (
<TPopUp
kind="errorPopup"
open={popupVisible}
onClose={handleErrorPopupClose}
className={css.errorPopup}
>
<div className={css.popupContainer}>
<p className={css.errMsg}>
{popupData &&
getErrorMessage(
popupData.errorCode,
popupData.errorMsg,
popupData.retDetailCode,
popupData.returnBindStrings
)}
</p>{' '}
<TButton className={css.popupBtn} onClick={handleErrorPopupClose}>
{$L('OK')}
</TButton>
</div>
</TPopUp>
)}
{activePopup === Config.ACTIVE_POPUP.networkErrorPopup && (
<TPopUp
kind="textPopup"
hasButton
hasText
button1Text={isInternetConnected ? 'Retry' : ''}
button2Text={'Exit'}
onClick={onClickNetworkError}
onClose={onExitNetworkError}
open={popupVisible}
text={"Failed to connect to SHOPTIME. Please check your device's network connection."}
/>
)}
{(loadingComplete && activePopup === Config.ACTIVE_POPUP.unSupportedCountryPopup) ||
(loadingComplete && activePopup === Config.ACTIVE_POPUP.changeCountyPopup) ? (
<TPopUp
kind="textPopup"
hasButton
hasText
button1Text={
activePopup !== Config.ACTIVE_POPUP.unSupportedCountryPopup
? $L(STRING_CONF.YES)
: $L(STRING_CONF.EXIT)
}
button2Text={activePopup == Config.ACTIVE_POPUP.changeCountyPopup && $L(STRING_CONF.NO)}
onClick={handlePopupClick}
onClose={handlePopupClose}
open={popupVisible}
text={getMessageByPopupType(activePopup)}
title={$L('Exit Shop Time')}
/>
) : null}
<SystemNotification />
{loadingComplete &&
activePopup === Config.ACTIVE_POPUP.endOfServicePopup &&
!skipEndOfServicePopup && <EndOfServicePopUp />}
{/* Pop up */}
{activePopup === Config.ACTIVE_POPUP.toast && (
<TPopUp
kind="toast"
open={popupVisible}
onClose={handleErrorPopupClose}
hasText
hasButton
button1Text={toastText}
button2Text={$L('OK')}
/>
)}
{/* OptionalTermsConfirmPopup */}
{activePopup === Config.ACTIVE_POPUP.optionalTermsConfirm && (
<OptionalTermsConfirm open={popupVisible} />
)}
{activePopup === Config.ACTIVE_POPUP.optionalTermsConfirmBottom && (
<OptionalTermsConfirmBottom open={popupVisible} />
)}
{/* {activePopup === Config.ACTIVE_POPUP.optionalConfirm && (
<TNewPopUp
kind="optionalConfirm"
open={true}
text="Get recommendations, special offers, and ads tailored just for you."
button1Text="Agree"
button2Text="Not Now"
onClose={handleClose}
onClick={handleAgree}
/>
)} */}
{/* /딥링크 테스트 */}
<div
style={{
position: 'fixed',
left: '0',
bottom: '0',
color: '#fff',
fontSize: '13px',
opacity: '.5',
zIndex: '999',
backgroundColor: 'black',
padding: '10px',
}}
>
deepLinkInfo
<p>{contentTarget}</p>
<p>v1101-001</p>
</div>
</div>
);
}