fix: 선택약관 3차수정

This commit is contained in:
djaco
2025-06-20 15:36:55 +09:00
parent fa480e96f7
commit f0418b3c2b
6 changed files with 209 additions and 121 deletions

View File

@@ -13,6 +13,7 @@ export const types = {
REGISTER_DEVICE_INFO: "REGISTER_DEVICE_INFO", REGISTER_DEVICE_INFO: "REGISTER_DEVICE_INFO",
GET_DEVICE_INFO: "GET_DEVICE_INFO", GET_DEVICE_INFO: "GET_DEVICE_INFO",
CLEAR_REGISTER_DEVICE_INFO: "CLEAR_REGISTER_DEVICE_INFO", CLEAR_REGISTER_DEVICE_INFO: "CLEAR_REGISTER_DEVICE_INFO",
REGISTER_DEVICE_RESET: "REGISTER_DEVICE_RESET",
// common actions // common actions
GET_HTTP_HEADER: "GET_HTTP_HEADER", GET_HTTP_HEADER: "GET_HTTP_HEADER",
@@ -216,4 +217,7 @@ export const types = {
GET_TERMS_AGREE_YN_START: "GET_TERMS_AGREE_YN_START", GET_TERMS_AGREE_YN_START: "GET_TERMS_AGREE_YN_START",
GET_TERMS_AGREE_YN_SUCCESS: "GET_TERMS_AGREE_YN_SUCCESS", GET_TERMS_AGREE_YN_SUCCESS: "GET_TERMS_AGREE_YN_SUCCESS",
GET_TERMS_AGREE_YN_FAILURE: "GET_TERMS_AGREE_YN_FAILURE", GET_TERMS_AGREE_YN_FAILURE: "GET_TERMS_AGREE_YN_FAILURE",
// device
REQ_REG_DEVICE_INFO: "REQ_REG_DEVICE_INFO",
}; };

View File

