From 10263b7f6578b3d695a962e5007bf2c1374675d7 Mon Sep 17 00:00:00 2001 From: djaco Date: Mon, 28 Jul 2025 15:05:36 +0900 Subject: [PATCH] =?UTF-8?q?[20250728]=20IntroPanel.new.jsx=20prettier=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/IntroPanel/IntroPanel.new.jsx | 200 ++++++++++-------- .../TermsOfService/OptionalTermsInfo.jsx | 86 ++++---- 2 files changed, 152 insertions(+), 134 deletions(-) diff --git a/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.jsx b/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.jsx index cdb8a032..28bd31f6 100644 --- a/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.jsx +++ b/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.jsx @@ -62,16 +62,22 @@ const RETRY_DELAY_MS = 1500; // 1.5 seconds // 조건부 IntroPanel 컴포넌트 (선택약관 존재 여부에 따라 다른 컴포넌트 렌더링) export default function IntroPanel(props) { - const optionalTermsAvailable = useSelector((state) => state.home.optionalTermsAvailable); - + const optionalTermsAvailable = useSelector( + (state) => state.home.optionalTermsAvailable, + ); + // 선택약관이 없으면 기존 IntroPanel.jsx 사용 if (!optionalTermsAvailable) { - console.log('[IntroPanel.new] optionalTermsAvailable = false, 기존 IntroPanel 사용'); + console.log( + "[IntroPanel.new] optionalTermsAvailable = false, 기존 IntroPanel 사용", + ); return ; } - + // 선택약관이 있으면 고급 IntroPanel 사용 - console.log('[IntroPanel.new] optionalTermsAvailable = true, 고급 IntroPanel 사용'); + console.log( + "[IntroPanel.new] optionalTermsAvailable = true, 고급 IntroPanel 사용", + ); return ; } @@ -96,7 +102,9 @@ function IntroPanelWithOptional({ ); // const eventInfos = useSelector((state) => state.event.eventData); const regDeviceData = useSelector((state) => state.device.regDeviceData); - const deviceRegistered = useSelector((state) => state.common.deviceRegistered); + const deviceRegistered = useSelector( + (state) => state.common.deviceRegistered, + ); // const regDeviceInfoData = useSelector( // (state) => state.device.regDeviceInfoData // ); @@ -128,7 +136,7 @@ function IntroPanelWithOptional({ // Chromium68 호환성을 위해 Optional Chaining 제거 if (termsData && termsData.data && termsData.data.terms) { return termsData.data.terms.filter( - (item) => item.trmsTpCd === "MST00401" || item.trmsTpCd === "MST00402" + (item) => item.trmsTpCd === "MST00401" || item.trmsTpCd === "MST00402", ); } return []; @@ -138,7 +146,7 @@ function IntroPanelWithOptional({ // Chromium68 호환성을 위해 Optional Chaining 제거 if (termsData && termsData.data && termsData.data.terms) { return termsData.data.terms.filter( - (item) => item.trmsTpCd === "MST00405" || item.trmsTpCd === "MST00406" + (item) => item.trmsTpCd === "MST00405" || item.trmsTpCd === "MST00406", ); } return []; @@ -146,12 +154,16 @@ function IntroPanelWithOptional({ const webOSVersion = useSelector((state) => { // Chromium68 호환성을 위해 Optional Chaining 제거 - if (state.common && state.common.appStatus && state.common.appStatus.webOSVersion) { + if ( + state.common && + state.common.appStatus && + state.common.appStatus.webOSVersion + ) { return state.common.appStatus.webOSVersion; } return null; }); - + // const webOSVersion = 4.5; // WebOS 버전별 UI 표시 모드 결정 // 이미지 표시: 4.0, 5.0, 23, 24 @@ -166,27 +178,26 @@ function IntroPanelWithOptional({ // 24 : 9.0.0~ // 25 : 10.0.0~ - const shouldShowBenefitsView = useMemo(() => { // if (!webOSVersion) return false; // webOSVersion 이 없거나 빈 문자열인 경우 이미지 보기 처리 if (!webOSVersion || webOSVersion === "") { return false; } - + const versionNum = Number.parseFloat(String(webOSVersion)); // 기존 로직 유지 const versionStr = String(webOSVersion); - + // 버전 문자열을 배열로 변환해서 비교 const parseVersionArray = (version) => { - return version.split('.').map(Number); + return version.split(".").map(Number); }; - + const currentVersionArray = parseVersionArray(versionStr); - + // 버전 구간별 약관 버전 매핑 let termsVersion = null; - + if (currentVersionArray[0] >= 10) { termsVersion = 25; } else if (currentVersionArray[0] >= 9) { @@ -203,18 +214,18 @@ function IntroPanelWithOptional({ // 4.x 버전은 세밀한 구분 필요 const minor = currentVersionArray[1] || 0; const patch = currentVersionArray[2] || 0; - + if (minor >= 5) { termsVersion = 4.5; // 4.5.0 이상 } else { termsVersion = 4.0; // 4.0.0 ~ 4.4.9 } } - + const textTermsVersions = [4.5, 6.0, 22]; // const imageTermsVersions = [4.0, 5.0, 23, 24]; const shouldShowText = textTermsVersions.includes(termsVersion); - + if (process.env.NODE_ENV === "development") { console.log("🔍 WebOS 버전별 UI 모드:"); console.log(" - webOSVersion:", webOSVersion); @@ -223,7 +234,7 @@ function IntroPanelWithOptional({ console.log(" - 매핑된 약관 버전:", termsVersion); console.log(" - shouldShowText (텍스트 모드):", shouldShowText); } - + return shouldShowText; }, [webOSVersion]); @@ -300,13 +311,13 @@ function IntroPanelWithOptional({ // // 이전 상태가 true이고 현재 상태가 false인 경우 (체크 해제) // if ((prevTermsChecked && !termsChecked) || (prevPrivacyChecked && !privacyChecked)) { // setRequiredAgreePopup(true); - // + // // // 3초 후 자동 닫기 // popupTimeoutRef.current = setTimeout(() => { // setRequiredAgreePopup(false); // }, 3000); // } - // + // // // 현재 상태를 이전 상태로 업데이트 // setPrevTermsChecked(termsChecked); // setPrevPrivacyChecked(privacyChecked); @@ -407,7 +418,9 @@ function IntroPanelWithOptional({ // [추가] 실제 처리 로직 분리 const executeAgree = useCallback( (retryCount = 0) => { - console.log(`[IntroPanel] executeAgree 실행 시작 (시도: ${retryCount + 1})`); + console.log( + `[IntroPanel] executeAgree 실행 시작 (시도: ${retryCount + 1})`, + ); // Redux에서 가져온 termsIdMap을 사용하여 동적으로 약관 ID 매핑 const agreeTerms = []; @@ -435,22 +448,26 @@ function IntroPanelWithOptional({ // ================== SUCCESS ================== if (newRegDeviceData && newRegDeviceData.retCode === 0) { dispatch(setDeviceRegistered(true)); - + // ✅ 선택약관 상태를 통합 액션으로 업데이트 (TV 환경 최적화) if (optionalChecked) { // 선택약관에 동의한 경우 - console.log("[IntroPanel] 선택약관 동의됨 - 통합 Redux 상태 업데이트"); + console.log( + "[IntroPanel] 선택약관 동의됨 - 통합 Redux 상태 업데이트", + ); dispatch(updateOptionalTermsAgreement(true)); } else { // 선택약관에 동의하지 않은 경우 - HomeBanner에서 팝업이 나올 수 있도록 상태를 초기화 - console.log("[IntroPanel] 선택약관 미동의 - HomeBanner 팝업 허용을 위해 상태 초기화"); + console.log( + "[IntroPanel] 선택약관 미동의 - HomeBanner 팝업 허용을 위해 상태 초기화", + ); dispatch(updateOptionalTermsAgreement(false)); setTimeout(() => { console.log("[IntroPanel] 선택약관 세션 리셋 실행"); dispatch(resetOptionalTermsSession()); }, 1000); } - + dispatch( getWelcomeEventInfo((eventInfos) => { if ( @@ -469,7 +486,7 @@ function IntroPanelWithOptional({ } dispatch( - sendLogTerms({ logTpNo: Config.LOG_TP_NO.TERMS.AGREE }) + sendLogTerms({ logTpNo: Config.LOG_TP_NO.TERMS.AGREE }), ); if (displayWelcomeEventPanel) { @@ -477,12 +494,12 @@ function IntroPanelWithOptional({ pushPanel({ name: panel_names.WELCOME_EVENT_PANEL, panelInfo: { eventInfos: eventInfos.data }, - }) + }), ); } } setIsProcessing(false); - }) + }), ); } else { // retCode가 0이 아닌 경우도 실패로 간주하고 재시도 @@ -495,10 +512,10 @@ function IntroPanelWithOptional({ setShowPopup(Config.ACTIVE_POPUP.alertPopup, { title: $L("Error"), text: $L( - "A temporary network error occurred. Please try again in a moment." + "A temporary network error occurred. Please try again in a moment.", ), button1Text: $L("OK"), - }) + }), ); setIsProcessing(false); } @@ -506,7 +523,9 @@ function IntroPanelWithOptional({ }, () => { // ================== FAIL ================== - console.error(`[IntroPanel] registerDevice 실패 (시도: ${retryCount + 1})`); + console.error( + `[IntroPanel] registerDevice 실패 (시도: ${retryCount + 1})`, + ); if (retryCount < MAX_RETRY_ATTEMPTS - 1) { setTimeout(() => { executeAgree(retryCount + 1); @@ -517,15 +536,15 @@ function IntroPanelWithOptional({ setShowPopup(Config.ACTIVE_POPUP.alertPopup, { title: $L("Error"), text: $L( - "A temporary network error occurred. Please try again in a moment." + "A temporary network error occurred. Please try again in a moment.", ), button1Text: $L("OK"), - }) + }), ); setIsProcessing(false); } - } - ) + }, + ), ); }, [ @@ -535,7 +554,7 @@ function IntroPanelWithOptional({ dispatch, webOSVersion, termsIdMap, - ] + ], ); // [추가] 재시도 메커니즘 시작 @@ -582,15 +601,15 @@ function IntroPanelWithOptional({ // button1Text: $L("OK"), // }), // ); - + // 새로운 requiredAgreePopup 사용 setRequiredAgreePopup(true); - + // 3초 후 자동 닫기 popupTimeoutRef.current = setTimeout(() => { setRequiredAgreePopup(false); }, 3000); - + return; } @@ -796,12 +815,14 @@ function IntroPanelWithOptional({ // privacyChecked, // shouldShowBenefitsView, // ); // 1단계: 제거 - + // 1단계: WebOS 버전 기반 고정 콘텐츠로 교체 const rightPanelContent = useMemo(() => { return shouldShowBenefitsView ? (
- {$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( + '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', + )}
) : ( {/* Terms & Conditions */}
- - + + {$L("Terms & Conditions")} @@ -897,20 +918,20 @@ function IntroPanelWithOptional({ {/* Privacy Policy */}
- - + + {$L("Privacy Policy")} @@ -919,21 +940,21 @@ function IntroPanelWithOptional({ {/* Optional Terms */}
- - + + {$L("Optional Terms")}
@@ -958,7 +979,7 @@ function IntroPanelWithOptional({ - ); } diff --git a/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/OptionalTermsInfo.jsx b/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/OptionalTermsInfo.jsx index 2df14baa..fcec442c 100644 --- a/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/OptionalTermsInfo.jsx +++ b/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/OptionalTermsInfo.jsx @@ -1,19 +1,19 @@ // src/views/MyPagePanel/MyPageSub/TermsOfService/OptionalTermsInfo.jsx -import React, { memo } from 'react'; -import kind from '@enact/core/kind'; -import PropTypes from 'prop-types'; -import $L from '@enact/i18n/$L'; +import React, { memo } from "react"; +import kind from "@enact/core/kind"; +import PropTypes from "prop-types"; +import $L from "@enact/i18n/$L"; -import css from './OptionalTermsInfo.module.less'; -import benefitImage from '/assets/images/benefits/image-benefits.png'; +import css from "./OptionalTermsInfo.module.less"; +import benefitImage from "/assets/images/benefits/image-benefits.png"; /** * OptionalTermsInfo 컴포넌트 * WebOS 버전에 따라 텍스트 또는 이미지로 선택적 약관 정보를 표시합니다. */ const OptionalTermsInfo = kind({ - name: 'OptionalTermsInfo', + name: "OptionalTermsInfo", propTypes: { /** @@ -25,7 +25,7 @@ const OptionalTermsInfo = kind({ * 표시 모드 - 텍스트 또는 이미지 * @type {('text'|'image')} */ - displayMode: PropTypes.oneOf(['text', 'image']), + displayMode: PropTypes.oneOf(["text", "image"]), /** * 이미지 모드일 때 사용할 이미지 소스들 (배열) @@ -45,68 +45,66 @@ const OptionalTermsInfo = kind({ /** * Spotlight ID */ - spotlightId: PropTypes.string + spotlightId: PropTypes.string, }, defaultProps: { - displayMode: 'text', - imageSources: [ - benefitImage, - ], - imageTitle: $L('Agree and Enjoy Special Benefits'), - textDescription: $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') + displayMode: "text", + imageSources: [benefitImage], + imageTitle: $L("Agree and Enjoy Special Benefits"), + textDescription: $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", + ), }, styles: { css, - className: 'termsInfo' + className: "termsInfo", }, computed: { - className: ({ className, styler }) => styler.append(className) + className: ({ className, styler }) => styler.append(className), }, - render: ({ - displayMode, - imageSources, - imageTitle, - textDescription, + render: ({ + displayMode, + imageSources, + imageTitle, + textDescription, spotlightId, - ...rest + ...rest }) => { const imageCount = imageSources ? imageSources.length : 0; - + return ( -
- {displayMode === 'text' ? ( +
+ {displayMode === "text" ? ( // 텍스트 모드
-

- {textDescription} -

+

{textDescription}

) : ( - // 이미지 모드 + // 이미지 모드
-
- {imageSources && imageSources.map((src, index) => ( - {$L(`Benefit - ))} +
+ {imageSources && + imageSources.map((src, index) => ( + {$L(`Benefit + ))}
)}
); - } + }, }); export default memo(OptionalTermsInfo); -export { OptionalTermsInfo }; \ No newline at end of file +export { OptionalTermsInfo };