[251210] feat: FeaturedBrandsPanel-TopBannerImage Popup
🕐 커밋 시간: 2025. 12. 10. 16:33:37 📊 변경 통계: • 총 파일: 6개 • 추가: +69줄 • 삭제: -5줄 📁 추가된 파일: + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerPopup.figma.jsx + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerPopup.jsx + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerPopup.module.less 📝 수정된 파일: ~ com.twin.app.shoptime/src/components/GlobalPopup/GlobalPopup.jsx ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/Banner/Banner.jsx ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerImage.jsx 🔧 주요 변경 내용: • UI 컴포넌트 아키텍처 개선 • 소규모 기능 개선 • 모듈 구조 개선
This commit is contained in:
@@ -18,6 +18,7 @@ import { setHidePopup } from '../../actions/commonActions';
|
||||
import { getPopupConfig } from '../../constants/popupConfig';
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
import TPopUp from '../TPopUp/TPopUp';
|
||||
import TopBannerPopup from '../../views/FeaturedBrandsPanel/TopBannerImage/TopBannerPopup';
|
||||
|
||||
// 커스텀 훅: 팝업 상태 관리
|
||||
const useGlobalPopupState = () => {
|
||||
@@ -128,9 +129,16 @@ const GlobalPopup = () => {
|
||||
secondaryData
|
||||
} = useGlobalPopupState();
|
||||
|
||||
const [imageDimensions, setImageDimensions] = React.useState({ width: 0, height: 0 });
|
||||
|
||||
const handlers = usePopupCloseHandlers();
|
||||
const previousPopupVisible = usePrevious(popupVisible);
|
||||
|
||||
const handleImageLoad = useCallback((dimensions) => {
|
||||
console.log("[GLOBAL-POPUP] Image dimensions received:", dimensions);
|
||||
setImageDimensions(dimensions);
|
||||
}, []);
|
||||
|
||||
// 현재 팝업 설정
|
||||
const currentConfig = useMemo(() => {
|
||||
if (!activePopup) return null;
|
||||
@@ -214,6 +222,47 @@ const GlobalPopup = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TopBannerImagePopup 특수 처리
|
||||
if (activePopup === 'topBannerImagePopup') {
|
||||
// Figma 디자인 기반 고정 크기
|
||||
// 너비: 1060px
|
||||
// 높이: 헤더(110px) + 이미지(556px) + 푸터(138px) = 804px
|
||||
const popupWidth = '1060px';
|
||||
const popupHeight = '804px';
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
zIndex: 9999
|
||||
}}>
|
||||
<div style={{
|
||||
width: popupWidth,
|
||||
height: popupHeight,
|
||||
backgroundColor: 'white',
|
||||
borderRadius: '12px',
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
}}>
|
||||
<TopBannerPopup
|
||||
title={popupData?.pupBanrImgNm || 'Popup'}
|
||||
imageUrl={popupData?.pupBanrImgUrl}
|
||||
imageAlt={popupData?.pupBanrImgNm || 'Popup Banner'}
|
||||
onImageLoad={handleImageLoad}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 설정이 없으면 기본 팝업도 렌더링하지 않음
|
||||
if (!currentConfig) {
|
||||
console.warn(`No configuration found for popup type: ${activePopup}`);
|
||||
|
||||
@@ -26,11 +26,12 @@ export default memo(function Banner({
|
||||
console.log("[FB-BANNER-COMP] isNBCU:", isNBCU);
|
||||
console.log("[FB-BANNER-COMP] brandTopBannerInfo:", brandTopBannerInfo);
|
||||
|
||||
// Top Banner 정보에서 필요한 필드 추출 (현재는 사용하지 않음)
|
||||
// Top Banner 정보에서 필요한 필드 추출
|
||||
const {
|
||||
banrImgUrl, // 배너 이미지 URL
|
||||
banrImgNm, // 배너 이미지 이름
|
||||
pupBanrImgUrl, // 팝업 배너 이미지 URL
|
||||
pupBanrImgNm, // 팝업 배너 이미지 이름
|
||||
pupBanrTtl, // 팝업 배너 타이틀
|
||||
banrNm // 배너 이름
|
||||
} = brandTopBannerInfo || {};
|
||||
@@ -76,6 +77,8 @@ export default memo(function Banner({
|
||||
banrImgUrl={banrImgUrl}
|
||||
banrImgNm={banrImgNm}
|
||||
banrNm={banrNm}
|
||||
pupBanrImgUrl={pupBanrImgUrl}
|
||||
pupBanrImgNm={pupBanrImgNm}
|
||||
spotlightId="nbcu-top-banner-image"
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import React, { memo, useCallback, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { setShowPopup } from "../../../actions/commonActions";
|
||||
import CustomImage from "../../../components/CustomImage/CustomImage";
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
import css from "./TopBannerImage.module.less";
|
||||
@@ -8,16 +10,26 @@ const Container = SpotlightContainerDecorator(
|
||||
"div"
|
||||
);
|
||||
|
||||
const TopBannerImage = memo(({ banrImgUrl, banrImgNm, banrNm, spotlightId }) => {
|
||||
const TopBannerImage = memo(({ banrImgUrl, banrImgNm, banrNm, pupBanrImgUrl, pupBanrImgNm, spotlightId }) => {
|
||||
console.log("[TOP-BANNER-IMG] Rendering with URL:", banrImgUrl);
|
||||
console.log("[TOP-BANNER-IMG] spotlightId:", spotlightId);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [imageDimensions, setImageDimensions] = useState({ width: 0, height: 0 });
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
console.log("[TOP-BANNER-IMG] Clicked");
|
||||
// 필요시 클릭 핸들러 로직 추가
|
||||
}, []);
|
||||
console.log("[TOP-BANNER-IMG] Clicked - Opening popup");
|
||||
if (pupBanrImgUrl) {
|
||||
console.log("[TOP-BANNER-IMG] Dispatching topBannerImagePopup");
|
||||
dispatch(setShowPopup({
|
||||
activePopup: 'topBannerImagePopup',
|
||||
data: {
|
||||
pupBanrImgUrl,
|
||||
pupBanrImgNm: pupBanrImgNm || banrImgNm || banrNm
|
||||
}
|
||||
}));
|
||||
}
|
||||
}, [dispatch, pupBanrImgUrl, pupBanrImgNm, banrImgNm, banrNm]);
|
||||
|
||||
const handleImageLoad = useCallback((e) => {
|
||||
const img = e.target;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<div style={{width: '100%', height: '100%', background: 'white', overflow: 'hidden', borderRadius: 12, flexDirection: 'column', justifyContent: 'center', alignItems: 'center', display: 'inline-flex'}}>
|
||||
<div style={{alignSelf: 'stretch', height: 119, padding: 30, background: '#E7EBEF', justifyContent: 'flex-start', alignItems: 'center', gap: 15, display: 'inline-flex'}}>
|
||||
<div style={{textAlign: 'center', color: 'black', fontSize: 42, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 42, wordWrap: 'break-word'}}>Wells Fargo Active Cash Credit Card</div>
|
||||
</div>
|
||||
<div style={{alignSelf: 'stretch', justifyContent: 'center', alignItems: 'center', display: 'inline-flex'}}>
|
||||
<img style={{flex: '1 1 0', height: 555.51}} src="https://placehold.co/1060x556" />
|
||||
</div>
|
||||
<div style={{alignSelf: 'stretch', paddingLeft: 60, paddingRight: 60, paddingTop: 30, paddingBottom: 30, justifyContent: 'center', alignItems: 'center', gap: 10, display: 'inline-flex'}}>
|
||||
<div style={{width: 300, height: 78, background: '#7A808D', borderRadius: 12, justifyContent: 'center', alignItems: 'center', gap: 10, display: 'flex'}}>
|
||||
<div style={{textAlign: 'center', color: 'white', fontSize: 30, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 30, wordWrap: 'break-word'}}>CLOSE</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,61 @@
|
||||
import React, { memo, useCallback, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { setHidePopup } from "../../../actions/commonActions";
|
||||
import css from "./TopBannerPopup.module.less";
|
||||
|
||||
const TopBannerPopup = memo(({ title, imageUrl, imageAlt, onImageLoad }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [imageDimensions, setImageDimensions] = useState({ width: 0, height: 0 });
|
||||
|
||||
const handleImageLoad = useCallback((e) => {
|
||||
const img = e.target;
|
||||
console.log("[TOP-BANNER-POPUP] Image loaded - dimensions:", img.naturalWidth, "x", img.naturalHeight);
|
||||
|
||||
const dimensions = {
|
||||
width: img.naturalWidth,
|
||||
height: img.naturalHeight
|
||||
};
|
||||
|
||||
setImageDimensions(dimensions);
|
||||
|
||||
// 부모 컴포넌트에 크기 전달
|
||||
if (onImageLoad) {
|
||||
onImageLoad(dimensions);
|
||||
}
|
||||
}, [onImageLoad]);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
console.log("[TOP-BANNER-POPUP] Closing popup");
|
||||
dispatch(setHidePopup());
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<div className={css.container}>
|
||||
{/* Title Section */}
|
||||
<div className={css.titleSection}>
|
||||
<div className={css.titleText}>{title}</div>
|
||||
</div>
|
||||
|
||||
{/* Image Section */}
|
||||
<div className={css.imageSection}>
|
||||
<img
|
||||
src={imageUrl}
|
||||
alt={imageAlt || "Popup Banner"}
|
||||
className={css.popupImage}
|
||||
onLoad={handleImageLoad}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Button Section */}
|
||||
<div className={css.buttonSection}>
|
||||
<button className={css.closeButton} onClick={handleClose} aria-label="Close popup">
|
||||
CLOSE
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
TopBannerPopup.displayName = "TopBannerPopup";
|
||||
|
||||
export default TopBannerPopup;
|
||||
@@ -0,0 +1,100 @@
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: white;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
// 헤더: 높이 110px (상단 마진 30 + 내용 50 + 하단 마진 30)
|
||||
.titleSection {
|
||||
flex: 0 0 110px;
|
||||
background: #E7EBEF;
|
||||
padding-top: 30px;
|
||||
padding-bottom: 30px;
|
||||
padding-left: 30px;
|
||||
padding-right: 30px;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.titleText {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
color: black;
|
||||
font-size: 42px;
|
||||
font-family: 'LG Smart UI', sans-serif;
|
||||
font-weight: 700;
|
||||
line-height: 42px;
|
||||
word-wrap: break-word;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
// 이미지: 높이 556px
|
||||
.imageSection {
|
||||
flex: 0 0 556px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
background: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.popupImage {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
// 푸터: 높이 138px (상단 마진 30 + 버튼 78 + 하단 마진 30)
|
||||
.buttonSection {
|
||||
flex: 0 0 138px;
|
||||
padding-left: 60px;
|
||||
padding-right: 60px;
|
||||
padding-top: 30px;
|
||||
padding-bottom: 30px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.closeButton {
|
||||
width: 300px;
|
||||
height: 78px;
|
||||
background: #7A808D;
|
||||
border-radius: 12px;
|
||||
border: none;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
|
||||
color: white;
|
||||
font-size: 30px;
|
||||
font-family: 'LG Smart UI', sans-serif;
|
||||
font-weight: 700;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
background: #6a7278;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: 2px solid #fff;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: #5a6268;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user