🕐 커밋 시간: 2025. 11. 24. 12:43:58 📊 변경 통계: • 총 파일: 40개 • 추가: +774줄 • 삭제: -581줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/appDataActions.js ~ com.twin.app.shoptime/src/actions/billingActions.js ~ com.twin.app.shoptime/src/actions/brandActions.js ~ com.twin.app.shoptime/src/actions/cancelActions.js ~ com.twin.app.shoptime/src/actions/cardActions.js ~ com.twin.app.shoptime/src/actions/cartActions.js ~ com.twin.app.shoptime/src/actions/checkoutActions.js ~ com.twin.app.shoptime/src/actions/commonActions.js ~ com.twin.app.shoptime/src/actions/convertActions.js ~ com.twin.app.shoptime/src/actions/couponActions.js ~ com.twin.app.shoptime/src/actions/deviceActions.js ~ com.twin.app.shoptime/src/actions/empActions.js ~ com.twin.app.shoptime/src/actions/eventActions.js ~ com.twin.app.shoptime/src/actions/forYouActions.js ~ com.twin.app.shoptime/src/actions/homeActions.js ~ com.twin.app.shoptime/src/actions/logActions.js ~ com.twin.app.shoptime/src/actions/mediaActions.js ~ com.twin.app.shoptime/src/actions/mockCartActions.js ~ com.twin.app.shoptime/src/actions/myPageActions.js ~ com.twin.app.shoptime/src/actions/onSaleActions.js ~ com.twin.app.shoptime/src/actions/orderActions.js ~ com.twin.app.shoptime/src/actions/panelActions.js ~ com.twin.app.shoptime/src/actions/panelNavigationActions.js ~ com.twin.app.shoptime/src/actions/pinCodeActions.js ~ com.twin.app.shoptime/src/actions/productActions.js ~ com.twin.app.shoptime/src/actions/queuedPanelActions.js ~ com.twin.app.shoptime/src/actions/searchActions.js ~ com.twin.app.shoptime/src/actions/shippingActions.js ~ com.twin.app.shoptime/src/actions/voiceActions.js ~ com.twin.app.shoptime/src/actions/webSpeechActions.js ~ com.twin.app.shoptime/src/reducers/localSettingsReducer.js ~ com.twin.app.shoptime/src/reducers/mediaOverlayReducer.js ~ com.twin.app.shoptime/src/reducers/mockCartReducer.js ~ com.twin.app.shoptime/src/reducers/playReducer.js ~ com.twin.app.shoptime/src/reducers/productReducer.js ~ com.twin.app.shoptime/src/reducers/videoOverlayReducer.js ~ com.twin.app.shoptime/src/views/UserReview/ShowUserReviews.jsx ~ com.twin.app.shoptime/src/views/UserReview/UserReviewPanel.jsx ~ com.twin.app.shoptime/src/views/UserReview/components/UserReviewsList.jsx ~ com.twin.app.shoptime/src/views/UserReview/components/VirtualScrollBar.jsx 🔧 함수 변경 내용: 📊 Function-level changes summary across 40 files: • Functions added: 14 • Functions modified: 34 • Functions deleted: 18 📋 By language: • javascript: 40 files, 66 function changes 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선 • 로깅 시스템 개선 • 설정 관리 시스템 개선 • UI 컴포넌트 아키텍처 개선
348 lines
10 KiB
JavaScript
348 lines
10 KiB
JavaScript
import Spotlight from '@enact/spotlight';
|
|
|
|
import { panel_names } from '../utils/Config';
|
|
import { popPanel, pushPanel, updatePanel } from './panelActions';
|
|
import { createDebugHelpers } from '../utils/debug';
|
|
|
|
// 디버그 헬퍼 설정
|
|
const DEBUG_MODE = false;
|
|
const { dlog, dwarn, derror } = createDebugHelpers(DEBUG_MODE);
|
|
|
|
let startMediaFocusTimer = null;
|
|
|
|
/**
|
|
* MediaPanel을 시작합니다 (modal 또는 fullscreen 모드)
|
|
* @param {Object} params
|
|
* @param {boolean} params.modal - true: 부분화면, false: 전체화면
|
|
* @param {string} params.modalContainerId - modal 모드일 때 컨테이너 ID
|
|
* @param {string} params.modalClassName - 추가 CSS 클래스
|
|
* @param {boolean} params.spotlightDisable - spotlight 비활성화 여부
|
|
* @param {string} params.showUrl - 비디오 URL
|
|
* @param {string} params.thumbnailUrl - 썸네일 URL
|
|
* @param {string} params.subtitle - 자막 URL (선택)
|
|
*/
|
|
export const startMediaPlayer =
|
|
({ modal, modalContainerId, modalClassName, spotlightDisable, ...rest }) =>
|
|
(dispatch, getState) => {
|
|
const panels = getState().panels.panels;
|
|
const topPanel = panels[panels.length - 1];
|
|
let panelWorkingAction = pushPanel;
|
|
|
|
dlog('[startMediaPlayer]-LoadingVideo 🚀 시작:', {
|
|
showUrl: rest?.showUrl?.substring(0, 50),
|
|
showNm: rest?.showNm,
|
|
prdtId: rest?.prdtId,
|
|
modal,
|
|
modalContainerId,
|
|
});
|
|
|
|
if (topPanel && topPanel.name === panel_names.MEDIA_PANEL) {
|
|
panelWorkingAction = updatePanel;
|
|
}
|
|
|
|
const allParams = {
|
|
modal,
|
|
modalContainerId,
|
|
modalClassName,
|
|
spotlightDisable,
|
|
...rest,
|
|
};
|
|
|
|
dispatch(
|
|
panelWorkingAction(
|
|
{
|
|
name: panel_names.MEDIA_PANEL,
|
|
panelInfo: allParams,
|
|
},
|
|
true
|
|
)
|
|
);
|
|
|
|
dlog('[startMediaPlayer]-LoadingVideo ✅ MediaPanel dispatch 완료');
|
|
|
|
if (modal && modalContainerId && !spotlightDisable) {
|
|
Spotlight.setPointerMode(false);
|
|
startMediaFocusTimer = setTimeout(() => {
|
|
Spotlight.focus(modalContainerId);
|
|
}, 0);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* MediaPanel의 modal 모드를 종료합니다
|
|
*/
|
|
export const finishMediaPreview = () => (dispatch, getState) => {
|
|
const panels = getState().panels.panels;
|
|
const topPanel = panels[panels.length - 1];
|
|
|
|
// dlog('[finishMediaPreview] ========== Called ==========');
|
|
// dlog('[finishMediaPreview] Current panels:', JSON.stringify(panels, null, 2));
|
|
// dlog('[finishMediaPreview] topPanel:', JSON.stringify(topPanel, null, 2));
|
|
|
|
if (topPanel && topPanel.name === panel_names.MEDIA_PANEL && topPanel.panelInfo.modal) {
|
|
// dlog('[finishMediaPreview] Closing modal MediaPanel');
|
|
|
|
if (startMediaFocusTimer) {
|
|
clearTimeout(startMediaFocusTimer);
|
|
startMediaFocusTimer = null;
|
|
}
|
|
dispatch(popPanel());
|
|
// dlog('[finishMediaPreview] popPanel dispatched');
|
|
} else {
|
|
// dlog('[finishMediaPreview] Not closing - no modal MediaPanel on top');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 강제로 DetailPanel ProductVideo MediaPanel을 종료합니다 (modal/fullscreen 모두)
|
|
*/
|
|
export const finishModalMediaForce = () => (dispatch, getState) => {
|
|
const panels = getState().panels.panels;
|
|
|
|
const hasProductVideoPanel = panels.some(
|
|
(panel) =>
|
|
panel.name === panel_names.MEDIA_PANEL &&
|
|
(panel.panelInfo?.modal || panel.panelInfo?.modalContainerId === 'product-video-player')
|
|
);
|
|
|
|
if (hasProductVideoPanel) {
|
|
if (startMediaFocusTimer) {
|
|
clearTimeout(startMediaFocusTimer);
|
|
startMediaFocusTimer = null;
|
|
}
|
|
dispatch(popPanel(panel_names.MEDIA_PANEL));
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Modal MediaPanel을 일시정지합니다 (패널은 유지)
|
|
*/
|
|
export const pauseModalMedia = () => (dispatch, getState) => {
|
|
const panels = getState().panels.panels;
|
|
|
|
const modalMediaPanel = panels.find(
|
|
(panel) => panel.name === panel_names.MEDIA_PANEL && panel.panelInfo?.modal
|
|
);
|
|
|
|
if (modalMediaPanel) {
|
|
// dlog('[pauseModalMedia] Pausing modal MediaPanel');
|
|
dispatch(
|
|
updatePanel({
|
|
name: panel_names.MEDIA_PANEL,
|
|
panelInfo: {
|
|
...modalMediaPanel.panelInfo,
|
|
isPaused: true,
|
|
},
|
|
})
|
|
);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Modal MediaPanel을 재생합니다 (일시정지 해제)
|
|
*/
|
|
export const resumeModalMedia = () => (dispatch, getState) => {
|
|
const panels = getState().panels.panels;
|
|
|
|
const modalMediaPanel = panels.find(
|
|
(panel) => panel.name === panel_names.MEDIA_PANEL && panel.panelInfo?.modal
|
|
);
|
|
|
|
if (modalMediaPanel && modalMediaPanel.panelInfo?.isPaused) {
|
|
// dlog('[resumeModalMedia] Resuming modal MediaPanel');
|
|
dispatch(
|
|
updatePanel({
|
|
name: panel_names.MEDIA_PANEL,
|
|
panelInfo: {
|
|
...modalMediaPanel.panelInfo,
|
|
isPaused: false,
|
|
},
|
|
})
|
|
);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* MediaPanel을 fullscreen 모드로 전환합니다
|
|
*/
|
|
export const switchMediaToFullscreen = () => (dispatch, getState) => {
|
|
const panels = getState().panels.panels;
|
|
|
|
// dlog('[switchMediaToFullscreen] ========== Called ==========');
|
|
// dlog('[switchMediaToFullscreen] Current panels:', JSON.stringify(panels, null, 2));
|
|
|
|
const modalMediaPanel = panels.find(
|
|
(panel) => panel.name === panel_names.MEDIA_PANEL && panel.panelInfo?.modal
|
|
);
|
|
|
|
// dlog(
|
|
// '[switchMediaToFullscreen] modalMediaPanel found:',
|
|
// JSON.stringify(modalMediaPanel, null, 2)
|
|
// );
|
|
|
|
if (modalMediaPanel) {
|
|
// dlog('[switchMediaToFullscreen] Switching to fullscreen - updating modal to false');
|
|
// dlog(
|
|
// '[switchMediaToFullscreen] Existing panelInfo:',
|
|
// JSON.stringify(modalMediaPanel.panelInfo, null, 2)
|
|
// );
|
|
|
|
const newPanelInfo = {
|
|
...modalMediaPanel.panelInfo,
|
|
modal: false,
|
|
};
|
|
|
|
// dlog(
|
|
// '[switchMediaToFullscreen] New panelInfo to dispatch:',
|
|
// JSON.stringify(newPanelInfo, null, 2)
|
|
// );
|
|
|
|
dispatch(
|
|
updatePanel({
|
|
name: panel_names.MEDIA_PANEL,
|
|
panelInfo: newPanelInfo,
|
|
})
|
|
);
|
|
// dlog('[switchMediaToFullscreen] updatePanel dispatched');
|
|
} else {
|
|
// dlog(
|
|
// '[switchMediaToFullscreen] No modal MediaPanel found - cannot switch to fullscreen'
|
|
// );
|
|
}
|
|
};
|
|
|
|
/**
|
|
* MediaPanel을 modal 모드로 전환합니다
|
|
*/
|
|
export const switchMediaToModal = (modalContainerId, modalClassName) => (dispatch, getState) => {
|
|
const panels = getState().panels.panels;
|
|
|
|
const mediaPanel = panels.find((panel) => panel.name === panel_names.MEDIA_PANEL);
|
|
|
|
if (mediaPanel && !mediaPanel.panelInfo?.modal) {
|
|
// dlog('[switchMediaToModal] Switching to modal');
|
|
dispatch(
|
|
updatePanel({
|
|
name: panel_names.MEDIA_PANEL,
|
|
panelInfo: {
|
|
...mediaPanel.panelInfo,
|
|
modal: true,
|
|
modalContainerId,
|
|
modalClassName,
|
|
},
|
|
})
|
|
);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Modal MediaPanel을 최소화합니다 (1px 크기로 축소, 재생은 계속)
|
|
* modal=false로 변경하여 background 클래스 적용 (modalContainerId는 복원을 위해 유지)
|
|
*/
|
|
export const minimizeModalMedia = () => (dispatch, getState) => {
|
|
const panels = getState().panels.panels;
|
|
|
|
dlog('[Minimize] ========== Called ==========');
|
|
dlog('[Minimize] Total panels:', panels.length);
|
|
dlog(
|
|
'[Minimize] All panels:',
|
|
panels
|
|
// JSON.stringify(
|
|
// panels.map((p) => ({ name: p.name, modal: p.panelInfo?.modal })),
|
|
// null,
|
|
// 2
|
|
// )
|
|
);
|
|
|
|
const modalMediaPanel = panels.find(
|
|
(panel) => panel.name === panel_names.MEDIA_PANEL && panel.panelInfo?.modal
|
|
);
|
|
|
|
// dlog('[Minimize] Found modalMediaPanel:', !!modalMediaPanel);
|
|
if (modalMediaPanel) {
|
|
dlog(
|
|
'[Minimize] modalMediaPanel.panelInfo:',
|
|
JSON.stringify(modalMediaPanel.panelInfo, null, 2)
|
|
);
|
|
// dlog('[Minimize] ✅ Minimizing modal MediaPanel (modal=false, isMinimized=true)');
|
|
dispatch(
|
|
updatePanel({
|
|
name: panel_names.MEDIA_PANEL,
|
|
panelInfo: {
|
|
...modalMediaPanel.panelInfo,
|
|
// modal: false, // fullscreen 모드로 전환
|
|
isMinimized: true, // modal-minimized 클래스 적용 (1px 크기)
|
|
shouldShrinkTo1px: true, // shrink 플래그 추가
|
|
// modalContainerId, modalClassName 등은 복원을 위해 유지
|
|
// isPaused는 변경하지 않음 - 재생은 계속됨
|
|
},
|
|
})
|
|
);
|
|
} else {
|
|
dlog('[Minimize] ❌ No modal MediaPanel found - cannot minimize');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Modal MediaPanel을 복원합니다 (최소화 해제)
|
|
* modal=true, isMinimized=false로 변경하여 원래 modal 위치로 복원
|
|
*/
|
|
export const restoreModalMedia = () => (dispatch, getState) => {
|
|
const panels = getState().panels.panels;
|
|
|
|
if (typeof window !== 'undefined' && window.detailPanelScrollTop !== 0) {
|
|
dlog(
|
|
'[restoreModalMedia] Blocked restore because detail panel scroll not zero:',
|
|
window.detailPanelScrollTop
|
|
);
|
|
return;
|
|
}
|
|
|
|
// dlog('[Restore]] ========== Called ==========');
|
|
// dlog('[Restore] Total panels:', panels.length);
|
|
// dlog(
|
|
// '[Restore] All panels:',
|
|
// JSON.stringify(
|
|
// panels.map((p) => ({
|
|
// name: p.name,
|
|
// modal: p.panelInfo?.modal,
|
|
// isMinimized: p.panelInfo?.isMinimized,
|
|
// })),
|
|
// null,
|
|
// 2
|
|
// )
|
|
// );
|
|
|
|
// modal=true AND isMinimized=true인 MediaPanel을 찾음 (최소화 상태)
|
|
const minimizedMediaPanel = panels.find(
|
|
(panel) =>
|
|
panel.name === panel_names.MEDIA_PANEL &&
|
|
panel.panelInfo?.modal &&
|
|
panel.panelInfo?.isMinimized
|
|
);
|
|
|
|
// dlog('[restoreModalMedia] Found minimizedMediaPanel:', !!minimizedMediaPanel);
|
|
if (minimizedMediaPanel) {
|
|
// dlog(
|
|
// '[restoreModalMedia] minimizedMediaPanel.panelInfo:',
|
|
// JSON.stringify(minimizedMediaPanel.panelInfo, null, 2)
|
|
// );
|
|
// dlog(
|
|
// '[restoreModalMedia] ✅ Restoring modal MediaPanel (modal=true, isMinimized=false)'
|
|
// );
|
|
dispatch(
|
|
updatePanel({
|
|
name: panel_names.MEDIA_PANEL,
|
|
panelInfo: {
|
|
...minimizedMediaPanel.panelInfo,
|
|
modal: true, // modal 모드로 복원 (원래 위치로 복귀)
|
|
isMinimized: false, // 최소화 해제
|
|
shouldShrinkTo1px: false, // shrink 플래그 초기화
|
|
},
|
|
})
|
|
);
|
|
} else {
|
|
// dlog('[restoreModalMedia] ❌ No minimized MediaPanel found - cannot restore');
|
|
}
|
|
};
|