[상품상세] 스타일 수정

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 눌렀을때 노출되는 화면에서 디자인 맞추기.(디자인 맞춰둠)
This commit is contained in:
junghoon86.park
2025-09-30 20:44:10 +09:00
parent d8479e89ec
commit de0a38e74e
14 changed files with 522 additions and 229 deletions

View File

@@ -5,7 +5,7 @@
.titleHead {
align-self: stretch;
padding: 30px;
background: #E7EBEF;
background: #e7ebef;
display: flex;
justify-content: flex-start; // center → flex-start
align-items: center;
@@ -14,7 +14,7 @@
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;
@@ -31,12 +31,13 @@
width: 50px;
height: 50px;
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,6 +63,12 @@
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;
@@ -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);
}
@@ -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;

View File

@@ -66,6 +66,10 @@
&.full {
width: 100%;
}
&.detail_small {
min-width: 312px;
max-width: 312px;
}
&.basic {
&.disabled {
background-color: #7a808d;

View File

@@ -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
)();

View File

@@ -8,6 +8,7 @@
z-index: 1; // 배경 컴포넌트(z-index: 0) 위에 표시
background: transparent !important; // 투명 배경으로 설정하여 뒤의 배경 컴포넌트가 보이도록
height: 100%;
overflow: hidden;
// 하위 요소들도 투명 배경 (detailPanelWrap 스코프 내에서만 적용)
> * {
background: transparent !important;

View File

@@ -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 }) => (
<SpottableComponent
@@ -152,7 +171,9 @@ export default function ProductAllSection({
const dispatch = useDispatch();
// Redux 상태
const webOSVersion = useSelector((state) => 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({
<div className={css.leftInfoWrapper}>
<div className={css.headerContent}>
<ProductTag productInfo={productData} />
{revwGrd && revwGrd !== '0.0' && (
{revwGrd && revwGrd !== "0.0" && (
<StarRating
rating={revwGrd}
aria-label={'star rating ' + revwGrd + ' out of 5'}
aria-label={"star rating " + revwGrd + " out of 5"}
/>
)}
</div>
@@ -525,11 +592,24 @@ export default function ProductAllSection({
productType={productType}
>
<div className={css.qrWrapper}>
<QRCode productInfo={productData} productType={productType} kind={'detail'} />
{isShowQRCode ? (
<QRCode
productInfo={productData}
productType={productType}
kind={"detail"}
/>
) : (
<div className={css.qrRollingWrap}>
<div className={css.innerText}>
<h3>{$L("Scan QR")}</h3>
<p>{$L("with your phone, Check Product")}</p>
<p>{$L("info & Purchase easily")}</p>
</div>
</div>
)}
</div>
</ProductOverview>
{/* BUY NOW + ADD TO CART 버튼들 (결제 가능 상품일 때만 렌더링) */}
{isBillingProductVisible && (
<HorizontalContainer className={css.buyNowCartContainer}>
<TButton
@@ -537,28 +617,37 @@ export default function ProductAllSection({
className={css.buyNowButton}
onClick={handleBuyNowClick}
onSpotlightUp={handleSpotlightUpToBackButton}
type="detail_small"
>
<div className={css.buyNowText}>{$L('BUY NOW')}</div>
<div className={css.buyNowText}>{$L("BUY NOW")}</div>
</TButton>
<TButton
spotlightId="detail-add-to-cart-button"
className={css.addToCartButton}
onClick={handleAddToCartClick}
onSpotlightUp={handleSpotlightUpToBackButton}
type="detail_small"
>
<div className={css.addToCartText}>{$L('ADD TO CART')}</div>
<div className={css.addToCartText}>{$L("ADD TO CART")}</div>
</TButton>
</HorizontalContainer>
)}
<Container className={css.buttonContainer}>
<Container
className={classNames(
css.buttonContainer,
isBillingProductVisible && css.buttonHasNoCart
)}
>
{/* BUY NOW + ADD TO CART 버튼들 (결제 가능 상품일 때만 렌더링) */}
<TButton
spotlightId={SpotlightIds.DETAIL_SHOPBYMOBILE}
className={css.shopByMobileButton}
onClick={handleShopByMobileOpen}
onSpotlightUp={handleSpotlightUpToBackButton}
>
<div className={css.shopByMobileText}>{$L('SHOP BY MOBILE')}</div>
<div className={css.shopByMobileText}>
{$L("SHOP BY MOBILE")}
</div>
</TButton>
{panelInfo && (
<div className={css.favoriteBtnWrapper}>
@@ -568,7 +657,7 @@ export default function ProductAllSection({
selectedPrdtId={panelInfo && panelInfo.prdtId}
favoriteFlag={favoriteFlag}
onFavoriteFlagChanged={onFavoriteFlagChanged}
kind={'item_detail'}
kind={"item_detail"}
/>
</div>
)}
@@ -577,7 +666,9 @@ export default function ProductAllSection({
<div className={css.callToOrderSection}>
{orderPhnNo && (
<>
<div className={css.callToOrderText}>{$L('Call to Order')}</div>
<div className={css.callToOrderText}>
{$L("Call to Order")}
</div>
<div className={css.phoneSection}>
<div className={css.phoneIconContainer}>
<div className={css.phoneIcon} />
@@ -595,31 +686,34 @@ export default function ProductAllSection({
<TButton
className={classNames(
css.productDetailsButton,
activeProductBtn ? css.active : ''
activeProductBtn ? css.active : ""
)}
onClick={handleProductDetailsClick}
spotlightId="product-details-button"
>
{$L('PRODUCT DETAILS')}
{$L("PRODUCT DETAILS")}
</TButton>
{hasReviews && (
<TButton
className={classNames(css.userReviewsButton, activeReviewBtn ? css.active : '')}
className={classNames(
css.userReviewsButton,
activeReviewBtn ? css.active : ""
)}
onClick={handleUserReviewsClick}
spotlightId="user-reviews-button"
>
{$L('USER REVIEWS')} ({reviewTotalCount})
{$L("USER REVIEWS")} ({reviewTotalCount})
</TButton>
)}
{hasYouMayAlsoLike && (
<TButton
className={classNames(
css.youMayLikeButton,
activeYouMayLikeBtn ? css.active : ''
activeYouMayLikeBtn ? css.active : ""
)}
onClick={handleYouMayAlsoLikeClick}
>
{$L('YOU MAY ALSO LIKE')}
{$L("YOU MAY ALSO LIKE")}
</TButton>
)}
{/* YouMayLike 버튼 렌더링 상태 로그 */}
@@ -633,13 +727,16 @@ export default function ProductAllSection({
})()} */}
</Container>
{panelInfo && panelInfo && panelInfo.type === 'theme' && !openThemeItemOverlay && (
{panelInfo &&
panelInfo &&
panelInfo.type === "theme" &&
!openThemeItemOverlay && (
<TButton
className={css.themeButton}
onClick={handleThemeItemButtonClick}
spotlightId="theme-open-button"
>
{$L('THEME ITEM')}
{$L("THEME ITEM")}
</TButton>
)}
@@ -673,7 +770,10 @@ export default function ProductAllSection({
onScroll={handleScroll}
>
<div className={css.productDetail}>
<div id="scroll-marker-product-details" className={css.scrollMarker}></div>
<div
id="scroll-marker-product-details"
className={css.scrollMarker}
></div>
{/* <LayoutSample onClick={handleLayoutSampleClick} /> */}
<div
id="product-details-section"
@@ -683,7 +783,7 @@ export default function ProductAllSection({
>
{renderItems.length > 0 ? (
renderItems.map((item, index) =>
item.type === 'video' ? (
item.type === "video" ? (
<ProductVideo
key="product-video-0"
productInfo={productData}
@@ -706,13 +806,21 @@ export default function ProductAllSection({
<ProductDetail productInfo={productData} />
)}
</div>
<div id="product-description-section" ref={descriptionRef}>
<div
id="product-description-section"
ref={descriptionRef}
onFocus={productFocus}
onBlur={_onBlur}
>
<ProductDescription productInfo={productData} />
</div>
{/* 리뷰가 있을 때만 UserReviews 섹션 표시 */}
{hasReviews && (
<>
<div id="scroll-marker-user-reviews" className={css.scrollMarker}></div>
<div
id="scroll-marker-user-reviews"
className={css.scrollMarker}
></div>
<div
id="user-reviews-section"
ref={reviewRef}
@@ -736,7 +844,10 @@ export default function ProductAllSection({
</div>
{hasYouMayAlsoLike && (
<div ref={youMayAlsoLikelRef}>
<div id="scroll-marker-you-may-also-like" className={css.scrollMarker}></div>
<div
id="scroll-marker-you-may-also-like"
className={css.scrollMarker}
></div>
<div id="you-may-also-like-section">
{/* {(() => {
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,
};

View File

@@ -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 {

View File

@@ -152,6 +152,7 @@
font-weight: 400;
line-height: 31px;
word-wrap: break-word;
overflow: hidden;
}
}
}

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -42,7 +42,7 @@
}
.price {
font-weight: bold;
font-size: 60px;
font-size: 52px;
color: @COLOR_WHITE;
margin-right: 9px;
line-height: 1;

View File

@@ -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
// }

View File

@@ -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;

View File

@@ -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)
)();
@@ -45,7 +53,7 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => {
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);
const handleRatingFilter = useCallback(
(rating) => {
console.log("[ProductId] Rating filter applied:", rating);
console.log(
"[ProductId] applyRatingFilter function:",
!!applyRatingFilter
);
applyRatingFilter(rating); // 'all' 값을 그대로 전달
}, [applyRatingFilter]);
},
[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 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 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) => {
const handleCancel = useCallback(
(e) => {
dispatch(popPanel());
e.stopPropagation();
}, [dispatch]);
},
[dispatch]
);
return (
<TPanel
@@ -259,7 +328,9 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => {
{/* 왼쪽 필터 영역 */}
<div className={css.reviewsSection__filters}>
<div className={css.reviewsSection__filters__title}>
<div className={css.reviewsSection__filters__title__text}>Filter Reviews</div>
<div className={css.reviewsSection__filters__title__text}>
Filter Reviews
</div>
</div>
{/* 모든 필터들을 묶는 컨테이너 */}
@@ -267,60 +338,82 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => {
{/* Rating 필터 섹션 */}
<div className={css.reviewsSection__filters__section}>
<div className={css.reviewsSection__filters__sectionTitle}>
<div className={css.reviewsSection__filters__sectionTitle__text}>Rating</div>
<div
className={css.reviewsSection__filters__sectionTitle__text}
>
Rating
</div>
</div>
<div className={css.reviewsSection__filters__group}>
<FilterItemButton
text={`All stars(${filterCounts?.rating?.all || reviewCount || 0})`}
text={`All star(${filterCounts?.rating?.all || reviewCount || 0})`}
onClick={handleAllStarsFilter}
spotlightId="filter-all-stars"
ariaLabel="Filter by all star ratings"
dataSpotlightDown="filter-5-stars"
isActive={currentFilter.type === 'rating' && currentFilter.value === 'all'}
isActive={
currentFilter.type === "rating" &&
currentFilter.value === "all"
}
/>
<FilterItemButton
text={`5 stars (${filterCounts?.rating?.[5] || 0})`}
text={`5 star (${filterCounts?.rating?.[5] || 0})`}
onClick={handle5StarsFilter}
spotlightId="filter-5-stars"
ariaLabel="Filter by 5 star ratings"
dataSpotlightUp="filter-all-stars"
dataSpotlightDown="filter-4-stars"
isActive={currentFilter.type === 'rating' && currentFilter.value === 5}
isActive={
currentFilter.type === "rating" &&
currentFilter.value === 5
}
/>
<FilterItemButton
text={`4 stars (${filterCounts?.rating?.[4] || 0})`}
text={`4 star (${filterCounts?.rating?.[4] || 0})`}
onClick={handle4StarsFilter}
spotlightId="filter-4-stars"
ariaLabel="Filter by 4 star ratings"
dataSpotlightUp="filter-5-stars"
dataSpotlightDown="filter-3-stars"
isActive={currentFilter.type === 'rating' && currentFilter.value === 4}
isActive={
currentFilter.type === "rating" &&
currentFilter.value === 4
}
/>
<FilterItemButton
text={`3 stars (${filterCounts?.rating?.[3] || 0})`}
text={`3 star (${filterCounts?.rating?.[3] || 0})`}
onClick={handle3StarsFilter}
spotlightId="filter-3-stars"
ariaLabel="Filter by 3 star ratings"
dataSpotlightUp="filter-4-stars"
dataSpotlightDown="filter-2-stars"
isActive={currentFilter.type === 'rating' && currentFilter.value === 3}
isActive={
currentFilter.type === "rating" &&
currentFilter.value === 3
}
/>
<FilterItemButton
text={`2 stars (${filterCounts?.rating?.[2] || 0})`}
text={`2 star (${filterCounts?.rating?.[2] || 0})`}
onClick={handle2StarsFilter}
spotlightId="filter-2-stars"
ariaLabel="Filter by 2 star ratings"
dataSpotlightUp="filter-3-stars"
dataSpotlightDown="filter-1-stars"
isActive={currentFilter.type === 'rating' && currentFilter.value === 2}
isActive={
currentFilter.type === "rating" &&
currentFilter.value === 2
}
/>
<FilterItemButton
text={`1 stars (${filterCounts?.rating?.[1] || 0})`}
text={`1 star (${filterCounts?.rating?.[1] || 0})`}
onClick={handle1StarsFilter}
spotlightId="filter-1-stars"
ariaLabel="Filter by 1 star ratings"
dataSpotlightUp="filter-2-stars"
isActive={currentFilter.type === 'rating' && currentFilter.value === 1}
isActive={
currentFilter.type === "rating" &&
currentFilter.value === 1
}
/>
</div>
</div>
@@ -328,7 +421,11 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => {
{/* Keywords 필터 섹션 */}
<div className={css.reviewsSection__filters__section}>
<div className={css.reviewsSection__filters__sectionTitle}>
<div className={css.reviewsSection__filters__sectionTitle__text}>Keywords</div>
<div
className={css.reviewsSection__filters__sectionTitle__text}
>
Keywords
</div>
</div>
<div className={css.reviewsSection__filters__group}>
<FilterItemButton
@@ -369,7 +466,11 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => {
{/* Sentiment 필터 섹션 */}
<div className={css.reviewsSection__filters__section}>
<div className={css.reviewsSection__filters__sectionTitle}>
<div className={css.reviewsSection__filters__sectionTitle__text}>Sentiment</div>
<div
className={css.reviewsSection__filters__sectionTitle__text}
>
Sentiment
</div>
</div>
<div className={css.reviewsSection__filters__group}>
<FilterItemButton
@@ -379,7 +480,10 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => {
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"
}
/>
<FilterItemButton
text={`Negative (${filterCounts?.sentiment?.negative || 0})`}
@@ -387,7 +491,10 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => {
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"
}
/>
</div>
</div>

View File

@@ -12,14 +12,14 @@
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;
// 각 라인의 마지막 아이템은 오른쪽 마진 제거
@@ -31,8 +31,8 @@
&: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;
}