From de0a38e74ecf1c096cc6e644589fc058a314fa09 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Tue, 30 Sep 2025 20:44:10 +0900 Subject: [PATCH] =?UTF-8?q?[=EC=83=81=ED=92=88=EC=83=81=EC=84=B8]=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. buy now, add to cart 버튼 크기문제 수정요청. (수정완료)  2. description, 배송문구 부분 포커스 시에도 product detail로 포커스 표시 요청.(수정완료)  3. Review Section "+ View More" 버튼 클릭이후 노출되는 이미지 팝업 리뷰 부분 이미지 수정요청.(수정완료) 4. user review 팝업에서 노출되는 세줄 아이콘 제거 요청.(수정완료) 5. review 팝업에서 컨텐츠 박스 이상 노출되는 텍스트 처리요청.(히든처리) 6. review 패널 오픈시에 필터 stars에서 s 제거요청.(수정완료) 7. review 패널 오픈시에 필터 margin값 변경요청.(변경 완료) 8. 가격과 할인값이 둘다 1000불 이상일때 가격노출부분 텍스트 크기 수정요청.(60->52px) 9. qr code 노출부분에서 시간이 지날시 텍스트 이미지 노출요청.(노출 처리) 10. 상단 타이틀 marquee변경 요청(처리완료) 11. 타이틀 상품명에 상품아이디 노출요청.(처리는 했지만 노출부분 확인필요) 12. shop by mobile 눌렀을때 노출되는 화면에서 디자인 맞추기.(디자인 맞춰둠) --- .../MobileSend/MobileSendPopUp.module.less | 39 ++- .../components/TButton/TButton.module.less | 4 + .../src/views/DetailPanel/DetailPanel.jsx | 8 +- .../views/DetailPanel/DetailPanel.module.less | 1 + .../ProductAllSection/ProductAllSection.jsx | 299 ++++++++++++------ .../ProductAllSection.module.less | 36 ++- .../UserReviewDetail.module.less | 1 + .../UserReviewsPopup/UserReviewsPopup.jsx | 4 +- .../UserReviewsPopup.module.less | 8 +- .../ShopByMobilePriceDisplay.module.less | 2 +- .../components/DetailMobileSendPopUp.jsx | 35 +- .../components/THeaderCustom.module.less | 5 +- .../src/views/UserReview/UserReviewPanel.jsx | 279 +++++++++++----- .../components/FilterItemButton.module.less | 30 +- 14 files changed, 522 insertions(+), 229 deletions(-) diff --git a/com.twin.app.shoptime/src/components/MobileSend/MobileSendPopUp.module.less b/com.twin.app.shoptime/src/components/MobileSend/MobileSendPopUp.module.less index 17eb39de..0a62f8b2 100644 --- a/com.twin.app.shoptime/src/components/MobileSend/MobileSendPopUp.module.less +++ b/com.twin.app.shoptime/src/components/MobileSend/MobileSendPopUp.module.less @@ -5,16 +5,16 @@ .titleHead { align-self: stretch; padding: 30px; - background: #E7EBEF; + background: #e7ebef; display: flex; - justify-content: flex-start; // center → flex-start + justify-content: flex-start; // center → flex-start align-items: center; .titleHead__text { - text-align: left; // center → left + text-align: left; // center → left color: black; font-size: 32px; - font-family: 'LG Smart UI'; + font-family: "LG Smart UI"; font-weight: 700; line-height: 42px; word-wrap: break-word; @@ -25,18 +25,19 @@ .headerTopRow { display: flex; align-items: center; - margin-bottom: 5px; // TV 호환: gap 대신 margin 사용 + margin-bottom: 5px; // TV 호환: gap 대신 margin 사용 .headerTopRow__brandLogo { width: 50px; height: 50px; - margin-right: 15px; // TV 호환: gap 대신 margin 사용 + margin-right: 15px; // TV 호환: gap 대신 margin 사용 + border-radius: 100%; } .headerTopRow__productId { color: #808080; font-size: 24px; - font-family: 'LG Smart UI'; + font-family: "LG Smart UI"; font-weight: 600; line-height: 18px; word-wrap: break-word; @@ -53,7 +54,7 @@ left: 0; top: 0; z-index: 0; - background-color: @COLOR_SKYBLUE; + content: ""; } display: flex; @@ -62,18 +63,24 @@ position: relative; z-index: 1; } + > .container__header__textBox { + margin-top: 30px; + margin-left: 15px; + width: 885px; + height: 100px; + } > .container__header__textBoxOnly { width: 100%; margin-left: 30px; } > .container__header__productImg { - margin: 30px 0px 0 30px; // 60px → 30px로 변경 + margin: 30px 0px 0 30px; // 60px → 30px로 변경 > .container__header__productImg__img { .border-solid(@size:1px,@color:#cccccc); - width: 100px; // 132px → 100px (Figma 크기) - height: 100px; // 132px → 100px (Figma 크기) + width: 100px; // 132px → 100px (Figma 크기) + height: 100px; // 132px → 100px (Figma 크기) margin-bottom: 20px; } } @@ -93,7 +100,7 @@ font-weight: normal; font-size: 28px; color: @COLOR_GRAY06; - padding: 10px 30px 0 30px; // 60px → 30px로 변경 + padding: 10px 30px 0 0px; // 60px → 30px로 변경 text-align: left; .elip(@clamp:1); } @@ -101,10 +108,10 @@ width: 100%; line-height: 60px; text-align: center; - padding: 10px 30px 10px 30px; // 60px → 30px로 변경 + padding: 10px 30px 10px 30px; // 60px → 30px로 변경 } .container__header__price { - padding: 0 30px 20px 30px; // 60px → 30px로 변경 + padding: 0 30px 20px 30px; // 60px → 30px로 변경 font-size: 28px; font-weight: bold; color: @PRIMARY_COLOR_RED; @@ -152,7 +159,7 @@ width: 345.5px; // 고정 너비 height: 412px; // PhoneInputSection과 동일한 높이 padding: 10px 30px 0 30px; // 위 10px, 좌우 30px, 아래 0 - background: #F8F8F8; + background: #f8f8f8; border-radius: 12px; display: flex; justify-content: flex-start; @@ -164,7 +171,7 @@ align-self: stretch; color: #808080; font-size: 20px; // 피그마 스펙대로 복원 - font-family: 'LG Smart UI'; + font-family: "LG Smart UI"; font-weight: 400; line-height: 24px; // 피그마 스펙대로 복원 word-wrap: break-word; diff --git a/com.twin.app.shoptime/src/components/TButton/TButton.module.less b/com.twin.app.shoptime/src/components/TButton/TButton.module.less index 61fc7db3..62beb2c9 100644 --- a/com.twin.app.shoptime/src/components/TButton/TButton.module.less +++ b/com.twin.app.shoptime/src/components/TButton/TButton.module.less @@ -66,6 +66,10 @@ &.full { width: 100%; } + &.detail_small { + min-width: 312px; + max-width: 312px; + } &.basic { &.disabled { background-color: #7a808d; diff --git a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx index 5b3539a1..3543bb4c 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx @@ -629,7 +629,13 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { ({ panelPrdtId, productData }) => fp.isNotNil(panelPrdtId) && fp.pipe(() => productData, fp.get("prdtNm"), fp.isNotNil)() - ? fp.pipe(() => productData, fp.get("prdtNm"))() + ? // ? fp.pipe(() => productData, fp.get("prdtNm"))() + // `${fp.get("prdtId")(productData)} ${fp.get("prdtNm")(productData)}` + fp.pipe( + () => productData, + (data) => + `${fp.get("prdtId")(data)} ${fp.get("prdtNm")(data)}` + )() : null )(); diff --git a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.module.less b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.module.less index cbfaf4f2..49c46f4d 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.module.less +++ b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.module.less @@ -8,6 +8,7 @@ z-index: 1; // 배경 컴포넌트(z-index: 0) 위에 표시 background: transparent !important; // 투명 배경으로 설정하여 뒤의 배경 컴포넌트가 보이도록 height: 100%; + overflow: hidden; // 하위 요소들도 투명 배경 (detailPanelWrap 스코프 내에서만 적용) > * { background: transparent !important; diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx index b9ed5954..a1a063a9 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx @@ -1,18 +1,31 @@ -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; import classNames from 'classnames'; import { throttle } from 'lodash'; import { PropTypes } from 'prop-types'; -import { useDispatch, useSelector } from 'react-redux'; +import { + useDispatch, + useSelector, +} from 'react-redux'; import Spotlight from '@enact/spotlight'; /* eslint-disable react/jsx-no-bind */ // src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx -import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; +import SpotlightContainerDecorator + from '@enact/spotlight/SpotlightContainerDecorator'; import Spottable from '@enact/spotlight/Spottable'; //image -import arrowDown from '../../../../assets/images/icons/ic_arrow_down_3x_new.png'; +import arrowDown + from '../../../../assets/images/icons/ic_arrow_down_3x_new.png'; +import indicatorDefaultImage + from '../../../../assets/images/img-thumb-empty-144@3x.png'; import { pushPanel } from '../../../actions/panelActions'; import { resetShowAllReviews } from '../../../actions/productActions'; import { showToast } from '../../../actions/toastActions'; @@ -46,13 +59,16 @@ import ProductTag from '../components/ProductTag'; import StarRating from '../components/StarRating'; // ProductContentSection imports import TScrollerDetail from '../components/TScroller/TScrollerDetail'; -import ProductDescription from '../ProductContentSection/ProductDescription/ProductDescription'; -import ProductDetail from '../ProductContentSection/ProductDetail/ProductDetail.new'; -import UserReviews from '../ProductContentSection/UserReviews/UserReviews'; -import ViewAllReviewsButton from '../ProductContentSection/UserReviews/ViewAllReviewsButton'; -import YouMayAlsoLike from '../ProductContentSection/YouMayAlsoLike/YouMayAlsoLike'; +import ProductDescription + from '../ProductContentSection/ProductDescription/ProductDescription'; +import ProductDetail + from '../ProductContentSection/ProductDetail/ProductDetail.new'; import ProductVideo from '../ProductContentSection/ProductVideo/ProductVideo'; -import indicatorDefaultImage from '../../../../assets/images/img-thumb-empty-144@3x.png'; +import UserReviews from '../ProductContentSection/UserReviews/UserReviews'; +import ViewAllReviewsButton + from '../ProductContentSection/UserReviews/ViewAllReviewsButton'; +import YouMayAlsoLike + from '../ProductContentSection/YouMayAlsoLike/YouMayAlsoLike'; import QRCode from '../ProductInfoSection/QRCode/QRCode'; import ProductOverview from '../ProductOverview/ProductOverview'; // CSS imports @@ -62,42 +78,45 @@ import css from './ProductAllSection.module.less'; const Container = SpotlightContainerDecorator( { - enterTo: 'last-focused', + enterTo: "last-focused", preserveld: true, - leaveFor: { right: 'content-scroller-container' }, - spotlightDirection: 'vertical', + leaveFor: { right: "content-scroller-container" }, + spotlightDirection: "vertical", }, - 'div' + "div" ); const ContentContainer = SpotlightContainerDecorator( { - enterTo: 'default-element', + enterTo: "default-element", preserveld: true, leaveFor: { - left: 'spotlight-product-info-section-container', + left: "spotlight-product-info-section-container", }, - restrict: 'none', - spotlightDirection: 'vertical', + restrict: "none", + spotlightDirection: "vertical", }, - 'div' + "div" ); const HorizontalContainer = SpotlightContainerDecorator( { - enterTo: 'last-focused', + enterTo: "last-focused", preserveld: true, - defaultElement: 'spotlight-product-info-section-container', - spotlightDirection: 'horizontal', + defaultElement: "spotlight-product-info-section-container", + spotlightDirection: "horizontal", }, - 'div' + "div" ); // FP: Pure function to determine product data based on typeP const getProductData = curry((productType, themeProductInfo, productInfo) => pipe( when( - () => isVal(productType) && productType === 'theme' && isVal(themeProductInfo), + () => + isVal(productType) && + productType === "theme" && + isVal(themeProductInfo), () => themeProductInfo ), defaultTo(productInfo), @@ -113,17 +132,17 @@ const deriveFavoriteFlag = curry((favoriteOverride, productData) => { return favoriteOverride; } // 그렇지 않으면 productData의 favorYn 값을 사용 (기본값 'N') - return pipe(get('favorYn'), defaultTo('N'))(productData); + return pipe(get("favorYn"), defaultTo("N"))(productData); }); // FP: Pure function to extract review grade and order phone const extractProductMeta = (productInfo) => ({ - revwGrd: get('revwGrd', productInfo), - orderPhnNo: get('orderPhnNo', productInfo), + revwGrd: get("revwGrd", productInfo), + orderPhnNo: get("orderPhnNo", productInfo), }); // 레이아웃 확인용 샘플 컴포넌트 - Spottable로 변경 -const SpottableComponent = Spottable('div'); +const SpottableComponent = Spottable("div"); const LayoutSample = ({ onClick }) => ( state.common.appStatus.webOSVersion); + const webOSVersion = useSelector( + (state) => state.common.appStatus.webOSVersion + ); const groupInfos = useSelector((state) => state.product.groupInfo); // YouMayLike 데이터는 API 응답 시간이 걸리므로 직접 구독 @@ -162,6 +183,33 @@ export default function ProductAllSection({ //하단부분까지 갔을때 체크용 const [documentHeight, setDocumentHeight] = useState(0); const [isBottom, setIsBottom] = useState(false); + + //qr코드 노출용 + const [isShowQRCode, setIsShowQRCode] = useState(true); + const timerRef = useRef(null); + + useEffect(() => { + const toggleQRCode = () => { + if (isShowQRCode) { + timerRef.current = setTimeout(() => { + setIsShowQRCode(false); + }, 10000); + } else { + timerRef.current = setTimeout(() => { + setIsShowQRCode(true); + }, 5000); + } + }; + + toggleQRCode(); + + return () => { + if (timerRef.current) { + clearTimeout(timerRef.current); + } + }; + }, [isShowQRCode]); + //버튼 active 표시용 const [activeProductBtn, setActiveProductBtn] = useState(false); @@ -176,20 +224,20 @@ export default function ProductAllSection({ // 단품(결제 가능 상품) - DetailPanel.backup.jsx와 동일한 로직 const isBillingProductVisible = useMemo(() => { return ( - productData?.pmtSuptYn === 'Y' && - productData?.grPrdtProcYn === 'N' && + productData?.pmtSuptYn === "Y" && + productData?.grPrdtProcYn === "N" && panelInfo?.prdtId && - webOSVersion >= '6.0' + webOSVersion >= "6.0" ); }, [productData, webOSVersion, panelInfo?.prdtId]); // 구매 불가 상품 - DetailPanel.backup.jsx와 동일한 로직 const isUnavailableProductVisible = useMemo(() => { return ( - productData?.pmtSuptYn === 'N' || - (productData?.pmtSuptYn === 'Y' && - productData?.grPrdtProcYn === 'N' && - webOSVersion < '6.0' && + productData?.pmtSuptYn === "N" || + (productData?.pmtSuptYn === "Y" && + productData?.grPrdtProcYn === "N" && + webOSVersion < "6.0" && panelInfo?.prdtId) ); }, [productData, webOSVersion, panelInfo?.prdtId]); @@ -197,8 +245,8 @@ export default function ProductAllSection({ // 그룹 상품 - DetailPanel.backup.jsx와 동일한 로직 const isGroupProductVisible = useMemo(() => { return ( - productData?.pmtSuptYn === 'Y' && - productData?.grPrdtProcYn === 'Y' && + productData?.pmtSuptYn === "Y" && + productData?.grPrdtProcYn === "Y" && groupInfos && groupInfos.length > 0 ); @@ -206,7 +254,10 @@ export default function ProductAllSection({ // 여행/테마 상품 - DetailPanel.backup.jsx와 동일한 로직 const isTravelProductVisible = useMemo(() => { - return panelInfo?.curationId && (panelInfo?.type === 'theme' || panelInfo?.type === 'hotel'); + return ( + panelInfo?.curationId && + (panelInfo?.type === "theme" || panelInfo?.type === "hotel") + ); }, [panelInfo]); // useReviews Hook 사용 - 모든 리뷰 관련 로직을 담당 @@ -232,7 +283,9 @@ export default function ProductAllSection({ // ProductAllSection 마운트 시 showAllReviews 초기화 useEffect(() => { - console.log('[ProductAllSection] Component mounted - resetting showAllReviews to false'); + console.log( + "[ProductAllSection] Component mounted - resetting showAllReviews to false" + ); dispatch(resetShowAllReviews()); }, []); // 빈 dependency array = 마운트 시에만 실행 @@ -254,9 +307,9 @@ export default function ProductAllSection({ (productData.imgUrls600 && productData.imgUrls600[0]) || (productData.imgUrls && productData.imgUrls[0]) || productData.thumbnailUrl || - 'https://placehold.co/150x150', - brandLogo: productData.patncLogoPath || 'https://placehold.co/50x50', - productName: productData.prdtNm || '상품명 정보가 없습니다', + "https://placehold.co/150x150", + brandLogo: productData.patncLogoPath || "https://placehold.co/50x50", + productName: productData.prdtNm || "상품명 정보가 없습니다", avgRating: stats.averageRating || 5, reviewCount: stats.totalReviews || 0, }, @@ -266,32 +319,33 @@ export default function ProductAllSection({ // BUY NOW 버튼 클릭 핸들러 - Toast로 BuyOption 표시 const handleBuyNowClick = useCallback(() => { - console.log('[BuyNow] Buy Now button clicked'); + console.log("[BuyNow] Buy Now button clicked"); dispatch( showToast({ - message: '', - type: 'buyOption', + message: "", + type: "buyOption", duration: 0, - position: 'bottom-center', + position: "bottom-center", }) ); }, [dispatch]); // ADD TO CART 버튼 클릭 핸들러 const handleAddToCartClick = useCallback(() => { - console.log('[AddToCart] Add To Cart button clicked'); + console.log("[AddToCart] Add To Cart button clicked"); // TODO: 장바구니 추가 로직 구현 }, []); // 디버깅: 실제 이미지 및 동영상 데이터 확인 useEffect(() => { - console.log('[ProductId] ProductAllSection productData check:', { + console.log("[ProductId] ProductAllSection productData check:", { hasProductData: !!productData, productDataPrdtId: productData && productData.prdtId, imgUrls600: productData && productData.imgUrls600, - imgUrls600Length: productData && productData.imgUrls600 && productData.imgUrls600.length, + imgUrls600Length: + productData && productData.imgUrls600 && productData.imgUrls600.length, imgUrls600Type: Array.isArray(productData && productData.imgUrls600) - ? 'array' + ? "array" : typeof (productData && productData.imgUrls600), // 동영상 관련 정보 추가 prdtMediaUrl: productData && productData.prdtMediaUrl, @@ -303,7 +357,10 @@ export default function ProductAllSection({ }); }, [productData, renderItems]); - const { revwGrd, orderPhnNo } = useMemo(() => extractProductMeta(productInfo), [productInfo]); + const { revwGrd, orderPhnNo } = useMemo( + () => extractProductMeta(productInfo), + [productInfo] + ); // FP: derive favorite flag from props with local override, avoid non-I/O useEffect const [favoriteOverride, setFavoriteOverride] = useState(null); @@ -326,7 +383,7 @@ export default function ProductAllSection({ // User Reviews 스크롤 핸들러 추가 const handleUserReviewsClick = useCallback( - () => scrollToSection('scroll-marker-user-reviews'), + () => scrollToSection("scroll-marker-user-reviews"), [] ); @@ -343,7 +400,7 @@ export default function ProductAllSection({ // 동영상이 있으면 첫 번째에 추가 (Indicator.jsx와 동일한 로직) if (productData && productData.prdtMediaUrl) { items.push({ - type: 'video', + type: "video", url: productData.prdtMediaUrl, thumbnail: productData.thumbnailUrl960 || indicatorDefaultImage, index: 0, @@ -351,12 +408,17 @@ export default function ProductAllSection({ } // 이미지들 추가 - if (productData && productData.imgUrls600 && productData.imgUrls600.length > 0) { + if ( + productData && + productData.imgUrls600 && + productData.imgUrls600.length > 0 + ) { productData.imgUrls600.forEach((image, imgIndex) => { items.push({ - type: 'image', + type: "image", url: image, - index: productData && productData.prdtMediaUrl ? imgIndex + 1 : imgIndex, + index: + productData && productData.prdtMediaUrl ? imgIndex + 1 : imgIndex, }); }); } @@ -375,7 +437,7 @@ export default function ProductAllSection({ // FP: Pure function for focus navigation to back button const handleSpotlightUpToBackButton = useCallback((e) => { e.stopPropagation(); - Spotlight.focus('spotlightId_backBtn'); + Spotlight.focus("spotlightId_backBtn"); }, []); // FP: Pure function for favorite flag change @@ -388,7 +450,7 @@ export default function ProductAllSection({ const handleThemeItemButtonClick = useCallback( pipe( () => setOpenThemeItemOverlay(true), - tap(() => setTimeout(() => Spotlight.focus('theme-close-button'), 0)) + tap(() => setTimeout(() => Spotlight.focus("theme-close-button"), 0)) ), [setOpenThemeItemOverlay] ); @@ -409,12 +471,12 @@ export default function ProductAllSection({ // FP: Curried scroll handlers const handleProductDetailsClick = useCallback( - () => scrollToSection('scroll-marker-product-details'), + () => scrollToSection("scroll-marker-product-details"), [scrollToSection] ); const handleYouMayAlsoLikeClick = useCallback( - () => scrollToSection('scroll-marker-you-may-also-like'), + () => scrollToSection("scroll-marker-you-may-also-like"), [scrollToSection] ); const scrollPositionRef = useRef(0); @@ -484,7 +546,12 @@ export default function ProductAllSection({ (descriptionRef.current?.scrollHeight || 0) + (reviewRef.current?.scrollHeight || 0) ); - }, [productDetailRef.current, descriptionRef.current, hasReviews, hasYouMayAlsoLike]); + }, [ + productDetailRef.current, + descriptionRef.current, + hasReviews, + hasYouMayAlsoLike, + ]); //spot관련 useEffect(() => { @@ -508,10 +575,10 @@ export default function ProductAllSection({
- {revwGrd && revwGrd !== '0.0' && ( + {revwGrd && revwGrd !== "0.0" && ( )}
@@ -525,11 +592,24 @@ export default function ProductAllSection({ productType={productType} >
- + {isShowQRCode ? ( + + ) : ( +
+
+

{$L("Scan QR")}

+

{$L("with your phone, Check Product")}

+

{$L("info & Purchase easily")}

+
+
+ )}
- {/* BUY NOW + ADD TO CART 버튼들 (결제 가능 상품일 때만 렌더링) */} {isBillingProductVisible && ( -
{$L('BUY NOW')}
+
{$L("BUY NOW")}
-
{$L('ADD TO CART')}
+
{$L("ADD TO CART")}
)} - - + + {/* BUY NOW + ADD TO CART 버튼들 (결제 가능 상품일 때만 렌더링) */} -
{$L('SHOP BY MOBILE')}
+
+ {$L("SHOP BY MOBILE")} +
{panelInfo && (
@@ -568,7 +657,7 @@ export default function ProductAllSection({ selectedPrdtId={panelInfo && panelInfo.prdtId} favoriteFlag={favoriteFlag} onFavoriteFlagChanged={onFavoriteFlagChanged} - kind={'item_detail'} + kind={"item_detail"} />
)} @@ -577,7 +666,9 @@ export default function ProductAllSection({
{orderPhnNo && ( <> -
{$L('Call to Order')}
+
+ {$L("Call to Order")} +
@@ -595,31 +686,34 @@ export default function ProductAllSection({ - {$L('PRODUCT DETAILS')} + {$L("PRODUCT DETAILS")} {hasReviews && ( - {$L('USER REVIEWS')} ({reviewTotalCount}) + {$L("USER REVIEWS")} ({reviewTotalCount}) )} {hasYouMayAlsoLike && ( - {$L('YOU MAY ALSO LIKE')} + {$L("YOU MAY ALSO LIKE")} )} {/* YouMayLike 버튼 렌더링 상태 로그 */} @@ -633,15 +727,18 @@ export default function ProductAllSection({ })()} */} - {panelInfo && panelInfo && panelInfo.type === 'theme' && !openThemeItemOverlay && ( - - {$L('THEME ITEM')} - - )} + {panelInfo && + panelInfo && + panelInfo.type === "theme" && + !openThemeItemOverlay && ( + + {$L("THEME ITEM")} + + )}
-
+
{/* */}
{renderItems.length > 0 ? ( renderItems.map((item, index) => - item.type === 'video' ? ( + item.type === "video" ? ( )}
-
+
{/* 리뷰가 있을 때만 UserReviews 섹션 표시 */} {hasReviews && ( <> -
+
{hasYouMayAlsoLike && (
-
+
{/* {(() => { console.log('[YouMayLike] YouMayAlsoLike 컴포넌트 렌더링:', { @@ -774,5 +885,5 @@ export default function ProductAllSection({ } ProductAllSection.propTypes = { - productType: PropTypes.oneOf(['buyNow', 'shopByMobile', 'theme']).isRequired, + productType: PropTypes.oneOf(["buyNow", "shopByMobile", "theme"]).isRequired, }; diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less index 2edb3558..84f9e601 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less @@ -710,7 +710,9 @@ display: flex; justify-content: flex-start; align-items: center; - + &.buttonHasNoCart { + padding-top: 0; + } > * { margin-right: 6px; &:last-child { @@ -885,7 +887,37 @@ display: flex; flex-direction: column; align-items: flex-end; - + .qrRollingWrap { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + text-align: center; + width: 240px; + height: 240px; + background: #fff; + border: 1px solid #fff; + .innerText { + width: 100%; + padding: 0 20px; + h3 { + word-break: break-word; + font-size: 36px; + font-weight: bold; + color: @PRIMARY_COLOR_RED; + & + p { + margin-top: 18px; + } + } + p { + font-size: 24px; + font-weight: bold; + line-height: 1.17; + color: @COLOR_GRAY05; + word-break: keep-all; + } + } + } > * { margin-bottom: 10px; &:last-child { diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviewDetail/UserReviewDetail.module.less b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviewDetail/UserReviewDetail.module.less index e44a6a76..902c4a98 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviewDetail/UserReviewDetail.module.less +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviewDetail/UserReviewDetail.module.less @@ -152,6 +152,7 @@ font-weight: 400; line-height: 31px; word-wrap: break-word; + overflow: hidden; } } } diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviewsPopup/UserReviewsPopup.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviewsPopup/UserReviewsPopup.jsx index 9d258938..ed2ce04e 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviewsPopup/UserReviewsPopup.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviewsPopup/UserReviewsPopup.jsx @@ -86,8 +86,8 @@ export default function UserReviewsPopup({ case "user-reviews": return { title: $L("User Reviews"), - hasIcon: true, - iconType: "user-reviews", + hasIcon: false, + iconType: null, }; case "customer-images": default: diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviewsPopup/UserReviewsPopup.module.less b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviewsPopup/UserReviewsPopup.module.less index 0c364b79..c19a9dd6 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviewsPopup/UserReviewsPopup.module.less +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviewsPopup/UserReviewsPopup.module.less @@ -118,9 +118,13 @@ // margin-bottom: 30px; // 세로 마진도 증가 margin-right: 6px; // 마진 증가로 균등 분배 > div { + width: 226px; + height: 220px; + overflow: hidden; > img { width: 226px; height: 220px; + object-fit: contain; } } @@ -145,7 +149,7 @@ width: 100%; height: 100%; border-radius: 12px; - object-fit: cover; + object-fit: contain; padding: 0; box-sizing: border-box; } @@ -191,7 +195,7 @@ width: 100%; height: 100%; border-radius: 12px; - object-fit: cover; + object-fit: contain; padding: 4px; box-sizing: border-box; } diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ShopByMobilePriceDisplay/ShopByMobilePriceDisplay.module.less b/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ShopByMobilePriceDisplay/ShopByMobilePriceDisplay.module.less index 31bf09e4..cafba670 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ShopByMobilePriceDisplay/ShopByMobilePriceDisplay.module.less +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ShopByMobilePriceDisplay/ShopByMobilePriceDisplay.module.less @@ -42,7 +42,7 @@ } .price { font-weight: bold; - font-size: 60px; + font-size: 52px; color: @COLOR_WHITE; margin-right: 9px; line-height: 1; diff --git a/com.twin.app.shoptime/src/views/DetailPanel/components/DetailMobileSendPopUp.jsx b/com.twin.app.shoptime/src/views/DetailPanel/components/DetailMobileSendPopUp.jsx index da6fc63c..2d7778ef 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/components/DetailMobileSendPopUp.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/components/DetailMobileSendPopUp.jsx @@ -1,14 +1,31 @@ -import React, { useCallback, useEffect, useMemo, useRef } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import MobileSendPopUp from "../../../components/MobileSend/MobileSendPopUp"; -import * as Config from "../../../utils/Config"; -import { setHidePopup, setShowPopup } from "../../../actions/commonActions"; -import Spotlight from "@enact/spotlight"; +import React, { + useCallback, + useEffect, + useMemo, + useRef, +} from 'react'; + +import { + useDispatch, + useSelector, +} from 'react-redux'; + +import Spotlight from '@enact/spotlight'; + +import { + setHidePopup, + setShowPopup, +} from '../../../actions/commonActions'; import { sendLogShopByMobile, sendLogTotalRecommend, -} from "../../../actions/logActions"; -import { $L, formatLocalDateTime } from "../../../utils/helperMethods"; +} from '../../../actions/logActions'; +import MobileSendPopUp from '../../../components/MobileSend/MobileSendPopUp'; +import * as Config from '../../../utils/Config'; +import { + $L, + formatLocalDateTime, +} from '../../../utils/helperMethods'; export default function DetailMobileSendPopUp({ panelInfo, @@ -167,11 +184,13 @@ export default function DetailMobileSendPopUp({ subTitle={mobileSendPopUpSubtitle} patncNm={productData?.patncNm} productImg={mobileSendPopUpProductImg} + productId={productData?.prdtId} patnrId={panelInfo?.patnrId} prdtId={panelInfo?.prdtId} smsTpCd={panelInfo?.type === "hotel" ? "APP00205" : "APP00201"} curationId={panelInfo?.curationId} curationNm={panelInfo?.curationNm} + brandLogo={productData?.patncLogoPath} // hotelId={ // panelInfo?.type === "hotel" && hotelInfos[selectedIndex]?.hotelId // } diff --git a/com.twin.app.shoptime/src/views/DetailPanel/components/THeaderCustom.module.less b/com.twin.app.shoptime/src/views/DetailPanel/components/THeaderCustom.module.less index dcb534a4..67e1dcd9 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/components/THeaderCustom.module.less +++ b/com.twin.app.shoptime/src/views/DetailPanel/components/THeaderCustom.module.less @@ -11,9 +11,10 @@ background-color: transparent; // DetailPanel에서는 배경 투명 .title { + width: 1710px; font-size: 25px; font-weight: 600; - color: #EAEAEA; + color: #eaeaea; padding-left: 0; letter-spacing: 1px; text-transform: uppercase; @@ -46,4 +47,4 @@ background-repeat: no-repeat; flex-shrink: 0; margin-right: 10px; // 파트너사 로고 후 10px gap -} \ No newline at end of file +} diff --git a/com.twin.app.shoptime/src/views/UserReview/UserReviewPanel.jsx b/com.twin.app.shoptime/src/views/UserReview/UserReviewPanel.jsx index 679fe1bb..7d55edaa 100644 --- a/com.twin.app.shoptime/src/views/UserReview/UserReviewPanel.jsx +++ b/com.twin.app.shoptime/src/views/UserReview/UserReviewPanel.jsx @@ -1,30 +1,38 @@ -import React, { useCallback, useEffect, useRef } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import classNames from "classnames"; +import React, { + useCallback, + useEffect, + useRef, +} from 'react'; -import { popPanel } from "../../actions/panelActions"; -import useReviews from "../../hooks/useReviews/useReviews"; -import UserReviewHeader from "./UserReviewHeader"; -import TPanel from "../../components/TPanel/TPanel"; -import TBody from "../../components/TBody/TBody"; -import StarRating from "../DetailPanel/components/StarRating"; -import FilterItemButton from "./components/FilterItemButton"; -import UserReviewsList from "./components/UserReviewsList"; -import fp from "../../utils/fp"; -import css from "./UserReviewPanel.module.less"; +import classNames from 'classnames'; +import { + useDispatch, + useSelector, +} from 'react-redux'; + +import { popPanel } from '../../actions/panelActions'; +import TBody from '../../components/TBody/TBody'; +import TPanel from '../../components/TPanel/TPanel'; +import useReviews from '../../hooks/useReviews/useReviews'; +import fp from '../../utils/fp'; +import StarRating from '../DetailPanel/components/StarRating'; +import FilterItemButton from './components/FilterItemButton'; +import UserReviewsList from './components/UserReviewsList'; +import UserReviewHeader from './UserReviewHeader'; +import css from './UserReviewPanel.module.less'; const UserReviewPanel = ({ className, panelInfo, spotlightId }) => { const dispatch = useDispatch(); // panelInfo에서 prdtId와 patnrId 추출 const prdtId = fp.pipe( () => panelInfo, - fp.get('prdtId'), + fp.get("prdtId"), fp.defaultTo(null) )(); const patnrId = fp.pipe( () => panelInfo, - fp.get('patnrId'), + fp.get("patnrId"), fp.defaultTo(null) )(); @@ -33,19 +41,19 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => { previewReviews, displayReviews, filteredReviews, - userReviewPanelReviews, // 페이징된 리뷰들 (3개씩) - userReviewPanelPage, // 현재 페이지 - userReviewPanelHasNext, // 다음 페이지 존재 여부 - userReviewPanelHasPrev, // 이전 페이지 존재 여부 + userReviewPanelReviews, // 페이징된 리뷰들 (3개씩) + userReviewPanelPage, // 현재 페이지 + userReviewPanelHasNext, // 다음 페이지 존재 여부 + userReviewPanelHasPrev, // 이전 페이지 존재 여부 userReviewPanelTotalPages, // 전체 페이지 수 - goToNextUserReviewPage, // 다음 페이지로 이동 - goToPrevUserReviewPage, // 이전 페이지로 이동 + goToNextUserReviewPage, // 다음 페이지로 이동 + goToPrevUserReviewPage, // 이전 페이지로 이동 applyRatingFilter, applySentimentFilter, clearAllFilters, currentFilter, filterCounts, - stats + stats, } = useReviews(prdtId, patnrId); // 포커스 복원을 위한 ref @@ -61,7 +69,7 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => { productDataPrdtId: productData.prdtId, hasProductData: !!productData, previewReviews: previewReviews ? previewReviews.length : 0, - displayReviews: displayReviews ? displayReviews.length : 0 + displayReviews: displayReviews ? displayReviews.length : 0, }); // UserReviewPanel은 새로운 API 호출 없이 기존 데이터만 사용 @@ -70,41 +78,43 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => { hasPreviewReviews: !!previewReviews, hasDisplayReviews: !!displayReviews, previewCount: previewReviews ? previewReviews.length : 0, - displayCount: displayReviews ? displayReviews.length : 0 + displayCount: displayReviews ? displayReviews.length : 0, }); // 데이터 파싱 - panelInfo에서 직접 가져오기 (Redux productData가 빈 객체가 되는 문제 해결) const productImage = fp.pipe( () => panelInfo, - fp.get('productImage'), - fp.defaultTo('https://placehold.co/150x150') + fp.get("productImage"), + fp.defaultTo("https://placehold.co/150x150") )(); const brandLogo = fp.pipe( () => panelInfo, - fp.get('brandLogo'), - fp.defaultTo('https://placehold.co/50x50') + fp.get("brandLogo"), + fp.defaultTo("https://placehold.co/50x50") )(); const productId = fp.pipe( () => panelInfo, - fp.get('prdtId'), + fp.get("prdtId"), fp.defaultTo(null) )(); const productName = fp.pipe( () => panelInfo, - fp.get('productName'), - fp.defaultTo('상품명 정보가 없습니다') + fp.get("productName"), + fp.defaultTo("상품명 정보가 없습니다") )(); // 페이징 후 포커스 복원 함수 - 중간 리뷰(index 1)로 포커스 const restoreFocusAfterPaging = useCallback(() => { setTimeout(() => { - const targetElement = document.querySelector(`[data-spotlight-id="user-review-1"]`); + const targetElement = document.querySelector( + `[data-spotlight-id="user-review-1"]` + ); if (targetElement && targetElement.focus) { targetElement.focus(); - console.log('[UserReviewPanel] 중간 리뷰로 포커스 복원 완료'); + console.log("[UserReviewPanel] 중간 리뷰로 포커스 복원 완료"); } }, 100); }, []); @@ -112,7 +122,7 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => { // 개선된 페이징 함수들 const handleNextPage = useCallback(() => { if (userReviewPanelHasNext) { - console.log('[UserReviewPanel] 다음 페이지로 이동'); + console.log("[UserReviewPanel] 다음 페이지로 이동"); goToNextUserReviewPage(); restoreFocusAfterPaging(); } @@ -120,7 +130,7 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => { const handlePrevPage = useCallback(() => { if (userReviewPanelHasPrev) { - console.log('[UserReviewPanel] 이전 페이지로 이동'); + console.log("[UserReviewPanel] 이전 페이지로 이동"); goToPrevUserReviewPage(); restoreFocusAfterPaging(); } @@ -132,44 +142,92 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => { const avgRating = stats.averageRating || 5; // 별점 필터링 핸들러들 - const handleRatingFilter = useCallback((rating) => { - console.log('[ProductId] Rating filter applied:', rating); - console.log('[ProductId] applyRatingFilter function:', !!applyRatingFilter); - applyRatingFilter(rating); // 'all' 값을 그대로 전달 - }, [applyRatingFilter]); + const handleRatingFilter = useCallback( + (rating) => { + console.log("[ProductId] Rating filter applied:", rating); + console.log( + "[ProductId] applyRatingFilter function:", + !!applyRatingFilter + ); + applyRatingFilter(rating); // 'all' 값을 그대로 전달 + }, + [applyRatingFilter] + ); - const handleAllStarsFilter = useCallback(() => handleRatingFilter('all'), [handleRatingFilter]); - const handle5StarsFilter = useCallback(() => handleRatingFilter(5), [handleRatingFilter]); - const handle4StarsFilter = useCallback(() => handleRatingFilter(4), [handleRatingFilter]); - const handle3StarsFilter = useCallback(() => handleRatingFilter(3), [handleRatingFilter]); - const handle2StarsFilter = useCallback(() => handleRatingFilter(2), [handleRatingFilter]); - const handle1StarsFilter = useCallback(() => handleRatingFilter(1), [handleRatingFilter]); + const handleAllStarsFilter = useCallback( + () => handleRatingFilter("all"), + [handleRatingFilter] + ); + const handle5StarsFilter = useCallback( + () => handleRatingFilter(5), + [handleRatingFilter] + ); + const handle4StarsFilter = useCallback( + () => handleRatingFilter(4), + [handleRatingFilter] + ); + const handle3StarsFilter = useCallback( + () => handleRatingFilter(3), + [handleRatingFilter] + ); + const handle2StarsFilter = useCallback( + () => handleRatingFilter(2), + [handleRatingFilter] + ); + const handle1StarsFilter = useCallback( + () => handleRatingFilter(1), + [handleRatingFilter] + ); + + const handleAromaClick = useCallback(() => console.log("Aroma clicked"), []); + const handleVanillaClick = useCallback( + () => console.log("Vanilla clicked"), + [] + ); + const handleCinnamonClick = useCallback( + () => console.log("Cinnamon clicked"), + [] + ); + const handleQualityClick = useCallback( + () => console.log("Quality clicked"), + [] + ); - const handleAromaClick = useCallback(() => console.log('Aroma clicked'), []); - const handleVanillaClick = useCallback(() => console.log('Vanilla clicked'), []); - const handleCinnamonClick = useCallback(() => console.log('Cinnamon clicked'), []); - const handleQualityClick = useCallback(() => console.log('Quality clicked'), []); - // 감정 필터링 핸들러들 - 별점 필터와 동일한 방식 - const handleSentimentFilter = useCallback((sentiment) => { - console.log('[ProductId] Sentiment filter applied:', sentiment); - applySentimentFilter(sentiment === 'all' ? null : sentiment); - }, [applySentimentFilter]); - - const handlePositiveClick = useCallback(() => handleSentimentFilter('positive'), [handleSentimentFilter]); - const handleNegativeClick = useCallback(() => handleSentimentFilter('negative'), [handleSentimentFilter]); + const handleSentimentFilter = useCallback( + (sentiment) => { + console.log("[ProductId] Sentiment filter applied:", sentiment); + applySentimentFilter(sentiment === "all" ? null : sentiment); + }, + [applySentimentFilter] + ); + + const handlePositiveClick = useCallback( + () => handleSentimentFilter("positive"), + [handleSentimentFilter] + ); + const handleNegativeClick = useCallback( + () => handleSentimentFilter("negative"), + [handleSentimentFilter] + ); // UserReviewPanel 마운트 시 기본 All stars 필터 적용 useEffect(() => { - if (prdtId && currentFilter.type === 'rating' && currentFilter.value === 'all') { - console.log('[ProductId] UserReviewPanel 기본 All stars 필터 이미 적용됨'); + if ( + prdtId && + currentFilter.type === "rating" && + currentFilter.value === "all" + ) { + console.log( + "[ProductId] UserReviewPanel 기본 All stars 필터 이미 적용됨" + ); } }, [prdtId, currentFilter]); - + // 메모리 해제를 위한 cleanup 함수 useEffect(() => { return () => { - console.log('[ProductId] UserReviewPanel unmounting - clearing filters'); + console.log("[ProductId] UserReviewPanel unmounting - clearing filters"); clearAllFilters(); // 필터 상태 초기화로 메모리 해제 }; }, [clearAllFilters]); @@ -186,22 +244,33 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => { userReviewPanelReviewsLength: userReviewPanelReviews.length, // UserReviewPanel에서 표시할 4개 currentFilter: currentFilter, filterCounts: filterCounts, - isDataFromCache: true // API 호출 없이 캐시된 데이터 사용 + isDataFromCache: true, // API 호출 없이 캐시된 데이터 사용 }); } catch (error) { console.error("[ProductId] UserReviewPanel 로그 오류:", error); } - }, [reviewCount, filteredCount, avgRating, displayReviews, userReviewPanelReviews, currentFilter, filterCounts]); + }, [ + reviewCount, + filteredCount, + avgRating, + displayReviews, + userReviewPanelReviews, + currentFilter, + filterCounts, + ]); const handleBackButton = useCallback(() => { console.log(`[ProductId] Back button clicked - returning to DetailPanel`); dispatch(popPanel()); }, [dispatch]); - const handleCancel = useCallback((e) => { - dispatch(popPanel()); - e.stopPropagation(); - }, [dispatch]); + const handleCancel = useCallback( + (e) => { + dispatch(popPanel()); + e.stopPropagation(); + }, + [dispatch] + ); return ( { {/* 왼쪽 필터 영역 */}
-
Filter Reviews
+
+ Filter Reviews +
{/* 모든 필터들을 묶는 컨테이너 */} @@ -267,60 +338,82 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => { {/* Rating 필터 섹션 */}
-
Rating
+
+ Rating +
@@ -328,7 +421,11 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => { {/* Keywords 필터 섹션 */}
-
Keywords
+
+ Keywords +
{ {/* Sentiment 필터 섹션 */}
-
Sentiment
+
+ Sentiment +
{ ariaLabel="Filter by positive sentiment" dataSpotlightUp="filter-quality" dataSpotlightDown="filter-negative" - isActive={currentFilter.type === 'sentiment' && currentFilter.value === 'positive'} + isActive={ + currentFilter.type === "sentiment" && + currentFilter.value === "positive" + } /> { spotlightId="filter-negative" ariaLabel="Filter by negative sentiment" dataSpotlightUp="filter-positive" - isActive={currentFilter.type === 'sentiment' && currentFilter.value === 'negative'} + isActive={ + currentFilter.type === "sentiment" && + currentFilter.value === "negative" + } />
diff --git a/com.twin.app.shoptime/src/views/UserReview/components/FilterItemButton.module.less b/com.twin.app.shoptime/src/views/UserReview/components/FilterItemButton.module.less index b0793931..a7670241 100644 --- a/com.twin.app.shoptime/src/views/UserReview/components/FilterItemButton.module.less +++ b/com.twin.app.shoptime/src/views/UserReview/components/FilterItemButton.module.less @@ -5,35 +5,35 @@ // TButton 기본 스타일 무력화 all: unset; box-sizing: border-box; - + // FilterItem 레이아웃 스타일 (요구사항에 맞는 스타일 적용) display: flex; padding: 20px; flex-direction: column; align-items: flex-start; border-radius: 100px; - border: 1px solid #DADADA; - background: #FFF; + border: 1px solid #dadada; + background: #fff; cursor: pointer; white-space: nowrap; - + // 고정 넓이와 마진 설정으로 일정한 간격 유지 (한 라인에 4개 표시) width: 90px; - margin-right: 40px; + margin-right: 15px; margin-bottom: 10px; - + // 각 라인의 마지막 아이템은 오른쪽 마진 제거 &:last-child { margin-right: 0; } - + // 포커스 상태: 빨간색 배경 &:focus { outline: none; box-shadow: none; - background: #D32F2F !important; // 빨간색 - border: 1px solid #D32F2F !important; - + background: #d32f2f !important; // 빨간색 + border: 1px solid #d32f2f !important; + .filterItemButton__text { color: white !important; } @@ -45,9 +45,9 @@ padding: 20px; flex-direction: column; align-items: flex-start; - background: #7A808D !important; // 회색 (선택됨) + background: #7a808d !important; // 회색 (선택됨) border-radius: 100px; - border: 1px solid #7A808D !important; + border: 1px solid #7a808d !important; white-space: nowrap; } @@ -55,7 +55,7 @@ text-align: center; color: black; font-size: 24px; - font-family: 'LG Smart UI'; + font-family: "LG Smart UI"; font-weight: 400; line-height: 24px; @@ -63,7 +63,7 @@ text-align: center; color: white; font-size: 24px; - font-family: 'LG Smart UI'; + font-family: "LG Smart UI"; font-weight: 400; line-height: 24px; } @@ -85,4 +85,4 @@ padding-right: 0; } } -} \ No newline at end of file +}