[20250728] IntroPanel.new.jsx prettier 설정

This commit is contained in:
djaco
2025-07-28 15:05:36 +09:00
parent 61ddd08e8c
commit 10263b7f65
2 changed files with 152 additions and 134 deletions

View File

@@ -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 <BasicIntroPanel {...props} />;
}
// 선택약관이 있으면 고급 IntroPanel 사용
console.log('[IntroPanel.new] optionalTermsAvailable = true, 고급 IntroPanel 사용');
console.log(
"[IntroPanel.new] optionalTermsAvailable = true, 고급 IntroPanel 사용",
);
return <IntroPanelWithOptional {...props} />;
}
@@ -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 ? (
<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')}
{$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
@@ -875,20 +896,20 @@ function IntroPanelWithOptional({
<div className={css.termsLeftPanel}>
{/* Terms & Conditions */}
<div className={css.termsItem}>
<TCheckBoxSquare
className={css.customeCheckbox}
selected={termsChecked}
onToggle={handleTermsToggle}
spotlightId="termsCheckbox"
ariaLabel={$L("Terms & Conditions checkbox")}
/>
<TButton
className={css.termsButton}
onClick={handleTermsClickMST00402}
spotlightId="termsButton"
type={TYPES.terms}
ariaLabel={$L("View Terms & Conditions")}
>
<TCheckBoxSquare
className={css.customeCheckbox}
selected={termsChecked}
onToggle={handleTermsToggle}
spotlightId="termsCheckbox"
ariaLabel={$L("Terms & Conditions checkbox")}
/>
<TButton
className={css.termsButton}
onClick={handleTermsClickMST00402}
spotlightId="termsButton"
type={TYPES.terms}
ariaLabel={$L("View Terms & Conditions")}
>
<span className={`${css.termsText} ${css.required}`}>
{$L("Terms & Conditions")}
</span>
@@ -897,20 +918,20 @@ function IntroPanelWithOptional({
{/* Privacy Policy */}
<div className={css.termsItem}>
<TCheckBoxSquare
className={css.customeCheckbox}
selected={privacyChecked}
onToggle={handlePrivacyToggle}
spotlightId="privacyCheckbox"
ariaLabel={$L("Privacy Policy checkbox")}
/>
<TButton
className={css.termsButton}
onClick={handleTermsClickMST00401}
spotlightId="privacyButton"
type={TYPES.terms}
ariaLabel={$L("View Privacy Policy")}
>
<TCheckBoxSquare
className={css.customeCheckbox}
selected={privacyChecked}
onToggle={handlePrivacyToggle}
spotlightId="privacyCheckbox"
ariaLabel={$L("Privacy Policy checkbox")}
/>
<TButton
className={css.termsButton}
onClick={handleTermsClickMST00401}
spotlightId="privacyButton"
type={TYPES.terms}
ariaLabel={$L("View Privacy Policy")}
>
<span className={`${css.termsText} ${css.required}`}>
{$L("Privacy Policy")}
</span>
@@ -919,21 +940,21 @@ function IntroPanelWithOptional({
{/* Optional Terms */}
<div className={css.termsItem}>
<TCheckBoxSquare
className={css.customeCheckbox}
selected={optionalChecked}
onToggle={handleOptionalToggle}
spotlightId="optionalCheckbox"
ariaLabel={$L("Optional Terms checkbox")}
/>
<TButton
className={css.termsButton}
onClick={handleOptionalTermsClickMST00405}
spotlightId="optionalButton"
type={TYPES.terms}
ariaLabel={$L("View Optional Terms")}
style={{ marginBottom: 0 }} // 제일 아래 버튼의 경우 margin-bottom 0
>
<TCheckBoxSquare
className={css.customeCheckbox}
selected={optionalChecked}
onToggle={handleOptionalToggle}
spotlightId="optionalCheckbox"
ariaLabel={$L("Optional Terms checkbox")}
/>
<TButton
className={css.termsButton}
onClick={handleOptionalTermsClickMST00405}
spotlightId="optionalButton"
type={TYPES.terms}
ariaLabel={$L("View Optional Terms")}
style={{ marginBottom: 0 }} // 제일 아래 버튼의 경우 margin-bottom 0
>
<span className={css.termsText}>{$L("Optional Terms")}</span>
</TButton>
</div>
@@ -958,7 +979,7 @@ function IntroPanelWithOptional({
<TButton
className={classNames(
css.agreeButton,
(!termsChecked || !privacyChecked) && css.disabled
(!termsChecked || !privacyChecked) && css.disabled,
)}
onClick={handleAgree}
spotlightId="agreeButton"
@@ -1068,10 +1089,9 @@ function IntroPanelWithOptional({
hasText
title={$L("")}
text={$L(
"Please check the box to accept the Terms & Conditions and Privacy Policy."
"Please check the box to accept the Terms & Conditions and Privacy Policy.",
)}
/>
</Region>
);
}

View File

@@ -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 (
<div
{...rest}
data-spotlight-id={spotlightId}
>
{displayMode === 'text' ? (
<div {...rest} data-spotlight-id={spotlightId}>
{displayMode === "text" ? (
// 텍스트 모드
<div className={css.textMode}>
<p className={css.textDescription}>
{textDescription}
</p>
<p className={css.textDescription}>{textDescription}</p>
</div>
) : (
// 이미지 모드
// 이미지 모드
<div className={css.imageMode}>
<div className={`${css.imageContainer} ${css[`imageCount${imageCount}`]}`}>
{imageSources && imageSources.map((src, index) => (
<img
key={index}
className={css.benefitImage}
src={src}
alt={$L(`Benefit image ${index + 1}`)}
/>
))}
<div
className={`${css.imageContainer} ${css[`imageCount${imageCount}`]}`}
>
{imageSources &&
imageSources.map((src, index) => (
<img
key={index}
className={css.benefitImage}
src={src}
alt={$L(`Benefit image ${index + 1}`)}
/>
))}
</div>
</div>
)}
</div>
);
}
},
});
export default memo(OptionalTermsInfo);
export { OptionalTermsInfo };
export { OptionalTermsInfo };