[251019] fix: PlayerPanel Optimization-2
🕐 커밋 시간: 2025. 10. 19. 22:13:44 📊 변경 통계: • 총 파일: 8개 • 추가: +264줄 • 삭제: -100줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/convertActions.js ~ com.twin.app.shoptime/src/components/TItemCard/TItemCard.new.jsx ~ com.twin.app.shoptime/src/components/TPopUp/TPopUp.module.less ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayChat.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayQRCode.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.new.jsx 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/actions/convertActions.js (javascript): ✅ Added: attemptConversion(), onSuccess(), onFail() ❌ Deleted: onSuccess(), onFail() 📄 com.twin.app.shoptime/src/components/TItemCard/TItemCard.new.jsx (javascript): 🔄 Modified: generateMockEnergyLabels() 📄 com.twin.app.shoptime/src/components/TPopUp/TPopUp.module.less (unknown): ✅ Added: style() ❌ Deleted: style() 📄 com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayChat.jsx (javascript): ✅ Added: PlayerOverlayChat(), propsAreEqual() 📄 com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx (javascript): ✅ Added: PlayerOverlayContents(), propsAreEqual() 📄 com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayQRCode.jsx (javascript): ✅ Added: PlayerOverlayQRCode(), propsAreEqual() 📄 com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.new.jsx (javascript): ✅ Added: PlayerPanelNew() 🔄 Modified: getLogTpNo() 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선 • UI 컴포넌트 아키텍처 개선
This commit is contained in:
@@ -3,85 +3,178 @@ import { TAxios } from '../api/TAxios';
|
||||
import { types } from './actionTypes';
|
||||
|
||||
/**
|
||||
* PDF를 이미지로 변환
|
||||
* PDF를 이미지로 변환 (재시도 로직 포함)
|
||||
* @param {string} pdfUrl - 변환할 PDF URL
|
||||
* @param {function} callback - 성공/실패 후 실행할 콜백 (error, imageUrl)
|
||||
* @param {number} maxRetries - 최대 재시도 횟수 (기본값: 5)
|
||||
* @param {number} timeout - 타임아웃 (기본값: 60000ms = 60초)
|
||||
*/
|
||||
export const convertPdfToImage = (pdfUrl, callback) => (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: types.CONVERT_PDF_TO_IMAGE,
|
||||
payload: pdfUrl,
|
||||
});
|
||||
export const convertPdfToImage =
|
||||
(pdfUrl, callback, maxRetries = 5, timeout = 60000) =>
|
||||
(dispatch, getState) => {
|
||||
let attempts = 0;
|
||||
let timeoutId = null;
|
||||
|
||||
const onSuccess = (response) => {
|
||||
// retCode 체크 (프로젝트 API 규약: 200이어도 retCode로 성공/실패 구분)
|
||||
const retCode = response.headers?.retcode || response.headers?.retCode;
|
||||
const attemptConversion = () => {
|
||||
attempts++;
|
||||
// console.log(`🔄 [EnergyLabel] Converting PDF attempt ${attempts}/${maxRetries + 1}:`, pdfUrl);
|
||||
|
||||
if (retCode !== undefined && retCode !== 0 && retCode !== '0') {
|
||||
const error = new Error(`API Error: retCode=${retCode}`);
|
||||
dispatch({
|
||||
type: types.CONVERT_PDF_TO_IMAGE_FAILURE,
|
||||
payload: { pdfUrl, error },
|
||||
});
|
||||
callback && callback(error, null);
|
||||
return;
|
||||
}
|
||||
// 타임아웃 설정
|
||||
timeoutId = setTimeout(() => {
|
||||
clearTimeout(timeoutId);
|
||||
const timeoutError = new Error(
|
||||
`Conversion timeout after ${timeout}ms (attempt ${attempts})`
|
||||
);
|
||||
console.warn(`⏱️ [EnergyLabel] Timeout on attempt ${attempts}:`, timeoutError.message);
|
||||
|
||||
let imageUrl;
|
||||
try {
|
||||
if (response.data instanceof Blob) {
|
||||
if (response.data.size < 100) {
|
||||
throw new Error('Invalid image data (size too small)');
|
||||
// 재시도 가능한 경우
|
||||
if (attempts < maxRetries + 1) {
|
||||
// console.log(`🔄 [EnergyLabel] Retrying... (${attempts}/${maxRetries + 1})`);
|
||||
attemptConversion();
|
||||
} else {
|
||||
// 최종 실패
|
||||
console.error(`❌ [EnergyLabel] Final failure after ${attempts} attempts:`, pdfUrl);
|
||||
dispatch({
|
||||
type: types.CONVERT_PDF_TO_IMAGE_FAILURE,
|
||||
payload: { pdfUrl, error: timeoutError },
|
||||
});
|
||||
callback && callback(timeoutError, null);
|
||||
}
|
||||
imageUrl = URL.createObjectURL(response.data);
|
||||
} else if (response.data instanceof ArrayBuffer) {
|
||||
if (response.data.byteLength < 100) {
|
||||
throw new Error('Invalid image data (size too small)');
|
||||
}, timeout);
|
||||
|
||||
dispatch({
|
||||
type: types.CONVERT_PDF_TO_IMAGE,
|
||||
payload: pdfUrl,
|
||||
});
|
||||
|
||||
const onSuccess = (response) => {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = null;
|
||||
}
|
||||
const blob = new Blob([response.data], { type: 'image/png' });
|
||||
imageUrl = URL.createObjectURL(blob);
|
||||
} else {
|
||||
const blob = new Blob([response.data], { type: 'image/png' });
|
||||
imageUrl = URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: types.CONVERT_PDF_TO_IMAGE_SUCCESS,
|
||||
payload: { pdfUrl, imageUrl },
|
||||
});
|
||||
// retCode 체크 (프로젝트 API 규약: 200이어도 retCode로 성공/실패 구분)
|
||||
const retCode = response.headers?.retcode || response.headers?.retCode;
|
||||
|
||||
callback && callback(null, imageUrl);
|
||||
} catch (error) {
|
||||
dispatch({
|
||||
type: types.CONVERT_PDF_TO_IMAGE_FAILURE,
|
||||
payload: { pdfUrl, error },
|
||||
});
|
||||
callback && callback(error, null);
|
||||
}
|
||||
if (retCode !== undefined && retCode !== 0 && retCode !== '0') {
|
||||
const error = new Error(`API Error: retCode=${retCode}`);
|
||||
console.warn(`⚠️ [EnergyLabel] API returned error on attempt ${attempts}:`, retCode);
|
||||
|
||||
// retCode 에러도 재시도
|
||||
if (attempts < maxRetries + 1) {
|
||||
console.log(
|
||||
`🔄 [EnergyLabel] Retrying due to API error... (${attempts}/${maxRetries + 1})`
|
||||
);
|
||||
attemptConversion();
|
||||
} else {
|
||||
console.error(
|
||||
`❌ [EnergyLabel] Final failure after ${attempts} attempts (API error):`,
|
||||
pdfUrl
|
||||
);
|
||||
dispatch({
|
||||
type: types.CONVERT_PDF_TO_IMAGE_FAILURE,
|
||||
payload: { pdfUrl, error },
|
||||
});
|
||||
callback && callback(error, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let imageUrl;
|
||||
try {
|
||||
if (response.data instanceof Blob) {
|
||||
if (response.data.size === 0) {
|
||||
throw new Error('Invalid image data (empty blob)');
|
||||
}
|
||||
imageUrl = URL.createObjectURL(response.data);
|
||||
} else if (response.data instanceof ArrayBuffer) {
|
||||
if (response.data.byteLength === 0) {
|
||||
throw new Error('Invalid image data (empty buffer)');
|
||||
}
|
||||
const blob = new Blob([response.data], { type: 'image/png' });
|
||||
imageUrl = URL.createObjectURL(blob);
|
||||
} else {
|
||||
const blob = new Blob([response.data], { type: 'image/png' });
|
||||
if (blob.size === 0) {
|
||||
throw new Error('Invalid image data (empty blob)');
|
||||
}
|
||||
imageUrl = URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
console.log(`✅ [EnergyLabel] Conversion successful on attempt ${attempts}:`, pdfUrl);
|
||||
dispatch({
|
||||
type: types.CONVERT_PDF_TO_IMAGE_SUCCESS,
|
||||
payload: { pdfUrl, imageUrl },
|
||||
});
|
||||
|
||||
callback && callback(null, imageUrl);
|
||||
} catch (error) {
|
||||
console.error(`❌ [EnergyLabel] Image creation failed on attempt ${attempts}:`, error);
|
||||
|
||||
// 이미지 생성 실패도 재시도
|
||||
if (attempts < maxRetries + 1) {
|
||||
console.log(
|
||||
`🔄 [EnergyLabel] Retrying due to image creation error... (${attempts}/${maxRetries + 1})`
|
||||
);
|
||||
attemptConversion();
|
||||
} else {
|
||||
console.error(
|
||||
`❌ [EnergyLabel] Final failure after ${attempts} attempts (image error):`,
|
||||
pdfUrl
|
||||
);
|
||||
dispatch({
|
||||
type: types.CONVERT_PDF_TO_IMAGE_FAILURE,
|
||||
payload: { pdfUrl, error },
|
||||
});
|
||||
callback && callback(error, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onFail = (error) => {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = null;
|
||||
}
|
||||
|
||||
console.warn(`⚠️ [EnergyLabel] Network error on attempt ${attempts}:`, error.message);
|
||||
|
||||
// 네트워크 에러도 재시도
|
||||
if (attempts < maxRetries + 1) {
|
||||
console.log(
|
||||
`🔄 [EnergyLabel] Retrying due to network error... (${attempts}/${maxRetries + 1})`
|
||||
);
|
||||
attemptConversion();
|
||||
} else {
|
||||
console.error(
|
||||
`❌ [EnergyLabel] Final failure after ${attempts} attempts (network error):`,
|
||||
pdfUrl
|
||||
);
|
||||
dispatch({
|
||||
type: types.CONVERT_PDF_TO_IMAGE_FAILURE,
|
||||
payload: { pdfUrl, error },
|
||||
});
|
||||
callback && callback(error, null);
|
||||
}
|
||||
};
|
||||
|
||||
TAxios(
|
||||
dispatch,
|
||||
getState,
|
||||
'post',
|
||||
URLS.CONVERT_IMG,
|
||||
{},
|
||||
{ pdfUrl },
|
||||
onSuccess,
|
||||
onFail,
|
||||
false,
|
||||
'blob'
|
||||
);
|
||||
};
|
||||
|
||||
attemptConversion();
|
||||
};
|
||||
|
||||
const onFail = (error) => {
|
||||
dispatch({
|
||||
type: types.CONVERT_PDF_TO_IMAGE_FAILURE,
|
||||
payload: { pdfUrl, error },
|
||||
});
|
||||
callback && callback(error, null);
|
||||
};
|
||||
|
||||
TAxios(
|
||||
dispatch,
|
||||
getState,
|
||||
'post',
|
||||
URLS.CONVERT_IMG,
|
||||
{},
|
||||
{ pdfUrl },
|
||||
onSuccess,
|
||||
onFail,
|
||||
false,
|
||||
'blob'
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 여러 PDF를 순차적으로 변환 (백그라운드)
|
||||
* @param {Array<string>} pdfUrls - 변환할 PDF URL 배열
|
||||
|
||||
@@ -339,26 +339,42 @@ export default memo(function TItemCardNew({
|
||||
|
||||
// PNG 이미지는 직접 표시
|
||||
if (pdfUrl.endsWith('.png')) {
|
||||
// console.log(`📸 [EnergyLabel] Displaying PNG directly:`, pdfUrl);
|
||||
dispatch({
|
||||
type: 'CONVERT_PDF_TO_IMAGE_SUCCESS',
|
||||
payload: { pdfUrl, imageUrl: pdfUrl },
|
||||
});
|
||||
dispatch(setShowPopup(Config.ACTIVE_POPUP.energyPopup));
|
||||
setTimeout(() => {
|
||||
Spotlight.focus(SpotlightIds.TPOPUP);
|
||||
}, 250);
|
||||
return;
|
||||
}
|
||||
|
||||
// PDF 변환 시작 (성공 시에만 팝업)
|
||||
// PDF 변환 시작 (최대 5회 재시도, 60초 타임아웃)
|
||||
// console.log(`📄 [EnergyLabel] Starting PDF conversion:`, pdfUrl);
|
||||
dispatch(
|
||||
convertPdfToImage(pdfUrl, (error, imageUrl) => {
|
||||
if (error) {
|
||||
console.error('[EnergyLabel] 변환 실패:', error.message || error);
|
||||
} else {
|
||||
dispatch(setShowPopup(Config.ACTIVE_POPUP.energyPopup));
|
||||
setTimeout(() => {
|
||||
Spotlight.focus(SpotlightIds.TPOPUP);
|
||||
}, 250);
|
||||
}
|
||||
})
|
||||
convertPdfToImage(
|
||||
pdfUrl,
|
||||
(error, imageUrl) => {
|
||||
if (error) {
|
||||
console.error('[EnergyLabel] 최종 변환 실패:', error.message || error);
|
||||
// 실패해도 팝업은 열어서 에러 메시지 표시
|
||||
dispatch(setShowPopup(Config.ACTIVE_POPUP.energyPopup));
|
||||
setTimeout(() => {
|
||||
Spotlight.focus(SpotlightIds.TPOPUP);
|
||||
}, 250);
|
||||
} else {
|
||||
console.log(`[EnergyLabel] PDF 변환 완료, 팝업 표시`);
|
||||
dispatch(setShowPopup(Config.ACTIVE_POPUP.energyPopup));
|
||||
setTimeout(() => {
|
||||
Spotlight.focus(SpotlightIds.TPOPUP);
|
||||
}, 250);
|
||||
}
|
||||
},
|
||||
5, // 최대 5회 재시도
|
||||
60000 // 60초 타임아웃
|
||||
)
|
||||
);
|
||||
},
|
||||
[dispatch]
|
||||
@@ -504,8 +520,28 @@ export default memo(function TItemCardNew({
|
||||
</SpottableComponent>
|
||||
|
||||
{(() => {
|
||||
const showPopup = activePopup === Config.ACTIVE_POPUP.energyPopup && currentPdfUrl;
|
||||
if (!showPopup) return null;
|
||||
// 팝업이 표시되어야 하는 조건 검증
|
||||
const isEnergyPopup = activePopup === Config.ACTIVE_POPUP.energyPopup;
|
||||
const hasPdfUrl = !!currentPdfUrl;
|
||||
const shouldShowPopup = isEnergyPopup && hasPdfUrl;
|
||||
|
||||
if (!shouldShowPopup) {
|
||||
// console.log('[EnergyLabel] Popup not showing:', {
|
||||
// isEnergyPopup,
|
||||
// hasPdfUrl,
|
||||
// popupVisible,
|
||||
// });
|
||||
return null;
|
||||
}
|
||||
|
||||
// console.log('[EnergyLabel] Rendering popup:', {
|
||||
// popupVisible,
|
||||
// activePopup,
|
||||
// currentPdfUrl,
|
||||
// isConverting: convert?.isConverting,
|
||||
// hasImage: !!convert?.convertedImage,
|
||||
// hasError: !!convert?.error,
|
||||
// });
|
||||
|
||||
return (
|
||||
<TPopUp
|
||||
@@ -534,9 +570,19 @@ export default memo(function TItemCardNew({
|
||||
{convert.error?.message || String(convert.error)}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
) : convert.isConverting ? (
|
||||
<div>
|
||||
<p>{$L(STRING_CONF.ENERGY_LOADING)}</p>
|
||||
<p style={{ fontSize: '0.8em', marginTop: '10px', color: '#999' }}>
|
||||
Converting PDF to image... (attempt in progress)
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<p>{$L(STRING_CONF.ENERGY_ERROR)}</p>
|
||||
<p style={{ fontSize: '0.8em', marginTop: '10px', color: '#999' }}>
|
||||
Unknown state - no image or error
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -544,6 +590,9 @@ export default memo(function TItemCardNew({
|
||||
) : (
|
||||
<div>
|
||||
<p>{$L(STRING_CONF.ENERGY_ERROR)}</p>
|
||||
<p style={{ fontSize: '0.8em', marginTop: '10px', color: '#999' }}>
|
||||
Convert reducer state not found
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -814,7 +814,7 @@
|
||||
}
|
||||
|
||||
.energyPopup {
|
||||
.default-style(@width: 960px);
|
||||
.default-style(@width: 700px);
|
||||
.info {
|
||||
background-color: #fff;
|
||||
.textLayer {
|
||||
|
||||
@@ -1,29 +1,22 @@
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import classNames from "classnames";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import classNames from 'classnames';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { setHidePopup, setShowPopup } from "../../../actions/commonActions";
|
||||
import CustomImage from "../../../components/CustomImage/CustomImage";
|
||||
import TButton from "../../../components/TButton/TButton";
|
||||
import TPopUp from "../../../components/TPopUp/TPopUp";
|
||||
import TQRCode from "../../../components/TQRCode/TQRCode";
|
||||
import { ACTIVE_POPUP } from "../../../utils/Config";
|
||||
import { $L } from "../../../utils/helperMethods";
|
||||
import css from "./PlayerOverlayChat.module.less";
|
||||
import { setHidePopup, setShowPopup } from '../../../actions/commonActions';
|
||||
import CustomImage from '../../../components/CustomImage/CustomImage';
|
||||
import TButton from '../../../components/TButton/TButton';
|
||||
import TPopUp from '../../../components/TPopUp/TPopUp';
|
||||
import TQRCode from '../../../components/TQRCode/TQRCode';
|
||||
import { ACTIVE_POPUP } from '../../../utils/Config';
|
||||
import { $L } from '../../../utils/helperMethods';
|
||||
import css from './PlayerOverlayChat.module.less';
|
||||
|
||||
export default function PlayerOverlayChat({
|
||||
currentTime,
|
||||
videoVerticalVisible,
|
||||
imageQRCodeUrl,
|
||||
QRCodeUrl,
|
||||
}) {
|
||||
function PlayerOverlayChat({ currentTime, videoVerticalVisible, imageQRCodeUrl, QRCodeUrl }) {
|
||||
const dispatch = useDispatch();
|
||||
const chatData = useSelector((state) => state.play.chatData);
|
||||
const [recentChats, setRecentChats] = useState([]);
|
||||
const { popupVisible, activePopup } = useSelector(
|
||||
(state) => state.common.popup
|
||||
);
|
||||
const { popupVisible, activePopup } = useSelector((state) => state.common.popup);
|
||||
|
||||
const handleQRCodeClick = useCallback(() => {
|
||||
dispatch(setShowPopup(ACTIVE_POPUP.qrPopup));
|
||||
@@ -47,34 +40,20 @@ export default function PlayerOverlayChat({
|
||||
useEffect(() => {
|
||||
const filteredChats = filterAndSelectRecentChat();
|
||||
setRecentChats(filteredChats);
|
||||
}, [currentTime, chatData]);
|
||||
}, [currentTime, chatData, videoVerticalVisible, filterAndSelectRecentChat]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{chatData && Object.keys(chatData).length > 0 && (
|
||||
<div
|
||||
className={classNames(
|
||||
css.chatContainer,
|
||||
videoVerticalVisible && css.verticalChat
|
||||
)}
|
||||
>
|
||||
<div className={classNames(css.chatContainer, videoVerticalVisible && css.verticalChat)}>
|
||||
<div className={css.chatHeader} aria-label="LIVE CHAT">
|
||||
{$L("LIVE CHAT")}
|
||||
{$L('LIVE CHAT')}
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
css.contents,
|
||||
videoVerticalVisible && css.verticalContent
|
||||
)}
|
||||
>
|
||||
<div className={classNames(css.contents, videoVerticalVisible && css.verticalContent)}>
|
||||
{recentChats &&
|
||||
recentChats.length > 0 &&
|
||||
recentChats.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={css.chatItem}
|
||||
style={{ order: -index }}
|
||||
>
|
||||
<div key={index} className={css.chatItem} style={{ order: -index }}>
|
||||
<div className={css.username} aria-label={item?.username}>
|
||||
{item?.username}
|
||||
</div>
|
||||
@@ -90,7 +69,7 @@ export default function PlayerOverlayChat({
|
||||
onClick={handleQRCodeClick}
|
||||
ariaLabel="TYPE A MESSAGE"
|
||||
>
|
||||
{"TYPE A MESSAGE"}
|
||||
{'TYPE A MESSAGE'}
|
||||
</TButton>
|
||||
)}
|
||||
{!videoVerticalVisible && (
|
||||
@@ -104,7 +83,7 @@ export default function PlayerOverlayChat({
|
||||
<TPopUp kind="qrPopup" open={popupVisible} onClose={onClose}>
|
||||
<div className={css.popupContainer}>
|
||||
<div className={css.header}>
|
||||
<h3 aria-label="QR CODE Heading 1">{$L("QR CODE")}</h3>
|
||||
<h3 aria-label="QR CODE Heading 1">{$L('QR CODE')}</h3>
|
||||
</div>
|
||||
|
||||
<div className={css.qrcodeContainer}>
|
||||
@@ -116,14 +95,10 @@ export default function PlayerOverlayChat({
|
||||
)}
|
||||
</div>
|
||||
<h3 aria-label="To send a message, please scan the QR code.">
|
||||
{$L("To send a message, please scan the QR code.")}
|
||||
{$L('To send a message, please scan the QR code.')}
|
||||
</h3>
|
||||
<TButton
|
||||
className={css.popupBtn}
|
||||
onClick={onClose}
|
||||
ariaLabel="Close"
|
||||
>
|
||||
{$L("CLOSE")}
|
||||
<TButton className={css.popupBtn} onClick={onClose} ariaLabel="Close">
|
||||
{$L('CLOSE')}
|
||||
</TButton>
|
||||
</div>
|
||||
</div>
|
||||
@@ -132,3 +107,14 @@ export default function PlayerOverlayChat({
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const propsAreEqual = (prev, next) => {
|
||||
return (
|
||||
prev.currentTime === next.currentTime &&
|
||||
prev.videoVerticalVisible === next.videoVerticalVisible &&
|
||||
prev.imageQRCodeUrl === next.imageQRCodeUrl &&
|
||||
prev.QRCodeUrl === next.QRCodeUrl
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(PlayerOverlayChat, propsAreEqual);
|
||||
|
||||
@@ -1,24 +1,14 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
} from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import Spotlight from '@enact/spotlight';
|
||||
import SpotlightContainerDecorator
|
||||
from '@enact/spotlight/SpotlightContainerDecorator';
|
||||
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
|
||||
import Spottable from '@enact/spotlight/Spottable';
|
||||
import Marquee from '@enact/ui/Marquee';
|
||||
|
||||
import defaultLogoImg
|
||||
from '../../../../assets/images/ic-tab-partners-default@3x.png';
|
||||
import defaultLogoImg from '../../../../assets/images/ic-tab-partners-default@3x.png';
|
||||
import { setShowPopup } from '../../../actions/commonActions';
|
||||
import CustomImage from '../../../components/CustomImage/CustomImage';
|
||||
import { ACTIVE_POPUP } from '../../../utils/Config';
|
||||
@@ -26,14 +16,11 @@ import { SpotlightIds } from '../../../utils/SpotlightIds';
|
||||
import PlayerTabButton from '../PlayerTabContents/TabButton/PlayerTabButton';
|
||||
import css from './PlayerOverlayContents.module.less';
|
||||
|
||||
const SpottableBtn = Spottable("button");
|
||||
const SpottableBtn = Spottable('button');
|
||||
|
||||
const Container = SpotlightContainerDecorator(
|
||||
{ enterTo: "default-element" },
|
||||
"div"
|
||||
);
|
||||
const Container = SpotlightContainerDecorator({ enterTo: 'default-element' }, 'div');
|
||||
|
||||
export default function PlayerOverlayContents({
|
||||
function PlayerOverlayContents({
|
||||
type,
|
||||
onClick,
|
||||
panelInfo,
|
||||
@@ -68,10 +55,10 @@ export default function PlayerOverlayContents({
|
||||
const backBtnRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (type === "MEDIA" && !panelInfo.modal && backBtnRef.current) {
|
||||
if (type === 'MEDIA' && !panelInfo.modal && backBtnRef.current) {
|
||||
Spotlight.focus(SpotlightIds.PLAYER_BACK_BUTTON);
|
||||
}
|
||||
}, [panelInfo?.shptmBanrTpNm, panelInfo.modal, backBtnRef.current]);
|
||||
}, [type, panelInfo.modal, backBtnRef]);
|
||||
|
||||
const handleSubtitleOnClick = useCallback(() => {
|
||||
if (!captionEnable) {
|
||||
@@ -79,11 +66,11 @@ export default function PlayerOverlayContents({
|
||||
}
|
||||
|
||||
setIsSubtitleActive((prev) => !prev);
|
||||
}, [captionEnable]);
|
||||
}, [dispatch, captionEnable]);
|
||||
|
||||
const patncLogoPath = useMemo(() => {
|
||||
let logo = playListInfo[selectedIndex]?.patncLogoPath;
|
||||
if (type === "MEDIA") {
|
||||
if (type === 'MEDIA') {
|
||||
logo = panelInfo?.patncLogoPath;
|
||||
}
|
||||
|
||||
@@ -92,7 +79,7 @@ export default function PlayerOverlayContents({
|
||||
|
||||
const partnerName = useMemo(() => {
|
||||
let name = playListInfo[selectedIndex]?.patncNm;
|
||||
if (type === "MEDIA") {
|
||||
if (type === 'MEDIA') {
|
||||
name = panelInfo?.patncNm;
|
||||
}
|
||||
|
||||
@@ -101,11 +88,11 @@ export default function PlayerOverlayContents({
|
||||
|
||||
const showName = useMemo(() => {
|
||||
let name = playListInfo[selectedIndex]?.showNm;
|
||||
if (type === "MEDIA") {
|
||||
if (type === 'MEDIA') {
|
||||
name = panelInfo?.showNm;
|
||||
}
|
||||
|
||||
return name ? name.replace(/<br\s*\/?>/gi, " ") : "";
|
||||
return name ? name.replace(/<br\s*\/?>/gi, ' ') : '';
|
||||
}, [playListInfo, selectedIndex, panelInfo]);
|
||||
|
||||
const onSpotlightMoveTabButton = (e) => {
|
||||
@@ -116,27 +103,27 @@ export default function PlayerOverlayContents({
|
||||
|
||||
const onSpotlightMoveMediaButton = (e) => {
|
||||
e.stopPropagation();
|
||||
if (type === "LIVE") {
|
||||
return Spotlight.focus("videoIndicator-down-button");
|
||||
if (type === 'LIVE') {
|
||||
return Spotlight.focus('videoIndicator-down-button');
|
||||
}
|
||||
Spotlight.focus("videoPlayer_mediaControls");
|
||||
Spotlight.focus('videoPlayer_mediaControls');
|
||||
};
|
||||
|
||||
const onSpotlightMoveSlider = useCallback(
|
||||
(e) => {
|
||||
if (type === "VOD") {
|
||||
if (type === 'VOD') {
|
||||
e.stopPropagation();
|
||||
|
||||
Spotlight.focus(SpotlightIds.PLAYER_SLIDER);
|
||||
}
|
||||
},
|
||||
[panelInfo]
|
||||
[type]
|
||||
);
|
||||
|
||||
const onSpotlightMoveSideTab = (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
Spotlight.focus("tab-0");
|
||||
Spotlight.focus('tab-0');
|
||||
};
|
||||
|
||||
const onSpotlightMoveBelowTab = (e) => {
|
||||
@@ -147,13 +134,13 @@ export default function PlayerOverlayContents({
|
||||
if (tabIndexV2 === 0) {
|
||||
// ShopNow 탭: Close 버튼으로
|
||||
// Spotlight.focus('below-tab-close-button');
|
||||
Spotlight.focus("shownow_close_button");
|
||||
Spotlight.focus('shownow_close_button');
|
||||
} else if (tabIndexV2 === 1) {
|
||||
// LIVE CHANNEL 탭: LIVE CHANNEL 버튼으로
|
||||
Spotlight.focus("below-tab-live-channel-button");
|
||||
Spotlight.focus('below-tab-live-channel-button');
|
||||
} else if (tabIndexV2 === 2) {
|
||||
// ShopNowButton: ShopNowButton으로
|
||||
Spotlight.focus("below-tab-shop-now-button");
|
||||
Spotlight.focus('below-tab-shop-now-button');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -163,7 +150,7 @@ export default function PlayerOverlayContents({
|
||||
|
||||
const currentSideButtonStatus = useMemo(() => {
|
||||
if (
|
||||
type !== "MEDIA" &&
|
||||
type !== 'MEDIA' &&
|
||||
!panelInfo?.modal &&
|
||||
!sideContentsVisible &&
|
||||
tabContainerVersion === 1
|
||||
@@ -189,67 +176,63 @@ export default function PlayerOverlayContents({
|
||||
return (
|
||||
<>
|
||||
<Container className={css.overlayContainer}>
|
||||
{type !== "MEDIA" &&
|
||||
playListInfo.length > 1 &&
|
||||
noLiveContentsVisible && (
|
||||
<>
|
||||
<div className={css.indicatorUpButton}>
|
||||
<SpottableBtn
|
||||
onClick={handleIndicatorUpClick}
|
||||
spotlightId="videoIndicator-up-button"
|
||||
onSpotlightRight={
|
||||
videoVerticalVisible
|
||||
? onSpotlightMoveSideTab
|
||||
: tabContainerVersion === 1
|
||||
? onSpotlightMoveTabButton
|
||||
: undefined
|
||||
}
|
||||
onSpotlightDown={
|
||||
tabContainerVersion === 2 && belowContentsVisible
|
||||
? onSpotlightMoveBelowTab
|
||||
: onSpotlightMoveSlider
|
||||
}
|
||||
aria-label="Previous channel"
|
||||
/>
|
||||
</div>
|
||||
<div className={css.indicatorDownButton}>
|
||||
<SpottableBtn
|
||||
onClick={handleIndicatorDownClick}
|
||||
spotlightId="videoIndicator-down-button"
|
||||
onSpotlightLeft={onSpotlightMoveSlider}
|
||||
onSpotlightUp={onSpotlightMoveSlider}
|
||||
onSpotlightRight={
|
||||
videoVerticalVisible
|
||||
? onSpotlightMoveSideTab
|
||||
: tabContainerVersion === 1
|
||||
? onSpotlightMoveTabButton
|
||||
: undefined
|
||||
}
|
||||
onSpotlightDown={
|
||||
tabContainerVersion === 2 && belowContentsVisible
|
||||
? onSpotlightMoveBelowTab
|
||||
{type !== 'MEDIA' && playListInfo.length > 1 && noLiveContentsVisible && (
|
||||
<>
|
||||
<div className={css.indicatorUpButton}>
|
||||
<SpottableBtn
|
||||
onClick={handleIndicatorUpClick}
|
||||
spotlightId="videoIndicator-up-button"
|
||||
onSpotlightRight={
|
||||
videoVerticalVisible
|
||||
? onSpotlightMoveSideTab
|
||||
: tabContainerVersion === 1
|
||||
? onSpotlightMoveTabButton
|
||||
: undefined
|
||||
}
|
||||
aria-label="Next channel"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
}
|
||||
onSpotlightDown={
|
||||
tabContainerVersion === 2 && belowContentsVisible
|
||||
? onSpotlightMoveBelowTab
|
||||
: onSpotlightMoveSlider
|
||||
}
|
||||
aria-label="Previous channel"
|
||||
/>
|
||||
</div>
|
||||
<div className={css.indicatorDownButton}>
|
||||
<SpottableBtn
|
||||
onClick={handleIndicatorDownClick}
|
||||
spotlightId="videoIndicator-down-button"
|
||||
onSpotlightLeft={onSpotlightMoveSlider}
|
||||
onSpotlightUp={onSpotlightMoveSlider}
|
||||
onSpotlightRight={
|
||||
videoVerticalVisible
|
||||
? onSpotlightMoveSideTab
|
||||
: tabContainerVersion === 1
|
||||
? onSpotlightMoveTabButton
|
||||
: undefined
|
||||
}
|
||||
onSpotlightDown={
|
||||
tabContainerVersion === 2 && belowContentsVisible
|
||||
? onSpotlightMoveBelowTab
|
||||
: undefined
|
||||
}
|
||||
aria-label="Next channel"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{currentSideButtonStatus && !videoVerticalVisible && (
|
||||
<PlayerTabButton
|
||||
setSideContentsVisible={setSideContentsVisible}
|
||||
sideContentsVisible={sideContentsVisible}
|
||||
onSpotlightLeft={
|
||||
type !== "MEDIA" &&
|
||||
playListInfo.length < 2 &&
|
||||
onSpotlightMoveBackButton
|
||||
type !== 'MEDIA' && playListInfo.length < 2 && onSpotlightMoveBackButton
|
||||
}
|
||||
videoType={type}
|
||||
/>
|
||||
)}
|
||||
|
||||
{cntry_cd === "US" && (
|
||||
{cntry_cd === 'US' && (
|
||||
<div className={css.videoButtonContainer}>
|
||||
<SpottableBtn
|
||||
className={classNames(
|
||||
@@ -278,8 +261,8 @@ export default function PlayerOverlayContents({
|
||||
ref={backBtnRef}
|
||||
/>
|
||||
<div
|
||||
className={classNames(type === "LIVE" && css.liveIcon)}
|
||||
aria-label={type === "LIVE" && "Live Icon"}
|
||||
className={classNames(type === 'LIVE' && css.liveIcon)}
|
||||
aria-label={type === 'LIVE' && 'Live Icon'}
|
||||
/>
|
||||
|
||||
{partnerName && (
|
||||
@@ -294,17 +277,14 @@ export default function PlayerOverlayContents({
|
||||
<h2 className={css.patnerName}>{partnerName}</h2>
|
||||
|
||||
<Marquee
|
||||
className={classNames(
|
||||
css.title,
|
||||
videoVerticalVisible && css.videoVerticalMarquee
|
||||
)}
|
||||
className={classNames(css.title, videoVerticalVisible && css.videoVerticalMarquee)}
|
||||
marqueeOn="render"
|
||||
>
|
||||
{showName}
|
||||
</Marquee>
|
||||
</div>
|
||||
</Container>
|
||||
{type === "VOD" && disclaimer && (
|
||||
{type === 'VOD' && disclaimer && (
|
||||
<div className={css.disclaimer}>
|
||||
<span className={css.icon} />
|
||||
<h3 aria-label={disclaimer}>{disclaimer}</h3>
|
||||
@@ -313,3 +293,21 @@ export default function PlayerOverlayContents({
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const propsAreEqual = (prev, next) => {
|
||||
return (
|
||||
prev.type === next.type &&
|
||||
prev.panelInfo?.showId === next.panelInfo?.showId &&
|
||||
prev.disclaimer === next.disclaimer &&
|
||||
prev.playListInfo === next.playListInfo &&
|
||||
prev.captionEnable === next.captionEnable &&
|
||||
prev.selectedIndex === next.selectedIndex &&
|
||||
prev.videoVerticalVisible === next.videoVerticalVisible &&
|
||||
prev.sideContentsVisible === next.sideContentsVisible &&
|
||||
prev.belowContentsVisible === next.belowContentsVisible &&
|
||||
prev.tabContainerVersion === next.tabContainerVersion &&
|
||||
prev.tabIndexV2 === next.tabIndexV2
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(PlayerOverlayContents, propsAreEqual);
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
import React, { useMemo } from "react";
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import classNames from "classnames";
|
||||
import { useSelector } from "react-redux";
|
||||
import classNames from 'classnames';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import TQRCode from "../../../components/TQRCode/TQRCode";
|
||||
import css from "./PlayerOverlayQRCode.module.less";
|
||||
import { getQRCodeUrl, scaleH, scaleW } from "../../../utils/helperMethods";
|
||||
import TQRCode from '../../../components/TQRCode/TQRCode';
|
||||
import css from './PlayerOverlayQRCode.module.less';
|
||||
import { getQRCodeUrl, scaleH, scaleW } from '../../../utils/helperMethods';
|
||||
|
||||
export default function PlayerOverlayQRCode({
|
||||
qrCurrentItem,
|
||||
type,
|
||||
modalScale,
|
||||
}) {
|
||||
function PlayerOverlayQRCode({ qrCurrentItem, type, modalScale }) {
|
||||
const { cntry_cd } = useSelector((state) => state.common.httpHeader);
|
||||
const deviceInfo = useSelector((state) => state.device.deviceInfo);
|
||||
|
||||
@@ -20,19 +16,19 @@ export default function PlayerOverlayQRCode({
|
||||
const { entryMenu, nowMenu } = useSelector((state) => state.common.menu);
|
||||
|
||||
const label = useMemo(() => {
|
||||
let text = "";
|
||||
let text = '';
|
||||
switch (cntry_cd) {
|
||||
case "US":
|
||||
text = "SCAN TO SHOP";
|
||||
case 'US':
|
||||
text = 'SCAN TO SHOP';
|
||||
break;
|
||||
case "GB":
|
||||
text = "SCAN TO SHOP";
|
||||
case 'GB':
|
||||
text = 'SCAN TO SHOP';
|
||||
break;
|
||||
case "DE":
|
||||
text = "ZUM EINKAUFEN SCANNEN";
|
||||
case 'DE':
|
||||
text = 'ZUM EINKAUFEN SCANNEN';
|
||||
break;
|
||||
case "RU":
|
||||
text = "ОТСКАНИРОВАТЬ кОД ДЛЯ ПОКУПКИ";
|
||||
case 'RU':
|
||||
text = 'ОТСКАНИРОВАТЬ кОД ДЛЯ ПОКУПКИ';
|
||||
break;
|
||||
}
|
||||
return text;
|
||||
@@ -41,48 +37,48 @@ export default function PlayerOverlayQRCode({
|
||||
const innerStylePosition = useMemo(() => {
|
||||
const { patnrId } = qrCurrentItem || {};
|
||||
let top, bottom, right, left;
|
||||
let transformOrigin = "";
|
||||
if (cntry_cd === "US" && (patnrId === "4" || patnrId === "11")) {
|
||||
let transformOrigin = '';
|
||||
if (cntry_cd === 'US' && (patnrId === '4' || patnrId === '11')) {
|
||||
top = 64;
|
||||
right = 80;
|
||||
transformOrigin = "top right";
|
||||
} else if (cntry_cd === "GB" && patnrId === "1") {
|
||||
transformOrigin = 'top right';
|
||||
} else if (cntry_cd === 'GB' && patnrId === '1') {
|
||||
bottom = 64;
|
||||
right = 120;
|
||||
transformOrigin = "bottom right";
|
||||
} else if (cntry_cd === "DE" && patnrId === "1") {
|
||||
transformOrigin = 'bottom right';
|
||||
} else if (cntry_cd === 'DE' && patnrId === '1') {
|
||||
bottom = 25;
|
||||
right = 41;
|
||||
transformOrigin = "bottom right";
|
||||
} else if (cntry_cd === "RU") {
|
||||
if (patnrId === "12") {
|
||||
transformOrigin = 'bottom right';
|
||||
} else if (cntry_cd === 'RU') {
|
||||
if (patnrId === '12') {
|
||||
top = 280;
|
||||
right = 84;
|
||||
transformOrigin = "top right";
|
||||
transformOrigin = 'top right';
|
||||
}
|
||||
if (type === "LIVE") {
|
||||
if (type === 'LIVE') {
|
||||
top = 90;
|
||||
left = 74;
|
||||
transformOrigin = "top left";
|
||||
transformOrigin = 'top left';
|
||||
}
|
||||
}
|
||||
if (!transformOrigin) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
position: "absolute",
|
||||
top: top ? scaleH(top * modalScale) + "px" : undefined,
|
||||
bottom: bottom ? scaleH(bottom * modalScale) + "px" : undefined,
|
||||
right: right ? scaleW(right * modalScale) + "px" : undefined,
|
||||
left: left ? scaleW(left * modalScale) + "px" : undefined,
|
||||
position: 'absolute',
|
||||
top: top ? scaleH(top * modalScale) + 'px' : undefined,
|
||||
bottom: bottom ? scaleH(bottom * modalScale) + 'px' : undefined,
|
||||
right: right ? scaleW(right * modalScale) + 'px' : undefined,
|
||||
left: left ? scaleW(left * modalScale) + 'px' : undefined,
|
||||
transform: `scale(${modalScale})`,
|
||||
transformOrigin: transformOrigin,
|
||||
};
|
||||
}, [qrCurrentItem, cntry_cd, modalScale, type]);
|
||||
|
||||
const { width, height } = useMemo(() => {
|
||||
if (cntry_cd === "GB") return { width: "132", height: "131" };
|
||||
return { width: "156", height: "156" };
|
||||
if (cntry_cd === 'GB') return { width: '132', height: '131' };
|
||||
return { width: '156', height: '156' };
|
||||
}, [cntry_cd]);
|
||||
|
||||
const { detailUrl } = useMemo(() => {
|
||||
@@ -94,13 +90,13 @@ export default function PlayerOverlayQRCode({
|
||||
prdtId: qrCurrentItem?.prdtId,
|
||||
entryMenu: entryMenu,
|
||||
nowMenu: nowMenu,
|
||||
liveFlag: "Y",
|
||||
qrType: "billingDetail",
|
||||
liveFlag: 'Y',
|
||||
qrType: 'billingDetail',
|
||||
});
|
||||
}, [serverHOST, serverType, deviceInfo, entryMenu, nowMenu, qrCurrentItem]);
|
||||
|
||||
const QRCodeUrl = useMemo(() => {
|
||||
if (type === "LIVE" && qrCurrentItem?.patncNm === "ShopLC") {
|
||||
if (type === 'LIVE' && qrCurrentItem?.patncNm === 'ShopLC') {
|
||||
return detailUrl;
|
||||
}
|
||||
return qrCurrentItem?.qrcodeUrl;
|
||||
@@ -112,10 +108,10 @@ export default function PlayerOverlayQRCode({
|
||||
<div
|
||||
className={classNames(
|
||||
css.container,
|
||||
cntry_cd === "US" && css.us,
|
||||
cntry_cd === "GB" && css.gb,
|
||||
cntry_cd === "RU" && css.ru,
|
||||
cntry_cd === "DE" && css.de
|
||||
cntry_cd === 'US' && css.us,
|
||||
cntry_cd === 'GB' && css.gb,
|
||||
cntry_cd === 'RU' && css.ru,
|
||||
cntry_cd === 'DE' && css.de
|
||||
)}
|
||||
style={innerStylePosition}
|
||||
>
|
||||
@@ -124,7 +120,7 @@ export default function PlayerOverlayQRCode({
|
||||
text={QRCodeUrl}
|
||||
width={width}
|
||||
height={height}
|
||||
ariaLabel="QR CODE, “SCAN TO SHOP” go to Shoptime App"
|
||||
ariaLabel='QR CODE, "SCAN TO SHOP" go to Shoptime App'
|
||||
/>
|
||||
<div className={css.text}>{label}</div>
|
||||
</div>
|
||||
@@ -133,3 +129,13 @@ export default function PlayerOverlayQRCode({
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const propsAreEqual = (prev, next) => {
|
||||
return (
|
||||
prev.qrCurrentItem?.showId === next.qrCurrentItem?.showId &&
|
||||
prev.type === next.type &&
|
||||
prev.modalScale === next.modalScale
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(PlayerOverlayQRCode, propsAreEqual);
|
||||
|
||||
@@ -830,7 +830,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
resetTimer(REGULAR_TIMEOUT);
|
||||
}
|
||||
},
|
||||
[resetTimer, videoVerticalVisible]
|
||||
[dispatch, resetTimer, videoVerticalVisible]
|
||||
);
|
||||
|
||||
const onClickBack = useCallback(
|
||||
@@ -892,7 +892,6 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
[
|
||||
dispatch,
|
||||
panelInfo,
|
||||
nowMenu,
|
||||
videoPlayer,
|
||||
sideContentsVisible,
|
||||
videoVerticalVisible,
|
||||
@@ -1400,7 +1399,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
}
|
||||
}
|
||||
},
|
||||
[currentLiveTimeSeconds, liveTotalTime]
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -1881,43 +1880,49 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
timerId.current = null;
|
||||
}, []);
|
||||
|
||||
const resetTimer = useCallback((timeout) => {
|
||||
if (timerId.current) {
|
||||
clearTimer();
|
||||
}
|
||||
const resetTimer = useCallback(
|
||||
(timeout) => {
|
||||
if (timerId.current) {
|
||||
clearTimer();
|
||||
}
|
||||
|
||||
if (initialEnter) {
|
||||
setInitialEnter(false);
|
||||
}
|
||||
if (initialEnter) {
|
||||
setInitialEnter(false);
|
||||
}
|
||||
|
||||
timerId.current = setTimeout(() => {
|
||||
setSideContentsVisible(false);
|
||||
// setBelowContentsVisible(false);
|
||||
}, timeout);
|
||||
}, []);
|
||||
timerId.current = setTimeout(() => {
|
||||
setSideContentsVisible(false);
|
||||
// setBelowContentsVisible(false);
|
||||
}, timeout);
|
||||
},
|
||||
[clearTimer, initialEnter, setInitialEnter, setSideContentsVisible]
|
||||
);
|
||||
|
||||
const clearTimerV2 = useCallback(() => {
|
||||
clearTimeout(timerIdV2.current);
|
||||
timerIdV2.current = null;
|
||||
}, []);
|
||||
|
||||
const resetTimerV2 = useCallback((timeout) => {
|
||||
// console.log('[TabContainerV2] resetTimerV2 호출', timeout);
|
||||
if (timerIdV2.current) {
|
||||
// console.log('[TabContainerV2] 기존 타이머 클리어');
|
||||
clearTimerV2();
|
||||
}
|
||||
const resetTimerV2 = useCallback(
|
||||
(timeout) => {
|
||||
// console.log('[TabContainerV2] resetTimerV2 호출', timeout);
|
||||
if (timerIdV2.current) {
|
||||
// console.log('[TabContainerV2] 기존 타이머 클리어');
|
||||
clearTimerV2();
|
||||
}
|
||||
|
||||
if (initialEnterV2) {
|
||||
// console.log('[TabContainerV2] initialEnterV2 false로 변경');
|
||||
setInitialEnterV2(false);
|
||||
}
|
||||
if (initialEnterV2) {
|
||||
// console.log('[TabContainerV2] initialEnterV2 false로 변경');
|
||||
setInitialEnterV2(false);
|
||||
}
|
||||
|
||||
timerIdV2.current = setTimeout(() => {
|
||||
// console.log('[TabContainerV2] 타이머 실행 - belowContentsVisible false로 변경');
|
||||
setBelowContentsVisible(false);
|
||||
}, timeout);
|
||||
}, []);
|
||||
timerIdV2.current = setTimeout(() => {
|
||||
// console.log('[TabContainerV2] 타이머 실행 - belowContentsVisible false로 변경');
|
||||
setBelowContentsVisible(false);
|
||||
}, timeout);
|
||||
},
|
||||
[clearTimerV2, initialEnterV2, setInitialEnterV2, setBelowContentsVisible]
|
||||
);
|
||||
|
||||
// Redux로 오버레이 숨김
|
||||
useEffect(() => {
|
||||
@@ -1982,7 +1987,14 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
clearTimer();
|
||||
}
|
||||
};
|
||||
}, [showSideContents, videoVerticalVisible, tabContainerVersion]);
|
||||
}, [
|
||||
showSideContents,
|
||||
videoVerticalVisible,
|
||||
tabContainerVersion,
|
||||
resetTimer,
|
||||
initialEnter,
|
||||
clearTimer,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (initialEnter || !sideContentsVisible || videoVerticalVisible) return;
|
||||
@@ -2041,7 +2053,14 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
clearTimerV2();
|
||||
}
|
||||
};
|
||||
}, [showBelowContents, videoVerticalVisible, tabContainerVersion]);
|
||||
}, [
|
||||
showBelowContents,
|
||||
videoVerticalVisible,
|
||||
tabContainerVersion,
|
||||
resetTimerV2,
|
||||
initialEnterV2,
|
||||
clearTimerV2,
|
||||
]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const videoContainer = document.querySelector(`.${css.videoContainer}`);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user