diff --git a/com.twin.app.shoptime/src/components/GlobalPopup/GlobalPopup.jsx b/com.twin.app.shoptime/src/components/GlobalPopup/GlobalPopup.jsx index e9627f02..96dc3849 100644 --- a/com.twin.app.shoptime/src/components/GlobalPopup/GlobalPopup.jsx +++ b/com.twin.app.shoptime/src/components/GlobalPopup/GlobalPopup.jsx @@ -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 ( +
+
+ +
+
+ ); + } + // 설정이 없으면 기본 팝업도 렌더링하지 않음 if (!currentConfig) { console.warn(`No configuration found for popup type: ${activePopup}`); diff --git a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/Banner/Banner.jsx b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/Banner/Banner.jsx index 66f5bc42..dfe9f9aa 100644 --- a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/Banner/Banner.jsx +++ b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/Banner/Banner.jsx @@ -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" /> )} diff --git a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerImage.jsx b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerImage.jsx index 742f4b52..af115f70 100644 --- a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerImage.jsx +++ b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerImage.jsx @@ -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; diff --git a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerPopup.figma.jsx b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerPopup.figma.jsx new file mode 100644 index 00000000..f3f203eb --- /dev/null +++ b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerPopup.figma.jsx @@ -0,0 +1,13 @@ +
+
+
Wells Fargo Active Cash Credit Card
+
+
+ +
+
+
+
CLOSE
+
+
+
\ No newline at end of file diff --git a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerPopup.jsx b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerPopup.jsx new file mode 100644 index 00000000..ac228719 --- /dev/null +++ b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerPopup.jsx @@ -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 ( +
+ {/* Title Section */} +
+
{title}
+
+ + {/* Image Section */} +
+ {imageAlt +
+ + {/* Button Section */} +
+ +
+
+ ); +}); + +TopBannerPopup.displayName = "TopBannerPopup"; + +export default TopBannerPopup; diff --git a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerPopup.module.less b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerPopup.module.less new file mode 100644 index 00000000..bc108b95 --- /dev/null +++ b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/TopBannerImage/TopBannerPopup.module.less @@ -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; + } +}