🕐 커밋 시간: 2025. 11. 24. 12:19:40 📊 변경 통계: • 총 파일: 6개 • 추가: +283줄 • 삭제: -255줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/mainActions.js ~ com.twin.app.shoptime/src/reducers/mainReducer.js ~ com.twin.app.shoptime/src/reducers/searchReducer.js ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.v2.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/actions/mainActions.js (javascript): 🔄 Modified: clearSubCategory() 📄 com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx (javascript): 🔄 Modified: Spottable() 📄 com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx (javascript): ✅ Added: Spottable() 🔄 Modified: clearAllTimers() 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선
502 lines
13 KiB
JavaScript
502 lines
13 KiB
JavaScript
import { URLS } from '../api/apiConfig';
|
|
import { TAxios, TAxiosAdvancedPromise } from '../api/TAxios';
|
|
import { convertUtcToLocal } from '../components/MediaPlayer/util';
|
|
import { CATEGORY_DATA_MAX_RESULTS_LIMIT, LOG_CONTEXT_NAME, LOG_MESSAGE_ID } from '../utils/Config';
|
|
import * as HelperMethods from '../utils/helperMethods';
|
|
import { types } from './actionTypes';
|
|
import { addReservation, changeAppStatus, deleteReservation } from './commonActions';
|
|
import { createDebugHelpers } from '../utils/debug';
|
|
|
|
// 디버그 헬퍼 설정
|
|
const DEBUG_MODE = false;
|
|
const { dlog, dwarn, derror } = createDebugHelpers(DEBUG_MODE);
|
|
|
|
//IF-LGSP-007
|
|
export const getMainLiveShow = (props) => (dispatch, getState) => {
|
|
const vodIncFlag = props?.vodIncFlag;
|
|
|
|
const onSuccess = (response) => {
|
|
dlog('@@ getMainLiveShow onSuccess', response.data);
|
|
|
|
dispatch({
|
|
type: types.GET_MAIN_LIVE_SHOW,
|
|
payload: response.data.data,
|
|
});
|
|
};
|
|
|
|
const onFail = (error) => {
|
|
derror('@@ getMainLiveShow onFail', error);
|
|
};
|
|
|
|
TAxios(dispatch, getState, 'get', URLS.GET_MAIN_LIVE_SHOW, { vodIncFlag }, {}, onSuccess, onFail);
|
|
};
|
|
|
|
// Live 알람 설정/해제 IF-LGSP-012
|
|
export const setMainLiveUpcomingAlarm = (props) => (dispatch, getState) => {
|
|
const { alamDispFlag, chanId, endDt, patnrId, patncNm, showId, showNm, strtDt } = props;
|
|
|
|
const onSuccess = (response) => {
|
|
dlog('setMainLiveUpcomingAlarm onSuccess', response.data);
|
|
|
|
if (alamDispFlag === 'Y') {
|
|
const convertedStrtDt = convertUtcToLocal(strtDt);
|
|
|
|
const data = {
|
|
startTime: {
|
|
year: convertedStrtDt.getFullYear(),
|
|
month: convertedStrtDt.getMonth() + 1,
|
|
day: convertedStrtDt.getDate(),
|
|
hour: convertedStrtDt.getHours(),
|
|
minute: convertedStrtDt.getMinutes(),
|
|
second: convertedStrtDt.getSeconds(),
|
|
},
|
|
params: {
|
|
message: `[${patncNm}] ${showNm}\n${HelperMethods.$L('Watch Now!')}`,
|
|
buttons: [
|
|
{
|
|
label: HelperMethods.$L('yes'),
|
|
},
|
|
{
|
|
label: HelperMethods.$L('no'),
|
|
},
|
|
],
|
|
launch: {
|
|
contentTarget: `V3_8002_Tv_FB_${patnrId}`,
|
|
},
|
|
showId: showId,
|
|
chanId: chanId,
|
|
},
|
|
};
|
|
|
|
dispatch(addReservation(data));
|
|
}
|
|
//
|
|
else if (alamDispFlag === 'N') {
|
|
dispatch(deleteReservation(showId));
|
|
}
|
|
};
|
|
|
|
const onFail = (error) => {
|
|
derror('setMainLiveUpcomingAlarm onFail', error);
|
|
};
|
|
|
|
TAxios(
|
|
dispatch,
|
|
getState,
|
|
'post',
|
|
URLS.SET_MAIN_LIVE_UPCOMING_ALARM,
|
|
{},
|
|
{ alamDispFlag, endDt, patnrId, showId, strtDt },
|
|
onSuccess,
|
|
onFail
|
|
);
|
|
};
|
|
|
|
// 디테일상품 조회 LF-LGSP-015
|
|
export const getMainCategoryDetail = (props) => (dispatch, getState) => {
|
|
const { patnrId, prdtId, liveReqFlag } = props;
|
|
|
|
dispatch(changeAppStatus({ showLoadingPanel: { show: true, type: 'wait' } }));
|
|
|
|
const onSuccess = (response) => {
|
|
dlog('getMainCategoryDetail onSuccess ', response.data);
|
|
|
|
dispatch({
|
|
type: types.GET_PRODUCT_DETAIL,
|
|
payload: response.data.data,
|
|
});
|
|
|
|
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
|
};
|
|
|
|
const onFail = (error) => {
|
|
derror('getMainCategoryDetail onFail', error);
|
|
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
|
};
|
|
|
|
TAxios(
|
|
dispatch,
|
|
getState,
|
|
'get',
|
|
URLS.GET_PRODUCT_DETAIL,
|
|
{ patnrId, prdtId, liveReqFlag },
|
|
{},
|
|
onSuccess,
|
|
onFail
|
|
);
|
|
};
|
|
|
|
// 영상 상세 보기 조회 LF-LGSP-047
|
|
export const getMainCategoryShowDetail = (props) => (dispatch, getState) => {
|
|
const { patnrId, showId, curationId } = props;
|
|
const onSuccess = (response) => {
|
|
dlog('getMainCategoryShowDetail onSuccess ', response.data);
|
|
|
|
dispatch({
|
|
type: types.GET_MAIN_CATEGORY_SHOW_DETAIL,
|
|
payload: response.data.data,
|
|
});
|
|
};
|
|
|
|
const onFail = (error) => {
|
|
derror('getMainCategoryShowDetail onFail', error);
|
|
};
|
|
|
|
TAxios(
|
|
dispatch,
|
|
getState,
|
|
'get',
|
|
URLS.GET_MAIN_CATEGORY_SHOW_DETAIL,
|
|
{ patnrId, showId, curationId },
|
|
{},
|
|
onSuccess,
|
|
onFail
|
|
);
|
|
};
|
|
|
|
// 서브카테고리 조회 IF-LGSP-051
|
|
let getSubCategoryKey = null;
|
|
let lastSubCategoryParams = {};
|
|
const SUB_CATEGORY_RETRY_LIMIT = 3;
|
|
const SUB_CATEGORY_RETRY_DELAY_MS = 400;
|
|
export const getSubCategory =
|
|
(params, pageNo = 1, key = null, clear = false, retryCount = 0) =>
|
|
(dispatch, getState) => {
|
|
const { lgCatCd, patnrIdList, tabType, filterType, recommendIncFlag } = params;
|
|
let pageSize = params.pageSize || CATEGORY_DATA_MAX_RESULTS_LIMIT;
|
|
|
|
if (pageNo === 1) {
|
|
if (
|
|
lastSubCategoryParams &&
|
|
JSON.stringify(lastSubCategoryParams) === JSON.stringify(params)
|
|
) {
|
|
dlog('getSubCategory ignore patch');
|
|
return;
|
|
}
|
|
lastSubCategoryParams = { ...params };
|
|
if (clear) {
|
|
dispatch(clearSubCategory());
|
|
}
|
|
}
|
|
|
|
let currentKey = key;
|
|
const onSuccess = (response) => {
|
|
dlog('getSubCategory onSuccess ', response.data);
|
|
|
|
if (pageNo === 1) {
|
|
getSubCategoryKey = new Date();
|
|
currentKey = getSubCategoryKey;
|
|
|
|
// ✅ recommendProduct 분리
|
|
const { recommendProduct, ...restData } = response.data.data;
|
|
|
|
dispatch({
|
|
type: types.GET_SUB_CATEGORY,
|
|
payload: {
|
|
...restData,
|
|
recommendProduct,
|
|
},
|
|
categoryParams: {
|
|
lgCatCd,
|
|
patnrIdList,
|
|
tabType,
|
|
filterType,
|
|
recommendIncFlag,
|
|
pageSize,
|
|
},
|
|
});
|
|
} else if (getSubCategoryKey === currentKey) {
|
|
const { recommendProduct, ...restData } = response.data.data;
|
|
|
|
dispatch({
|
|
type: types.GET_SUB_CATEGORY,
|
|
payload: {
|
|
...restData,
|
|
recommendProduct,
|
|
},
|
|
append: true,
|
|
startIndex: (pageNo - 1) * pageSize,
|
|
});
|
|
}
|
|
};
|
|
|
|
const onFail = (error) => {
|
|
const nextRetryCount = retryCount + 1;
|
|
const canRetry = nextRetryCount < SUB_CATEGORY_RETRY_LIMIT;
|
|
|
|
if (canRetry) {
|
|
dwarn('getSubCategory retry', {
|
|
lgCatCd,
|
|
pageNo,
|
|
retryCount: nextRetryCount,
|
|
});
|
|
|
|
setTimeout(() => {
|
|
dispatch(getSubCategory(params, pageNo, currentKey, clear, nextRetryCount));
|
|
}, SUB_CATEGORY_RETRY_DELAY_MS * nextRetryCount);
|
|
return;
|
|
}
|
|
|
|
derror('getSubCategory onFail', error);
|
|
if (pageNo === 1) {
|
|
lastSubCategoryParams = {};
|
|
}
|
|
};
|
|
|
|
TAxios(
|
|
dispatch,
|
|
getState,
|
|
'get',
|
|
URLS.GET_SUB_CATEGORY,
|
|
{ lgCatCd, patnrIdList, pageSize, pageNo, tabType, filterType, recommendIncFlag },
|
|
{},
|
|
onSuccess,
|
|
onFail
|
|
);
|
|
};
|
|
|
|
export const continueGetSubCategory = (key, pageNo) => (dispatch, getState) => {
|
|
if (!lastSubCategoryParams) {
|
|
// <<<<<<< HEAD
|
|
dwarn('No previous category parameters found');
|
|
// =======
|
|
// console.warn("No previous category parameters found");
|
|
// >>>>>>> gitlab/develop
|
|
return;
|
|
}
|
|
|
|
const subCategoryData = getState().main.subCategoryData;
|
|
const targetData =
|
|
// <<<<<<< HEAD
|
|
subCategoryData[key]?.subCatItemList || subCategoryData[key]?.subCatShowList || [];
|
|
// =======
|
|
// subCategoryData[key]?.subCatItemList ||
|
|
// subCategoryData[key]?.subCatShowList ||
|
|
// [];
|
|
// >>>>>>> gitlab/develop
|
|
const totalCount = subCategoryData[key]?.total ?? 0;
|
|
const startIndex = CATEGORY_DATA_MAX_RESULTS_LIMIT * (pageNo - 1);
|
|
if (
|
|
(startIndex <= 1 && !targetData) ||
|
|
startIndex < targetData.length ||
|
|
totalCount - 1 <= startIndex
|
|
) {
|
|
//ignore query
|
|
return;
|
|
}
|
|
// <<<<<<< HEAD
|
|
dispatch(getSubCategory({ ...lastSubCategoryParams }, pageNo, getSubCategoryKey));
|
|
// =======
|
|
// dispatch(
|
|
// getSubCategory({ ...lastSubCategoryParams }, pageNo, getSubCategoryKey)
|
|
// );
|
|
// >>>>>>> gitlab/develop
|
|
};
|
|
|
|
const clearSubCategory = () => ({
|
|
type: types.CLEAR_SUB_CATEGORY,
|
|
});
|
|
|
|
// TOP20 영상 목록 조회 IF-LGSP-069
|
|
export const getTop20Show = () => (dispatch, getState) => {
|
|
const onSuccess = (response) => {
|
|
dlog('getTop20Show onSuccess ', response.data);
|
|
|
|
dispatch({
|
|
type: types.GET_TOP_20_SHOW,
|
|
payload: response.data.data,
|
|
});
|
|
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
|
};
|
|
|
|
const onFail = (error) => {
|
|
derror('getTop20Show onFail', error);
|
|
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
|
|
};
|
|
|
|
TAxios(dispatch, getState, 'get', URLS.GET_TOP20_SHOW, {}, {}, onSuccess, onFail);
|
|
};
|
|
|
|
// 유메이라이크 아이템 리스트 IF-LGSP-201
|
|
export const getMainYouMayLike =
|
|
({ lgCatCd, exclCurationId, exclPatnrId, exclPrdtId, catDpTh3, catDpTh4 }) =>
|
|
(dispatch, getState) => {
|
|
// console.log('[YouMayLike] API 요청 시작:', {
|
|
// lgCatCd,
|
|
// exclCurationId,
|
|
// exclPatnrId,
|
|
// exclPrdtId,
|
|
// catDpTh3,
|
|
// catDpTh4
|
|
// });
|
|
|
|
const onSuccess = (response) => {
|
|
// console.log('[YouMayLike] API 응답 성공 (onSuccess):', {
|
|
// fullResponse: response.data,
|
|
// dataField: response.data.data,
|
|
// hasYoumaylike: !!(response.data.data && response.data.data.youmaylike),
|
|
// youmaylikeLength: response.data.data?.youmaylike?.length || 0,
|
|
// youmaylikeData: response.data.data?.youmaylike
|
|
// });
|
|
|
|
// console.log('[YouMayLike] Redux dispatch 전 - payload:', response.data.data);
|
|
|
|
dispatch({
|
|
type: types.GET_YOUMAYLIKE,
|
|
payload: response.data.data,
|
|
});
|
|
|
|
// console.log('[YouMayLike] Redux dispatch 완료');
|
|
};
|
|
|
|
const onFail = (error) => {
|
|
// console.error('[YouMayLike] API 요청 실패 (onFail):', {
|
|
// error: error,
|
|
// errorMessage: error?.message,
|
|
// errorResponse: error?.response,
|
|
// errorData: error?.response?.data
|
|
// });
|
|
console.error('getMainYouMayLike onFail', error);
|
|
};
|
|
|
|
TAxios(
|
|
dispatch,
|
|
getState,
|
|
'get',
|
|
URLS.GET_YOUMAYLIKE,
|
|
// <<<<<<< HEAD
|
|
{ lgCatCd, exclCurationId, exclPatnrId, exclPrdtId, catDpTh3, catDpTh4 },
|
|
// =======
|
|
// { lgCatCd, catDpTh3, catDpTh4, exclCurationId, exclPatnrId, exclPrdtId },
|
|
// >>>>>>> gitlab/develop
|
|
{},
|
|
onSuccess,
|
|
onFail
|
|
);
|
|
};
|
|
|
|
// 찜 여부 확인 IF-LGSP-075
|
|
export const getMyFavoriteFlag = (params) => (dispatch, getState) => {
|
|
const { patnrId, prdtId } = params;
|
|
|
|
const onSuccess = (response) => {
|
|
dlog('getMyFavoriteFlag onSuccess ', response.data);
|
|
dispatch({
|
|
type: types.GET_MY_FAVORITE_FLAG,
|
|
payload: response.data.data,
|
|
});
|
|
};
|
|
const onFail = (error) => {
|
|
derror('getMyFavoriteFlag onFail', error);
|
|
};
|
|
|
|
TAxios(
|
|
dispatch,
|
|
getState,
|
|
'get',
|
|
URLS.GET_MY_FAVORITE_FLAG,
|
|
{ patnrId, prdtId },
|
|
{},
|
|
onSuccess,
|
|
onFail
|
|
);
|
|
};
|
|
// 상품 찜하기 IF-LGSP-014
|
|
export const setMainLikeCategory = (params) => (dispatch, getState) => {
|
|
const { patnrId, prdtId } = params;
|
|
|
|
const onSuccess = (response) => {
|
|
dlog('setMainLikeCategory onSuccess ', response.data);
|
|
dispatch({
|
|
type: types.SET_MAIN_LIKE_CATEGORY,
|
|
payload: response.data.data,
|
|
});
|
|
};
|
|
const onFail = (error) => {
|
|
console.error('setMainLikeCategory onFail', error);
|
|
};
|
|
|
|
TAxios(
|
|
dispatch,
|
|
getState,
|
|
'post',
|
|
URLS.SET_MAIN_LIKE_CATEGORY,
|
|
{},
|
|
{ patnrId, prdtId },
|
|
onSuccess,
|
|
onFail
|
|
);
|
|
};
|
|
|
|
// HOME Live Full 영상 상세 보기 정보 조회 IF-LGSP-302
|
|
export const getHomeFullVideoInfo =
|
|
({ lgCatCd }) =>
|
|
(dispatch, getState) => {
|
|
const onSuccess = (response) => {
|
|
dlog('getHomeFullVideoInfo onSuccess', response.data.data.showInfos);
|
|
|
|
// ✨ DEBUG: youmaylikeInfos 데이터 확인
|
|
dlog('[DEBUG] GET_HOME_FULL_VIDEO_INFO - API Response:', {
|
|
youmaylikeInfos: response.data.data.youmaylikeInfos,
|
|
youmaylikeInfos_length: response.data.data.youmaylikeInfos?.length,
|
|
liveChannelInfos_length: response.data.data.liveChannelInfos?.length,
|
|
featuredShowsInfos_length: response.data.data.featuredShowsInfos?.length,
|
|
});
|
|
|
|
dispatch({
|
|
type: types.GET_HOME_FULL_VIDEO_INFO,
|
|
payload: { data: response.data.data, lgCatCd },
|
|
});
|
|
};
|
|
|
|
const onFail = (error) => {
|
|
derror('getHomeFullVideoInfo onSuccess', error);
|
|
};
|
|
|
|
TAxios(
|
|
dispatch,
|
|
getState,
|
|
'get',
|
|
URLS.GET_HOME_FULL_VIDEO_INFO,
|
|
{ lgCatCd },
|
|
{},
|
|
onSuccess,
|
|
onFail
|
|
);
|
|
};
|
|
|
|
// 메인화면 Live 현재 방송 상품 조회 IF-LGSP-046
|
|
export const getMainLiveShowNowProduct =
|
|
({ patnrId, showId, lstChgDt }) =>
|
|
(dispatch, getState) => {
|
|
return TAxiosAdvancedPromise(
|
|
dispatch,
|
|
getState,
|
|
'get',
|
|
URLS.GET_MAIN_LIVE_SHOW_NOW_PRODUCT,
|
|
{ patnrId, showId, lstChgDt },
|
|
{},
|
|
{
|
|
retries: 2, // 3회까지 재시도 (처음 시도 + 2회 재시도)
|
|
retryDelay: 500, // 500ms 간격으로 재시도
|
|
throwOnError: false, // 에러를 throw하지 않고 객체로 반환
|
|
}
|
|
).then((result) => {
|
|
if (result.success && result.data?.data) {
|
|
dispatch({
|
|
type: types.GET_MAIN_LIVE_SHOW_NOW_PRODUCT,
|
|
payload: result.data.data,
|
|
});
|
|
} else {
|
|
console.error('getMainLiveShowNowProduct onFail', result.error);
|
|
}
|
|
return result;
|
|
});
|
|
};
|
|
|
|
export const clearShopNowInfo = () => {
|
|
return {
|
|
type: types.CLEAR_SHOPNOW_INFO,
|
|
};
|
|
};
|