fix: 기획자의견 반영 수정 250619

This commit is contained in:
djaco
2025-06-19 20:57:58 +09:00
parent 8b30bdd563
commit 19a533b856
9 changed files with 392 additions and 180 deletions

View File

@@ -185,7 +185,7 @@ function AppBase(props) {
// return () => stopFocusMonitoring();
// }, []);
// 임시 작업용 코드
// 임시 작업용 코드 -> 인트로 팝업 표시
// useEffect(() => {
// const timer = setTimeout(() => {
// dispatch(
@@ -388,7 +388,7 @@ function AppBase(props) {
}, [webOSVersion, deviceId]);
// 테스트용 팝업 표시
// 테스트용 인트로 화면 표시
// useEffect(() => {
// setTimeout(() => {
// console.log("App.js optionalTermsTest 팝업 표시");

View File

@@ -2,7 +2,8 @@
@import "../../style/utils.module.less";
.tabs {
.size(@w: 1680px, @h: 67px);
// .size(@w: 1680px, @h: 67px);
.size(@w: 100%, @h: 67px);
display: flex;
position: relative;

View File

@@ -13,6 +13,7 @@ import { cancelFocusElement, focusElement } from "../../actions/commonActions";
import { SpotlightIds } from "../../utils/SpotlightIds";
import CustomImage from "../CustomImage/CustomImage";
import TButton from "../TButton/TButton";
import TButtonScroller from "../TButtonScroller/TButtonScroller";
import css from "./TNewPopUp.module.less";
import { $L } from "../../utils/helperMethods";
@@ -67,6 +68,7 @@ const KINDS = [
"optionalAgreement",
"normal",
"optionalConfirm",
"figmaTermsPopup",
];
// 각 kind별 클래스명 매핑
@@ -224,6 +226,17 @@ const CLASS_MAPPINGS = {
text: "optionalConfirmText",
buttonContainer: "optionalConfirmButtonContainer",
contentContainer: "optionalConfirmContentContainer" // 👈 추가
},
figmaTermsPopup: {
info: "figmaTermsInfo",
contentContainer: "figmaTermsContentContainer",
termsCard: "figmaTermsCard",
titleBar: "figmaTermsTitleBar",
titleText: "figmaTermsTitleText",
contentBody: "figmaTermsContentBody",
buttonContainer: "figmaTermsButtonContainer",
agreeButton: "figmaTermsAgreeButton",
closeButton: "figmaTermsCloseButton"
}
};
@@ -314,6 +327,8 @@ export default function TNewPopUp({
focusTarget = 'introTermsAgreeBtn';
} else if (kind === 'optionalConfirm') {
focusTarget = 'optionalConfirmAgreeBtn';
} else if (kind === 'figmaTermsPopup') {
focusTarget = 'figma-terms-close';
} else if (spotlightId) {
focusTarget = spotlightId;
}
@@ -609,7 +624,7 @@ export default function TNewPopUp({
{/* 다른 종류들의 children */}
{kind !== "optionalAgreement" && kind !== "optionalConfirm" && children}
{kind !== "optionalAgreement" && kind !== "optionalConfirm" && kind !== "figmaTermsPopup" && children}
{hasIndicator && (
<>
@@ -712,6 +727,49 @@ export default function TNewPopUp({
</OptionalConfirmButtonSection>
</div>
)}
{/* [추가] figmaTermsPopup을 위한 전용 렌더링 블록 */}
{kind === "figmaTermsPopup" && (
<div className={getClassName(kind, "contentContainer")}>
<div className={getClassName(kind, "termsCard")}>
<div className={getClassName(kind, "titleBar")}>
<div className={getClassName(kind, "titleText")}>
{title}
</div>
</div>
<div className={getClassName(kind, "contentBody")}>
<TButtonScroller
boxHeight={460}
width={844}
>
<div
className={getClassName(kind, "scrollerContent")}
dangerouslySetInnerHTML={{ __html: text }}
/>
</TButtonScroller>
</div>
</div>
<ButtonContainerComp className={getClassName(kind, "buttonContainer")}>
{/* 기획 변경으로 Agree 버튼 임시 숨김 처리
<TButton
className={getClassName(kind, "agreeButton")}
onClick={onIntroTermsAgreeClick}
spotlightId="figma-terms-agree"
type="agree"
>
{$L('Agree')}
</TButton>
*/}
<TButton
className={getClassName(kind, "closeButton")}
onClick={onClose}
spotlightId="figma-terms-close"
>
{$L('Close')}
</TButton>
</ButtonContainerComp>
</div>
)}
</Container>
</Alert>
);

View File

@@ -1029,6 +1029,77 @@
}
}
}
/* 👇 새로운 약관 팝업 스타일 */
&.figmaTermsPopup {
.figmaTermsInfo {
.size(@w: 1064px, @h: 750px);
padding: 60px 57px 40px;
background: #E6EBF0;
box-shadow: 0px 20px 12px rgba(0, 0, 0, 0.30);
border-radius: 4px;
}
.figmaTermsContentContainer {
display: flex;
flex-direction: column;
gap: 40px;
}
.figmaTermsCard {
background: white;
border-radius: 4px;
border: 1px solid #CCCCCC;
overflow: hidden;
display: flex;
flex-direction: column;
}
.figmaTermsTitleBar {
padding: 17px 31px;
border-bottom: 1px solid #CCCCCC;
}
.figmaTermsTitleText {
color: #C70850;
font-size: 30px;
font-weight: 700;
}
.figmaTermsContentBody {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
.scrollerContent {
padding: 31px;
font-size: 26px;
line-height: 1.5;
}
}
.figmaTermsButtonContainer {
display: flex;
justify-content: center;
gap: 12px;
}
.figmaTermsAgreeButton {
.size(240px, 80px);
// type="agree"의 포커스 시 font-size 변경을 막음
&.focused,
&:focus { // :focus도 함께 처리
font-size: 30px !important;
}
}
.figmaTermsCloseButton {
// TButton의 기본 스타일을 그대로 사용하도록 크기만 지정
.size(240px, 80px);
}
}
}
// optionalConfirm일 때만 기존 위치 스타일 무력화

