[상품 상세 노출 변경에 따른 처리]

- 상품명 노출추가.
 - theadercustom부분에 themetitle부분 처리.
 - qr 크기 조절.(240px -> 190px)
 - 금액 노출부분 하단으로 떨구도록
This commit is contained in:
junghoon86.park
2025-12-01 18:18:13 +09:00
parent 579512402e
commit c522fe2777
11 changed files with 173 additions and 88 deletions

View File

@@ -1,25 +1,46 @@
// src/views/DetailPanel/DetailPanel.new.jsx
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
import React, {
useCallback,
useEffect,
useLayoutEffect,
useMemo,
useRef,
useState,
} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
useDispatch,
useSelector,
} from 'react-redux';
import Spotlight from '@enact/spotlight';
import { setContainerLastFocusedElement } from '@enact/spotlight/src/container';
import { getDeviceAdditionInfo } from '../../actions/deviceActions';
import { getThemeCurationDetailInfo, updateHomeInfo } from '../../actions/homeActions';
import { getMainCategoryDetail, getMainYouMayLike } from '../../actions/mainActions';
import { finishModalMediaForce } from '../../actions/mediaActions';
import { popPanel, updatePanel } from '../../actions/panelActions';
import {
// <<<<<<< HEAD
getThemeCurationDetailInfo,
updateHomeInfo,
} from '../../actions/homeActions';
import {
getMainCategoryDetail,
getMainYouMayLike,
} from '../../actions/mainActions';
import { finishModalMediaForce } from '../../actions/mediaActions';
import {
popPanel,
updatePanel,
} from '../../actions/panelActions';
import {
finishVideoPreview,
pauseFullscreenVideo,
resumeFullscreenVideo,
pauseModalVideo,
resumeFullscreenVideo,
resumeModalVideo,
} from '../../actions/playActions';
import { clearProductDetail, getProductOptionId } from '../../actions/productActions';
import {
clearProductDetail,
getProductOptionId,
} from '../../actions/productActions';
import { clearAllToasts } from '../../actions/toastActions';
import TBody from '../../components/TBody/TBody';
import TPanel from '../../components/TPanel/TPanel';
@@ -31,6 +52,7 @@ import THeaderCustom from './components/THeaderCustom';
import css from './DetailPanel.module.less';
import ProductAllSection from './ProductAllSection/ProductAllSection';
import ThemeItemListOverlay from './ThemeItemListOverlay/ThemeItemListOverlay';
// =======
// changeAppStatus,
// changeLocalSettings,
@@ -929,12 +951,12 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
}
}, [themeData, selectedIndex]);
// 타이틀과 aria-label 메모이제이션 (성능 최적화)
// 타이틀과 aria-label 메모이제이션 (성능 최적화 // themeTitle과 haederTitle 분리.)
const headerTitle = useMemo(
() =>
fp.pipe(
() => ({ panelPrdtId, productData, panelType, themeData }),
({ panelPrdtId, productData, panelType, themeData }) => {
() => ({ panelPrdtId, productData }),
({ panelPrdtId, productData }) => {
const productTitle = fp.pipe(
() => ({ panelPrdtId, productData }),
({ panelPrdtId, productData }) =>
@@ -943,7 +965,17 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
? fp.pipe(() => productData, fp.get('prdtNm'))()
: null
)();
return productTitle || '';
}
)(),
[panelPrdtId, productData]
);
const themeHeaderTitle = useMemo(
() =>
fp.pipe(
() => ({ panelType, themeData }),
({ panelType, themeData }) => {
const themeTitle = fp.pipe(
() => ({ panelType, themeData }),
({ panelType, themeData }) =>
@@ -952,12 +984,14 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
: null
)();
return productTitle || themeTitle || '';
return themeTitle || '';
}
)(),
[panelPrdtId, productData, panelType, themeData]
[panelType, themeData]
);
const ariaLabel = useMemo(
() =>
fp.pipe(
@@ -1071,6 +1105,9 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
className={css.header}
prdtId={productData?.prdtId}
title={headerTitle}
themeTitle={themeHeaderTitle}
selectedIndex={selectedIndex}
type={panelInfo?.type === "theme" ? "theme" : null}
onBackButton
onClick={onBackClick(false)}
onBackButtonFocus={onBackButtonFocus}
@@ -1079,8 +1116,9 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
onSpotlightLeft={onSpotlightUpTButton}
marqueeDisabled={false}
ariaLabel={ariaLabel}
logoImg={productData?.patncLogoPath}
logoImg={productData?.patncLogoPath ? productData?.patncLogoPath : themeData?.productInfos[0]?.patncLogoPath}
patnrId={panelPatnrId}
themeData={themeData}
/>
<TBody
className={css.tbody}

View File

@@ -1544,7 +1544,10 @@ export default function ProductAllSection({
>
<div className={css.qrWrapper}>
{isShowQRCode ? (
<QRCode productInfo={productData} productType={productType} kind={'detail'} />
<>
{/* <QRCode productInfo={productData} productType={productType} kind={'detail'} /> */}
<QRCode productInfo={productData} productType={productType} />
</>
) : (
<div className={css.qrRollingWrap}>
<div className={css.innerText}>

View File

@@ -321,12 +321,12 @@
.qrcode {
> div:first-child {
// 명시적으로 크기 고정 및 오버플로우 처리
width: 240px !important;
height: 240px !important;
max-width: 240px !important;
max-height: 240px !important;
min-width: 240px !important;
min-height: 240px !important;
width: 190px !important;
height: 190px !important;
max-width: 190px !important;
max-height: 190px !important;
min-width: 190px !important;
min-height: 190px !important;
overflow: hidden;
box-sizing: border-box;
@@ -346,8 +346,8 @@
justify-content: center;
align-items: center;
text-align: center;
width: 240px;
height: 240px;
width: 190px;
height: 190px;
background: #fff;
border: 1px solid #fff;
.innerText {
@@ -355,7 +355,7 @@
padding: 0 20px;
h3 {
word-break: break-word;
font-size: 36px;
font-size: 30px;
font-weight: bold;
color: @PRIMARY_COLOR_RED;
& + p {
@@ -363,7 +363,7 @@
}
}
p {
font-size: 24px;
font-size: 18px;
font-weight: bold;
line-height: 1.17;
color: @COLOR_GRAY05;

View File

@@ -11,13 +11,13 @@
}
&.detailQrcode {
> div:first-child {
width: 240px;
height: 240px;
width: 190px;
height: 190px;
}
}
.tooltip {
margin-top: 10px;
width: 240px;
width: 190px;
height: 60px;
background: #000;
color: #fff;
@@ -39,7 +39,7 @@
position: relative;
width: 100%;
height: 44px;
font-size: 20px;
font-size: 16px;
line-height: 22px;
letter-spacing: -1px;
display: flex;

View File

@@ -2,10 +2,12 @@
@import "../../../style/utils.module.less";
.container {
margin-bottom: 10px;
// .size(@w:100%,@h:100%);
.size(@w:100%,@h:334px);
.size(@w:100%,@h:370px);
.productInfoWrapper {
.flex(@justifyCenter:flex-start,@alignCenter:flex-start);
flex-wrap: wrap;
// margin: 54px 0 10px 0;
margin: 20px 0 10px 0;
// 고정 높이로 인해 QR 영역과 하단 버튼 영역 사이에 과도한 여백이 생김

View File

@@ -171,6 +171,10 @@ export default function ProductPriceDisplay({ productType, productInfo }) {
<>
{productType && productInfo && (
/* <div> */
<>
<div className={css.productNm}>
{productInfo.prdtNm}
</div>
<div style={{ margin: "0 10px 0 0", width: "380px" }}>
{/* shop by mobile (구매불가) 상품 price render */}
{(productType === "shopByMobile" || isThemeShopByMobile) && (
@@ -213,6 +217,7 @@ export default function ProductPriceDisplay({ productType, productInfo }) {
})}
</div>
</div>
</>
)}
{(() => {
// 팝업이 표시되어야 하는 조건 검증

View File

@@ -184,3 +184,13 @@
height: auto;
object-fit: contain; // 비율 유지하면서 컨테이너에 맞춤
}
.productNm {
width: 100%;
font-weight: bold;
font-size: 36px;
color: @COLOR_WHITE;
flex:none;
.elip(2);
margin-bottom: 20px;
}

View File

@@ -123,14 +123,16 @@ export default function ShopByMobilePriceDisplay({
<span className={css.price}>
{isDiscountedPriceEmpty ? offerInfo : discountedPrice}
</span>
</div>
{isDiscounted && (
<div className={css.btmLayer2}>
<span className={css.discountedPrc}>
{originalPrice && isOriginalPriceEmpty
? offerInfo
: originalPrice}
</span>
)}
</div>
)}
</div>
);
} else if (TYPE_CASE.case3) {
@@ -150,14 +152,17 @@ export default function ShopByMobilePriceDisplay({
<span className={css.price}>
{isDiscountedPriceEmpty ? offerInfo : discountedPrice}
</span>
</div>
{isDiscounted && (
<div className={css.btmLayer2}>
<span className={css.discountedPrc}>
{originalPrice && isOriginalPriceEmpty
? offerInfo
: originalPrice}
</span>
)}
</div>
)}
{/* 할부 */}
</div>
);
@@ -172,7 +177,7 @@ export default function ShopByMobilePriceDisplay({
)}
<span className={css.name}>{$L("Shop Time Price")}</span>
</div>
<div className={css.btmLayer}>
<div className={css.btmLayer2}>
<span className={css.price}>{discountedPrice}</span>
{discountedPrice !== originalPrice && (
<span className={css.discountedPrc}>

View File

@@ -40,6 +40,11 @@
display: flex;
align-items: center;
}
.btmLayer2 {
margin: 5px 0;
display: flex;
align-items: center;
}
.price {
font-weight: bold;
font-size: 52px;

View File

@@ -24,6 +24,9 @@ const SpottableComponent = Spottable("button");
export default function THeaderCustom({
prdtId,
title,
type,
themeTitle,
selectedIndex,
className,
onBackButton,
onSpotlightUp,
@@ -36,15 +39,18 @@ export default function THeaderCustom({
kind,
logoImg,
patnrId,
themeData,
...rest
}) {
const convertedTitle = useMemo(() => {
if (title && typeof title === "string") {
const cleanedTitle = title.replace(/(\r\n|\n)/g, "");
return $L(marqueeDisabled ? title : cleanedTitle);
} else if(type === "theme") {
return themeData?.productInfos[selectedIndex].prdtNm;
}
return "";
}, [marqueeDisabled, title]);
}, [marqueeDisabled, title, selectedIndex, themeData, type]);
const _onClick = useCallback(
(e) => {
@@ -87,6 +93,9 @@ export default function THeaderCustom({
role="button"
/>
)}
{type === "theme" && themeTitle && (
<span className={css.themeTitle} dangerouslySetInnerHTML={{ __html: themeTitle }} />
)}
{kind ? (
""
) : (

View File

@@ -54,3 +54,11 @@
margin-right: 10px; // 파트너사 로고 후 10px gap
border-radius: 100%;
}
.themeTitle {
font-size: 25px;
font-weight: 600;
color: #eaeaea;
width: max-content;
margin-right: 20px;
}