[에너지 라벨 노출 관련 작업]
- 상세 가격하단 노출 처리 및 스타일 수정 - youmayalsolike 부분에 노출 처리 및 스타일 수정 - 검색결과 아이템 부분에 노출 처리.
This commit is contained in:
@@ -1,20 +1,40 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
} from 'react-redux';
|
||||
|
||||
import { Job } from '@enact/core/util';
|
||||
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
|
||||
import SpotlightContainerDecorator
|
||||
from '@enact/spotlight/SpotlightContainerDecorator';
|
||||
import Spottable from '@enact/spotlight/Spottable';
|
||||
|
||||
import { clearThemeDetail } from '../../../../actions/homeActions';
|
||||
import { popPanel, pushPanel, updatePanel } from '../../../../actions/panelActions';
|
||||
import {
|
||||
popPanel,
|
||||
pushPanel,
|
||||
updatePanel,
|
||||
} from '../../../../actions/panelActions';
|
||||
import { finishVideoPreview } from '../../../../actions/playActions';
|
||||
import THeader from '../../../../components/THeader/THeader';
|
||||
import TItemCard from '../../../../components/TItemCard/TItemCard';
|
||||
import TVerticalPagenator from '../../../../components/TVerticalPagenator/TVerticalPagenator';
|
||||
import TVirtualGridList from '../../../../components/TVirtualGridList/TVirtualGridList';
|
||||
import TItemCardNew from '../../../../components/TItemCard/TItemCard.new';
|
||||
import TVerticalPagenator
|
||||
from '../../../../components/TVerticalPagenator/TVerticalPagenator';
|
||||
import TVirtualGridList
|
||||
from '../../../../components/TVirtualGridList/TVirtualGridList';
|
||||
import useScrollTo from '../../../../hooks/useScrollTo';
|
||||
import { LOG_CONTEXT_NAME, LOG_MESSAGE_ID, panel_names } from '../../../../utils/Config';
|
||||
import {
|
||||
LOG_CONTEXT_NAME,
|
||||
LOG_MESSAGE_ID,
|
||||
panel_names,
|
||||
} from '../../../../utils/Config';
|
||||
import { $L } from '../../../../utils/helperMethods';
|
||||
import css from './YouMayAlsoLike.module.less';
|
||||
|
||||
@@ -136,6 +156,7 @@ export default function YouMayAlsoLike({
|
||||
patncNm,
|
||||
brndNm,
|
||||
lgCatCd,
|
||||
euEnrgLblInfos,
|
||||
} = product;
|
||||
|
||||
const handleItemClick = () => {
|
||||
@@ -166,7 +187,7 @@ export default function YouMayAlsoLike({
|
||||
cursorOpen.current.stop();
|
||||
};
|
||||
return (
|
||||
<TItemCard
|
||||
<TItemCardNew
|
||||
key={prdtId}
|
||||
contextName={LOG_CONTEXT_NAME.YOUMAYLIKE}
|
||||
messageId={LOG_MESSAGE_ID.CONTENTCLICK}
|
||||
@@ -186,6 +207,7 @@ export default function YouMayAlsoLike({
|
||||
onClick={handleItemClick}
|
||||
label={index * 1 + 1 + ' of ' + newYoumaylikeProductData.length}
|
||||
lastLabel=" go to detail, button"
|
||||
euEnrgLblInfos={euEnrgLblInfos}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
> div:nth-child(2) {
|
||||
margin-top: 15px;
|
||||
/* desc wrapper */
|
||||
> div > h3 {
|
||||
> div > div > h3 {
|
||||
/* title */
|
||||
color: rgba(234, 234, 234, 1);
|
||||
.size(@w:100%,@h:64px);
|
||||
|
||||
@@ -1,19 +1,59 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { useSelector } from 'react-redux';
|
||||
import {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
} from 'react-redux';
|
||||
|
||||
import Spotlight from '@enact/spotlight';
|
||||
import Spottable from '@enact/spotlight/Spottable';
|
||||
|
||||
import {
|
||||
setHidePopup,
|
||||
setShowPopup,
|
||||
} from '../../../../actions/commonActions';
|
||||
import {
|
||||
clearConvertedImage,
|
||||
convertPdfToImage,
|
||||
} from '../../../../actions/convertActions';
|
||||
import CustomImage from '../../../../components/CustomImage/CustomImage';
|
||||
import TPopUp from '../../../../components/TPopUp/TPopUp';
|
||||
import usePriceInfo from '../../../../hooks/usePriceInfo';
|
||||
import * as Config from '../../../../utils/Config';
|
||||
import { $L } from '../../../../utils/helperMethods';
|
||||
import { SpotlightIds } from '../../../../utils/SpotlightIds';
|
||||
import BuyNowPriceDisplay from './BuyNowPriceDisplay/BuyNowPriceDisplay';
|
||||
import css from './ProductPriceDisplay.module.less';
|
||||
import ShopByMobilePriceDisplay
|
||||
from './ShopByMobilePriceDisplay/ShopByMobilePriceDisplay';
|
||||
|
||||
const SpottableComponent = Spottable("div");
|
||||
|
||||
const STRING_CONF = {
|
||||
ENERGY_LOADING: "Loading energy label...",
|
||||
ENERGY_ERROR: "Failed to load energy label",
|
||||
};
|
||||
|
||||
export default function ProductPriceDisplay({ productType, productInfo }) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [currentPdfUrl, setCurrentPdfUrl] = useState(null);
|
||||
|
||||
const cursorVisible = useSelector(
|
||||
(state) => state.common.appStatus.cursorVisible
|
||||
);
|
||||
const { activePopup, popupVisible } = useSelector(
|
||||
(state) => state.common.popup
|
||||
);
|
||||
|
||||
const convert = useSelector((state) => state.convert);
|
||||
|
||||
|
||||
const webOSVersion = useSelector(
|
||||
(state) => state.common.appStatus.webOSVersion
|
||||
);
|
||||
@@ -27,6 +67,7 @@ export default function ProductPriceDisplay({ productType, productInfo }) {
|
||||
patnrName,
|
||||
installmentMonths,
|
||||
orderPhnNo,
|
||||
euEnrgLblInfos,
|
||||
} = productInfo;
|
||||
|
||||
const {
|
||||
@@ -65,6 +106,67 @@ export default function ProductPriceDisplay({ productType, productInfo }) {
|
||||
);
|
||||
}, [productType, productInfo?.pmtSuptYn, webOSVersion]);
|
||||
|
||||
const handleClosePopup = useCallback(() => {
|
||||
if (convert?.convertedImage && convert.convertedImage.startsWith("blob:")) {
|
||||
URL.revokeObjectURL(convert.convertedImage);
|
||||
}
|
||||
|
||||
dispatch(setHidePopup());
|
||||
dispatch(clearConvertedImage());
|
||||
setCurrentPdfUrl(null);
|
||||
}, [dispatch, convert?.convertedImage]);
|
||||
|
||||
const onEnergyClick = useCallback(
|
||||
(e, pdfUrl) => {
|
||||
e.stopPropagation();
|
||||
setCurrentPdfUrl(pdfUrl);
|
||||
|
||||
// PNG 이미지는 직접 표시
|
||||
if (pdfUrl.endsWith(".png")) {
|
||||
// console.log(`📸 [EnergyLabel] Displaying PNG directly:`, pdfUrl);
|
||||
dispatch({
|
||||
type: "CONVERT_PDF_TO_IMAGE_SUCCESS",
|
||||
payload: { pdfUrl, imageUrl: pdfUrl },
|
||||
});
|
||||
dispatch(setShowPopup(Config.ACTIVE_POPUP.energyPopup));
|
||||
setTimeout(() => {
|
||||
Spotlight.focus(SpotlightIds.TPOPUP);
|
||||
}, 250);
|
||||
return;
|
||||
}
|
||||
|
||||
// PDF 변환 시작 (최대 5회 재시도, 60초 타임아웃)
|
||||
// console.log(`📄 [EnergyLabel] Starting PDF conversion:`, pdfUrl);
|
||||
dispatch(
|
||||
convertPdfToImage(
|
||||
pdfUrl,
|
||||
(error, imageUrl) => {
|
||||
if (error) {
|
||||
console.error(
|
||||
"[EnergyLabel] 최종 변환 실패:",
|
||||
error.message || error
|
||||
);
|
||||
// 실패해도 팝업은 열어서 에러 메시지 표시
|
||||
dispatch(setShowPopup(Config.ACTIVE_POPUP.energyPopup));
|
||||
setTimeout(() => {
|
||||
Spotlight.focus(SpotlightIds.TPOPUP);
|
||||
}, 250);
|
||||
} else {
|
||||
console.log(`[EnergyLabel] PDF 변환 완료, 팝업 표시`);
|
||||
dispatch(setShowPopup(Config.ACTIVE_POPUP.energyPopup));
|
||||
setTimeout(() => {
|
||||
Spotlight.focus(SpotlightIds.TPOPUP);
|
||||
}, 250);
|
||||
}
|
||||
},
|
||||
5, // 최대 5회 재시도
|
||||
60000 // 60초 타임아웃
|
||||
)
|
||||
);
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{productType && productInfo && (
|
||||
@@ -91,8 +193,125 @@ export default function ProductPriceDisplay({ productType, productInfo }) {
|
||||
isDiscounted={isDiscounted}
|
||||
/>
|
||||
)}
|
||||
<div className={css.enrgLbImgBox}>
|
||||
{euEnrgLblInfos && euEnrgLblInfos.map((item, index)=>{
|
||||
return(
|
||||
<SpottableComponent
|
||||
key={index}
|
||||
spotlightDisabled={Boolean(!cursorVisible)}
|
||||
onClick={(e) => onEnergyClick(e, item.enrgLblUrl)}
|
||||
aria-label={`Energy Efficiency ${item.enrgGrade || ""}`}
|
||||
className={css.enrgLbImg}
|
||||
>
|
||||
<CustomImage
|
||||
alt={`Energy Label ${item.enrgGrade || index + 1}`}
|
||||
delay={0}
|
||||
src={item.enrgLblIcnUrl}
|
||||
/>
|
||||
</SpottableComponent>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{(() => {
|
||||
// 팝업이 표시되어야 하는 조건 검증
|
||||
const isEnergyPopup = activePopup === Config.ACTIVE_POPUP.energyPopup;
|
||||
const hasPdfUrl = !!currentPdfUrl;
|
||||
const shouldShowPopup = isEnergyPopup && hasPdfUrl;
|
||||
|
||||
if (!shouldShowPopup) {
|
||||
// console.log('[EnergyLabel] Popup not showing:', {
|
||||
// isEnergyPopup,
|
||||
// hasPdfUrl,
|
||||
// popupVisible,
|
||||
// });
|
||||
return null;
|
||||
}
|
||||
|
||||
// console.log('[EnergyLabel] Rendering popup:', {
|
||||
// popupVisible,
|
||||
// activePopup,
|
||||
// currentPdfUrl,
|
||||
// isConverting: convert?.isConverting,
|
||||
// hasImage: !!convert?.convertedImage,
|
||||
// hasError: !!convert?.error,
|
||||
// });
|
||||
|
||||
return (
|
||||
<TPopUp
|
||||
kind="energyPopup"
|
||||
title={$L("Energy Efficiency")}
|
||||
hasText
|
||||
open={popupVisible}
|
||||
hasButton
|
||||
button1Text={$L("CLOSE")}
|
||||
onClose={handleClosePopup}
|
||||
>
|
||||
<div className={css.energyPopupContent}>
|
||||
{convert ? (
|
||||
<>
|
||||
<div className={css.energyImagesContainer}>
|
||||
{convert.convertedImage ? (
|
||||
<img
|
||||
alt="Energy Label"
|
||||
src={convert.convertedImage}
|
||||
className={css.energyImage}
|
||||
/>
|
||||
) : convert.error ? (
|
||||
<div>
|
||||
<p>{$L(STRING_CONF.ENERGY_ERROR)}</p>
|
||||
<p style={{ fontSize: "0.8em", marginTop: "10px" }}>
|
||||
{convert.error?.message || String(convert.error)}
|
||||
</p>
|
||||
</div>
|
||||
) : convert.isConverting ? (
|
||||
<div>
|
||||
<p>{$L(STRING_CONF.ENERGY_LOADING)}</p>
|
||||
<p
|
||||
style={{
|
||||
fontSize: "0.8em",
|
||||
marginTop: "10px",
|
||||
color: "#999",
|
||||
}}
|
||||
>
|
||||
Converting PDF to image... (attempt in progress)
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<p>{$L(STRING_CONF.ENERGY_ERROR)}</p>
|
||||
<p
|
||||
style={{
|
||||
fontSize: "0.8em",
|
||||
marginTop: "10px",
|
||||
color: "#999",
|
||||
}}
|
||||
>
|
||||
Unknown state - no image or error
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div>
|
||||
<p>{$L(STRING_CONF.ENERGY_ERROR)}</p>
|
||||
<p
|
||||
style={{
|
||||
fontSize: "0.8em",
|
||||
marginTop: "10px",
|
||||
color: "#999",
|
||||
}}
|
||||
>
|
||||
Convert reducer state not found
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</TPopUp>
|
||||
);
|
||||
})()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -99,3 +99,90 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.enrgLbImgBox {
|
||||
display:flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
.enrgLbImg {
|
||||
width:62px;
|
||||
height:38px;
|
||||
border:4px solid transparent;
|
||||
&:focus {
|
||||
border: 4px solid @PRIMARY_COLOR_RED;
|
||||
box-shadow: 0 0 22px 0 rgba(0, 0, 0, 0.5);
|
||||
border-radius: 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
> img {
|
||||
width:100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popupContainer {
|
||||
.header {
|
||||
.size(@w: 780px , @h: 102px);
|
||||
.flex(@display: flex, @justifyCenter: center, @alignCenter: center, @direction: row);
|
||||
background-color: #e7ebef;
|
||||
|
||||
> h3 {
|
||||
font-size: 36px;
|
||||
color: #222222;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.qrcodeContainer {
|
||||
padding: 30px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.qrcode {
|
||||
.size(@w: 360px , @h: 360px);
|
||||
background-color: #ffffff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 0 0 1px #dadada inset;
|
||||
margin-bottom: 41px;
|
||||
}
|
||||
|
||||
> h3 {
|
||||
display: flex;
|
||||
text-align: center;
|
||||
word-break: break-word;
|
||||
line-height: 1.27;
|
||||
}
|
||||
|
||||
.popupBtn {
|
||||
.size(@w: 300px , @h: 78px);
|
||||
margin-top: 38px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 🔽 에너지 라벨 팝업 스타일 (1920x1080 TV 화면 기준)
|
||||
.energyPopupContent {
|
||||
width: 100%;
|
||||
max-height: 800px; // 팝업 타이틀/버튼 영역 제외한 콘텐츠 최대 높이
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.energyImagesContainer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.energyImage {
|
||||
max-width: 100%;
|
||||
max-height: 750px; // 1080px - 타이틀(~120px) - 버튼(~120px) - 여백(~90px)
|
||||
width: auto;
|
||||
height: auto;
|
||||
object-fit: contain; // 비율 유지하면서 컨테이너에 맞춤
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ import { useDispatch } from 'react-redux';
|
||||
|
||||
import Spotlight from '@enact/spotlight';
|
||||
|
||||
import { pushPanel, updatePanel } from '../../../actions/panelActions';
|
||||
import {
|
||||
pushPanel,
|
||||
updatePanel,
|
||||
} from '../../../actions/panelActions';
|
||||
import { navigateToDetailPanel } from '../../../actions/panelNavigationActions';
|
||||
import TItemCardNew from '../../../components/TItemCard/TItemCard.new';
|
||||
import TScroller from '../../../components/TScroller/TScroller';
|
||||
@@ -62,7 +65,7 @@ const ItemCard = ({ onClick, itemInfo, searchQuery }) => {
|
||||
<>
|
||||
<TScroller className={css.container} spotlightId={SpotlightIds.SEARCH_ITEM}>
|
||||
{itemInfo.map((item, index) => {
|
||||
const { thumbnail, title, dcPrice, price, soldout, contentId } = item;
|
||||
const { thumbnail, title, dcPrice, price, soldout, contentId,euEnrgLblInfos } = item;
|
||||
const tokens = contentId && contentId.split('_');
|
||||
const patnrId = tokens?.[4] || '';
|
||||
const prdtId = tokens?.[5] || '';
|
||||
@@ -83,6 +86,7 @@ const ItemCard = ({ onClick, itemInfo, searchQuery }) => {
|
||||
{...(index === 0 ? { 'data-spotlight-up': 'searchtabContainer' } : {})}
|
||||
label={index * 1 + 1 + ' of ' + itemInfo.length + 1}
|
||||
lastLabel=" go to detail, button"
|
||||
euEnrgLblInfos={euEnrgLblInfos}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user