View File

@@ -1,6 +1,7 @@
// src: views/IntroPanel/IntroPanel.new.jsx
import React, { useCallback, useEffect, useState, useMemo } from "react";
import React, { useCallback, useEffect, useState, useMemo, useRef } from "react";
import { flushSync } from "react-dom";
import { useDispatch, useSelector } from "react-redux";
@@ -12,7 +13,7 @@ import {
setExitApp,
setHidePopup,
setShowPopup,
setTermsAgreeYn,
// setTermsAgreeYn,
} from "../../actions/commonActions";
import { registerDevice } from "../../actions/deviceActions";
import { getWelcomeEventInfo } from "../../actions/eventActions";
@@ -24,12 +25,12 @@ import {
} from "../../actions/logActions";
import { popPanel, pushPanel } from "../../actions/panelActions";
import TButton, { TYPES } from "../../components/TButton/TButton";
import TButtonScroller from "../../components/TButtonScroller/TButtonScroller";
import TButtonTab from "../../components/TButtonTab/TButtonTab";
// import TButtonScroller from "../../components/TButtonScroller/TButtonScroller";
// import TButtonTab from "../../components/TButtonTab/TButtonTab";
import TCheckBoxSquare from "../../components/TCheckBox/TCheckBoxSquare";
import TPanel from "../../components/TPanel/TPanel";
import TPopUp, { CONTENT_TYPES } from "../../components/TPopUp/TPopUp";
// import TNewPopUp from "../../components/TPopUp/TNewPopUp";
import TNewPopUp from "../../components/TPopUp/TNewPopUp";
import OptionalTermsInfo from "../MyPagePanel/MyPageSub/TermsOfService/OptionalTermsInfo";
import useDebugKey from "../../hooks/useDebugKey";
import * as Config from "../../utils/Config";
@@ -56,7 +57,9 @@ export default function IntroPanel({
delete rest.panelInfo;
useDebugKey({});
const dispatch = useDispatch(); const termsData = useSelector((state) => state.home.termsData);
const dispatch = useDispatch();
const blurTimeout = useRef(null);
const termsData = useSelector((state) => state.home.termsData);
const { popupVisible, activePopup, ...popupState } = useSelector(
(state) => state.common.popup
);
@@ -69,13 +72,7 @@ export default function IntroPanel({
// registerDevice API 호출 중 여부
const [isProcessing, setIsProcessing] = useState(false);
const [showExitMessagePopup, setShowExitMessagePopup] = useState(false);
// const introTermsData = termsData?.data?.terms.filter(
// (item) => item.trmsTpCd === "MST00401" || item.trmsTpCd === "MST00402"
// );
// const optionalTermsData = termsData?.data?.terms.filter(
// (item) => item.trmsTpCd === "MST00405"
// );
const [isRequiredFocused, setIsRequiredFocused] = useState(false);
const introTermsData = useMemo(() => {
return termsData?.data?.terms.filter(
@@ -124,6 +121,7 @@ export default function IntroPanel({
const [privacyChecked, setPrivacyChecked] = useState(true); // Privacy Policy 기본 체크
const [optionalChecked, setOptionalChecked] = useState(false); // Optional Terms 기본 체크 안됨
const [selectAllChecked, setSelectAllChecked] = useState(false);
const [focusedItem, setFocusedItem] = useState(null); // 포커스 추적 상태 추가
useEffect(() => {
dispatch(sendLogGNB(Config.LOG_MENU.TERMS_CONDITIONS));
@@ -163,31 +161,23 @@ export default function IntroPanel({
// Select All 상태 업데이트
useEffect(() => {
setSelectAllChecked(termsChecked && privacyChecked && optionalChecked);
const allChecked = termsChecked && privacyChecked && optionalChecked;
setSelectAllChecked(allChecked);
if (allChecked) {
Spotlight.focus("agreeButton");
}
}, [termsChecked, privacyChecked, optionalChecked]);
// 컴포넌트 마운트 후 1.5초 뒤에 agreeButton으로 강제 포커스
// 컴포넌트 마운트 후 0.5초 뒤에 selectAllCheckbox으로 강제 포커스
useEffect(() => {
// 1.5초(1500ms) 후에 실행될 타이머 설정
const focusTimer = setTimeout(() => {
console.log('[Focus] 1.5초 후 agreeButton으로 강제 포커스 시도');
focusById("selectAllCheckbox");
}, 500);
// focusById 함수를 사용하여 강제 포커스 (force: true)
const focusSuccess = focusById('agreeButton', true);
if (focusSuccess) {
console.log('[Focus] agreeButton 포커스 성공');
} else {
console.warn('[Focus] agreeButton 포커스 실패');
}
}, 1500);
// 컴포넌트 언마운트 시 타이머 정리
return () => {
clearTimeout(focusTimer);
console.log('[Focus] agreeButton 포커스 타이머 정리됨');
};
}, []); // 빈 dependency 배열로 컴포넌트 마운트 시에만 실행
}, []);
// 약관 팝업 동의여부에 따른 이벤트 핸들러
const handleTermsAgree = useCallback(() => {
@@ -334,6 +324,22 @@ export default function IntroPanel({
}
}, [dispatch, activePopup]);
const handleFocus = useCallback((item) => {
if (blurTimeout.current) {
clearTimeout(blurTimeout.current);
blurTimeout.current = null;
}
setFocusedItem(item);
setIsRequiredFocused(item === 'required');
}, []);
const handleBlur = useCallback(() => {
blurTimeout.current = setTimeout(() => {
setFocusedItem(null);
setIsRequiredFocused(false);
}, 0);
}, []);
// 체크박스 핸들러들
const handleTermsToggle = useCallback(({ selected }) => {
setTermsChecked(selected);
@@ -355,9 +361,52 @@ export default function IntroPanel({
}, []);
useEffect(() => {
Spotlight.focus("selectAllCheckbox");
}, []);
const rightPanelContent = useMemo(() => {
const hasRequiredUnchecked = !termsChecked || !privacyChecked;
// 우선순위 1: 필수 약관이 체크 안됨 → 항상 경고 메시지
if (hasRequiredUnchecked) {
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 className={css.warningContainer}>
<p className={css.warningText}>{$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>
);
}
// 우선순위 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>
<p className={css.successText}>{$L("Thank you for agreeing to required terms!")}</p>
</div>
);
}
// 우선순위 3: 기본값 → 선택 약관 정보
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"
/>
)}
</>
);
}, [termsChecked, privacyChecked, isRequiredFocused, shouldShowBenefitsView]);
useEffect(() => {
Spotlight.focus();
@@ -408,6 +457,17 @@ export default function IntroPanel({
const title = "welcome to shoptime!";
delete rest.isOnTop;
// [추가] 약관 종류에 따라 팝업 제목을 반환하는 헬퍼 함수
const getTermsPopupTitle = (terms) => {
if (!terms) return '';
switch (terms.trmsTpCd) {
case "MST00401": return $L("Privacy Policy");
case "MST00402": return $L("Terms & Conditions");
case "MST00405": return $L("Optional Terms");
default: return '';
}
};
return (
<Region title={title + description}>
<TPanel
@@ -445,17 +505,21 @@ export default function IntroPanel({
className={css.customeCheckbox}
selected={termsChecked}
onToggle={handleTermsToggle}
onFocus={() => handleFocus('required')}
onBlur={handleBlur}
spotlightId="termsCheckbox"
ariaLabel={$L("Terms & Conditions checkbox")}
/>
<TButton
className={css.termsButton}
onClick={() => handleTermsClick("MST00402")}
onFocus={() => handleFocus('required')}
onBlur={handleBlur}
spotlightId="termsButton"
type={TYPES.terms}
ariaLabel={$L("View Terms & Conditions")}
>
<span className={css.termsText}>
<span className={`${css.termsText} ${css.required}`}>
{$L("Terms & Conditions")}
</span>
</TButton>
@@ -467,17 +531,21 @@ export default function IntroPanel({
className={css.customeCheckbox}
selected={privacyChecked}
onToggle={handlePrivacyToggle}
onFocus={() => handleFocus('required')}
onBlur={handleBlur}
spotlightId="privacyCheckbox"
ariaLabel={$L("Privacy Policy checkbox")}
/>
<TButton
className={css.termsButton}
onClick={() => handleTermsClick("MST00401")}
onFocus={() => handleFocus('required')}
onBlur={handleBlur}
spotlightId="privacyButton"
type={TYPES.terms}
ariaLabel={$L("View Privacy Policy")}
>
<span className={css.termsText}>
<span className={`${css.termsText} ${css.required}`}>
{$L("Privacy Policy")}
</span>
</TButton>
@@ -489,12 +557,16 @@ export default function IntroPanel({
className={css.customeCheckbox}
selected={optionalChecked}
onToggle={handleOptionalToggle}
onFocus={() => handleFocus('optional')}
onBlur={handleBlur}
spotlightId="optionalCheckbox"
ariaLabel={$L("Optional Terms checkbox")}
/>
<TButton
className={css.termsButton}
onClick={() => handleOptionalTermsClick("MST00405")}
onFocus={() => handleFocus('optional')}
onBlur={handleBlur}
spotlightId="optionalButton"
type={TYPES.terms}
ariaLabel={$L("View Optional Terms")}
@@ -506,19 +578,7 @@ export default function IntroPanel({
</div>
</div>
<div className={css.termsRightPanel}>
{shouldShowBenefitsView ? (
// WebOS 텍스트 표시 버전 (4.5, 6.0, 22): 기존 텍스트 설명
<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>
) : (
// WebOS 이미지 표시 버전 (4.0, 5.0, 23, 24): OptionalTermsInfo 컴포넌트로 이미지 표시
<OptionalTermsInfo
displayMode="image"
imageTitle={$L('Agree and Enjoy Special Benefits')}
spotlightId="optional-terms-info"
/>
)}
{rightPanelContent}
</div>
</div>
@@ -544,6 +604,8 @@ export default function IntroPanel({
spotlightId="agreeButton"
type={TYPES.agree}
ariaLabel={$L("Agree to terms")}
disabled={!termsChecked || !privacyChecked}
spotlightDisabled={!termsChecked || !privacyChecked}
>
{$L("Agree")}
</TButton>
@@ -562,19 +624,37 @@ export default function IntroPanel({
{/* 약관 보기 팝업 */}
{activePopup === Config.ACTIVE_POPUP.termsPopup && (
<TPopUp
kind="introTermsPopup"
contentType={CONTENT_TYPES.TERMS} // 추가
open={popupVisible}
onClose={onClose}
onTermsAgree={handleTermsAgree} // onClick에서 변경
termsData={currentTerms} // 추가
hasButton
button1Text={$L("Agree")}
button2Text={$L("Close")}
spotlightId="tPopupBtn1"
/>
)} {/* DO NOT AGREE */}
<>
{/*
<TPopUp
kind="introTermsPopup"
contentType={CONTENT_TYPES.TERMS}
open={popupVisible}
onClose={onClose}
onTermsAgree={handleTermsAgree}
termsData={currentTerms}
hasButton
button1Text={$L("Agree")}
button2Text={$L("Close")}
spotlightId="tPopupBtn1"
/>
*/}
{/* TermsPopup 호출은 완전히 삭제 */}
{/* TNewPopUp을 사용한 새로운 팝업 구현 */}
<TNewPopUp
open={popupVisible}
kind="figmaTermsPopup"
title={getTermsPopupTitle(currentTerms)}
text={currentTerms?.trmsCntt || ''}
onIntroTermsAgreeClick={handleTermsAgree} // Agree 버튼 핸들러 연결
onClose={onClose} // Close 버튼 핸들러 연결
/>
</>
)}
{/* DO NOT AGREE */}
{activePopup === Config.ACTIVE_POPUP.exitPopup && (
<TPopUp
kind="exitPopup"
@@ -588,7 +668,9 @@ export default function IntroPanel({
title={$L("Exit Shop Time")}
text={$L("Are you sure you want to exit Shop Time?")}
/>
)} {/* ALERT POPUP (필수 약관 알림) */}
)}
{/* ALERT POPUP (필수 약관 알림) */}
{activePopup === Config.ACTIVE_POPUP.alertPopup && (
<TPopUp
kind="textPopup"
@@ -601,6 +683,7 @@ export default function IntroPanel({
text={$L("Please agree to Terms & Conditions and Privacy Policy.")}
/>
)}
{/* Final Exit Message Popup */}
{showExitMessagePopup && (
<TPopUp

View File

@@ -1,6 +1,15 @@
@import "../../style/CommonStyle.module.less";
@import "../../style/utils.module.less";
@COLOR_GREEN: #207847;
@COLOR_RED: #C91D53;
@COLOR_GRAY: #807F81;
@COLOR_GRAY02: #CFCFCF;
@COLOR_GRAY03: #57585A;
@COLOR_GRAY04: #C5C6C9;
@COLOR_GRAY05: #F8F8F8;
@COLOR_GRAY06: #57585A;
.panel {
> section {
color: @COLOR_GRAY06;
@@ -10,9 +19,12 @@
.introLayout {
width: 100%;
height: 100%;
padding: 45.5px 43px;
padding-top: 45.5px;
padding-bottom: 45.5px;
padding-left: 43px;
padding-right: 43px;
flex-direction: column;
justify-content: flex-start;
justify-content: space-between;
align-items: center;
gap: 40px;
display: inline-flex;
@@ -136,7 +148,6 @@
will-change: transform;
.termsText {
// color: #207847;
color: black;
font-size: 35px;
font-family: 'LG Smart UI';
@@ -144,37 +155,26 @@
line-height: 35px;
word-wrap: break-word;
transition: color 0.3s ease;
&.required {
color: @COLOR_GREEN;
}
}
// ✅ 포커스 상태 (화살표 키 네비게이션용)
// ✅ 포커스 및 호버 상태 (통합)
&.focused,
&:focus,
&:focus-visible {
&:focus-visible,
&:hover {
outline: 4px #C91D53 solid !important;
outline-offset: 2px !important;
background-color: rgba(201, 29, 83, 0.1) !important;
transform: translateY(-2px) !important;
box-shadow: 0 4px 12px rgba(201, 29, 83, 0.3) !important;
.termsText {
// color: #C70850 !important;
font-weight: bold !important;
}
}
// ✅ 호버 효과 (마우스용)
&:hover {
outline: 2px #C91D53 solid;
outline-offset: 2px;
background-color: rgba(201, 29, 83, 0.1);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(201, 29, 83, 0.3);
.termsText {
color: #C70850;
font-weight: bold;
}
}
}
}
} .termsRightPanel {
@@ -255,7 +255,7 @@
transition: all 0.3s ease;
// 포커스 상태
&.focused {
&.focused:not(:disabled) {
background-color: #a40640 !important;
border-color: #a40640 !important;
color: white !important;
@@ -263,7 +263,7 @@
}
// 호버 효과
&:hover {
&:hover:not(:disabled) {
background-color: #a40640 !important;
border-color: #a40640 !important;
color: white !important;
@@ -342,71 +342,6 @@
}
}
// ✅ 로컬 체크박스 스타일 (전체 교체)
// .customCheckbox {
// width: 45px;
// height: 45px;
// position: relative;
// // 기본 상자 스타일
// &:before {
// content: '';
// width: 42px;
// height: 42px;
// background-color: @COLOR_WHITE;
// border: 2px solid @COLOR_GRAY02;
// border-radius: 4px;
// display: block;
// transition: background-color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
// }
// // --- 상태별 스타일 정의 ---
// // [상태 2] 선택됨: 선택되면 배경을 진한 붉은색으로 만듭니다.
// &.selected:before {
// background-color: #C91D53;
// border-color: #C91D53;
// }
// // [상태 3] 포커스 받았지만, 선택은 안됨: 이때만 배경을 연한 붉은색으로 만듭니다.
// &.focused:not(.selected):before {
// background-color: rgba(201, 29, 83, 0.1);
// }
// // [상태 1] 포커스 받음: 어떤 상태든 포커스를 받으면 굵고 붉은 테두리와 그림자 효과를 줍니다.
// // 이 규칙을 다른 상태들보다 아래에 두어 우선순위를 높입니다.
// &.focused:before {
// border: 4px solid #C91D53;
// box-shadow: 0 0 10px rgba(199, 8, 80, 0.3);
// }
// // [상태 4] 선택됨 (체크마크): 선택되었을 때만 체크마크를 표시합니다.
// &.selected:after {
// content: '✓';
// color: @COLOR_WHITE;
// font-size: 24px;
// font-weight: bold;
// position: absolute;
// top: 50%;
// left: 50%;
// transform: translate(-50%, -50%);
// }
// // [상태 5] 비활성화됨
// &.disabled:before {
// background-color: @COLOR_GRAY01;
// border-color: @COLOR_GRAY02;
// opacity: 0.5;
// }
// // [상태 6] 비활성화 상태에서 포커스 받음
// &.disabled.focused:before {
// background-color: #C91D53;
// border-color: #C91D53; // 비활성화 포커스는 배경색만 변경하므로, 테두리는 포커스 기본 스타일을 따름
// opacity: 1;
// }
// }
// ✅ 로컬 체크박스 스타일 (전체 교체)
.customCheckbox {
width: 45px;
@@ -464,3 +399,30 @@
transform: translate(-50%, -50%);
}
}
// ✅ [추가] 필수 약관 안내 패널 스타일
.requiredInfoPanel {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start; // 왼쪽 정렬
}
.infoText {
color: @COLOR_GRAY;
font-size: 28px;
line-height: 1.4;
}
.warningContainer {
margin-top: 20px;
}
.warningText {
color: @COLOR_RED;
font-size: 28px;
line-height: 1.4;
font-weight: bold;
}

View File

@@ -80,10 +80,10 @@
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.benefitImage:hover {
transform: scale(1.08);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
}
// .benefitImage:hover {
// transform: scale(1.08);
// box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
// }
.imageCount1 .benefitImage {
height: 95%;

View File

@@ -10,6 +10,7 @@ import { useDispatch, useSelector } from "react-redux";
import Spotlight from "@enact/spotlight";
import { Job } from "@enact/core/util";
import classnames from "classnames";
import {
changeLocalSettings,
@@ -283,6 +284,10 @@ export default function TermsOfService({ title, cbScrollTo }) {
// setDisagreeConfirmOpen(false);
}, []);
const isOptionalTab = useMemo(() => {
return termsList[selectedTab]?.trmsTpCd === "MST00405";
}, [termsList, selectedTab]);
const termsAriaLabel = useMemo(() => {
if (!termsList || !termsList[selectedTab]) return "";
@@ -300,37 +305,46 @@ export default function TermsOfService({ title, cbScrollTo }) {
<THeader title={title} ariaLabel="TERMS OF SERVICE, heading 1" />
<TBody cbScrollTo={cbScrollTo} className={css.tBody}>
<div className={css.termsContainer}>
<div className={css.contentsBox}>
<div className={classnames(css.contentsBox, { [css.optionalTabActive]: isOptionalTab })}>
<TButtonTab
contents={tabList}
className={css.tTab}
onItemClick={handleItemClick}
selectedIndex={selectedTab && selectedTab}
/>
<TButtonScroller
boxHeight={
termsList[selectedTab]?.trmsTpCd === "MST00405"
? scaleH(469)
: scaleH(714)
}
width={scaleW(1680)}
resetScrollPosition={resetScroll}
>
<div className={css.textBox} aria-label={termsAriaLabel}>
<div
className={css.text}
dangerouslySetInnerHTML={{
__html: termsList && termsList[selectedTab]?.termsContents,
}}
/>
</div>
</TButtonScroller>
<div className={css.scrollerWrapper}>
{isOptionalTab ? (
<div className={css.textBox} aria-label={termsAriaLabel}>
<div
className={css.text}
dangerouslySetInnerHTML={{
__html: termsList && termsList[selectedTab]?.termsContents,
}}
/>
</div>
) : (
<TButtonScroller
boxHeight={scaleH(714)}
width={scaleW(1680)}
resetScrollPosition={resetScroll}
>
<div className={css.textBox} aria-label={termsAriaLabel}>
<div
className={css.text}
dangerouslySetInnerHTML={{
__html: termsList && termsList[selectedTab]?.termsContents,
}}
/>
</div>
</TButtonScroller>
)}
</div>
{termsList[selectedTab]?.trmsTpCd === "MST00405" ? (
<div className={css.optionalContainer}>
<div className={css.checkboxContainer}>
<TCheckBoxSquare
selected={isOptionalChecked}
selected={optionalTermsAgree || isOptionalChecked}
onToggle={handleOptionalCheckboxToggle}
spotlightId="optional-agree-checkbox"
spotlightDisabled={spotlightDisabled || optionalTermsAgree}
@@ -461,7 +475,7 @@ export default function TermsOfService({ title, cbScrollTo }) {
onClose={() => setOptionalDisagreePopupOpen(false)}
onClick={confirmOptionalDisagree}
hasText
text={$L("Are you sure you want to disagree with the optional terms?")}
text={$L("You will not receive personalized shopping benefits")}
/>
{/* 필수약관 체크 확인 팝업 */}
<TPopUp

View File

@@ -9,7 +9,11 @@
background: @BG_COLOR_01;
padding-top: 42px;
.contentsBox {
padding: 0px 60px;
position: relative;
width: 100%;
height: 100%;
background: white;
padding: 0 40px;
.textBox {
.size(@w:1680px, @h:100%);
background-color: @BG_COLOR_02;
@@ -38,6 +42,25 @@
color: #808080;
}
}
&.optionalTabActive {
display: flex;
flex-direction: column;
padding-bottom: 60px;
box-sizing: border-box;
.tTab {
flex-shrink: 0;
}
.scrollerWrapper {
flex-grow: 1;
min-height: 0;
}
.optionalContainer {
flex-shrink: 0;
}
}
}
}