@@ -12,6 +12,7 @@ const OptionalConfirm = ({
open, open,
spotlightId, spotlightId,
className, className,
onClose,
onOptionalTermsClick, // 약관 자세히 보기 버튼 클릭 핸들러 onOptionalTermsClick, // 약관 자세히 보기 버튼 클릭 핸들러
onOptionalAgreeClick, // 동의 버튼 클릭 핸들러 onOptionalAgreeClick, // 동의 버튼 클릭 핸들러
onOptionalDeclineClick, // 거절 또는 다음에 하기 버튼 클릭 핸들러 onOptionalDeclineClick, // 거절 또는 다음에 하기 버튼 클릭 핸들러
@@ -25,6 +26,7 @@ const OptionalConfirm = ({
spotlightId={spotlightId} spotlightId={spotlightId}
spotlightRestrict="self-only" // 필요에 따라 props로 설정 가능하게 있습니다. spotlightRestrict="self-only" // 필요에 따라 props로 설정 가능하게 있습니다.
className={`${css.optionalConfirmPopup} ${className || ''}`.trim()} className={`${css.optionalConfirmPopup} ${className || ''}`.trim()}
onClose={onClose}
onOptionalTermsClick={onOptionalTermsClick} onOptionalTermsClick={onOptionalTermsClick}
onOptionalAgreeClick={onOptionalAgreeClick} onOptionalAgreeClick={onOptionalAgreeClick}
onOptionalDeclineClick={onOptionalDeclineClick} onOptionalDeclineClick={onOptionalDeclineClick}
@@ -41,6 +43,8 @@ OptionalConfirm.propTypes = {
spotlightId: PropTypes.string.isRequired, spotlightId: PropTypes.string.isRequired,
/** 추가적인 CSS 클래스 */ /** 추가적인 CSS 클래스 */
className: PropTypes.string, className: PropTypes.string,
/** 팝업의 닫기 이벤트 핸들러 (ESC 키 등) */
onClose: PropTypes.func,
/** 약관 자세히 보기 버튼 클릭 시 호출될 함수 */ /** 약관 자세히 보기 버튼 클릭 시 호출될 함수 */
onOptionalTermsClick: PropTypes.func, onOptionalTermsClick: PropTypes.func,
/** 동의 버튼 클릭 시 호출될 함수 */ /** 동의 버튼 클릭 시 호출될 함수 */
@@ -55,6 +59,7 @@ OptionalConfirm.propTypes = {
OptionalConfirm.defaultProps = { OptionalConfirm.defaultProps = {
className: '', className: '',
onClose: () => console.log('OptionalConfirm: onClose not provided'),
onOptionalTermsClick: () => console.log('OptionalConfirm: onOptionalTermsClick not provided'), onOptionalTermsClick: () => console.log('OptionalConfirm: onOptionalTermsClick not provided'),
onOptionalAgreeClick: () => console.log('OptionalConfirm: onOptionalAgreeClick not provided'), onOptionalAgreeClick: () => console.log('OptionalConfirm: onOptionalAgreeClick not provided'),
onOptionalDeclineClick: () => console.log('OptionalConfirm: onOptionalDeclineClick not provided'), onOptionalDeclineClick: () => console.log('OptionalConfirm: onOptionalDeclineClick not provided'),

View File

@@ -1,4 +1,7 @@
import { types } from "../actions/actionTypes"; import { types } from "../actions/actionTypes";
import {
GET_TERMS_AGREE_YN_FAIL,
} from "../actions/commonActions";
const initialState = { const initialState = {
regDeviceData: {}, regDeviceData: {},
@@ -25,9 +28,13 @@ export const deviceReducer = (state = initialState, action) => {
case types.CLEAR_REGISTER_DEVICE_INFO: case types.CLEAR_REGISTER_DEVICE_INFO:
return { return {
...state, ...state,
regDeviceInfoData: { retCode: undefined }, regDeviceData: null,
};
case types.REGISTER_DEVICE_RESET:
return {
...state,
regDeviceData: null,
}; };
default: default:
return state; return state;
} }

View File

@@ -321,6 +321,7 @@ export default function HomeBanner({
<OptionalConfirm <OptionalConfirm
open={isOptionalConfirmVisible} open={isOptionalConfirmVisible}
spotlightId="optional-confirm-popup" spotlightId="optional-confirm-popup"
onClose={handleOptionalDeclineClick}
onOptionalTermsClick={handleOptionalTermsClick} onOptionalTermsClick={handleOptionalTermsClick}
onOptionalAgreeClick={handleOptionalAgreeClick} onOptionalAgreeClick={handleOptionalAgreeClick}
onOptionalDeclineClick={handleOptionalDeclineClick} onOptionalDeclineClick={handleOptionalDeclineClick}
@@ -337,7 +338,7 @@ export default function HomeBanner({
<TNewPopUp <TNewPopUp
kind="introTermsPopup" kind="introTermsPopup"
open={isOptionalTermsVisible} open={isOptionalTermsVisible}
// onClose={handleTermsPopupClosed} onClose={handleTermsPopupClosed}
onClick={handleTermsPopupClosed} onClick={handleTermsPopupClosed}
onIntroTermsAgreeClick={handleTermsPopupAgree} onIntroTermsAgreeClick={handleTermsPopupAgree}
hasButton hasButton

View File

@@ -117,24 +117,25 @@ export default function IntroPanel({
// 상태 관리 // 상태 관리
const [currentTerms, setCurrentTerms] = useState(null); const [currentTerms, setCurrentTerms] = useState(null);
const [termsChecked, setTermsChecked] = useState(true); // Terms & Conditions 기본 체크 const [termsChecked, setTermsChecked] = useState(false); // Terms & Conditions 기본 체크
const [privacyChecked, setPrivacyChecked] = useState(true); // Privacy Policy 기본 체크 const [privacyChecked, setPrivacyChecked] = useState(false); // Privacy Policy 기본 체크
const [optionalChecked, setOptionalChecked] = useState(false); // Optional Terms 기본 체크 안됨 const [optionalChecked, setOptionalChecked] = useState(false); // Optional Terms 기본 체크 안됨
const [selectAllChecked, setSelectAllChecked] = useState(false); const [selectAllChecked, setSelectAllChecked] = useState(false);
const [focusedItem, setFocusedItem] = useState(null); // 포커스 추적 상태 추가 const [focusedItem, setFocusedItem] = useState(null); // 포커스 추적 상태 추가
useEffect(() => { useEffect(() => {
dispatch({ type: types.REGISTER_DEVICE_RESET });
dispatch(sendLogGNB(Config.LOG_MENU.TERMS_CONDITIONS)); dispatch(sendLogGNB(Config.LOG_MENU.TERMS_CONDITIONS));
}, []); }, [dispatch]);
// 컴포넌트 마운트 시 현재 Redux 상태 로깅 // 컴포넌트 마운트 시 현재 Redux 상태 로깅
useEffect(() => { // useEffect(() => {
console.log('🔍 IntroPanel 마운트 시 Redux 상태:'); // console.log('🔍 IntroPanel 마운트 시 Redux 상태:');
console.log(' - regDeviceData:', regDeviceData); // console.log(' - regDeviceData:', regDeviceData);
console.log(' - regDeviceInfoData:', regDeviceInfoData); // console.log(' - regDeviceInfoData:', regDeviceInfoData);
console.log(' - eventInfos:', eventInfos); // console.log(' - eventInfos:', eventInfos);
console.log(' - termsData:', termsData); // console.log(' - termsData:', termsData);
}, []); // }, []);
// 디버깅용 WebOS 버전 로그 // 디버깅용 WebOS 버전 로그
useEffect(() => { useEffect(() => {
@@ -247,16 +248,16 @@ export default function IntroPanel({
if (isProcessing) return; if (isProcessing) return;
// 필수 약관이 체크되어 있는지 확인 // 필수 약관이 체크되어 있는지 확인
if (!termsChecked || !privacyChecked) { // if (!termsChecked || !privacyChecked) {
// 필수 약관이 체크되지 않았을 때 알림 // // 필수 약관이 체크되지 않았을 때 알림
// window.alert($L("Please agree to Terms & Conditions and Privacy Policy.")); // // window.alert($L("Please agree to Terms & Conditions and Privacy Policy."));
dispatch(setShowPopup(Config.ACTIVE_POPUP.alertPopup, { // dispatch(setShowPopup(Config.ACTIVE_POPUP.alertPopup, {
title: $L("Required Terms"), // title: $L("Required Terms"),
text: $L("Please agree to Terms & Conditions and Privacy Policy."), // text: $L("Please agree to Terms & Conditions and Privacy Policy."),
button1Text: $L("OK") // button1Text: $L("OK")
})); // }));
return; // return;
} // }
setIsProcessing(true); setIsProcessing(true);
// 약관 동의 처리 시작 시 로딩 상태로 설정 // 약관 동의 처리 시작 시 로딩 상태로 설정
@@ -352,7 +353,10 @@ export default function IntroPanel({
useEffect(() => { useEffect(() => {
// isProcessing이 true일 때만 실패 체크 (= handleAgree 클릭 후에만) // isProcessing이 true일 때만 실패 체크 (= handleAgree 클릭 후에만)
if (isProcessing && regDeviceData && regDeviceData.retCode !== 0) { if (isProcessing && regDeviceData && regDeviceData.retCode !== 0) {
console.error("registerDevice 실패:", regDeviceData); console.error(
`[IntroPanel] registerDevice 실패: isProcessing=${isProcessing}, retCode=${regDeviceData.retCode}`,
regDeviceData
);
dispatch( dispatch(
setShowPopup(Config.ACTIVE_POPUP.alertPopup, { setShowPopup(Config.ACTIVE_POPUP.alertPopup, {
title: $L("Error"), title: $L("Error"),
@@ -394,13 +398,11 @@ export default function IntroPanel({
blurTimeout.current = null; blurTimeout.current = null;
} }
setFocusedItem(item); setFocusedItem(item);
setIsRequiredFocused(item === 'required');
}, []); }, []);
const handleBlur = useCallback(() => { const handleBlur = useCallback(() => {
blurTimeout.current = setTimeout(() => { blurTimeout.current = setTimeout(() => {
setFocusedItem(null); setFocusedItem(null);
setIsRequiredFocused(false);
}, 0); }, 0);
}, []); }, []);
@@ -426,6 +428,32 @@ export default function IntroPanel({
const rightPanelContent = useMemo(() => { const rightPanelContent = useMemo(() => {
const requiredItemIds = [
"termsCheckbox",
"termsButton",
"privacyCheckbox",
"privacyButton",
];
if (!requiredItemIds.includes(focusedItem)) {
return (
<>
{shouldShowBenefitsView ? (
<div className={css.optionalDescription}>
{$L(
'By checking "Optional terms", you allow Shop Time to use your activity (views, purchases, searches, etc.) to show you more relevant content, product recommendations, special offers, and ads. If you do not check, you can still use all basic Shop Time features'
)}
</div>
) : (
<OptionalTermsInfo
displayMode="image"
imageTitle={$L("Agree and Enjoy Special Benefits")}
spotlightId="optional-terms-info"
/>
)}
</>
);
}
const hasRequiredUnchecked = !termsChecked || !privacyChecked; const hasRequiredUnchecked = !termsChecked || !privacyChecked;
// 우선순위 1: 필수 약관이 체크 안됨 → 항상 경고 메시지 // 우선순위 1: 필수 약관이 체크 안됨 → 항상 경고 메시지
@@ -433,54 +461,43 @@ export default function IntroPanel({
return ( return (
<div className={css.requiredInfoPanel}> <div className={css.requiredInfoPanel}>
<p className={css.infoText}>{$L("Required Consent")}</p> <p className={css.infoText}>{$L("Required Consent")}</p>
<p className={css.infoText}>{$L("(Necessary for using the service)")}</p> <p className={css.infoText}>
{$L("(Necessary for using the service)")}
</p>
<div className={css.warningContainer}> <div className={css.warningContainer}>
<p className={css.warningText}>{$L("Please agree to the required Terms & Conditions and")}</p> <p className={css.warningText}>
<p className={css.warningText}>{$L("Privacy Policy to start enjoying Shop Time")}</p> {$L("Please agree to the required Terms & Conditions and")}
</p>
<p className={css.warningText}>
{$L("Privacy Policy to start enjoying Shop Time")}
</p>
</div> </div>
</div> </div>
); );
} }
// 우선순위 2: 필수 약관에 포커스 있음 → 필수 약관 안내 // 우선순위 2: 필수 약관에 포커스 있음 → 필수 약관 안내
if (isRequiredFocused) {
return (
<div className={css.requiredInfoPanel}>
<p className={css.infoText}>{$L("Required Consent")}</p>
<p className={css.infoText}>{$L("(Necessary for using the service)")}</p>
</div>
);
}
// 우선순위 3: 기본값 → 선택 약관 정보
return ( return (
<> <div className={css.requiredInfoPanel}>
{shouldShowBenefitsView ? ( <p className={css.infoText}>{$L("Required Consent")}</p>
<div className={css.optionalDescription}> <p className={css.infoText}>
{$L('By checking "Optional terms", you allow Shop Time to use your activity (views, purchases, searches, etc.) to show you more relevant content, product recommendations, special offers, and ads. If you do not check, you can still use all basic Shop Time features')} {$L("(Necessary for using the service)")}
</div> </p>
) : ( </div>
<OptionalTermsInfo
displayMode="image"
imageTitle={$L('Agree and Enjoy Special Benefits')}
spotlightId="optional-terms-info"
/>
)}
</>
); );
}, [termsChecked, privacyChecked, isRequiredFocused, shouldShowBenefitsView]); }, [termsChecked, privacyChecked, focusedItem, shouldShowBenefitsView]);
useEffect(() => { useEffect(() => {
Spotlight.focus(); Spotlight.focus();
}, [popupVisible]); }, [popupVisible]);
useEffect(() => { // useEffect(() => {
if (regDeviceInfoData && regDeviceInfoData.retCode === 0) { // if (regDeviceInfoData && regDeviceInfoData.retCode === 0) {
dispatch(setHidePopup()); // dispatch(setHidePopup());
dispatch(popPanel(panel_names.INTRO_PANEL)); // dispatch(popPanel(panel_names.INTRO_PANEL));
} // }
}, [dispatch, regDeviceInfoData]); // }, [dispatch, regDeviceInfoData]);
const description = $L( const description = $L(
"Check out more LIVE SHOWS now and enjoy shopping at Shop Time's special price on your TV by agreeing to the LG TV Shopping Terms and Conditions." "Check out more LIVE SHOWS now and enjoy shopping at Shop Time's special price on your TV by agreeing to the LG TV Shopping Terms and Conditions."
@@ -536,7 +553,7 @@ export default function IntroPanel({
className={css.customeCheckbox} className={css.customeCheckbox}
selected={termsChecked} selected={termsChecked}
onToggle={handleTermsToggle} onToggle={handleTermsToggle}
onFocus={() => handleFocus('required')} onFocus={() => handleFocus('termsCheckbox')}
onBlur={handleBlur} onBlur={handleBlur}
spotlightId="termsCheckbox" spotlightId="termsCheckbox"
ariaLabel={$L("Terms & Conditions checkbox")} ariaLabel={$L("Terms & Conditions checkbox")}
@@ -544,7 +561,7 @@ export default function IntroPanel({
<TButton <TButton
className={css.termsButton} className={css.termsButton}
onClick={() => handleTermsClick("MST00402")} onClick={() => handleTermsClick("MST00402")}
onFocus={() => handleFocus('required')} onFocus={() => handleFocus('termsButton')}
onBlur={handleBlur} onBlur={handleBlur}
spotlightId="termsButton" spotlightId="termsButton"
type={TYPES.terms} type={TYPES.terms}
@@ -562,7 +579,7 @@ export default function IntroPanel({
className={css.customeCheckbox} className={css.customeCheckbox}
selected={privacyChecked} selected={privacyChecked}
onToggle={handlePrivacyToggle} onToggle={handlePrivacyToggle}
onFocus={() => handleFocus('required')} onFocus={() => handleFocus('privacyCheckbox')}
onBlur={handleBlur} onBlur={handleBlur}
spotlightId="privacyCheckbox" spotlightId="privacyCheckbox"
ariaLabel={$L("Privacy Policy checkbox")} ariaLabel={$L("Privacy Policy checkbox")}
@@ -570,7 +587,7 @@ export default function IntroPanel({
<TButton <TButton
className={css.termsButton} className={css.termsButton}
onClick={() => handleTermsClick("MST00401")} onClick={() => handleTermsClick("MST00401")}
onFocus={() => handleFocus('required')} onFocus={() => handleFocus('privacyButton')}
onBlur={handleBlur} onBlur={handleBlur}
spotlightId="privacyButton" spotlightId="privacyButton"
type={TYPES.terms} type={TYPES.terms}
@@ -588,7 +605,7 @@ export default function IntroPanel({
className={css.customeCheckbox} className={css.customeCheckbox}
selected={optionalChecked} selected={optionalChecked}
onToggle={handleOptionalToggle} onToggle={handleOptionalToggle}
onFocus={() => handleFocus('optional')} onFocus={() => handleFocus('optionalCheckbox')}
onBlur={handleBlur} onBlur={handleBlur}
spotlightId="optionalCheckbox" spotlightId="optionalCheckbox"
ariaLabel={$L("Optional Terms checkbox")} ariaLabel={$L("Optional Terms checkbox")}
@@ -596,7 +613,7 @@ export default function IntroPanel({
<TButton <TButton
className={css.termsButton} className={css.termsButton}
onClick={() => handleOptionalTermsClick("MST00405")} onClick={() => handleOptionalTermsClick("MST00405")}
onFocus={() => handleFocus('optional')} onFocus={() => handleFocus('optionalButton')}
onBlur={handleBlur} onBlur={handleBlur}
spotlightId="optionalButton" spotlightId="optionalButton"
type={TYPES.terms} type={TYPES.terms}
@@ -619,6 +636,8 @@ export default function IntroPanel({
className={css.selectAllCheckbox} className={css.selectAllCheckbox}
selected={selectAllChecked} selected={selectAllChecked}
onToggle={handleSelectAllToggle} onToggle={handleSelectAllToggle}
onFocus={() => handleFocus('selectAllCheckbox')}
onBlur={handleBlur}
spotlightId="selectAllCheckbox" spotlightId="selectAllCheckbox"
ariaLabel={$L("Select All checkbox")} ariaLabel={$L("Select All checkbox")}
/> />
@@ -632,6 +651,8 @@ export default function IntroPanel({
<TButton <TButton
className={css.agreeButton} className={css.agreeButton}
onClick={handleAgree} onClick={handleAgree}
onFocus={() => handleFocus('agreeButton')}
onBlur={handleBlur}
spotlightId="agreeButton" spotlightId="agreeButton"
type={TYPES.agree} type={TYPES.agree}
ariaLabel={$L("Agree to terms")} ariaLabel={$L("Agree to terms")}
@@ -643,6 +664,8 @@ export default function IntroPanel({
<TButton <TButton
className={css.disagreeButton} className={css.disagreeButton}
onClick={handleDisagree} onClick={handleDisagree}
onFocus={() => handleFocus('disagreeButton')}
onBlur={handleBlur}
spotlightId="disagreeButton" spotlightId="disagreeButton"
type={TYPES.agree} type={TYPES.agree}
ariaLabel={$L("Do not agree to terms")} ariaLabel={$L("Do not agree to terms")}
@@ -710,8 +733,8 @@ export default function IntroPanel({
hasButton hasButton
button1Text={popupState.button1Text || $L("OK")} button1Text={popupState.button1Text || $L("OK")}
hasText hasText
title={$L("Required Terms")} title={popupState.title || ""}
text={$L("Please agree to Terms & Conditions and Privacy Policy.")} text={popupState.text || ""}
/> />
)} )}

View File

@@ -49,7 +49,7 @@ export default function TermsOfService({ title, cbScrollTo }) {
const [optionalDisagreePopupOpen, setOptionalDisagreePopupOpen] = const [optionalDisagreePopupOpen, setOptionalDisagreePopupOpen] =
useState(false); useState(false);
const [showCheckboxAlert, setShowCheckboxAlert] = useState(false); const [showCheckboxAlert, setShowCheckboxAlert] = useState(false);
const agreePopupTimeoutRef = useRef(null);
const { popupVisible } = useSelector((state) => state.common?.popup); const { popupVisible } = useSelector((state) => state.common?.popup);
const { optionalTermsAgree } = useSelector((state) => state.common); const { optionalTermsAgree } = useSelector((state) => state.common);
@@ -60,16 +60,33 @@ export default function TermsOfService({ title, cbScrollTo }) {
); );
const [spotlightDisabled, setSpotlightDisabled] = useState(true); const [spotlightDisabled, setSpotlightDisabled] = useState(true);
const [termsList, setTermsList] = useState([]); const [termsList, setTermsList] = useState([]);
const termsListRef = useRef(termsList);
const dispatch = useDispatch(); const dispatch = useDispatch();
const focusJob = useRef(null); const focusJob = useRef(null);
useEffect(() => {
return () => {
if (agreePopupTimeoutRef.current) {
clearTimeout(agreePopupTimeoutRef.current);
}
};
}, []);
useEffect(() => { useEffect(() => {
dispatch(fetchCurrentUserHomeTerms()); dispatch(fetchCurrentUserHomeTerms());
}, [dispatch]); }, [dispatch]);
useEffect(() => { useEffect(() => {
// console.log(
// "[TermsOfService] termsData:",
// JSON.stringify(termsData, null, 2)
// );
// console.log(
// "[TermsOfService] empTermsData:",
// JSON.stringify(empTermsData, null, 2)
// );
const newTabList = []; const newTabList = [];
const tempList = []; const tempList = [];
const newTrmsCdList = []; const newTrmsCdList = [];
@@ -106,11 +123,19 @@ export default function TermsOfService({ title, cbScrollTo }) {
setTabList(newTabList); setTabList(newTabList);
setTermsList(tempList); setTermsList(tempList);
// console.log(
// "[TermsOfService] Final termsList:",
// JSON.stringify(tempList, null, 2)
// );
setTrmsCdList(newTrmsCdList); setTrmsCdList(newTrmsCdList);
setSpotlightDisabled(false); setSpotlightDisabled(false);
}, [termsData, empTermsData, webOSVersion]); }, [termsData, empTermsData, webOSVersion]);
useEffect(() => {
termsListRef.current = termsList;
}, [termsList]);
useEffect(() => { useEffect(() => {
if (termsData && termsData.data && termsData.data.terms) { if (termsData && termsData.data && termsData.data.terms) {
dispatch(getTermsAgreeYn()); dispatch(getTermsAgreeYn());
@@ -216,39 +241,47 @@ export default function TermsOfService({ title, cbScrollTo }) {
); );
const handleOptionalAgree = useCallback(() => { const handleOptionalAgree = useCallback(() => {
console.log( // console.log(
"handleOptionalAgree called with isChecked:", // "handleOptionalAgree called with isChecked:",
isOptionalChecked // isOptionalChecked
); // );
if (isOptionalChecked) { // if (isOptionalChecked) {
const firstThreeTermIds = termsList const firstThreeTermIds = termsList
.slice(0, 3) .slice(0, 3)
.map((term) => term.termsId) .map((term) => term.termsId)
.filter(Boolean); .filter(Boolean);
if (firstThreeTermIds.length > 0) { if (firstThreeTermIds.length > 0) {
const payload = { termsList: firstThreeTermIds, notTermsList: [] }; const payload = { termsList: firstThreeTermIds, notTermsList: [] };
console.log("Dispatching setMyPageTermsAgree with payload:", payload); // console.log("Dispatching setMyPageTermsAgree with payload:", payload);
dispatch( dispatch(
setMyPageTermsAgree(payload, (response) => { setMyPageTermsAgree(payload, (response) => {
console.log("setMyPageTermsAgree callback response:", response); // console.log("setMyPageTermsAgree callback response:", response);
if (response.retCode === "000" || response.retCode === 0) { if (response.retCode === "000" || response.retCode === 0) {
console.log("Optional terms agreement successful."); console.log("Optional terms agreement successful.");
// 약관 동의의 후 약관 정보 조회 // 약관 동의의 후 약관 정보 조회
dispatch(fetchCurrentUserHomeTerms()); dispatch(fetchCurrentUserHomeTerms());
setAgreePopup(true); setAgreePopup(true);
} else {
console.error("Optional terms agreement failed:", response); if (agreePopupTimeoutRef.current) {
clearTimeout(agreePopupTimeoutRef.current);
} }
})
); agreePopupTimeoutRef.current = setTimeout(() => {
} else { setAgreePopup(false);
console.log("No terms found to agree to."); }, 3000);
} } else {
console.error("Optional terms agreement failed:", response);
}
})
);
} else { } else {
console.log("Checkbox not checked, not proceeding with agreement."); // console.log("No terms found to agree to.");
setShowCheckboxAlert(true);
} }
// } else {
// console.log("Checkbox not checked, not proceeding with agreement.");
// setShowCheckboxAlert(true);
// }
}, [dispatch, termsList, isOptionalChecked]); }, [dispatch, termsList, isOptionalChecked]);
const handleOptionalDisagree = useCallback(() => { const handleOptionalDisagree = useCallback(() => {
@@ -256,32 +289,43 @@ export default function TermsOfService({ title, cbScrollTo }) {
}, []); }, []);
const confirmOptionalDisagree = useCallback(() => { const confirmOptionalDisagree = useCallback(() => {
const optionalTerm = termsList.find( const currentTermsList = termsListRef.current;
// console.log("optionalTermsAgree:", currentTermsList);
const optionalTerm = currentTermsList.find(
(term) => term.trmsTpCd === "MST00405" (term) => term.trmsTpCd === "MST00405"
); );
// console.log("optionalTerm:", JSON.stringify(optionalTerm, null, 2));
// if (optionalTerm) {
// console.log("optionalTerm.termsId:", optionalTerm.termsId);
// }
if (optionalTerm && optionalTerm.termsId) { if (optionalTerm && optionalTerm.termsId) {
const payload = { const payload = {
mandatoryIncludeYn: "N", mandatoryIncludeYn: "N",
termsList: [optionalTerm.termsId], termsList: [optionalTerm.termsId],
}; };
console.log("Dispatching setMyTermsWithdraw with payload:", payload); // console.log("Dispatching setMyTermsWithdraw with payload:", payload);
// 선택약관 철회 // 선택약관 철회
dispatch(setMyTermsWithdraw(payload, (response) => { dispatch(
console.log("setMyTermsWithdraw callback response:", response); setMyTermsWithdraw(payload, (response) => {
if (response.retCode === "000" || response.retCode === 0) { // console.log("setMyTermsWithdraw callback response:", response);
console.log("Optional terms withdrawal successful."); if (response.retCode === "000" || response.retCode === 0) {
// 약관 철회 후 약관 정보 조회 console.log("Optional terms withdrawal successful.");
dispatch(fetchCurrentUserHomeTerms()); // 약관 철회 후 약관 정보 조회
setIsOptionalChecked(false); dispatch(fetchCurrentUserHomeTerms());
} else { setIsOptionalChecked(false);
console.error("Optional terms withdrawal failed:", response); } else {
} console.error("Optional terms withdrawal failed:", response);
})); }
setOptionalDisagreePopupOpen(false);
})
);
} else { } else {
console.log("No optional term found to disagree."); // console.log("No optional term found to disagree.");
setOptionalDisagreePopupOpen(false);
} }
setOptionalDisagreePopupOpen(false); }, [dispatch]);
}, [termsList, dispatch]);
const onCancelDisagree = useCallback(() => { const onCancelDisagree = useCallback(() => {
// setDisagreeConfirmOpen(false); // setDisagreeConfirmOpen(false);
@@ -462,23 +506,27 @@ export default function TermsOfService({ title, cbScrollTo }) {
/> />
<TPopUp <TPopUp
kind="textPopup" kind="exitPopup"
open={agreePopup} open={agreePopup}
onClose={() => setAgreePopup(false)} onClose={() => setAgreePopup(false)}
hasButton
button1Text={$L("OK")}
hasText hasText
title={$L("Agreement Complete")} title={$L("")}
text={$L("Your agreement has been processed.")} text={$L(
"From now on, you can receive personalized shopping benefits."
)}
/> />
{/* 새로 추가된 optionalAgreement 팝업 */} {/* 새로 추가된 optionalAgreement 팝업 */}
<TPopUp <TPopUp
kind="optionalAgreement" kind="exitPopup"
open={optionalDisagreePopupOpen} open={optionalDisagreePopupOpen}
onClose={() => setOptionalDisagreePopupOpen(false)} onClose={() => setOptionalDisagreePopupOpen(false)}
onClick={confirmOptionalDisagree} onExit={confirmOptionalDisagree}
hasButton
button1Text={$L("Yes")}
button2Text={$L("No")}
hasText hasText
title={$L("")}
text={$L("You will not receive personalized shopping benefits")} text={$L("You will not receive personalized shopping benefits")}
/> />
{/* 필수약관 체크 확인 팝업 */} {/* 필수약관 체크 확인 팝업 */}