[251115] fix: ProductVideo.v3.jsx 전체화면 전환
🕐 커밋 시간: 2025. 11. 15. 14:47:47 📊 변경 통계: • 총 파일: 8개 • 추가: +261줄 • 삭제: -242줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/deviceActions.js ~ com.twin.app.shoptime/src/actions/homeActions.js ~ com.twin.app.shoptime/src/actions/mainActions.js ~ com.twin.app.shoptime/src/actions/productActions.js ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v3.jsx ~ com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/actions/homeActions.js (javascript): 🔄 Modified: checkEnterThroughGNB() ❌ Deleted: clearPersistentVideoInfo() 📄 com.twin.app.shoptime/src/actions/productActions.js (javascript): 🔄 Modified: createGetThunk(), getVideoIndicatorFocus() ❌ Deleted: fetchAllReviewsWithSequentialPaging() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx (javascript): 🔄 Modified: extractProductMeta() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.jsx (javascript): 🔄 Modified: Spottable() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v3.jsx (javascript): 🔄 Modified: Spottable() 📄 com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx (javascript): 🔄 Modified: normalizeModalStyle() 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선
This commit is contained in:
@@ -1,14 +1,9 @@
|
|||||||
import { URLS } from "../api/apiConfig";
|
import { URLS } from '../api/apiConfig';
|
||||||
import {
|
import { runDelayedAction, setTokenRefreshing, TAxios, TAxiosAdvancedPromise } from '../api/TAxios';
|
||||||
runDelayedAction,
|
import * as lunaSend from '../lunaSend';
|
||||||
setTokenRefreshing,
|
import { types } from './actionTypes';
|
||||||
TAxios,
|
import { changeLocalSettings } from './commonActions';
|
||||||
TAxiosAdvancedPromise,
|
import { fetchCurrentUserHomeTerms } from './homeActions';
|
||||||
} from "../api/TAxios";
|
|
||||||
import * as lunaSend from "../lunaSend";
|
|
||||||
import { types } from "./actionTypes";
|
|
||||||
import { changeLocalSettings } from "./commonActions";
|
|
||||||
import { fetchCurrentUserHomeTerms } from "./homeActions";
|
|
||||||
|
|
||||||
const MAX_RETRY_COUNT = 3;
|
const MAX_RETRY_COUNT = 3;
|
||||||
const RETRY_DELAY = 2000; // 2 seconds
|
const RETRY_DELAY = 2000; // 2 seconds
|
||||||
@@ -17,7 +12,7 @@ const RETRY_DELAY = 2000; // 2 seconds
|
|||||||
export const getAuthenticationCode = () => (dispatch, getState) => {
|
export const getAuthenticationCode = () => (dispatch, getState) => {
|
||||||
setTokenRefreshing(true);
|
setTokenRefreshing(true);
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("getAuthenticationCode onSuccess: ", response.data);
|
console.log('getAuthenticationCode onSuccess: ', response.data);
|
||||||
const accessToken = response.data.data.accessToken;
|
const accessToken = response.data.data.accessToken;
|
||||||
const refreshToken = response.data.data.refreshToken ?? null;
|
const refreshToken = response.data.data.refreshToken ?? null;
|
||||||
|
|
||||||
@@ -27,21 +22,11 @@ export const getAuthenticationCode = () => (dispatch, getState) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("getAuthenticationCode onFail: ", error);
|
console.error('getAuthenticationCode onFail: ', error);
|
||||||
setTokenRefreshing(false);
|
setTokenRefreshing(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
TAxios(
|
TAxios(dispatch, getState, 'get', URLS.GET_AUTHENTICATION_CODE, {}, {}, onSuccess, onFail, true);
|
||||||
dispatch,
|
|
||||||
getState,
|
|
||||||
"get",
|
|
||||||
URLS.GET_AUTHENTICATION_CODE,
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
onSuccess,
|
|
||||||
onFail,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// IF-LGSP-001 디바이스 등록 및 약관 동의
|
// IF-LGSP-001 디바이스 등록 및 약관 동의
|
||||||
@@ -50,7 +35,7 @@ export const registerDevice =
|
|||||||
const { agreeTerms } = params;
|
const { agreeTerms } = params;
|
||||||
|
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("registerDevice onSuccess: ", response.data);
|
console.log('registerDevice onSuccess: ', response.data);
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.REGISTER_DEVICE,
|
type: types.REGISTER_DEVICE,
|
||||||
@@ -65,7 +50,7 @@ export const registerDevice =
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("registerDevice onFail: ", error);
|
console.error('registerDevice onFail: ', error);
|
||||||
if (onFailCallback) {
|
if (onFailCallback) {
|
||||||
onFailCallback(error);
|
onFailCallback(error);
|
||||||
}
|
}
|
||||||
@@ -74,7 +59,7 @@ export const registerDevice =
|
|||||||
TAxios(
|
TAxios(
|
||||||
dispatch,
|
dispatch,
|
||||||
getState,
|
getState,
|
||||||
"post",
|
'post',
|
||||||
URLS.REGISTER_DEVICE,
|
URLS.REGISTER_DEVICE,
|
||||||
{},
|
{},
|
||||||
{ agreeTerms },
|
{ agreeTerms },
|
||||||
@@ -89,7 +74,7 @@ export const registerDeviceInfo = (params) => (dispatch, getState) => {
|
|||||||
const { evntTpCd, evntId, evntApplcnFlag, entryMenu, mbphNo } = params;
|
const { evntTpCd, evntId, evntApplcnFlag, entryMenu, mbphNo } = params;
|
||||||
|
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("registerDeviceInfo onSuccess: ", response.data);
|
console.log('registerDeviceInfo onSuccess: ', response.data);
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.REGISTER_DEVICE_INFO,
|
type: types.REGISTER_DEVICE_INFO,
|
||||||
@@ -99,13 +84,13 @@ export const registerDeviceInfo = (params) => (dispatch, getState) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("registerDeviceInfo onFail: ", error);
|
console.error('registerDeviceInfo onFail: ', error);
|
||||||
};
|
};
|
||||||
|
|
||||||
TAxios(
|
TAxios(
|
||||||
dispatch,
|
dispatch,
|
||||||
getState,
|
getState,
|
||||||
"post",
|
'post',
|
||||||
URLS.REGISTER_DEVICE_INFO,
|
URLS.REGISTER_DEVICE_INFO,
|
||||||
{},
|
{},
|
||||||
{ evntTpCd, evntId, evntApplcnFlag, entryMenu, mbphNo },
|
{ evntTpCd, evntId, evntApplcnFlag, entryMenu, mbphNo },
|
||||||
@@ -117,7 +102,7 @@ export const registerDeviceInfo = (params) => (dispatch, getState) => {
|
|||||||
// 디바이스 부가 정보 조회 IF-LGSP-003
|
// 디바이스 부가 정보 조회 IF-LGSP-003
|
||||||
export const getDeviceAdditionInfo = () => (dispatch, getState) => {
|
export const getDeviceAdditionInfo = () => (dispatch, getState) => {
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("getDeviceAdditionInfo onSuccess: ", response.data);
|
console.log('getDeviceAdditionInfo onSuccess: ', response.data);
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.GET_DEVICE_INFO,
|
type: types.GET_DEVICE_INFO,
|
||||||
@@ -126,26 +111,17 @@ export const getDeviceAdditionInfo = () => (dispatch, getState) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("getDeviceAdditionInfo onFail: ", error);
|
console.error('getDeviceAdditionInfo onFail: ', error);
|
||||||
};
|
};
|
||||||
|
|
||||||
TAxios(
|
TAxios(dispatch, getState, 'get', URLS.GET_DEVICE_INFO, {}, {}, onSuccess, onFail);
|
||||||
dispatch,
|
|
||||||
getState,
|
|
||||||
"get",
|
|
||||||
URLS.GET_DEVICE_INFO,
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
onSuccess,
|
|
||||||
onFail
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 인증번호 재요청 IF-LGSP-096
|
// 인증번호 재요청 IF-LGSP-096
|
||||||
export const getReAuthenticationCode = () => (dispatch, getState) => {
|
export const getReAuthenticationCode = () => (dispatch, getState) => {
|
||||||
setTokenRefreshing(true);
|
setTokenRefreshing(true);
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("getReAuthenticationCode onSuccess: ", response.data);
|
// console.log("getReAuthenticationCode onSuccess: ", response.data);
|
||||||
const accessToken = response.data.data.accessToken;
|
const accessToken = response.data.data.accessToken;
|
||||||
dispatch(changeLocalSettings({ accessToken }));
|
dispatch(changeLocalSettings({ accessToken }));
|
||||||
setTokenRefreshing(false);
|
setTokenRefreshing(false);
|
||||||
@@ -153,14 +129,14 @@ export const getReAuthenticationCode = () => (dispatch, getState) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("getReAuthenticationCode onFail: ", error);
|
console.error('getReAuthenticationCode onFail: ', error);
|
||||||
setTokenRefreshing(false);
|
setTokenRefreshing(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
TAxios(
|
TAxios(
|
||||||
dispatch,
|
dispatch,
|
||||||
getState,
|
getState,
|
||||||
"get",
|
'get',
|
||||||
URLS.GET_RE_AUTHENTICATION_CODE,
|
URLS.GET_RE_AUTHENTICATION_CODE,
|
||||||
{},
|
{},
|
||||||
{},
|
{},
|
||||||
|
|||||||
@@ -1,62 +1,67 @@
|
|||||||
import { URLS } from "../api/apiConfig";
|
import { URLS } from '../api/apiConfig';
|
||||||
import { TAxios,TAxiosPromise } from "../api/TAxios";
|
import { TAxios, TAxiosPromise } from '../api/TAxios';
|
||||||
import { types } from "./actionTypes";
|
import { types } from './actionTypes';
|
||||||
import { changeAppStatus, getTermsAgreeYn } from "./commonActions";
|
import { changeAppStatus, getTermsAgreeYn } from './commonActions';
|
||||||
import { collectBannerPositions } from "../utils/domUtils";
|
import { collectBannerPositions } from '../utils/domUtils';
|
||||||
|
|
||||||
// 약관 정보 조회 IF-LGSP-005
|
// 약관 정보 조회 IF-LGSP-005
|
||||||
export const getHomeTerms = (props) => (dispatch, getState) => {
|
export const getHomeTerms = (props) => (dispatch, getState) => {
|
||||||
const { trmsTpCdList, mbrNo } = props;
|
const { trmsTpCdList, mbrNo } = props;
|
||||||
|
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("getHomeTerms onSuccess ", response.data);
|
console.log('getHomeTerms onSuccess ', response.data);
|
||||||
|
|
||||||
if (response.data.retCode === 0) {
|
if (response.data.retCode === 0) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.GET_HOME_TERMS,
|
type: types.GET_HOME_TERMS,
|
||||||
payload: response.data,
|
payload: response.data,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 약관 ID 매핑을 별도로 생성하여 저장
|
// 약관 ID 매핑을 별도로 생성하여 저장
|
||||||
// Chromium68 호환성을 위해 Optional Chaining 제거
|
// Chromium68 호환성을 위해 Optional Chaining 제거
|
||||||
if (response.data && response.data.data && response.data.data.terms) {
|
if (response.data && response.data.data && response.data.data.terms) {
|
||||||
const termsIdMap = {};
|
const termsIdMap = {};
|
||||||
let hasOptionalTerms = false; // MST00405 존재 여부 확인
|
let hasOptionalTerms = false; // MST00405 존재 여부 확인
|
||||||
|
|
||||||
response.data.data.terms.forEach(term => {
|
response.data.data.terms.forEach((term) => {
|
||||||
if (term.trmsTpCd && term.trmsId) {
|
if (term.trmsTpCd && term.trmsId) {
|
||||||
termsIdMap[term.trmsTpCd] = term.trmsId;
|
termsIdMap[term.trmsTpCd] = term.trmsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MST00405 선택약관 존재 여부 확인
|
// MST00405 선택약관 존재 여부 확인
|
||||||
if (term.trmsTpCd === "MST00405") {
|
if (term.trmsTpCd === 'MST00405') {
|
||||||
hasOptionalTerms = true;
|
hasOptionalTerms = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.SET_TERMS_ID_MAP,
|
type: types.SET_TERMS_ID_MAP,
|
||||||
payload: termsIdMap,
|
payload: termsIdMap,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 선택약관 존재 여부 상태 설정
|
// 선택약관 존재 여부 상태 설정
|
||||||
// TODO: 테스트용 - 임시로 false 강제 설정
|
// TODO: 테스트용 - 임시로 false 강제 설정
|
||||||
const forceDisableOptionalTerms = false; // 테스트 완료 후 false로 변경
|
const forceDisableOptionalTerms = false; // 테스트 완료 후 false로 변경
|
||||||
const finalOptionalTermsValue = forceDisableOptionalTerms ? false : hasOptionalTerms;
|
const finalOptionalTermsValue = forceDisableOptionalTerms ? false : hasOptionalTerms;
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.SET_OPTIONAL_TERMS_AVAILABILITY,
|
type: types.SET_OPTIONAL_TERMS_AVAILABILITY,
|
||||||
payload: finalOptionalTermsValue,
|
payload: finalOptionalTermsValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("[optionalTermsAvailable] 실제값:", hasOptionalTerms, "강제설정값:", finalOptionalTermsValue);
|
console.log(
|
||||||
|
'[optionalTermsAvailable] 실제값:',
|
||||||
if (process.env.NODE_ENV === "development") {
|
hasOptionalTerms,
|
||||||
console.log("약관 ID 매핑 생성:", termsIdMap);
|
'강제설정값:',
|
||||||
console.log("선택약관 존재 여부:", hasOptionalTerms);
|
finalOptionalTermsValue
|
||||||
|
);
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
console.log('약관 ID 매핑 생성:', termsIdMap);
|
||||||
|
console.log('선택약관 존재 여부:', hasOptionalTerms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
dispatch(getTermsAgreeYn());
|
dispatch(getTermsAgreeYn());
|
||||||
}, 0);
|
}, 0);
|
||||||
@@ -64,13 +69,13 @@ export const getHomeTerms = (props) => (dispatch, getState) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("getHomeTerms onFail ", error);
|
console.error('getHomeTerms onFail ', error);
|
||||||
};
|
};
|
||||||
|
|
||||||
TAxios(
|
TAxios(
|
||||||
dispatch,
|
dispatch,
|
||||||
getState,
|
getState,
|
||||||
"get",
|
'get',
|
||||||
URLS.GET_HOME_TERMS,
|
URLS.GET_HOME_TERMS,
|
||||||
{ trmsTpCdList, mbrNo },
|
{ trmsTpCdList, mbrNo },
|
||||||
{},
|
{},
|
||||||
@@ -82,64 +87,71 @@ export const getHomeTerms = (props) => (dispatch, getState) => {
|
|||||||
// 현재 로그인 사용자 기준으로 약관 정보 조회 (인자 없이 호출 가능)
|
// 현재 로그인 사용자 기준으로 약관 정보 조회 (인자 없이 호출 가능)
|
||||||
export const fetchCurrentUserHomeTerms = () => (dispatch, getState) => {
|
export const fetchCurrentUserHomeTerms = () => (dispatch, getState) => {
|
||||||
const loginUserData = getState().common.appStatus.loginUserData;
|
const loginUserData = getState().common.appStatus.loginUserData;
|
||||||
|
|
||||||
if (!loginUserData || !loginUserData.userNumber) {
|
if (!loginUserData || !loginUserData.userNumber) {
|
||||||
console.error("fetchCurrentUserHomeTerms: userNumber (mbrNo) is not available. User might not be logged in.");
|
console.error(
|
||||||
|
'fetchCurrentUserHomeTerms: userNumber (mbrNo) is not available. User might not be logged in.'
|
||||||
|
);
|
||||||
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mbrNo = loginUserData.userNumber;
|
const mbrNo = loginUserData.userNumber;
|
||||||
const trmsTpCdList = "MST00401, MST00402, MST00405"; // 기본 약관 코드 리스트
|
const trmsTpCdList = 'MST00401, MST00402, MST00405'; // 기본 약관 코드 리스트
|
||||||
|
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("fetchCurrentUserHomeTerms onSuccess ", response.data);
|
console.log('fetchCurrentUserHomeTerms onSuccess ', response.data);
|
||||||
|
|
||||||
if (response.data.retCode === 0) {
|
if (response.data.retCode === 0) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.GET_HOME_TERMS, // 기존 GET_HOME_TERMS 타입을 재사용
|
type: types.GET_HOME_TERMS, // 기존 GET_HOME_TERMS 타입을 재사용
|
||||||
payload: response.data,
|
payload: response.data,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 약관 ID 매핑을 별도로 생성하여 저장
|
// 약관 ID 매핑을 별도로 생성하여 저장
|
||||||
// Chromium68 호환성을 위해 Optional Chaining 제거
|
// Chromium68 호환성을 위해 Optional Chaining 제거
|
||||||
if (response.data && response.data.data && response.data.data.terms) {
|
if (response.data && response.data.data && response.data.data.terms) {
|
||||||
const termsIdMap = {};
|
const termsIdMap = {};
|
||||||
let hasOptionalTerms = false; // MST00405 존재 여부 확인
|
let hasOptionalTerms = false; // MST00405 존재 여부 확인
|
||||||
|
|
||||||
response.data.data.terms.forEach(term => {
|
response.data.data.terms.forEach((term) => {
|
||||||
if (term.trmsTpCd && term.trmsId) {
|
if (term.trmsTpCd && term.trmsId) {
|
||||||
termsIdMap[term.trmsTpCd] = term.trmsId;
|
termsIdMap[term.trmsTpCd] = term.trmsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MST00405 선택약관 존재 여부 확인
|
// MST00405 선택약관 존재 여부 확인
|
||||||
if (term.trmsTpCd === "MST00405") {
|
if (term.trmsTpCd === 'MST00405') {
|
||||||
hasOptionalTerms = true;
|
hasOptionalTerms = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.SET_TERMS_ID_MAP,
|
type: types.SET_TERMS_ID_MAP,
|
||||||
payload: termsIdMap,
|
payload: termsIdMap,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 선택약관 존재 여부 상태 설정
|
// 선택약관 존재 여부 상태 설정
|
||||||
// TODO: 테스트용 - 임시로 false 강제 설정
|
// TODO: 테스트용 - 임시로 false 강제 설정
|
||||||
const forceDisableOptionalTerms = false; // 테스트 완료 후 false로 변경
|
const forceDisableOptionalTerms = false; // 테스트 완료 후 false로 변경
|
||||||
const finalOptionalTermsValue = forceDisableOptionalTerms ? false : hasOptionalTerms;
|
const finalOptionalTermsValue = forceDisableOptionalTerms ? false : hasOptionalTerms;
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.SET_OPTIONAL_TERMS_AVAILABILITY,
|
type: types.SET_OPTIONAL_TERMS_AVAILABILITY,
|
||||||
payload: finalOptionalTermsValue,
|
payload: finalOptionalTermsValue,
|
||||||
});
|
});
|
||||||
console.log("[optionalTermsAvailable] 실제값:", hasOptionalTerms, "강제설정값:", finalOptionalTermsValue);
|
console.log(
|
||||||
|
'[optionalTermsAvailable] 실제값:',
|
||||||
|
hasOptionalTerms,
|
||||||
|
'강제설정값:',
|
||||||
|
finalOptionalTermsValue
|
||||||
|
);
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
console.log("약관 ID 매핑 생성:", termsIdMap);
|
console.log('약관 ID 매핑 생성:', termsIdMap);
|
||||||
console.log("선택약관 존재 여부:", hasOptionalTerms);
|
console.log('선택약관 존재 여부:', hasOptionalTerms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getHomeTerms와 동일하게 getTermsAgreeYn 후속 처리
|
// getHomeTerms와 동일하게 getTermsAgreeYn 후속 처리
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
dispatch(getTermsAgreeYn());
|
dispatch(getTermsAgreeYn());
|
||||||
@@ -149,129 +161,129 @@ export const fetchCurrentUserHomeTerms = () => (dispatch, getState) => {
|
|||||||
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("fetchCurrentUserHomeTerms onFail ", error);
|
console.error('fetchCurrentUserHomeTerms onFail ', error);
|
||||||
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
||||||
};
|
};
|
||||||
|
|
||||||
TAxios(
|
TAxios(
|
||||||
dispatch,
|
dispatch,
|
||||||
getState,
|
getState,
|
||||||
"get",
|
'get',
|
||||||
URLS.GET_HOME_TERMS, // 동일한 API 엔드포인트 사용
|
URLS.GET_HOME_TERMS, // 동일한 API 엔드포인트 사용
|
||||||
{ trmsTpCdList, mbrNo },
|
{ trmsTpCdList, mbrNo },
|
||||||
{},
|
{},
|
||||||
onSuccess,
|
onSuccess,
|
||||||
onFail
|
onFail
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 기존 TAxios 패턴과 일치하는 안전한 Redux Action
|
// 기존 TAxios 패턴과 일치하는 안전한 Redux Action
|
||||||
export const fetchCurrentUserHomeTermsSafe = () => async (dispatch, getState) => {
|
export const fetchCurrentUserHomeTermsSafe = () => async (dispatch, getState) => {
|
||||||
const loginUserData = getState().common.appStatus.loginUserData;
|
const loginUserData = getState().common.appStatus.loginUserData;
|
||||||
|
|
||||||
if (!loginUserData || !loginUserData.userNumber) {
|
if (!loginUserData || !loginUserData.userNumber) {
|
||||||
console.error("fetchCurrentUserHomeTerms: userNumber is not available");
|
console.error('fetchCurrentUserHomeTerms: userNumber is not available');
|
||||||
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
||||||
return { success: false, message: "사용자 정보가 없습니다." };
|
return { success: false, message: '사용자 정보가 없습니다.' };
|
||||||
}
|
}
|
||||||
|
|
||||||
const mbrNo = loginUserData.userNumber;
|
const mbrNo = loginUserData.userNumber;
|
||||||
const trmsTpCdList = "MST00401, MST00402, MST00405";
|
const trmsTpCdList = 'MST00401, MST00402, MST00405';
|
||||||
|
|
||||||
console.log("Fetching home terms for user:", mbrNo);
|
console.log('Fetching home terms for user:', mbrNo);
|
||||||
|
|
||||||
// 안전한 API 호출 (기존 TAxios 패턴과 동일)
|
// 안전한 API 호출 (기존 TAxios 패턴과 동일)
|
||||||
const result = await TAxiosPromise(
|
const result = await TAxiosPromise(dispatch, getState, 'get', URLS.GET_HOME_TERMS, {
|
||||||
dispatch,
|
trmsTpCdList,
|
||||||
getState,
|
mbrNo,
|
||||||
"get",
|
});
|
||||||
URLS.GET_HOME_TERMS,
|
|
||||||
{ trmsTpCdList, mbrNo }
|
|
||||||
);
|
|
||||||
|
|
||||||
// 네트워크 에러인 경우
|
// 네트워크 에러인 경우
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
console.error("fetchCurrentUserHomeTerms network error:", result.error);
|
console.error('fetchCurrentUserHomeTerms network error:', result.error);
|
||||||
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
||||||
return { success: false, message: "네트워크 오류가 발생했습니다." };
|
return { success: false, message: '네트워크 오류가 발생했습니다.' };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 기존 TAxios처럼 특별한 retCode들은 TAxios 내부에서 이미 처리됨
|
// 기존 TAxios처럼 특별한 retCode들은 TAxios 내부에서 이미 처리됨
|
||||||
// (401, 402, 501, 602, 603, 604 등은 TAxios에서 알아서 처리하고 onSuccess가 호출되지 않음)
|
// (401, 402, 501, 602, 603, 604 등은 TAxios에서 알아서 처리하고 onSuccess가 호출되지 않음)
|
||||||
|
|
||||||
console.log("fetchCurrentUserHomeTerms response:", result.data);
|
console.log('fetchCurrentUserHomeTerms response:', result.data);
|
||||||
|
|
||||||
// 정상적으로 onSuccess가 호출된 경우에만 여기까지 옴
|
// 정상적으로 onSuccess가 호출된 경우에만 여기까지 옴
|
||||||
if (result.data && result.data.retCode === 0) {
|
if (result.data && result.data.retCode === 0) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.GET_HOME_TERMS,
|
type: types.GET_HOME_TERMS,
|
||||||
payload: result.data,
|
payload: result.data,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 약관 ID 매핑을 별도로 생성하여 저장
|
// 약관 ID 매핑을 별도로 생성하여 저장
|
||||||
// Chromium68 호환성을 위해 Optional Chaining 제거
|
// Chromium68 호환성을 위해 Optional Chaining 제거
|
||||||
if (result.data && result.data.data && result.data.data.terms) {
|
if (result.data && result.data.data && result.data.data.terms) {
|
||||||
const termsIdMap = {};
|
const termsIdMap = {};
|
||||||
let hasOptionalTerms = false; // MST00405 존재 여부 확인
|
let hasOptionalTerms = false; // MST00405 존재 여부 확인
|
||||||
|
|
||||||
result.data.data.terms.forEach(term => {
|
result.data.data.terms.forEach((term) => {
|
||||||
if (term.trmsTpCd && term.trmsId) {
|
if (term.trmsTpCd && term.trmsId) {
|
||||||
termsIdMap[term.trmsTpCd] = term.trmsId;
|
termsIdMap[term.trmsTpCd] = term.trmsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MST00405 선택약관 존재 여부 확인
|
// MST00405 선택약관 존재 여부 확인
|
||||||
if (term.trmsTpCd === "MST00405") {
|
if (term.trmsTpCd === 'MST00405') {
|
||||||
hasOptionalTerms = true;
|
hasOptionalTerms = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.SET_TERMS_ID_MAP,
|
type: types.SET_TERMS_ID_MAP,
|
||||||
payload: termsIdMap,
|
payload: termsIdMap,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 선택약관 존재 여부 상태 설정 2025-07-03
|
// 선택약관 존재 여부 상태 설정 2025-07-03
|
||||||
// TODO: 테스트용 - 임시로 false 강제 설정
|
// TODO: 테스트용 - 임시로 false 강제 설정
|
||||||
const forceDisableOptionalTerms = false; // 테스트 완료 후 false로 변경
|
const forceDisableOptionalTerms = false; // 테스트 완료 후 false로 변경
|
||||||
const finalOptionalTermsValue = forceDisableOptionalTerms ? false : hasOptionalTerms;
|
const finalOptionalTermsValue = forceDisableOptionalTerms ? false : hasOptionalTerms;
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.SET_OPTIONAL_TERMS_AVAILABILITY,
|
type: types.SET_OPTIONAL_TERMS_AVAILABILITY,
|
||||||
payload: finalOptionalTermsValue,
|
payload: finalOptionalTermsValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
console.log("약관 ID 매핑 생성:", termsIdMap);
|
console.log('약관 ID 매핑 생성:', termsIdMap);
|
||||||
console.log("선택약관 존재 여부 - 실제값:", hasOptionalTerms, "강제설정값:", finalOptionalTermsValue);
|
console.log(
|
||||||
|
'선택약관 존재 여부 - 실제값:',
|
||||||
|
hasOptionalTerms,
|
||||||
|
'강제설정값:',
|
||||||
|
finalOptionalTermsValue
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 후속 액션 호출 (기존과 동일)
|
// 후속 액션 호출 (기존과 동일)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
dispatch(getTermsAgreeYn());
|
dispatch(getTermsAgreeYn());
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
return { success: true, data: result.data };
|
return { success: true, data: result.data };
|
||||||
} else {
|
} else {
|
||||||
// retCode가 0이 아닌 일반적인 API 에러
|
// retCode가 0이 아닌 일반적인 API 에러
|
||||||
// Chromium68 호환성을 위해 Optional Chaining 제거
|
// Chromium68 호환성을 위해 Optional Chaining 제거
|
||||||
console.error("API returned non-zero retCode:", result.data && result.data.retCode);
|
console.error('API returned non-zero retCode:', result.data && result.data.retCode);
|
||||||
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: (result.data && result.data.retMsg) || "서버 오류가 발생했습니다."
|
message: (result.data && result.data.retMsg) || '서버 오류가 발생했습니다.',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 메뉴 목록 조회 IF-LGSP-044
|
// 메뉴 목록 조회 IF-LGSP-044
|
||||||
export const getHomeMenu = () => (dispatch, getState) => {
|
export const getHomeMenu = () => (dispatch, getState) => {
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("getHomeMenu onSuccess ", response.data);
|
// console.log("getHomeMenu onSuccess ", response.data);
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.GET_HOME_MENU,
|
type: types.GET_HOME_MENU,
|
||||||
@@ -280,29 +292,20 @@ export const getHomeMenu = () => (dispatch, getState) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("getHomeMenu onFail ", error);
|
console.error('getHomeMenu onFail ', error);
|
||||||
};
|
};
|
||||||
|
|
||||||
TAxios(
|
TAxios(dispatch, getState, 'get', URLS.GET_HOME_MENU, {}, {}, onSuccess, onFail);
|
||||||
dispatch,
|
|
||||||
getState,
|
|
||||||
"get",
|
|
||||||
URLS.GET_HOME_MENU,
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
onSuccess,
|
|
||||||
onFail
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 테마 전시 정보 상세 조회 IF-LGSP-060
|
// 테마 전시 정보 상세 조회 IF-LGSP-060
|
||||||
export const getThemeCurationDetailInfo = (params) => (dispatch, getState) => {
|
export const getThemeCurationDetailInfo = (params) => (dispatch, getState) => {
|
||||||
const { patnrId, curationId, bgImgNo } = params;
|
const { patnrId, curationId, bgImgNo } = params;
|
||||||
|
|
||||||
dispatch(changeAppStatus({ showLoadingPanel: { show: true, type: "wait" } }));
|
dispatch(changeAppStatus({ showLoadingPanel: { show: true, type: 'wait' } }));
|
||||||
|
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("getThemeCurationDetailInfo onSuccess", response.data);
|
console.log('getThemeCurationDetailInfo onSuccess', response.data);
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.GET_THEME_CURATION_DETAIL_INFO,
|
type: types.GET_THEME_CURATION_DETAIL_INFO,
|
||||||
@@ -313,14 +316,14 @@ export const getThemeCurationDetailInfo = (params) => (dispatch, getState) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("getThemeCurationDetailInfo onFail", error);
|
console.error('getThemeCurationDetailInfo onFail', error);
|
||||||
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
||||||
};
|
};
|
||||||
|
|
||||||
TAxios(
|
TAxios(
|
||||||
dispatch,
|
dispatch,
|
||||||
getState,
|
getState,
|
||||||
"get",
|
'get',
|
||||||
URLS.GET_THEME_CURATION_DETAIL_INFO,
|
URLS.GET_THEME_CURATION_DETAIL_INFO,
|
||||||
{ patnrId, curationId, bgImgNo },
|
{ patnrId, curationId, bgImgNo },
|
||||||
{},
|
{},
|
||||||
@@ -332,10 +335,10 @@ export const getThemeCurationDetailInfo = (params) => (dispatch, getState) => {
|
|||||||
export const getThemeHotelDetailInfo = (params) => (dispatch, getState) => {
|
export const getThemeHotelDetailInfo = (params) => (dispatch, getState) => {
|
||||||
const { patnrId, curationId } = params;
|
const { patnrId, curationId } = params;
|
||||||
|
|
||||||
dispatch(changeAppStatus({ showLoadingPanel: { show: true, type: "wait" } }));
|
dispatch(changeAppStatus({ showLoadingPanel: { show: true, type: 'wait' } }));
|
||||||
|
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("getThemeHotelDetailInfo onSuccess", response.data);
|
console.log('getThemeHotelDetailInfo onSuccess', response.data);
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.GET_THEME_HOTEL_DETAIL_INFO,
|
type: types.GET_THEME_HOTEL_DETAIL_INFO,
|
||||||
@@ -346,14 +349,14 @@ export const getThemeHotelDetailInfo = (params) => (dispatch, getState) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("getThemeHotelDetailInfo onFail", error);
|
console.error('getThemeHotelDetailInfo onFail', error);
|
||||||
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
||||||
};
|
};
|
||||||
|
|
||||||
TAxios(
|
TAxios(
|
||||||
dispatch,
|
dispatch,
|
||||||
getState,
|
getState,
|
||||||
"get",
|
'get',
|
||||||
URLS.GET_THEME_HOTEL_DETAIL_INFO,
|
URLS.GET_THEME_HOTEL_DETAIL_INFO,
|
||||||
{ patnrId, curationId },
|
{ patnrId, curationId },
|
||||||
{},
|
{},
|
||||||
@@ -364,7 +367,7 @@ export const getThemeHotelDetailInfo = (params) => (dispatch, getState) => {
|
|||||||
// HOME LAYOUT 정보 조회 IF-LGSP-300
|
// HOME LAYOUT 정보 조회 IF-LGSP-300
|
||||||
export const getHomeLayout = () => (dispatch, getState) => {
|
export const getHomeLayout = () => (dispatch, getState) => {
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("getHomeLayout onSuccess", response.data);
|
console.log('getHomeLayout onSuccess', response.data);
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.GET_HOME_LAYOUT,
|
type: types.GET_HOME_LAYOUT,
|
||||||
@@ -374,57 +377,39 @@ export const getHomeLayout = () => (dispatch, getState) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("getHomeLayout onFail", error);
|
console.error('getHomeLayout onFail', error);
|
||||||
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
||||||
};
|
};
|
||||||
|
|
||||||
TAxios(
|
TAxios(dispatch, getState, 'get', URLS.GET_HOME_LAYOUT, {}, {}, onSuccess, onFail);
|
||||||
dispatch,
|
|
||||||
getState,
|
|
||||||
"get",
|
|
||||||
URLS.GET_HOME_LAYOUT,
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
onSuccess,
|
|
||||||
onFail
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// HOME Main Contents Banner 정보 조회 IF-LGSP-301
|
// HOME Main Contents Banner 정보 조회 IF-LGSP-301
|
||||||
export const getHomeMainContents = () => (dispatch, getState) => {
|
export const getHomeMainContents = () => (dispatch, getState) => {
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("getHomeMainContents onSuccess", response.data);
|
console.log('getHomeMainContents onSuccess', response.data);
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.GET_HOME_MAIN_CONTENTS,
|
type: types.GET_HOME_MAIN_CONTENTS,
|
||||||
payload: response.data.data,
|
payload: response.data.data,
|
||||||
status: "fulfilled",
|
status: 'fulfilled',
|
||||||
});
|
});
|
||||||
|
|
||||||
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("getHomeMainContents onFail", error);
|
console.error('getHomeMainContents onFail', error);
|
||||||
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
||||||
};
|
};
|
||||||
|
|
||||||
TAxios(
|
TAxios(dispatch, getState, 'get', URLS.GET_HOME_MAIN_CONTENTS, {}, {}, onSuccess, onFail);
|
||||||
dispatch,
|
|
||||||
getState,
|
|
||||||
"get",
|
|
||||||
URLS.GET_HOME_MAIN_CONTENTS,
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
onSuccess,
|
|
||||||
onFail
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Theme 전시 정보 조회 : IF-LGSP-045
|
// Theme 전시 정보 조회 : IF-LGSP-045
|
||||||
export const getThemeCurationInfo = () => (dispatch, getState) => {
|
export const getThemeCurationInfo = () => (dispatch, getState) => {
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("getThemeCurationInfo onSuccess", response.data);
|
console.log('getThemeCurationInfo onSuccess', response.data);
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.GET_THEME_CURATION_INFO,
|
type: types.GET_THEME_CURATION_INFO,
|
||||||
@@ -435,30 +420,21 @@ export const getThemeCurationInfo = () => (dispatch, getState) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("getThemeCurationInfo onFail", error);
|
console.error('getThemeCurationInfo onFail', error);
|
||||||
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
||||||
};
|
};
|
||||||
|
|
||||||
TAxios(
|
TAxios(dispatch, getState, 'get', URLS.GET_THEME_CURATION_INFO, {}, {}, onSuccess, onFail);
|
||||||
dispatch,
|
|
||||||
getState,
|
|
||||||
"get",
|
|
||||||
URLS.GET_THEME_CURATION_INFO,
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
onSuccess,
|
|
||||||
onFail
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 테마 메뉴(=테마 페이지) 선반 조회 : IF-LGSP-095
|
// 테마 메뉴(=테마 페이지) 선반 조회 : IF-LGSP-095
|
||||||
export const getThemeMenuShelfInfo = (props) => (dispatch, getState) => {
|
export const getThemeMenuShelfInfo = (props) => (dispatch, getState) => {
|
||||||
const { curationId } = props;
|
const { curationId } = props;
|
||||||
|
|
||||||
dispatch(changeAppStatus({ showLoadingPanel: { show: true, type: "wait" } }));
|
dispatch(changeAppStatus({ showLoadingPanel: { show: true, type: 'wait' } }));
|
||||||
|
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log("getThemeMenuShelfInfo onSuccess", response.data);
|
console.log('getThemeMenuShelfInfo onSuccess', response.data);
|
||||||
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.GET_THEME_MENU_SHELF_INFO,
|
type: types.GET_THEME_MENU_SHELF_INFO,
|
||||||
@@ -467,14 +443,14 @@ export const getThemeMenuShelfInfo = (props) => (dispatch, getState) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
console.error("getThemeMenuShelfInfo onFail", error);
|
console.error('getThemeMenuShelfInfo onFail', error);
|
||||||
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
||||||
};
|
};
|
||||||
|
|
||||||
TAxios(
|
TAxios(
|
||||||
dispatch,
|
dispatch,
|
||||||
getState,
|
getState,
|
||||||
"get",
|
'get',
|
||||||
URLS.GET_THEME_MENU_SHELF_INFO,
|
URLS.GET_THEME_MENU_SHELF_INFO,
|
||||||
{ curationId },
|
{ curationId },
|
||||||
{},
|
{},
|
||||||
@@ -514,8 +490,8 @@ export const checkEnterThroughGNB = (boolean) => ({
|
|||||||
|
|
||||||
export const setBannerIndex = (bannerId, index) => {
|
export const setBannerIndex = (bannerId, index) => {
|
||||||
if (!bannerId) {
|
if (!bannerId) {
|
||||||
console.warn("setBannerIndex called with undefined bannerId");
|
console.warn('setBannerIndex called with undefined bannerId');
|
||||||
return { type: "NO_OP" };
|
return { type: 'NO_OP' };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
type: types.SET_BANNER_INDEX,
|
type: types.SET_BANNER_INDEX,
|
||||||
@@ -568,11 +544,11 @@ export const collectAndSaveBannerPositions = (bannerIds) => async (dispatch) =>
|
|||||||
try {
|
try {
|
||||||
const positions = await collectBannerPositions(bannerIds);
|
const positions = await collectBannerPositions(bannerIds);
|
||||||
dispatch(setBannerPositions(positions));
|
dispatch(setBannerPositions(positions));
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
console.log("[homeActions] 배너 위치 수집 완료:", positions);
|
console.log('[homeActions] 배너 위치 수집 완료:', positions);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[homeActions] 배너 위치 수집 실패:", error);
|
console.error('[homeActions] 배너 위치 수집 실패:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,18 +1,10 @@
|
|||||||
import { URLS } from '../api/apiConfig';
|
import { URLS } from '../api/apiConfig';
|
||||||
import { TAxios } from '../api/TAxios';
|
import { TAxios } from '../api/TAxios';
|
||||||
import { convertUtcToLocal } from '../components/MediaPlayer/util';
|
import { convertUtcToLocal } from '../components/MediaPlayer/util';
|
||||||
import {
|
import { CATEGORY_DATA_MAX_RESULTS_LIMIT, LOG_CONTEXT_NAME, LOG_MESSAGE_ID } from '../utils/Config';
|
||||||
CATEGORY_DATA_MAX_RESULTS_LIMIT,
|
|
||||||
LOG_CONTEXT_NAME,
|
|
||||||
LOG_MESSAGE_ID,
|
|
||||||
} from '../utils/Config';
|
|
||||||
import * as HelperMethods from '../utils/helperMethods';
|
import * as HelperMethods from '../utils/helperMethods';
|
||||||
import { types } from './actionTypes';
|
import { types } from './actionTypes';
|
||||||
import {
|
import { addReservation, changeAppStatus, deleteReservation } from './commonActions';
|
||||||
addReservation,
|
|
||||||
changeAppStatus,
|
|
||||||
deleteReservation,
|
|
||||||
} from './commonActions';
|
|
||||||
|
|
||||||
//IF-LGSP-007
|
//IF-LGSP-007
|
||||||
export const getMainLiveShow = (props) => (dispatch, getState) => {
|
export const getMainLiveShow = (props) => (dispatch, getState) => {
|
||||||
@@ -233,7 +225,7 @@ export const getSubCategory =
|
|||||||
getState,
|
getState,
|
||||||
'get',
|
'get',
|
||||||
URLS.GET_SUB_CATEGORY,
|
URLS.GET_SUB_CATEGORY,
|
||||||
{ lgCatCd, patnrIdList, pageSize, pageNo, tabType, filterType,recommendIncFlag },
|
{ lgCatCd, patnrIdList, pageSize, pageNo, tabType, filterType, recommendIncFlag },
|
||||||
{},
|
{},
|
||||||
onSuccess,
|
onSuccess,
|
||||||
onFail
|
onFail
|
||||||
@@ -435,7 +427,7 @@ export const getMainLiveShowNowProduct =
|
|||||||
({ patnrId, showId, lstChgDt }) =>
|
({ patnrId, showId, lstChgDt }) =>
|
||||||
(dispatch, getState) => {
|
(dispatch, getState) => {
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
console.log('getMainLiveShowNowProduct onSuccess', response.data);
|
// console.log('getMainLiveShowNowProduct onSuccess', response.data);
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.GET_MAIN_LIVE_SHOW_NOW_PRODUCT,
|
type: types.GET_MAIN_LIVE_SHOW_NOW_PRODUCT,
|
||||||
|
|||||||
@@ -169,15 +169,15 @@ export const getProductOption = createGetThunk({
|
|||||||
// IF-LGSP-101용 API 응답에서 reviewList + reviewDetail 추출
|
// IF-LGSP-101용 API 응답에서 reviewList + reviewDetail 추출
|
||||||
const extractReviewListApiData = (apiResponse) => {
|
const extractReviewListApiData = (apiResponse) => {
|
||||||
try {
|
try {
|
||||||
console.log('[UserReviewList] 📥 extractReviewListApiData 호출 - 원본 응답:', apiResponse);
|
// console.log('[UserReviewList] 📥 extractReviewListApiData 호출 - 원본 응답:', apiResponse);
|
||||||
|
|
||||||
// ⭐ 핵심: retCode가 0인지 먼저 확인 (HTTP 200이어도 API 에러일 수 있음)
|
// ⭐ 핵심: retCode가 0인지 먼저 확인 (HTTP 200이어도 API 에러일 수 있음)
|
||||||
if (apiResponse && apiResponse.retCode !== 0) {
|
if (apiResponse && apiResponse.retCode !== 0) {
|
||||||
console.error('[UserReviewList] ❌ API 에러 - retCode !== 0:', {
|
// console.error('[UserReviewList] ❌ API 에러 - retCode !== 0:', {
|
||||||
retCode: apiResponse.retCode,
|
// retCode: apiResponse.retCode,
|
||||||
retMsg: apiResponse.retMsg,
|
// retMsg: apiResponse.retMsg,
|
||||||
fullResponse: apiResponse
|
// fullResponse: apiResponse
|
||||||
});
|
// });
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,59 +193,67 @@ const extractReviewListApiData = (apiResponse) => {
|
|||||||
const reviewDetail = apiData.reviewDetail || {};
|
const reviewDetail = apiData.reviewDetail || {};
|
||||||
|
|
||||||
// reviewDetail.reviewList에 실제 데이터가 있으면 사용
|
// reviewDetail.reviewList에 실제 데이터가 있으면 사용
|
||||||
if (reviewDetail.reviewList && Array.isArray(reviewDetail.reviewList) && reviewList.length === 0) {
|
if (
|
||||||
|
reviewDetail.reviewList &&
|
||||||
|
Array.isArray(reviewDetail.reviewList) &&
|
||||||
|
reviewList.length === 0
|
||||||
|
) {
|
||||||
reviewList = reviewDetail.reviewList;
|
reviewList = reviewDetail.reviewList;
|
||||||
console.log('[UserReviewList] 🔄 reviewDetail.reviewList에서 데이터 추출됨');
|
// console.log('[UserReviewList] 🔄 reviewDetail.reviewList에서 데이터 추출됨');
|
||||||
}
|
}
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
reviewList: reviewList,
|
reviewList: reviewList,
|
||||||
reviewDetail: reviewDetail
|
reviewDetail: reviewDetail,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('[UserReviewList] 📊 apiResponse.data 경로에서 추출:', {
|
// console.log('[UserReviewList] 📊 apiResponse.data 경로에서 추출:', {
|
||||||
reviewListLength: data.reviewList.length,
|
// reviewListLength: data.reviewList.length,
|
||||||
reviewDetailKeys: Object.keys(data.reviewDetail),
|
// reviewDetailKeys: Object.keys(data.reviewDetail),
|
||||||
reviewDetail: data.reviewDetail,
|
// reviewDetail: data.reviewDetail,
|
||||||
reviewListSample: data.reviewList.length > 0 ? data.reviewList[0] : 'empty'
|
// reviewListSample: data.reviewList.length > 0 ? data.reviewList[0] : 'empty'
|
||||||
});
|
// });
|
||||||
} else if (apiResponse) {
|
} else if (apiResponse) {
|
||||||
// 직접 경로에서 추출
|
// 직접 경로에서 추출
|
||||||
let reviewList = apiResponse.reviewList || [];
|
let reviewList = apiResponse.reviewList || [];
|
||||||
const reviewDetail = apiResponse.reviewDetail || {};
|
const reviewDetail = apiResponse.reviewDetail || {};
|
||||||
|
|
||||||
// reviewDetail.reviewList에 실제 데이터가 있으면 사용
|
// reviewDetail.reviewList에 실제 데이터가 있으면 사용
|
||||||
if (reviewDetail.reviewList && Array.isArray(reviewDetail.reviewList) && reviewList.length === 0) {
|
if (
|
||||||
|
reviewDetail.reviewList &&
|
||||||
|
Array.isArray(reviewDetail.reviewList) &&
|
||||||
|
reviewList.length === 0
|
||||||
|
) {
|
||||||
reviewList = reviewDetail.reviewList;
|
reviewList = reviewDetail.reviewList;
|
||||||
console.log('[UserReviewList] 🔄 reviewDetail.reviewList에서 데이터 추출됨');
|
// console.log('[UserReviewList] 🔄 reviewDetail.reviewList에서 데이터 추출됨');
|
||||||
}
|
}
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
reviewList: reviewList,
|
reviewList: reviewList,
|
||||||
reviewDetail: reviewDetail
|
reviewDetail: reviewDetail,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('[UserReviewList] 📊 직접 경로에서 추출:', {
|
// console.log('[UserReviewList] 📊 직접 경로에서 추출:', {
|
||||||
reviewListLength: data.reviewList.length,
|
// reviewListLength: data.reviewList.length,
|
||||||
reviewDetailKeys: Object.keys(data.reviewDetail),
|
// reviewDetailKeys: Object.keys(data.reviewDetail),
|
||||||
reviewDetail: data.reviewDetail,
|
// reviewDetail: data.reviewDetail,
|
||||||
reviewListSample: data.reviewList.length > 0 ? data.reviewList[0] : 'empty'
|
// reviewListSample: data.reviewList.length > 0 ? data.reviewList[0] : 'empty'
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data || (!data.reviewList && !data.reviewDetail)) {
|
if (!data || (!data.reviewList && !data.reviewDetail)) {
|
||||||
console.warn('[UserReviewList] ⚠️ reviewList와 reviewDetail 모두 없음:', apiResponse);
|
// console.warn('[UserReviewList] ⚠️ reviewList와 reviewDetail 모두 없음:', apiResponse);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[UserReviewList] ✅ 추출 완료:', {
|
// console.log('[UserReviewList] ✅ 추출 완료:', {
|
||||||
reviewListLength: data.reviewList.length,
|
// reviewListLength: data.reviewList.length,
|
||||||
reviewDetail: data.reviewDetail
|
// reviewDetail: data.reviewDetail
|
||||||
});
|
// });
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[UserReviewList] ❌ extractReviewListApiData 에러:', error);
|
// console.error('[UserReviewList] ❌ extractReviewListApiData 에러:', error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -367,7 +375,12 @@ export const getVideoIndicatorFocus = (focused) => (dispatch) => {
|
|||||||
// 순차 페이징으로 모든 리뷰 데이터를 수집하는 함수 (TV 앱 성능 최적화)
|
// 순차 페이징으로 모든 리뷰 데이터를 수집하는 함수 (TV 앱 성능 최적화)
|
||||||
// Option 2: 순차 페칭 (메모리 효율, 서버 부하 감소)
|
// Option 2: 순차 페칭 (메모리 효율, 서버 부하 감소)
|
||||||
// ⭐ 재시도 로직 포함: 타임아웃/미응답 케이스 대비
|
// ⭐ 재시도 로직 포함: 타임아웃/미응답 케이스 대비
|
||||||
const fetchAllReviewsWithSequentialPaging = async (dispatch, getState, requestParams, retryCount = 0) => {
|
const fetchAllReviewsWithSequentialPaging = async (
|
||||||
|
dispatch,
|
||||||
|
getState,
|
||||||
|
requestParams,
|
||||||
|
retryCount = 0
|
||||||
|
) => {
|
||||||
const MAX_RETRIES = 2; // 최대 2회 재시도 (총 3회 시도)
|
const MAX_RETRIES = 2; // 최대 2회 재시도 (총 3회 시도)
|
||||||
const {
|
const {
|
||||||
prdtId,
|
prdtId,
|
||||||
@@ -377,15 +390,15 @@ const fetchAllReviewsWithSequentialPaging = async (dispatch, getState, requestPa
|
|||||||
pageSize = 100, // 최대값으로 설정하여 페이징 횟수 최소화
|
pageSize = 100, // 최대값으로 설정하여 페이징 횟수 최소화
|
||||||
} = requestParams;
|
} = requestParams;
|
||||||
|
|
||||||
console.log('[UserReviewList] 🚀 순차 페이징 시작:', {
|
// console.log('[UserReviewList] 🚀 순차 페이징 시작:', {
|
||||||
prdtId,
|
// prdtId,
|
||||||
patnrId,
|
// patnrId,
|
||||||
filterTpCd,
|
// filterTpCd,
|
||||||
filterTpVal,
|
// filterTpVal,
|
||||||
pageSize,
|
// pageSize,
|
||||||
retryCount,
|
// retryCount,
|
||||||
isRetry: retryCount > 0
|
// isRetry: retryCount > 0
|
||||||
});
|
// });
|
||||||
|
|
||||||
let allReviews = [];
|
let allReviews = [];
|
||||||
let currentReviewDetail = null;
|
let currentReviewDetail = null;
|
||||||
@@ -401,13 +414,13 @@ const fetchAllReviewsWithSequentialPaging = async (dispatch, getState, requestPa
|
|||||||
filterTpCd,
|
filterTpCd,
|
||||||
pageSize,
|
pageSize,
|
||||||
pageNo,
|
pageNo,
|
||||||
cntryCd: 'US'
|
cntryCd: 'US',
|
||||||
};
|
};
|
||||||
|
|
||||||
// filterTpCd가 'ALL'이 아니면 filterTpVal 추가
|
// filterTpCd가 'ALL'이 아니면 filterTpVal 추가
|
||||||
if (filterTpCd !== 'ALL') {
|
if (filterTpCd !== 'ALL') {
|
||||||
if (!filterTpVal) {
|
if (!filterTpVal) {
|
||||||
console.warn('[UserReviewList] ⚠️ filterTpCd가 ALL이 아니면 filterTpVal은 필수입니다');
|
// console.warn('[UserReviewList] ⚠️ filterTpCd가 ALL이 아니면 filterTpVal은 필수입니다');
|
||||||
}
|
}
|
||||||
params.filterTpVal = filterTpVal;
|
params.filterTpVal = filterTpVal;
|
||||||
}
|
}
|
||||||
@@ -416,13 +429,13 @@ const fetchAllReviewsWithSequentialPaging = async (dispatch, getState, requestPa
|
|||||||
// ⭐ 타임아웃 추가: TAxios의 콜백이 호출되지 않는 경우를 대비 (모든 오류 상황 처리)
|
// ⭐ 타임아웃 추가: TAxios의 콜백이 호출되지 않는 경우를 대비 (모든 오류 상황 처리)
|
||||||
const REQUEST_TIMEOUT = 5000; // 5초 타임아웃 (재인증, 팝업 등 오류 상황 처리 포함)
|
const REQUEST_TIMEOUT = 5000; // 5초 타임아웃 (재인증, 팝업 등 오류 상황 처리 포함)
|
||||||
|
|
||||||
console.log(`[UserReviewList] 🔄 API 요청 시작 (page ${pageNo}):`, {
|
// console.log(`[UserReviewList] 🔄 API 요청 시작 (page ${pageNo}):`, {
|
||||||
prdtId,
|
// prdtId,
|
||||||
patnrId,
|
// patnrId,
|
||||||
filterTpCd,
|
// filterTpCd,
|
||||||
pageSize,
|
// pageSize,
|
||||||
pageNo
|
// pageNo
|
||||||
});
|
// });
|
||||||
|
|
||||||
const response = await Promise.race([
|
const response = await Promise.race([
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
@@ -430,80 +443,89 @@ const fetchAllReviewsWithSequentialPaging = async (dispatch, getState, requestPa
|
|||||||
|
|
||||||
const onSuccess = (res) => {
|
const onSuccess = (res) => {
|
||||||
if (callbackCalled) {
|
if (callbackCalled) {
|
||||||
console.warn(`[UserReviewList] ⚠️ onSuccess 중복 호출 (page ${pageNo})`);
|
// console.warn(`[UserReviewList] ⚠️ onSuccess 중복 호출 (page ${pageNo})`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callbackCalled = true;
|
callbackCalled = true;
|
||||||
|
|
||||||
console.log(`[UserReviewList] ✅ API 응답 수신 (page ${pageNo}):`, {
|
// console.log(`[UserReviewList] ✅ API 응답 수신 (page ${pageNo}):`, {
|
||||||
status: res?.status,
|
// status: res?.status,
|
||||||
statusText: res?.statusText,
|
// statusText: res?.statusText,
|
||||||
retCode: res?.data?.retCode,
|
// retCode: res?.data?.retCode,
|
||||||
dataExists: !!res?.data,
|
// dataExists: !!res?.data,
|
||||||
reviewDetailExists: !!res?.data?.data?.reviewDetail
|
// reviewDetailExists: !!res?.data?.data?.reviewDetail
|
||||||
});
|
// });
|
||||||
resolve(res);
|
resolve(res);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (err) => {
|
const onFail = (err) => {
|
||||||
if (callbackCalled) {
|
if (callbackCalled) {
|
||||||
console.warn(`[UserReviewList] ⚠️ onFail 중복 호출 (page ${pageNo})`);
|
// console.warn(`[UserReviewList] ⚠️ onFail 중복 호출 (page ${pageNo})`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callbackCalled = true;
|
callbackCalled = true;
|
||||||
|
|
||||||
console.error(`[UserReviewList] ❌ API 콜백 에러 발생 (page ${pageNo}):`, {
|
// console.error(`[UserReviewList] ❌ API 콜백 에러 발생 (page ${pageNo}):`, {
|
||||||
errorMessage: err?.message,
|
// errorMessage: err?.message,
|
||||||
errorStatus: err?.response?.status,
|
// errorStatus: err?.response?.status,
|
||||||
errorStatusText: err?.response?.statusText,
|
// errorStatusText: err?.response?.statusText,
|
||||||
errorRetCode: err?.data?.retCode,
|
// errorRetCode: err?.data?.retCode,
|
||||||
errorRetMsg: err?.data?.retMsg,
|
// errorRetMsg: err?.data?.retMsg,
|
||||||
errorType: typeof err
|
// errorType: typeof err
|
||||||
});
|
// });
|
||||||
reject(err);
|
reject(err);
|
||||||
};
|
};
|
||||||
|
|
||||||
// API 호출
|
// API 호출
|
||||||
console.log(`[UserReviewList] 📡 TAxios 호출 (page ${pageNo})`);
|
// console.log(`[UserReviewList] 📡 TAxios 호출 (page ${pageNo})`);
|
||||||
TAxios(dispatch, getState, 'get', URLS.GET_USER_REVIEW_LIST, params, {}, onSuccess, onFail);
|
TAxios(
|
||||||
|
dispatch,
|
||||||
|
getState,
|
||||||
|
'get',
|
||||||
|
URLS.GET_USER_REVIEW_LIST,
|
||||||
|
params,
|
||||||
|
{},
|
||||||
|
onSuccess,
|
||||||
|
onFail
|
||||||
|
);
|
||||||
}),
|
}),
|
||||||
// 타임아웃 Promise (onFail이 호출되지 않은 경우에 대비)
|
// 타임아웃 Promise (onFail이 호출되지 않은 경우에 대비)
|
||||||
new Promise((_, reject) =>
|
new Promise((_, reject) =>
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const timeoutError = new Error(`API request timeout without callback (page ${pageNo})`);
|
const timeoutError = new Error(`API request timeout without callback (page ${pageNo})`);
|
||||||
console.error(`[UserReviewList] ⏱️ API 응답 타임아웃 (page ${pageNo}):`, {
|
// console.error(`[UserReviewList] ⏱️ API 응답 타임아웃 (page ${pageNo}):`, {
|
||||||
timeout: REQUEST_TIMEOUT,
|
// timeout: REQUEST_TIMEOUT,
|
||||||
prdtId,
|
// prdtId,
|
||||||
patnrId,
|
// patnrId,
|
||||||
pageNo,
|
// pageNo,
|
||||||
reason: '5초 이내 onSuccess/onFail 콜백이 호출되지 않음'
|
// reason: '5초 이내 onSuccess/onFail 콜백이 호출되지 않음'
|
||||||
});
|
// });
|
||||||
reject(timeoutError);
|
reject(timeoutError);
|
||||||
}, REQUEST_TIMEOUT)
|
}, REQUEST_TIMEOUT)
|
||||||
)
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// ⭐ 핵심: HTTP 200이어도 response.data.retCode를 반드시 확인해야 함
|
// ⭐ 핵심: HTTP 200이어도 response.data.retCode를 반드시 확인해야 함
|
||||||
const retCode = response?.data?.retCode;
|
const retCode = response?.data?.retCode;
|
||||||
|
|
||||||
console.log(`[UserReviewList] 📄 페이지 ${pageNo} 응답 상태 확인:`, {
|
// console.log(`[UserReviewList] 📄 페이지 ${pageNo} 응답 상태 확인:`, {
|
||||||
pageNo,
|
// pageNo,
|
||||||
httpStatus: response?.status,
|
// httpStatus: response?.status,
|
||||||
retCode: retCode,
|
// retCode: retCode,
|
||||||
retMsg: response?.data?.retMsg,
|
// retMsg: response?.data?.retMsg,
|
||||||
reviewListLength: response?.data?.data?.reviewDetail?.reviewList?.length || 0,
|
// reviewListLength: response?.data?.data?.reviewDetail?.reviewList?.length || 0,
|
||||||
totRvwCnt: response?.data?.data?.reviewDetail?.totRvwCnt
|
// totRvwCnt: response?.data?.data?.reviewDetail?.totRvwCnt
|
||||||
});
|
// });
|
||||||
|
|
||||||
// retCode가 0이 아니면 API 에러 (HTTP 200이어도 실제 데이터 없을 수 있음)
|
// retCode가 0이 아니면 API 에러 (HTTP 200이어도 실제 데이터 없을 수 있음)
|
||||||
if (retCode !== 0) {
|
if (retCode !== 0) {
|
||||||
console.error(`[UserReviewList] ❌ API 에러 - retCode !== 0 (page ${pageNo}):`, {
|
// console.error(`[UserReviewList] ❌ API 에러 - retCode !== 0 (page ${pageNo}):`, {
|
||||||
retCode,
|
// retCode,
|
||||||
retMsg: response?.data?.retMsg,
|
// retMsg: response?.data?.retMsg,
|
||||||
pageNo,
|
// pageNo,
|
||||||
prdtId,
|
// prdtId,
|
||||||
totalCollected: allReviews.length
|
// totalCollected: allReviews.length
|
||||||
});
|
// });
|
||||||
throw new Error(`API Error: retCode=${retCode}, message=${response?.data?.retMsg}`);
|
throw new Error(`API Error: retCode=${retCode}, message=${response?.data?.retMsg}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,7 +533,7 @@ const fetchAllReviewsWithSequentialPaging = async (dispatch, getState, requestPa
|
|||||||
const reviewData = extractReviewListApiData(response.data);
|
const reviewData = extractReviewListApiData(response.data);
|
||||||
|
|
||||||
if (!reviewData || !reviewData.reviewList) {
|
if (!reviewData || !reviewData.reviewList) {
|
||||||
console.warn('[UserReviewList] ⚠️ 리뷰 데이터 추출 실패, 페이징 종료');
|
// console.warn('[UserReviewList] ⚠️ 리뷰 데이터 추출 실패, 페이징 종료');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,12 +545,12 @@ const fetchAllReviewsWithSequentialPaging = async (dispatch, getState, requestPa
|
|||||||
// 5. 현재 페이지의 리뷰들을 전체 리스트에 추가
|
// 5. 현재 페이지의 리뷰들을 전체 리스트에 추가
|
||||||
allReviews = allReviews.concat(reviewData.reviewList);
|
allReviews = allReviews.concat(reviewData.reviewList);
|
||||||
|
|
||||||
console.log(`[UserReviewList] ✅ 페이지 ${pageNo} 수집 완료:`, {
|
// console.log(`[UserReviewList] ✅ 페이지 ${pageNo} 수집 완료:`, {
|
||||||
pageNo,
|
// pageNo,
|
||||||
currentPageCount: reviewData.reviewList.length,
|
// currentPageCount: reviewData.reviewList.length,
|
||||||
totalCollected: allReviews.length,
|
// totalCollected: allReviews.length,
|
||||||
totRvwCnt: currentReviewDetail?.totRvwCnt
|
// totRvwCnt: currentReviewDetail?.totRvwCnt
|
||||||
});
|
// });
|
||||||
|
|
||||||
// 6. 페이징 종료 조건 확인
|
// 6. 페이징 종료 조건 확인
|
||||||
// rvwListCnt < pageSize이면 마지막 페이지
|
// rvwListCnt < pageSize이면 마지막 페이지
|
||||||
@@ -538,24 +560,24 @@ const fetchAllReviewsWithSequentialPaging = async (dispatch, getState, requestPa
|
|||||||
|
|
||||||
if (receivedCount < pageSize || allReviews.length >= totalReviews) {
|
if (receivedCount < pageSize || allReviews.length >= totalReviews) {
|
||||||
hasMore = false;
|
hasMore = false;
|
||||||
console.log('[UserReviewList] 📊 페이징 종료:', {
|
// console.log('[UserReviewList] 📊 페이징 종료:', {
|
||||||
reason: receivedCount < pageSize ? '받은 개수 < pageSize' : '수집된 개수 >= 총 개수',
|
// reason: receivedCount < pageSize ? '받은 개수 < pageSize' : '수집된 개수 >= 총 개수',
|
||||||
receivedCount,
|
// receivedCount,
|
||||||
pageSize,
|
// pageSize,
|
||||||
totalCollected: allReviews.length,
|
// totalCollected: allReviews.length,
|
||||||
totalReviews
|
// totalReviews
|
||||||
});
|
// });
|
||||||
} else {
|
} else {
|
||||||
pageNo++;
|
pageNo++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. 모든 리뷰 수집 완료, Redux에 디스패치
|
// 7. 모든 리뷰 수집 완료, Redux에 디스패치
|
||||||
console.log('[UserReviewList] 🎉 모든 리뷰 수집 완료:', {
|
// console.log('[UserReviewList] 🎉 모든 리뷰 수집 완료:', {
|
||||||
totalCollected: allReviews.length,
|
// totalCollected: allReviews.length,
|
||||||
totRvwCnt: currentReviewDetail?.totRvwCnt,
|
// totRvwCnt: currentReviewDetail?.totRvwCnt,
|
||||||
pages: pageNo - 1
|
// pages: pageNo - 1
|
||||||
});
|
// });
|
||||||
|
|
||||||
// Redux 디스패치를 위한 최종 데이터 구성
|
// Redux 디스패치를 위한 최종 데이터 구성
|
||||||
const isAllFilter = filterTpCd === 'ALL';
|
const isAllFilter = filterTpCd === 'ALL';
|
||||||
@@ -565,59 +587,61 @@ const fetchAllReviewsWithSequentialPaging = async (dispatch, getState, requestPa
|
|||||||
reviewList: allReviews,
|
reviewList: allReviews,
|
||||||
reviewDetail: currentReviewDetail,
|
reviewDetail: currentReviewDetail,
|
||||||
prdtId,
|
prdtId,
|
||||||
...(isAllFilter ? {} : { filterTpCd, filterTpVal })
|
...(isAllFilter ? {} : { filterTpCd, filterTpVal }),
|
||||||
};
|
};
|
||||||
|
|
||||||
const action = {
|
const action = {
|
||||||
type: actionType,
|
type: actionType,
|
||||||
payload: finalPayload
|
payload: finalPayload,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('[UserReviewList] 📦 Redux 디스패치:', {
|
// console.log('[UserReviewList] 📦 Redux 디스패치:', {
|
||||||
actionType,
|
// actionType,
|
||||||
totalReviews: allReviews.length,
|
// totalReviews: allReviews.length,
|
||||||
totRvwCnt: currentReviewDetail?.totRvwCnt,
|
// totRvwCnt: currentReviewDetail?.totRvwCnt,
|
||||||
prdtId
|
// prdtId
|
||||||
});
|
// });
|
||||||
|
|
||||||
dispatch(action);
|
dispatch(action);
|
||||||
|
|
||||||
return finalPayload;
|
return finalPayload;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// ⭐ 핵심: 다양한 형태의 에러를 안전하게 처리
|
// ⭐ 핵심: 다양한 형태의 에러를 안전하게 처리
|
||||||
const errorMessage = error?.message || (error instanceof Error ? error.toString() : JSON.stringify(error));
|
const errorMessage =
|
||||||
|
error?.message || (error instanceof Error ? error.toString() : JSON.stringify(error));
|
||||||
const httpStatus = error?.response?.status;
|
const httpStatus = error?.response?.status;
|
||||||
const apiRetCode = error?.response?.data?.retCode;
|
const apiRetCode = error?.response?.data?.retCode;
|
||||||
const apiRetMsg = error?.response?.data?.retMsg;
|
const apiRetMsg = error?.response?.data?.retMsg;
|
||||||
|
|
||||||
console.error('[fetchAllReviewsWithSequentialPaging] ❌ 에러 발생:', {
|
// console.error('[fetchAllReviewsWithSequentialPaging] ❌ 에러 발생:', {
|
||||||
errorMessage: errorMessage,
|
// errorMessage: errorMessage,
|
||||||
errorType: typeof error,
|
// errorType: typeof error,
|
||||||
httpStatus: httpStatus,
|
// httpStatus: httpStatus,
|
||||||
apiRetCode: apiRetCode,
|
// apiRetCode: apiRetCode,
|
||||||
apiRetMsg: apiRetMsg,
|
// apiRetMsg: apiRetMsg,
|
||||||
prdtId,
|
// prdtId,
|
||||||
patnrId,
|
// patnrId,
|
||||||
pageNo,
|
// pageNo,
|
||||||
currentCollected: allReviews.length,
|
// currentCollected: allReviews.length,
|
||||||
retryCount,
|
// retryCount,
|
||||||
maxRetries: MAX_RETRIES
|
// maxRetries: MAX_RETRIES
|
||||||
});
|
// });
|
||||||
|
|
||||||
// ⭐ 타임아웃 에러인 경우 재시도
|
// ⭐ 타임아웃 에러인 경우 재시도
|
||||||
const isTimeoutError = errorMessage.includes('timeout') || errorMessage.includes('without callback');
|
const isTimeoutError =
|
||||||
|
errorMessage.includes('timeout') || errorMessage.includes('without callback');
|
||||||
if (isTimeoutError && retryCount < MAX_RETRIES) {
|
if (isTimeoutError && retryCount < MAX_RETRIES) {
|
||||||
console.log(`[fetchAllReviewsWithSequentialPaging] 🔄 타임아웃으로 인한 재시도 (${retryCount + 1}/${MAX_RETRIES}):`, {
|
// console.log(`[fetchAllReviewsWithSequentialPaging] 🔄 타임아웃으로 인한 재시도 (${retryCount + 1}/${MAX_RETRIES}):`, {
|
||||||
prdtId,
|
// prdtId,
|
||||||
patnrId,
|
// patnrId,
|
||||||
pageNo,
|
// pageNo,
|
||||||
retryCount,
|
// retryCount,
|
||||||
delayMs: 1000 * (retryCount + 1)
|
// delayMs: 1000 * (retryCount + 1)
|
||||||
});
|
// });
|
||||||
|
|
||||||
// 지수 백오프: 1초, 2초 대기 후 재시도
|
// 지수 백오프: 1초, 2초 대기 후 재시도
|
||||||
const delayMs = 1000 * (retryCount + 1);
|
const delayMs = 1000 * (retryCount + 1);
|
||||||
await new Promise(resolve => setTimeout(resolve, delayMs));
|
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
||||||
|
|
||||||
// 재귀 호출로 재시도
|
// 재귀 호출로 재시도
|
||||||
return fetchAllReviewsWithSequentialPaging(dispatch, getState, requestParams, retryCount + 1);
|
return fetchAllReviewsWithSequentialPaging(dispatch, getState, requestParams, retryCount + 1);
|
||||||
@@ -630,51 +654,47 @@ const fetchAllReviewsWithSequentialPaging = async (dispatch, getState, requestPa
|
|||||||
|
|
||||||
// User Review List 추가 조회 IF-LGSP-101 (순차 페이징으로 모든 데이터 수집)
|
// User Review List 추가 조회 IF-LGSP-101 (순차 페이징으로 모든 데이터 수집)
|
||||||
export const getUserReviewList = (requestParams) => async (dispatch, getState) => {
|
export const getUserReviewList = (requestParams) => async (dispatch, getState) => {
|
||||||
const {
|
const { prdtId, patnrId, filterTpCd = 'ALL', filterTpVal } = requestParams;
|
||||||
prdtId,
|
|
||||||
patnrId,
|
|
||||||
filterTpCd = 'ALL',
|
|
||||||
filterTpVal
|
|
||||||
} = requestParams;
|
|
||||||
|
|
||||||
console.log('[getUserReviewList] 🚀 getUserReviewList 호출됨 (순차 페이징 사용):', {
|
// console.log('[getUserReviewList] 🚀 getUserReviewList 호출됨 (순차 페이징 사용):', {
|
||||||
prdtId,
|
// prdtId,
|
||||||
patnrId,
|
// patnrId,
|
||||||
filterTpCd,
|
// filterTpCd,
|
||||||
filterTpVal,
|
// filterTpVal,
|
||||||
timestamp: new Date().toISOString()
|
// timestamp: new Date().toISOString()
|
||||||
});
|
// });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// fetchAllReviewsWithSequentialPaging 함수를 호출하여 모든 리뷰 수집
|
// fetchAllReviewsWithSequentialPaging 함수를 호출하여 모든 리뷰 수집
|
||||||
const result = await fetchAllReviewsWithSequentialPaging(dispatch, getState, requestParams);
|
const result = await fetchAllReviewsWithSequentialPaging(dispatch, getState, requestParams);
|
||||||
|
|
||||||
console.log('[getUserReviewList] ✅ 모든 리뷰 수집 완료:', {
|
// console.log('[getUserReviewList] ✅ 모든 리뷰 수집 완료:', {
|
||||||
totalReviews: result.reviewList.length,
|
// totalReviews: result.reviewList.length,
|
||||||
totRvwCnt: result.reviewDetail?.totRvwCnt,
|
// totRvwCnt: result.reviewDetail?.totRvwCnt,
|
||||||
prdtId,
|
// prdtId,
|
||||||
filterTpCd,
|
// filterTpCd,
|
||||||
filterTpVal
|
// filterTpVal
|
||||||
});
|
// });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// ⭐ 핵심: 다양한 형태의 에러를 안전하게 처리
|
// ⭐ 핵심: 다양한 형태의 에러를 안전하게 처리
|
||||||
const errorMessage = error?.message || (error instanceof Error ? error.toString() : JSON.stringify(error));
|
const errorMessage =
|
||||||
|
error?.message || (error instanceof Error ? error.toString() : JSON.stringify(error));
|
||||||
const httpStatus = error?.response?.status;
|
const httpStatus = error?.response?.status;
|
||||||
const apiRetCode = error?.response?.data?.retCode;
|
const apiRetCode = error?.response?.data?.retCode;
|
||||||
const apiRetMsg = error?.response?.data?.retMsg;
|
const apiRetMsg = error?.response?.data?.retMsg;
|
||||||
|
|
||||||
console.error('[getUserReviewList] ❌ 순차 페이징 중 에러 발생:', {
|
// console.error('[getUserReviewList] ❌ 순차 페이징 중 에러 발생:', {
|
||||||
errorMessage: errorMessage,
|
// errorMessage: errorMessage,
|
||||||
errorType: typeof error,
|
// errorType: typeof error,
|
||||||
httpStatus: httpStatus,
|
// httpStatus: httpStatus,
|
||||||
apiRetCode: apiRetCode,
|
// apiRetCode: apiRetCode,
|
||||||
apiRetMsg: apiRetMsg,
|
// apiRetMsg: apiRetMsg,
|
||||||
prdtId,
|
// prdtId,
|
||||||
patnrId,
|
// patnrId,
|
||||||
filterTpCd,
|
// filterTpCd,
|
||||||
filterTpVal,
|
// filterTpVal,
|
||||||
stack: error?.stack
|
// stack: error?.stack
|
||||||
});
|
// });
|
||||||
|
|
||||||
// Redux 상태에 에러 정보 저장 (선택사항)
|
// Redux 상태에 에러 정보 저장 (선택사항)
|
||||||
// dispatch({
|
// dispatch({
|
||||||
@@ -708,7 +728,7 @@ const extractReviewFiltersApiData = (apiResponse) => {
|
|||||||
console.error('[ReviewFilters] ❌ API 에러 - retCode !== 0:', {
|
console.error('[ReviewFilters] ❌ API 에러 - retCode !== 0:', {
|
||||||
retCode: retCode,
|
retCode: retCode,
|
||||||
retMsg: apiResponse?.retMsg,
|
retMsg: apiResponse?.retMsg,
|
||||||
fullResponse: apiResponse
|
fullResponse: apiResponse,
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -721,7 +741,7 @@ const extractReviewFiltersApiData = (apiResponse) => {
|
|||||||
prdtId: reviewFilterInfos.prdtId,
|
prdtId: reviewFilterInfos.prdtId,
|
||||||
hasFilters: !!reviewFilterInfos.filters,
|
hasFilters: !!reviewFilterInfos.filters,
|
||||||
filtersLength: reviewFilterInfos.filters ? reviewFilterInfos.filters.length : 0,
|
filtersLength: reviewFilterInfos.filters ? reviewFilterInfos.filters.length : 0,
|
||||||
reviewFilterInfosKeys: Object.keys(reviewFilterInfos)
|
reviewFilterInfosKeys: Object.keys(reviewFilterInfos),
|
||||||
});
|
});
|
||||||
|
|
||||||
data = reviewFilterInfos;
|
data = reviewFilterInfos;
|
||||||
@@ -734,7 +754,7 @@ const extractReviewFiltersApiData = (apiResponse) => {
|
|||||||
console.log('[ReviewFilters] ✅ 추출 완료:', {
|
console.log('[ReviewFilters] ✅ 추출 완료:', {
|
||||||
patnrId: data.patnrId,
|
patnrId: data.patnrId,
|
||||||
prdtId: data.prdtId,
|
prdtId: data.prdtId,
|
||||||
filtersLength: data.filters.length
|
filtersLength: data.filters.length,
|
||||||
});
|
});
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
@@ -746,16 +766,13 @@ const extractReviewFiltersApiData = (apiResponse) => {
|
|||||||
|
|
||||||
// Review Filters 조회 IF-LGSP-100
|
// Review Filters 조회 IF-LGSP-100
|
||||||
export const getReviewFilters = (requestParams) => (dispatch, getState) => {
|
export const getReviewFilters = (requestParams) => (dispatch, getState) => {
|
||||||
const {
|
const { prdtId, patnrId } = requestParams;
|
||||||
prdtId,
|
|
||||||
patnrId
|
|
||||||
} = requestParams;
|
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
prdtId,
|
prdtId,
|
||||||
patnrId,
|
patnrId,
|
||||||
// 우선순위 1: cntryCd 기본값 'US' 설정 (TV 환경에서는 자동으로 header로 전달됨)
|
// 우선순위 1: cntryCd 기본값 'US' 설정 (TV 환경에서는 자동으로 header로 전달됨)
|
||||||
cntryCd: 'US'
|
cntryCd: 'US',
|
||||||
};
|
};
|
||||||
|
|
||||||
const body = {};
|
const body = {};
|
||||||
@@ -765,7 +782,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
|
|||||||
params,
|
params,
|
||||||
body,
|
body,
|
||||||
url: URLS.GET_REVIEW_FILTERS,
|
url: URLS.GET_REVIEW_FILTERS,
|
||||||
timestamp: new Date().toISOString()
|
timestamp: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (response) => {
|
||||||
@@ -777,8 +794,8 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
|
|||||||
httpStatus: response?.status,
|
httpStatus: response?.status,
|
||||||
retCode: retCode,
|
retCode: retCode,
|
||||||
retMsg: retMsg,
|
retMsg: retMsg,
|
||||||
hasData: !!(response?.data?.data),
|
hasData: !!response?.data?.data,
|
||||||
dataExists: !!response?.data
|
dataExists: !!response?.data,
|
||||||
});
|
});
|
||||||
|
|
||||||
// retCode !== 0이면 extractReviewFiltersApiData에서 처리하고 null 반환됨
|
// retCode !== 0이면 extractReviewFiltersApiData에서 처리하고 null 반환됨
|
||||||
@@ -788,7 +805,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
|
|||||||
console.warn('[ReviewFilters] ⚠️ 필터 데이터 추출 실패:', {
|
console.warn('[ReviewFilters] ⚠️ 필터 데이터 추출 실패:', {
|
||||||
retCode: retCode,
|
retCode: retCode,
|
||||||
retMsg: retMsg,
|
retMsg: retMsg,
|
||||||
reason: retCode !== 0 ? 'retCode !== 0' : 'filters 데이터 없음'
|
reason: retCode !== 0 ? 'retCode !== 0' : 'filters 데이터 없음',
|
||||||
});
|
});
|
||||||
return; // 실패 시 dispatch하지 않음
|
return; // 실패 시 dispatch하지 않음
|
||||||
}
|
}
|
||||||
@@ -796,7 +813,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
|
|||||||
console.log('[ReviewFilters] 📊 필터 데이터 추출 성공:', {
|
console.log('[ReviewFilters] 📊 필터 데이터 추출 성공:', {
|
||||||
patnrId: filtersData.patnrId,
|
patnrId: filtersData.patnrId,
|
||||||
prdtId: filtersData.prdtId,
|
prdtId: filtersData.prdtId,
|
||||||
filtersLength: filtersData.filters ? filtersData.filters.length : 0
|
filtersLength: filtersData.filters ? filtersData.filters.length : 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const action = {
|
const action = {
|
||||||
@@ -804,7 +821,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
|
|||||||
payload: {
|
payload: {
|
||||||
...filtersData,
|
...filtersData,
|
||||||
prdtId: prdtId,
|
prdtId: prdtId,
|
||||||
patnrId: patnrId
|
patnrId: patnrId,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -812,7 +829,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
|
|||||||
actionType: types.GET_REVIEW_FILTERS,
|
actionType: types.GET_REVIEW_FILTERS,
|
||||||
patnrId: patnrId,
|
patnrId: patnrId,
|
||||||
prdtId: prdtId,
|
prdtId: prdtId,
|
||||||
filtersLength: filtersData.filters ? filtersData.filters.length : 0
|
filtersLength: filtersData.filters ? filtersData.filters.length : 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
dispatch(action);
|
dispatch(action);
|
||||||
@@ -839,6 +856,6 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
|
|||||||
// All Star 필터 해제 - API 호출 없이 상태만 초기화
|
// All Star 필터 해제 - API 호출 없이 상태만 초기화
|
||||||
export const clearReviewFilter = () => (dispatch) => {
|
export const clearReviewFilter = () => (dispatch) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.CLEAR_REVIEW_FILTER
|
type: types.CLEAR_REVIEW_FILTER,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -628,15 +628,15 @@ export default function ProductAllSection({
|
|||||||
[setOpenThemeItemOverlay]
|
[setOpenThemeItemOverlay]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleProductDetailsClick = useCallback(
|
const handleProductDetailsClick = useCallback(() => {
|
||||||
() => scrollToSection('scroll-marker-product-details'),
|
dispatch(minimizeModalMedia());
|
||||||
[scrollToSection]
|
scrollToSection('scroll-marker-product-details');
|
||||||
);
|
}, [scrollToSection, dispatch]);
|
||||||
|
|
||||||
const handleYouMayAlsoLikeClick = useCallback(
|
const handleYouMayAlsoLikeClick = useCallback(() => {
|
||||||
() => scrollToSection('scroll-marker-you-may-also-like'),
|
dispatch(minimizeModalMedia());
|
||||||
[scrollToSection]
|
scrollToSection('scroll-marker-you-may-also-like');
|
||||||
);
|
}, [scrollToSection, dispatch]);
|
||||||
const scrollPositionRef = useRef(0);
|
const scrollPositionRef = useRef(0);
|
||||||
const prevScrollPositionRef = useRef(0); // 이전 스크롤 위치 추적
|
const prevScrollPositionRef = useRef(0); // 이전 스크롤 위치 추적
|
||||||
const prevScrollTopRef = useRef(0); // HomePanel 스타일 스크롤 위치 추적
|
const prevScrollTopRef = useRef(0); // HomePanel 스타일 스크롤 위치 추적
|
||||||
@@ -644,6 +644,8 @@ export default function ProductAllSection({
|
|||||||
const mediaMinimizedRef = useRef(false);
|
const mediaMinimizedRef = useRef(false);
|
||||||
|
|
||||||
const handleArrowClickAlternative = useCallback(() => {
|
const handleArrowClickAlternative = useCallback(() => {
|
||||||
|
dispatch(minimizeModalMedia());
|
||||||
|
|
||||||
const currentHeight = scrollPositionRef.current;
|
const currentHeight = scrollPositionRef.current;
|
||||||
const scrollAmount = 200;
|
const scrollAmount = 200;
|
||||||
|
|
||||||
@@ -659,7 +661,7 @@ export default function ProductAllSection({
|
|||||||
if (isAtBottom) {
|
if (isAtBottom) {
|
||||||
setIsBottom(isAtBottom);
|
setIsBottom(isAtBottom);
|
||||||
}
|
}
|
||||||
}, [documentHeight, scrollTop]);
|
}, [documentHeight, scrollTop, dispatch]);
|
||||||
|
|
||||||
const handleScroll = useCallback(
|
const handleScroll = useCallback(
|
||||||
(e) => {
|
(e) => {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export default function ProductVideo({
|
|||||||
// autoPlay 기능: 컴포넌트 마운트 시 자동으로 비디오 재생
|
// autoPlay 기능: 컴포넌트 마운트 시 자동으로 비디오 재생
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (autoPlay && canPlayVideo && !hasAutoPlayed && productInfo) {
|
if (autoPlay && canPlayVideo && !hasAutoPlayed && productInfo) {
|
||||||
console.log('[ProductVideo] Auto-playing video');
|
// console.log('[ProductVideo] Auto-playing video');
|
||||||
setHasAutoPlayed(true);
|
setHasAutoPlayed(true);
|
||||||
|
|
||||||
// 짧은 딸레이 후 재생 시작 (컴포넌트 마운트 완료 후)
|
// 짧은 딸레이 후 재생 시작 (컴포넌트 마운트 완료 후)
|
||||||
@@ -113,7 +113,7 @@ export default function ProductVideo({
|
|||||||
const videoContainerOnFocus = useCallback(() => {
|
const videoContainerOnFocus = useCallback(() => {
|
||||||
if (canPlayVideo) {
|
if (canPlayVideo) {
|
||||||
setFocused(true);
|
setFocused(true);
|
||||||
console.log('[ProductVideo] Calling restoreModalMedia');
|
// console.log('[ProductVideo] Calling restoreModalMedia');
|
||||||
// ProductVideo에 포커스가 돌아오면 비디오 복원
|
// ProductVideo에 포커스가 돌아오면 비디오 복원
|
||||||
// dispatch(restoreModalMedia());
|
// dispatch(restoreModalMedia());
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ export default function ProductVideo({
|
|||||||
}, [canPlayVideo, dispatch, onFocus]);
|
}, [canPlayVideo, dispatch, onFocus]);
|
||||||
|
|
||||||
const videoContainerOnBlur = useCallback(() => {
|
const videoContainerOnBlur = useCallback(() => {
|
||||||
console.log('[ProductVideo] onBlur called - canPlayVideo:', canPlayVideo);
|
// console.log('[ProductVideo] onBlur called - canPlayVideo:', canPlayVideo);
|
||||||
// if (canPlayVideo) {
|
// if (canPlayVideo) {
|
||||||
// setFocused(false);
|
// setFocused(false);
|
||||||
// // 포커스를 잃으면 모달 MediaPanel을 최소화하여 1px 상태로 유지
|
// // 포커스를 잃으면 모달 MediaPanel을 최소화하여 1px 상태로 유지
|
||||||
@@ -149,10 +149,10 @@ export default function ProductVideo({
|
|||||||
|
|
||||||
// MediaPanel 비디오 클릭 핸들러 + 모달 토글 기능
|
// MediaPanel 비디오 클릭 핸들러 + 모달 토글 기능
|
||||||
const handleVideoClick = useCallback(() => {
|
const handleVideoClick = useCallback(() => {
|
||||||
console.log('[ProductVideo] ========== handleVideoClick 호출 ==========');
|
// console.log('[ProductVideo] ========== handleVideoClick 호출 ==========');
|
||||||
console.log('[ProductVideo] canPlayVideo:', canPlayVideo);
|
// console.log('[ProductVideo] canPlayVideo:', canPlayVideo);
|
||||||
console.log('[ProductVideo] panels.length:', panels.length);
|
// console.log('[ProductVideo] panels.length:', panels.length);
|
||||||
console.log('[ProductVideo] All panels:', JSON.stringify(panels, null, 2));
|
// console.log('[ProductVideo] All panels:', JSON.stringify(panels, null, 2));
|
||||||
|
|
||||||
if (canPlayVideo) {
|
if (canPlayVideo) {
|
||||||
const currentTopPanel = panels[panels.length - 1];
|
const currentTopPanel = panels[panels.length - 1];
|
||||||
@@ -163,19 +163,19 @@ export default function ProductVideo({
|
|||||||
currentTopPanel.name === panel_names.MEDIA_PANEL &&
|
currentTopPanel.name === panel_names.MEDIA_PANEL &&
|
||||||
currentTopPanel.panelInfo.modal === true;
|
currentTopPanel.panelInfo.modal === true;
|
||||||
|
|
||||||
console.log('[ProductVideo] currentTopPanel:', JSON.stringify(currentTopPanel, null, 2));
|
// console.log('[ProductVideo] currentTopPanel:', JSON.stringify(currentTopPanel, null, 2));
|
||||||
console.log('[ProductVideo] isCurrentlyPlayingModal:', isCurrentlyPlayingModal);
|
// console.log('[ProductVideo] isCurrentlyPlayingModal:', isCurrentlyPlayingModal);
|
||||||
|
|
||||||
// modal로 재생 중이면 전체화면으로 전환
|
// modal로 재생 중이면 전체화면으로 전환
|
||||||
if (isCurrentlyPlayingModal) {
|
if (isCurrentlyPlayingModal) {
|
||||||
console.log(
|
// console.log(
|
||||||
'[ProductVideo] *** Switching to fullscreen mode via switchMediaToFullscreen ***'
|
// '[ProductVideo] *** Switching to fullscreen mode via switchMediaToFullscreen ***'
|
||||||
);
|
// );
|
||||||
dispatch(switchMediaToFullscreen());
|
dispatch(switchMediaToFullscreen());
|
||||||
setModalState(false);
|
setModalState(false);
|
||||||
} else {
|
} else {
|
||||||
console.log('[ProductVideo] *** Starting modal MediaPanel ***');
|
// console.log('[ProductVideo] *** Starting modal MediaPanel ***');
|
||||||
console.log('[ProductVideo] productInfo:', JSON.stringify(productInfo, null, 2));
|
// console.log('[ProductVideo] productInfo:', JSON.stringify(productInfo, null, 2));
|
||||||
// 처음 재생 시작 - modal=true로 시작
|
// 처음 재생 시작 - modal=true로 시작
|
||||||
dispatch(
|
dispatch(
|
||||||
startMediaPlayer({
|
startMediaPlayer({
|
||||||
|
|||||||
@@ -58,17 +58,17 @@ export default function ProductVideo({
|
|||||||
topPanel.panelInfo.modal === true &&
|
topPanel.panelInfo.modal === true &&
|
||||||
prevModalStateRef.current === false
|
prevModalStateRef.current === false
|
||||||
) {
|
) {
|
||||||
console.log('[ProductVideo] MediaPanel returned to modal - restoring focus to ProductVideo');
|
// console.log('[ProductVideo] MediaPanel returned to modal - restoring focus to ProductVideo');
|
||||||
|
|
||||||
// VideoPlayer의 controlsHandleAbove가 자동으로 포커스를 빼앗지 않도록
|
// VideoPlayer의 controlsHandleAbove가 자동으로 포커스를 빼앗지 않도록
|
||||||
// 약간의 딜레이 후에 강제로 포커스 설정
|
// 약간의 딜레이 후에 강제로 포커스 설정
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
console.log('[ProductVideo] Forcing focus to product-video-player');
|
// console.log('[ProductVideo] Forcing focus to product-video-player');
|
||||||
const element = document.querySelector('[data-spotlight-id="product-video-player"]');
|
const element = document.querySelector('[data-spotlight-id="product-video-player"]');
|
||||||
if (element) {
|
if (element) {
|
||||||
// Spotlight 내부 포커스 강제 설정
|
// Spotlight 내부 포커스 강제 설정
|
||||||
Spotlight.focus('product-video-player');
|
Spotlight.focus('product-video-player');
|
||||||
console.log('[ProductVideo] Focus set to product-video-player');
|
// console.log('[ProductVideo] Focus set to product-video-player');
|
||||||
}
|
}
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ export default function ProductVideo({
|
|||||||
|
|
||||||
// MediaPanel이 닫혔을 때 modalState를 true로 복원
|
// MediaPanel이 닫혔을 때 modalState를 true로 복원
|
||||||
if (!topPanel || topPanel.name !== panel_names.MEDIA_PANEL) {
|
if (!topPanel || topPanel.name !== panel_names.MEDIA_PANEL) {
|
||||||
console.log('[ProductVideo] MediaPanel closed - restoring modal state');
|
// console.log('[ProductVideo] MediaPanel closed - restoring modal state');
|
||||||
setModalState(true);
|
setModalState(true);
|
||||||
prevModalStateRef.current = null;
|
prevModalStateRef.current = null;
|
||||||
}
|
}
|
||||||
@@ -91,11 +91,11 @@ export default function ProductVideo({
|
|||||||
topPanel?.name === panel_names.MEDIA_PANEL && topPanel?.panelInfo?.modal === true;
|
topPanel?.name === panel_names.MEDIA_PANEL && topPanel?.panelInfo?.modal === true;
|
||||||
|
|
||||||
if (autoPlay && canPlayVideo && !hasAutoPlayed && productInfo && !isMediaPanelAlreadyPlaying) {
|
if (autoPlay && canPlayVideo && !hasAutoPlayed && productInfo && !isMediaPanelAlreadyPlaying) {
|
||||||
console.log('[ProductVideo]-LoadingVideo 🎯 AutoPlay 시작:', {
|
// console.log('[ProductVideo]-LoadingVideo 🎯 AutoPlay 시작:', {
|
||||||
prdtId: productInfo?.prdtId,
|
// prdtId: productInfo?.prdtId,
|
||||||
prdtNm: productInfo?.prdtNm,
|
// prdtNm: productInfo?.prdtNm,
|
||||||
prdtMediaUrl: productInfo?.prdtMediaUrl?.substring(0, 50),
|
// prdtMediaUrl: productInfo?.prdtMediaUrl?.substring(0, 50),
|
||||||
});
|
// });
|
||||||
setHasAutoPlayed(true);
|
setHasAutoPlayed(true);
|
||||||
|
|
||||||
// 짧은 딜레이 후 재생 시작 (컴포넌트 마운트 완료 후)
|
// 짧은 딜레이 후 재생 시작 (컴포넌트 마운트 완료 후)
|
||||||
@@ -160,7 +160,7 @@ export default function ProductVideo({
|
|||||||
const videoContainerOnFocus = useCallback(() => {
|
const videoContainerOnFocus = useCallback(() => {
|
||||||
if (canPlayVideo) {
|
if (canPlayVideo) {
|
||||||
setFocused(true);
|
setFocused(true);
|
||||||
console.log('[ProductVideo] Calling restoreModalMedia');
|
// console.log('[ProductVideo] Calling restoreModalMedia');
|
||||||
// ProductVideo에 포커스가 돌아오면 비디오 복원
|
// ProductVideo에 포커스가 돌아오면 비디오 복원
|
||||||
// dispatch(restoreModalMedia());
|
// dispatch(restoreModalMedia());
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ export default function ProductVideo({
|
|||||||
}, [canPlayVideo, dispatch, onFocus]);
|
}, [canPlayVideo, dispatch, onFocus]);
|
||||||
|
|
||||||
const videoContainerOnBlur = useCallback(() => {
|
const videoContainerOnBlur = useCallback(() => {
|
||||||
console.log('[ProductVideo] onBlur called - canPlayVideo:', canPlayVideo);
|
// console.log('[ProductVideo] onBlur called - canPlayVideo:', canPlayVideo);
|
||||||
// if (canPlayVideo) {
|
// if (canPlayVideo) {
|
||||||
// setFocused(false);
|
// setFocused(false);
|
||||||
// // 포커스를 잃으면 모달 MediaPanel을 최소화하여 1px 상태로 유지
|
// // 포커스를 잃으면 모달 MediaPanel을 최소화하여 1px 상태로 유지
|
||||||
@@ -197,10 +197,10 @@ export default function ProductVideo({
|
|||||||
|
|
||||||
// MediaPanel 비디오 클릭 핸들러 + 모달 토글 기능
|
// MediaPanel 비디오 클릭 핸들러 + 모달 토글 기능
|
||||||
const handleVideoClick = useCallback(() => {
|
const handleVideoClick = useCallback(() => {
|
||||||
console.log('[ProductVideo] ========== handleVideoClick 호출 ==========');
|
// console.log('[ProductVideo] ========== handleVideoClick 호출 ==========');
|
||||||
console.log('[ProductVideo] canPlayVideo:', canPlayVideo);
|
// console.log('[ProductVideo] canPlayVideo:', canPlayVideo);
|
||||||
console.log('[ProductVideo] panels.length:', panels.length);
|
// console.log('[ProductVideo] panels.length:', panels.length);
|
||||||
console.log('[ProductVideo] All panels:', JSON.stringify(panels, null, 2));
|
// console.log('[ProductVideo] All panels:', JSON.stringify(panels, null, 2));
|
||||||
|
|
||||||
if (canPlayVideo) {
|
if (canPlayVideo) {
|
||||||
const currentTopPanel = panels[panels.length - 1];
|
const currentTopPanel = panels[panels.length - 1];
|
||||||
@@ -211,19 +211,31 @@ export default function ProductVideo({
|
|||||||
currentTopPanel.name === panel_names.MEDIA_PANEL &&
|
currentTopPanel.name === panel_names.MEDIA_PANEL &&
|
||||||
currentTopPanel.panelInfo.modal === true;
|
currentTopPanel.panelInfo.modal === true;
|
||||||
|
|
||||||
console.log('[ProductVideo] currentTopPanel:', JSON.stringify(currentTopPanel, null, 2));
|
// console.log('[ProductVideo] currentTopPanel:', JSON.stringify(currentTopPanel, null, 2));
|
||||||
console.log('[ProductVideo] isCurrentlyPlayingModal:', isCurrentlyPlayingModal);
|
// console.log('[ProductVideo] isCurrentlyPlayingModal:', isCurrentlyPlayingModal);
|
||||||
|
|
||||||
// modal로 재생 중이면 전체화면으로 전환
|
// modal로 재생 중이면 전체화면으로 전환
|
||||||
if (isCurrentlyPlayingModal) {
|
if (isCurrentlyPlayingModal) {
|
||||||
console.log(
|
// console.log(
|
||||||
'[ProductVideo] *** Switching to fullscreen mode via switchMediaToFullscreen ***'
|
// '[ProductVideo] *** Switching to fullscreen mode via switchMediaToFullscreen ***'
|
||||||
);
|
// );
|
||||||
dispatch(switchMediaToFullscreen());
|
dispatch(switchMediaToFullscreen());
|
||||||
setModalState(false);
|
setModalState(false);
|
||||||
|
|
||||||
|
// 전체화면 전환 후 VideoPlayer에 포커스 설정
|
||||||
|
setTimeout(() => {
|
||||||
|
// console.log('[ProductVideo] Focusing to fullscreen video player');
|
||||||
|
const focusTarget =
|
||||||
|
document.querySelector('[data-spotlight-id="modal-video-player"]') ||
|
||||||
|
document.querySelector('[data-spotlight-id="product-video-player"]');
|
||||||
|
if (focusTarget) {
|
||||||
|
Spotlight.focus('modal-video-player');
|
||||||
|
// console.log('[ProductVideo] Focus set to fullscreen video player');
|
||||||
|
}
|
||||||
|
}, 50);
|
||||||
} else {
|
} else {
|
||||||
console.log('[ProductVideo] *** Starting modal MediaPanel ***');
|
// console.log('[ProductVideo] *** Starting modal MediaPanel ***');
|
||||||
console.log('[ProductVideo] productInfo:', JSON.stringify(productInfo, null, 2));
|
// console.log('[ProductVideo] productInfo:', JSON.stringify(productInfo, null, 2));
|
||||||
// 처음 재생 시작 - modal=true로 시작
|
// 처음 재생 시작 - modal=true로 시작
|
||||||
setIsVideoPlaying(true); // 비디오 재생 flag 설정
|
setIsVideoPlaying(true); // 비디오 재생 flag 설정
|
||||||
if (onVideoPlaying) {
|
if (onVideoPlaying) {
|
||||||
|
|||||||
@@ -2237,7 +2237,7 @@ const MediaPanel = React.forwardRef(
|
|||||||
modalScale={panelInfo.modal ? modalScale : 1}
|
modalScale={panelInfo.modal ? modalScale : 1}
|
||||||
modalClassName={panelInfo.modal && panelInfo.modalClassName}
|
modalClassName={panelInfo.modal && panelInfo.modalClassName}
|
||||||
spotlightId={
|
spotlightId={
|
||||||
panelInfo.modal ? undefined : panelInfo.modalContainerId || spotlightId
|
panelInfo.modal ? 'modal-video-player' : panelInfo.modalContainerId || spotlightId
|
||||||
}
|
}
|
||||||
handleIndicatorDownClick={handleIndicatorDownClick}
|
handleIndicatorDownClick={handleIndicatorDownClick}
|
||||||
handleIndicatorUpClick={handleIndicatorUpClick}
|
handleIndicatorUpClick={handleIndicatorUpClick}
|
||||||
|
|||||||
Reference in New Issue
Block a user