fix: IntroPanel간헐적 Agree미작동 해결, termsIdMap 추가
This commit is contained in:
@@ -57,6 +57,7 @@ export const types = {
|
||||
|
||||
// home actions
|
||||
GET_HOME_TERMS: "GET_HOME_TERMS",
|
||||
SET_TERMS_ID_MAP: "SET_TERMS_ID_MAP",
|
||||
GET_HOME_MENU: "GET_HOME_MENU",
|
||||
GET_HOME_LAYOUT: "GET_HOME_LAYOUT",
|
||||
GET_HOME_MAIN_CONTENTS: "GET_HOME_MAIN_CONTENTS",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { URLS } from "../api/apiConfig";
|
||||
import { TAxios } from "../api/TAxios";
|
||||
import { TAxios,TAxiosPromise } from "../api/TAxios";
|
||||
import { types } from "./actionTypes";
|
||||
import { changeAppStatus, getTermsAgreeYn } from "./commonActions";
|
||||
|
||||
@@ -15,6 +15,26 @@ export const getHomeTerms = (props) => (dispatch, getState) => {
|
||||
type: types.GET_HOME_TERMS,
|
||||
payload: response.data,
|
||||
});
|
||||
|
||||
// 약관 ID 매핑을 별도로 생성하여 저장
|
||||
if (response.data?.data?.terms) {
|
||||
const termsIdMap = {};
|
||||
response.data.data.terms.forEach(term => {
|
||||
if (term.trmsTpCd && term.trmsId) {
|
||||
termsIdMap[term.trmsTpCd] = term.trmsId;
|
||||
}
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: types.SET_TERMS_ID_MAP,
|
||||
payload: termsIdMap,
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.log("약관 ID 매핑 생성:", termsIdMap);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
dispatch(getTermsAgreeYn());
|
||||
}, 0);
|
||||
@@ -58,6 +78,26 @@ export const fetchCurrentUserHomeTerms = () => (dispatch, getState) => {
|
||||
type: types.GET_HOME_TERMS, // 기존 GET_HOME_TERMS 타입을 재사용
|
||||
payload: response.data,
|
||||
});
|
||||
|
||||
// 약관 ID 매핑을 별도로 생성하여 저장
|
||||
if (response.data?.data?.terms) {
|
||||
const termsIdMap = {};
|
||||
response.data.data.terms.forEach(term => {
|
||||
if (term.trmsTpCd && term.trmsId) {
|
||||
termsIdMap[term.trmsTpCd] = term.trmsId;
|
||||
}
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: types.SET_TERMS_ID_MAP,
|
||||
payload: termsIdMap,
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.log("약관 ID 매핑 생성:", termsIdMap);
|
||||
}
|
||||
}
|
||||
|
||||
// getHomeTerms와 동일하게 getTermsAgreeYn 후속 처리
|
||||
setTimeout(() => {
|
||||
dispatch(getTermsAgreeYn());
|
||||
@@ -85,6 +125,87 @@ export const fetchCurrentUserHomeTerms = () => (dispatch, getState) => {
|
||||
);
|
||||
};
|
||||
|
||||
// 기존 TAxios 패턴과 일치하는 안전한 Redux Action
|
||||
export const fetchCurrentUserHomeTermsSafe = () => async (dispatch, getState) => {
|
||||
const loginUserData = getState().common.appStatus.loginUserData;
|
||||
|
||||
if (!loginUserData || !loginUserData.userNumber) {
|
||||
console.error("fetchCurrentUserHomeTerms: userNumber is not available");
|
||||
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
||||
return { success: false, message: "사용자 정보가 없습니다." };
|
||||
}
|
||||
|
||||
const mbrNo = loginUserData.userNumber;
|
||||
const trmsTpCdList = "MST00401, MST00402, MST00405";
|
||||
|
||||
console.log("Fetching home terms for user:", mbrNo);
|
||||
|
||||
// 안전한 API 호출 (기존 TAxios 패턴과 동일)
|
||||
const result = await TAxiosPromise(
|
||||
dispatch,
|
||||
getState,
|
||||
"get",
|
||||
URLS.GET_HOME_TERMS,
|
||||
{ trmsTpCdList, mbrNo }
|
||||
);
|
||||
|
||||
// 네트워크 에러인 경우
|
||||
if (!result.success) {
|
||||
console.error("fetchCurrentUserHomeTerms network error:", result.error);
|
||||
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
||||
return { success: false, message: "네트워크 오류가 발생했습니다." };
|
||||
}
|
||||
|
||||
// 기존 TAxios처럼 특별한 retCode들은 TAxios 내부에서 이미 처리됨
|
||||
// (401, 402, 501, 602, 603, 604 등은 TAxios에서 알아서 처리하고 onSuccess가 호출되지 않음)
|
||||
|
||||
console.log("fetchCurrentUserHomeTerms response:", result.data);
|
||||
|
||||
// 정상적으로 onSuccess가 호출된 경우에만 여기까지 옴
|
||||
if (result.data && result.data.retCode === 0) {
|
||||
dispatch({
|
||||
type: types.GET_HOME_TERMS,
|
||||
payload: result.data,
|
||||
});
|
||||
|
||||
// 약관 ID 매핑을 별도로 생성하여 저장
|
||||
if (result.data?.data?.terms) {
|
||||
const termsIdMap = {};
|
||||
result.data.data.terms.forEach(term => {
|
||||
if (term.trmsTpCd && term.trmsId) {
|
||||
termsIdMap[term.trmsTpCd] = term.trmsId;
|
||||
}
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: types.SET_TERMS_ID_MAP,
|
||||
payload: termsIdMap,
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.log("약관 ID 매핑 생성:", termsIdMap);
|
||||
}
|
||||
}
|
||||
|
||||
// 후속 액션 호출 (기존과 동일)
|
||||
setTimeout(() => {
|
||||
dispatch(getTermsAgreeYn());
|
||||
}, 0);
|
||||
|
||||
return { success: true, data: result.data };
|
||||
} else {
|
||||
// retCode가 0이 아닌 일반적인 API 에러
|
||||
console.error("API returned non-zero retCode:", result.data?.retCode);
|
||||
dispatch({ type: types.GET_TERMS_AGREE_YN_FAILURE });
|
||||
return {
|
||||
success: false,
|
||||
message: result.data?.retMsg || "서버 오류가 발생했습니다."
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 메뉴 목록 조회 IF-LGSP-044
|
||||
export const getHomeMenu = () => (dispatch, getState) => {
|
||||
const onSuccess = (response) => {
|
||||
|
||||
@@ -25,6 +25,7 @@ const initialState = {
|
||||
ownerId: null,
|
||||
isPaused: false,
|
||||
},
|
||||
termsIdMap: {}, // added new property to initialState
|
||||
};
|
||||
|
||||
export const homeReducer = (state = initialState, action) => {
|
||||
@@ -35,6 +36,12 @@ export const homeReducer = (state = initialState, action) => {
|
||||
termsData: action.payload,
|
||||
};
|
||||
|
||||
case types.SET_TERMS_ID_MAP:
|
||||
return {
|
||||
...state,
|
||||
termsIdMap: action.payload,
|
||||
};
|
||||
|
||||
case types.GET_HOME_MENU: {
|
||||
let menuItems = [];
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ export default function HomeBanner({
|
||||
}, [dispatch]);
|
||||
|
||||
const termsData = useSelector((state) => state.home.termsData);
|
||||
const termsIdMap = useSelector((state) => state.home.termsIdMap);
|
||||
const optionalTermsData = useSelector((state) =>
|
||||
state.home.termsData?.data?.terms.find(
|
||||
(term) => term.trmsTpCd === "MST00405",
|
||||
@@ -128,35 +129,76 @@ export default function HomeBanner({
|
||||
}, [termsData, termsLoading, isGnbOpened]);
|
||||
|
||||
const handleOptionalAgree = useCallback(() => {
|
||||
console.log("handleAgree Click");
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.log("[HomeBanner] handleAgree Click");
|
||||
}
|
||||
|
||||
if (!termsIdMap || Object.keys(termsIdMap).length === 0) {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.error("[HomeBanner] termsIdMap이 없습니다:", termsIdMap);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const requiredTermTypes = ["MST00401", "MST00402", "MST00405"];
|
||||
const missingTerms = requiredTermTypes.filter(
|
||||
(type) => !termsIdMap[type],
|
||||
);
|
||||
|
||||
if (missingTerms.length > 0) {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.error("[HomeBanner] 누락된 약관 타입:", missingTerms);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const termsList = [];
|
||||
|
||||
if (termsIdMap["MST00401"]) {
|
||||
termsList.push(termsIdMap["MST00401"]); // 개인정보처리방침
|
||||
}
|
||||
if (termsIdMap["MST00402"]) {
|
||||
termsList.push(termsIdMap["MST00402"]); // 이용약관
|
||||
}
|
||||
if (termsIdMap["MST00405"]) {
|
||||
termsList.push(termsIdMap["MST00405"]); // 선택약관
|
||||
}
|
||||
|
||||
// 약관 동의할 항목들 (string array)
|
||||
const termsList = ["TID0000222", "TID0000223", "TID0000232"];
|
||||
// 동의하지 않을 항목들 (빈 배열)
|
||||
const notTermsList = [];
|
||||
console.log("OptionalTermsConfirm -약관 동의 API 호출 파라미터:", {
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.log("[HomeBanner] 현재 termsIdMap:", termsIdMap);
|
||||
console.log("[HomeBanner] 약관 동의 API 호출 파라미터:", {
|
||||
termsList,
|
||||
notTermsList,
|
||||
});
|
||||
}
|
||||
|
||||
const callback = (response) => {
|
||||
if (response.retCode === "000" || response.retCode === 0) {
|
||||
console.log("약관 동의 성공:", response);
|
||||
// 약관 정보 갱신
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.log("[HomeBanner] 약관 동의 성공:", response);
|
||||
}
|
||||
dispatch(fetchCurrentUserHomeTerms());
|
||||
} else {
|
||||
console.error("약관 동의 실패:", response);
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.error("[HomeBanner] 약관 동의 실패:", response);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
console.log("OptionalTermsConfirm - 약관 동의 API 호출 payload:", {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.log("[HomeBanner] 약관 동의 API 호출 payload:", {
|
||||
termsList,
|
||||
notTermsList,
|
||||
});
|
||||
}
|
||||
|
||||
dispatch(setMyPageTermsAgree({ termsList, notTermsList }, callback));
|
||||
}, [dispatch]);
|
||||
}, [dispatch, termsIdMap]);
|
||||
|
||||
const handleOptionalTermsClick = useCallback(() => {
|
||||
console.log("약관 자세히 보기 클릭");
|
||||
console.log("[HomeBanner] 약관 자세히 보기 클릭");
|
||||
setIsOptionalConfirmVisible(false);
|
||||
setIsOptionalTermsVisible(true);
|
||||
// 약관 상세 팝업을 띄우는 로직 추가
|
||||
@@ -165,10 +207,10 @@ export default function HomeBanner({
|
||||
const handleOptionalAgreeClick = useCallback(() => {
|
||||
handleOptionalAgree();
|
||||
setIsOptionalConfirmVisible(false);
|
||||
}, []);
|
||||
}, [handleOptionalAgree]);
|
||||
|
||||
const handleOptionalDeclineClick = useCallback(() => {
|
||||
console.log("거절/다음에 하기 버튼 클릭");
|
||||
console.log("[HomeBanner] 거절/다음에 하기 버튼 클릭");
|
||||
setIsOptionalConfirmVisible(false);
|
||||
// 거절 처리 로직 추가
|
||||
}, []);
|
||||
@@ -182,10 +224,10 @@ export default function HomeBanner({
|
||||
|
||||
// 선택약관 팝업 Agree
|
||||
const handleTermsPopupAgree = useCallback(() => {
|
||||
console.log("handleTermsPopupAgree");
|
||||
console.log("[HomeBanner] handleTermsPopupAgree");
|
||||
handleOptionalAgree();
|
||||
setIsOptionalTermsVisible(false);
|
||||
}, []);
|
||||
}, [handleOptionalAgree]);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const _handleShelfFocus = useCallback(() => {
|
||||
|
||||
@@ -64,6 +64,7 @@ export default function IntroPanel({
|
||||
const dispatch = useDispatch();
|
||||
// const blurTimeout = useRef(null);
|
||||
const termsData = useSelector((state) => state.home.termsData);
|
||||
const termsIdMap = useSelector((state) => state.home.termsIdMap);
|
||||
const { popupVisible, activePopup, ...popupState } = useSelector(
|
||||
(state) => state.common.popup,
|
||||
);
|
||||
@@ -76,6 +77,8 @@ export default function IntroPanel({
|
||||
// registerDevice API 호출 중 여부
|
||||
const [isProcessing, setIsProcessing] = useState(false);
|
||||
const [showExitMessagePopup, setShowExitMessagePopup] = useState(false);
|
||||
// race condition 방지를 위한 안전장치
|
||||
const processingTimeoutRef = useRef(null);
|
||||
// const [isRequiredFocused, setIsRequiredFocused] = useState(false);
|
||||
|
||||
const { focusedItem, setFocusAsync, clearFocusAsync } = useSafeFocusState();
|
||||
@@ -262,7 +265,10 @@ export default function IntroPanel({
|
||||
}, [dispatch]);
|
||||
|
||||
const handleAgree = useCallback(() => {
|
||||
if (isProcessing) return;
|
||||
console.log("[IntroPanel] handleAgree isProcessing=", isProcessing);
|
||||
if (isProcessing){
|
||||
return;
|
||||
}
|
||||
|
||||
// 필수 약관이 체크되어 있는지 확인
|
||||
// if (!termsChecked || !privacyChecked) {
|
||||
@@ -277,24 +283,32 @@ export default function IntroPanel({
|
||||
// }
|
||||
|
||||
setIsProcessing(true);
|
||||
|
||||
// 안전장치: 30초 후 자동으로 isProcessing 해제
|
||||
processingTimeoutRef.current = setTimeout(() => {
|
||||
console.warn("[IntroPanel] handleAgree 타임아웃 - isProcessing 강제 해제");
|
||||
setIsProcessing(false);
|
||||
}, 30000);
|
||||
|
||||
// 약관 동의 처리 시작 시 로딩 상태로 설정
|
||||
dispatch({ type: types.GET_TERMS_AGREE_YN_START });
|
||||
|
||||
// 약관 ID 정확하게 매핑
|
||||
// Redux에서 가져온 termsIdMap을 사용하여 동적으로 약관 ID 매핑
|
||||
const agreeTerms = [];
|
||||
|
||||
if (termsChecked) {
|
||||
agreeTerms.push("TID0000222"); // MST00402 -> TID0000222 (이용약관)
|
||||
if (termsChecked && termsIdMap["MST00402"]) {
|
||||
agreeTerms.push(termsIdMap["MST00402"]); // 이용약관
|
||||
}
|
||||
if (privacyChecked) {
|
||||
agreeTerms.push("TID0000223"); // MST00401 -> TID0000223 (개인정보처리방침)
|
||||
if (privacyChecked && termsIdMap["MST00401"]) {
|
||||
agreeTerms.push(termsIdMap["MST00401"]); // 개인정보처리방침
|
||||
}
|
||||
if (optionalChecked) {
|
||||
agreeTerms.push("TID0000232"); // MST00405 -> TID0000232 (선택약관)
|
||||
if (optionalChecked && termsIdMap["MST00405"]) {
|
||||
agreeTerms.push(termsIdMap["MST00405"]); // 선택약관
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.log("최종 전송될 agreeTerms:", agreeTerms);
|
||||
console.log("[IntroPanel] 현재 termsIdMap:", termsIdMap);
|
||||
console.log("[IntroPanel] 최종 전송될 agreeTerms:", agreeTerms);
|
||||
}
|
||||
|
||||
dispatch(
|
||||
@@ -334,6 +348,7 @@ export default function IntroPanel({
|
||||
}
|
||||
dispatch(popPanel(panel_names.INTRO_PANEL));
|
||||
setIsProcessing(false);
|
||||
clearTimeout(processingTimeoutRef.current); // 타임아웃 정리
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
@@ -345,6 +360,7 @@ export default function IntroPanel({
|
||||
}),
|
||||
);
|
||||
setIsProcessing(false);
|
||||
clearTimeout(processingTimeoutRef.current); // 타임아웃 정리
|
||||
}
|
||||
},
|
||||
() => {
|
||||
@@ -356,6 +372,7 @@ export default function IntroPanel({
|
||||
}),
|
||||
);
|
||||
setIsProcessing(false);
|
||||
clearTimeout(processingTimeoutRef.current); // 타임아웃 정리
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -366,6 +383,7 @@ export default function IntroPanel({
|
||||
dispatch,
|
||||
isProcessing,
|
||||
webOSVersion,
|
||||
termsIdMap,
|
||||
]);
|
||||
|
||||
// 실패 감지를 위한 useEffect 추가
|
||||
@@ -386,9 +404,19 @@ export default function IntroPanel({
|
||||
}),
|
||||
);
|
||||
setIsProcessing(false);
|
||||
clearTimeout(processingTimeoutRef.current); // 타임아웃 정리
|
||||
}
|
||||
}, [regDeviceData, dispatch, isProcessing]); // isProcessing 의존성 추가
|
||||
|
||||
// 컴포넌트 언마운트 시 타임아웃 정리
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (processingTimeoutRef.current) {
|
||||
clearTimeout(processingTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleDisagree = useCallback(() => {
|
||||
dispatch(setShowPopup(Config.ACTIVE_POPUP.exitPopup));
|
||||
dispatch(sendLogTerms({ logTpNo: Config.LOG_TP_NO.TERMS.DO_NOT_AGREE }));
|
||||
|
||||
Reference in New Issue
Block a user