[상품 상세] panelInfo?.patnrId 내려오는 부분 수정

- string 으로 내려와서 number로 넣어둔부분은 제거.
This commit is contained in:
junghoon86.park
2025-12-15 17:01:27 +09:00
parent 802484debd
commit 486fb5efd5

View File

@@ -9,30 +9,21 @@ import 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';
import couponImg from '../../../../assets/images/icons/coupon.png';
import arrowDownIcon from '../../../../assets/images/icons/ic-arrow-down.svg';
// import Spottable from '@enact/spotlight/Spottable';
//image
import arrowDown
from '../../../../assets/images/icons/ic_arrow_down_3x_new.png';
import indicatorDefaultImage
from '../../../../assets/images/img-thumb-empty-144@3x.png';
import {
setHidePopup,
setShowPopup,
} from '../../../actions/commonActions.js';
import arrowDown from '../../../../assets/images/icons/ic_arrow_down_3x_new.png';
import indicatorDefaultImage from '../../../../assets/images/img-thumb-empty-144@3x.png';
import { setHidePopup, setShowPopup } from '../../../actions/commonActions.js';
import {
getProductCouponDownload,
getProductCouponSearch,
@@ -62,8 +53,7 @@ import CustomImage from '../../../components/CustomImage/CustomImage.jsx';
// ProductInfoSection imports
import TButton, { TYPES } from '../../../components/TButton/TButton';
import TPopUp from '../../../components/TPopUp/TPopUp.jsx';
import TVirtualGridList
from '../../../components/TVirtualGridList/TVirtualGridList.jsx';
import TVirtualGridList from '../../../components/TVirtualGridList/TVirtualGridList.jsx';
import useReviews from '../../../hooks/useReviews/useReviews';
import useScrollTo from '../../../hooks/useScrollTo';
import { BUYNOW_CONFIG } from '../../../utils/BuyNowConfig';
@@ -89,10 +79,7 @@ import {
tap,
when,
} from '../../../utils/fp';
import {
$L,
formatGMTString,
} from '../../../utils/helperMethods';
import { $L, formatGMTString } from '../../../utils/helperMethods';
import { SpotlightIds } from '../../../utils/SpotlightIds';
import ShowUserReviews from '../../UserReview/ShowUserReviews';
// import CustomScrollbar from '../components/CustomScrollbar/CustomScrollbar';
@@ -103,21 +90,14 @@ import StarRating from '../components/StarRating';
// ProductContentSection imports
import TScrollerDetail from '../components/TScroller/TScrollerDetail';
import DetailPanelSkeleton from '../DetailPanelSkeleton/DetailPanelSkeleton';
import ProductDescription
from '../ProductContentSection/ProductDescription/ProductDescription';
import ProductDetail
from '../ProductContentSection/ProductDetail/ProductDetail.new';
import {
ProductVideoV2,
} from '../ProductContentSection/ProductVideo/ProductVideo.v2.jsx';
import ProductVideo
from '../ProductContentSection/ProductVideo/ProductVideo.v3';
import SeeMoreProducts
from '../ProductContentSection/SeeMoreProducts/SeeMoreProducts';
import ProductDescription from '../ProductContentSection/ProductDescription/ProductDescription';
import ProductDetail from '../ProductContentSection/ProductDetail/ProductDetail.new';
import { ProductVideoV2 } from '../ProductContentSection/ProductVideo/ProductVideo.v2.jsx';
import ProductVideo from '../ProductContentSection/ProductVideo/ProductVideo.v3';
import SeeMoreProducts from '../ProductContentSection/SeeMoreProducts/SeeMoreProducts';
import UserReviews from '../ProductContentSection/UserReviews/UserReviews';
// import ViewAllReviewsButton from '../ProductContentSection/UserReviews/ViewAllReviewsButton';
import YouMayAlsoLike
from '../ProductContentSection/YouMayAlsoLike/YouMayAlsoLike';
import YouMayAlsoLike from '../ProductContentSection/YouMayAlsoLike/YouMayAlsoLike';
import QRCode from '../ProductInfoSection/QRCode/QRCode';
import ProductOverview from '../ProductOverview/ProductOverview';
// CSS imports
@@ -166,7 +146,8 @@ const ShopByMobileContainer = SpotlightContainerDecorator(
spotlightDirection: 'horizontal',
enterTo: 'last-focused',
restrict: 'self-only',
defaultElement: SpotlightIds?.DETAIL_SHOPBYMOBILE || 'detail_shop_by_mobile',
defaultElement:
SpotlightIds?.DETAIL_SHOPBYMOBILE || 'detail_shop_by_mobile',
},
'div'
);
@@ -258,17 +239,27 @@ 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);
const nowMenu = useSelector((state) => state.common.menu.nowMenu);
// YouMayLike 데이터는 API 응답 시간이 걸리므로 직접 구독
const youmaylikeData = useSelector((state) => state.main.youmaylikeData);
//coupon
const { partnerCoupon } = useSelector((state) => state.coupon.productCouponSearchData);
const { userNumber } = useSelector((state) => state.common.appStatus.loginUserData);
const { popupVisible, activePopup } = useSelector((state) => state.common.popup);
const cursorVisible = useSelector((state) => state.common.appStatus.cursorVisible);
const { partnerCoupon } = useSelector(
(state) => state.coupon.productCouponSearchData
);
const { userNumber } = useSelector(
(state) => state.common.appStatus.loginUserData
);
const { popupVisible, activePopup } = useSelector(
(state) => state.common.popup
);
const cursorVisible = useSelector(
(state) => state.common.appStatus.cursorVisible
);
// 🆕 [251210] patnrId=21 카테고리 그룹 데이터
const brandShopByShowCategoryGroups = useSelector(
(state) => state.brand.brandShopByShowCategoryGroups
@@ -293,12 +284,15 @@ export default function ProductAllSection({
// 출처 정보 통합 (향후 확장성 대비)
// YouMayLike 상품이 아닐 경우 fromPanel을 초기화하여 오기 방지
const fromPanel = useMemo(() => ({
const fromPanel = useMemo(
() => ({
fromYouMayLike: panelInfo?.fromPanel?.fromYouMayLike || false,
// 향후 다른 출처 플래그들 추가 가능
// fromRecommendation: panelInfo?.fromPanel?.fromRecommendation || false,
// fromSearch: panelInfo?.fromPanel?.fromSearch || false,
}), [panelInfo?.fromPanel?.fromYouMayLike]);
}),
[panelInfo?.fromPanel?.fromYouMayLike]
);
//구매 하단 토스트 노출 확인을 위한 용도
const [openToast, setOpenToast] = useState(false);
@@ -332,16 +326,13 @@ export default function ProductAllSection({
scrollTop({ y: 0, animate: true });
setTimeout(() => {
if (hasVideo) {
Spotlight.focus("product-video-player");
Spotlight.focus('product-video-player');
} else {
Spotlight.focus("product-detail-container-0");
Spotlight.focus('product-detail-container-0');
}
}, 100);
}
}, [
scrollTop,
hasVideo
]);
}, [scrollTop, hasVideo]);
const fetchCouponData = useCallback(() => {
dispatch(
@@ -403,7 +394,9 @@ export default function ProductAllSection({
const handleCouponTotDownload = useCallback(() => {
if (selectedCoupon && userNumber) {
const couponCodesArray = couponCodes.split(',').map((code) => parseInt(code.trim()));
const couponCodesArray = couponCodes
.split(',')
.map((code) => parseInt(code.trim()));
setDownloadCouponArr((prevArr) => [...prevArr, ...couponCodesArray]);
dispatch(
@@ -474,7 +467,9 @@ export default function ProductAllSection({
return;
}
setDownloadCouponArr((prevArr) => [...prevArr, cpnSno]);
dispatch(getProductCouponDownload({ mbrNo: userNumber, cpnSno: cpnSno }));
dispatch(
getProductCouponDownload({ mbrNo: userNumber, cpnSno: cpnSno })
);
dispatch(showToast({ message: 'Your coupon download is complete.' }));
};
@@ -489,7 +484,13 @@ export default function ProductAllSection({
>
<div
className={css.couponItem}
aria-label={'Purchase over ' + cpnAplyMinPurcAmt + 'up to ' + cpnAplyMaxDcAmt + ' off'}
aria-label={
'Purchase over ' +
cpnAplyMinPurcAmt +
'up to ' +
cpnAplyMaxDcAmt +
' off'
}
>
<div className={css.couponTopContents}>
{shptmDcTpCd === 'CPN00401' && (
@@ -505,7 +506,9 @@ export default function ProductAllSection({
<div className={css.couponMiddleContents}>
<span>
{$L('Purchase over ${cpnAplyMinPurcAmt} (up to ${cpnAplyMaxDcAmt} off)')
{$L(
'Purchase over ${cpnAplyMinPurcAmt} (up to ${cpnAplyMaxDcAmt} off)'
)
.replace('{cpnAplyMinPurcAmt}', cpnAplyMinPurcAmt)
.replace('{cpnAplyMaxDcAmt}', cpnAplyMaxDcAmt)}
</span>
@@ -518,7 +521,9 @@ export default function ProductAllSection({
<div
className={classNames(
css.couponBottomButton,
downloadCouponArr.length > 0 && downloadCouponArr.includes(cpnSno) && css.disable,
downloadCouponArr.length > 0 &&
downloadCouponArr.includes(cpnSno) &&
css.disable,
duplDwldYn === 'N' && downloadYn === 'Y' && css.disable,
!downloadCouponArr.includes(cpnSno) &&
index === selectedCouponIndex &&
@@ -527,7 +532,9 @@ export default function ProductAllSection({
)}
aria-label="Download Button"
>
{downloadCouponArr.length > 0 && downloadCouponArr.includes(cpnSno) && duplDwldYn === 'N'
{downloadCouponArr.length > 0 &&
downloadCouponArr.includes(cpnSno) &&
duplDwldYn === 'N'
? $L('DOWNLOAD COMPLETED')
: $L('DOWNLOAD')}
</div>
@@ -566,13 +573,20 @@ export default function ProductAllSection({
const [activeButton, setActiveButton] = useState(null);
const productData = useMemo(
() => getProductData(productType, themeProductInfo, themeProducts, selectedIndex, productInfo),
() =>
getProductData(
productType,
themeProductInfo,
themeProducts,
selectedIndex,
productInfo
),
[productType, themeProductInfo, themeProducts, selectedIndex, productInfo]
);
// 🆕 [251211] patnrId=21인 경우 QR 데이터 확인
useEffect(() => {
if (productData?.patnrId === 21 || productData?.patnrId === "21") {
if (productData?.patnrId === 21 || productData?.patnrId === '21') {
console.log('[QR-Data] patnrId=21 QR 데이터 확인:', {
patnrId: productData?.patnrId,
prdtId: productData?.prdtId,
@@ -629,7 +643,9 @@ export default function ProductAllSection({
if (webOSVersion < '6.0') {
return (
productData?.pmtSuptYn === 'N' ||
(productData?.pmtSuptYn === 'Y' && productData?.grPrdtProcYn === 'N' && panelInfo?.prdtId)
(productData?.pmtSuptYn === 'Y' &&
productData?.grPrdtProcYn === 'N' &&
panelInfo?.prdtId)
);
}
@@ -650,7 +666,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 사용 - 모든 리뷰 관련 로직을 담당
@@ -722,13 +741,13 @@ export default function ProductAllSection({
if (productData && Object.keys(productData).length > 0) {
// sendLogDetail - 제품 상세 버튼 클릭 로깅 (Source와 동일)
const detailLogParams = {
curationId: productData?.curationId ?? "",
curationNm: productData?.curationNm ?? "",
inDt: "",
linkTpCd: panelInfo?.linkTpCd ?? "",
curationId: productData?.curationId ?? '',
curationNm: productData?.curationNm ?? '',
inDt: '',
linkTpCd: panelInfo?.linkTpCd ?? '',
logTpNo: LOG_TP_NO.DETAIL.DETAIL_BUTTON_CLICK,
patncNm: productData?.patncNm ?? "",
patnrId: productData?.patnrId ?? "",
patncNm: productData?.patncNm ?? '',
patnrId: productData?.patnrId ?? '',
};
dispatch(sendLogDetail(detailLogParams));
@@ -745,14 +764,22 @@ export default function ProductAllSection({
menuType = Config.LOG_MENU.DETAIL_PAGE_PRODUCT_DETAIL;
}
dispatch(sendLogTotalRecommend({
dispatch(
sendLogTotalRecommend({
menu: menuType,
buttonTitle: "DESCRIPTION",
buttonTitle: 'DESCRIPTION',
contextName: LOG_CONTEXT_NAME.DETAILPAGE,
messageId: LOG_MESSAGE_ID.BUTTONCLICK,
}));
})
);
}
}, [productData, panelInfo, isBillingProductVisible, isGroupProductVisible, isTravelProductVisible]);
}, [
productData,
panelInfo,
isBillingProductVisible,
isGroupProductVisible,
isTravelProductVisible,
]);
// sendLogGNB 로깅 - Source의 DetailPanel 컴포넌트들과 동일한 패턴
useEffect(() => {
@@ -774,7 +801,9 @@ export default function ProductAllSection({
}
// YouMayLike에서 상품 선택 시 메뉴 변경 (Source의 isYouMayLikeOpened와 동일 패턴)
const menu = (fromPanel?.fromYouMayLike !== undefined && fromPanel?.fromYouMayLike === true)
const menu =
fromPanel?.fromYouMayLike !== undefined &&
fromPanel?.fromYouMayLike === true
? `${baseMenu}/${Config.LOG_MENU.DETAIL_PAGE_YOU_MAY_LIKE}`
: baseMenu;
@@ -798,15 +827,17 @@ export default function ProductAllSection({
// sendLogGNB 전송 후 플래그 초기화 (1회 사용 후 비활성화)
useEffect(() => {
if (fromPanel?.fromYouMayLike === true) {
dispatch(updatePanel({
dispatch(
updatePanel({
name: panel_names.DETAIL_PANEL,
panelInfo: {
...panelInfo,
fromPanel: {
fromYouMayLike: false // 플래그 초기화
}
}
}));
fromYouMayLike: false, // 플래그 초기화
},
},
})
);
}
}, [fromPanel?.fromYouMayLike, dispatch, panelInfo]);
@@ -831,24 +862,24 @@ export default function ProductAllSection({
lastProductDetailLogKeyRef.current = logKey;
const params = {
befPrice: productData?.priceInfo?.split("|")[0],
curationId: productData?.curationId ?? "",
curationNm: productData?.curationNm ?? "",
befPrice: productData?.priceInfo?.split('|')[0],
curationId: productData?.curationId ?? '',
curationNm: productData?.curationNm ?? '',
entryMenu: entryMenuRef.current,
expsOrd: "1",
expsOrd: '1',
inDt: formatGMTString(new Date()),
lastPrice: productData?.priceInfo?.split("|")[1],
lgCatCd: productData?.catCd ?? "",
lgCatNm: productData?.catNm ?? "",
linkTpCd: panelInfo?.linkTpCd ?? "",
lastPrice: productData?.priceInfo?.split('|')[1],
lgCatCd: productData?.catCd ?? '',
lgCatNm: productData?.catNm ?? '',
linkTpCd: panelInfo?.linkTpCd ?? '',
logTpNo,
patncNm: productData?.patncNm ?? "",
patnrId: productData?.patnrId ?? "",
prdtId: productData?.prdtId ?? "",
prdtNm: productData?.prdtNm ?? "",
revwGrd: productData?.revwGrd ?? "",
rewdAplyFlag: productData.priceInfo?.split("|")[2],
tsvFlag: productData?.todaySpclFlag ?? "",
patncNm: productData?.patncNm ?? '',
patnrId: productData?.patnrId ?? '',
prdtId: productData?.prdtId ?? '',
prdtNm: productData?.prdtNm ?? '',
revwGrd: productData?.revwGrd ?? '',
rewdAplyFlag: productData.priceInfo?.split('|')[2],
tsvFlag: productData?.todaySpclFlag ?? '',
};
dispatch(sendLogProductDetail(params));
@@ -885,13 +916,22 @@ export default function ProductAllSection({
// 🚀 SingleOption.jsx의 sendLogTotalRecommend 로직 추가
if (productData && Object.keys(productData).length > 0) {
const { priceInfo, patncNm, prdtId, prdtNm, brndNm, catNm, showId, showNm } = productData;
const regularPrice = priceInfo?.split("|")[0];
const discountPrice = priceInfo?.split("|")[1];
const discountRate = priceInfo?.split("|")[4];
const {
priceInfo,
patncNm,
prdtId,
prdtNm,
brndNm,
catNm,
showId,
showNm,
} = productData;
const regularPrice = priceInfo?.split('|')[0];
const discountPrice = priceInfo?.split('|')[1];
const discountRate = priceInfo?.split('|')[4];
// Option 정보는 현재 선택된 옵션이 없으므로 기본값 사용
const prodOptCval = ""; // 실제로는 선택된 옵션 값이 들어가야 함
const prodOptCval = ''; // 실제로는 선택된 옵션 값이 들어가야 함
dispatch(
sendLogTotalRecommend({
@@ -906,8 +946,8 @@ export default function ProductAllSection({
category: catNm,
contextName: Config.LOG_CONTEXT_NAME.DETAILPAGE,
messageId: Config.LOG_MESSAGE_ID.BUY_NOW,
showId: showId ?? "",
showNm: showNm ?? "",
showId: showId ?? '',
showNm: showNm ?? '',
})
);
}
@@ -947,23 +987,29 @@ export default function ProductAllSection({
);
//닫히도록
const handleCloseToast = useCallback((e) => {
const handleCloseToast = useCallback(
(e) => {
// 팝업이 열려있으면 닫지 않음
if (popupVisible) {
return; // 팝업이 활성이면 무시
}
dispatch(clearAllToasts());
setOpenToast(false);
}, [dispatch, popupVisible]);
},
[dispatch, popupVisible]
);
const handleFocus = useCallback((e)=>{
const handleFocus = useCallback(
(e) => {
// 팝업이 열려있으면 닫지 않음
if (popupVisible && cursorVisible) {
return; // 팝업이 활성이면 무시
}
dispatch(clearAllToasts());
setOpenToast(false);
},[dispatch, popupVisible, cursorVisible])
},
[dispatch, popupVisible, cursorVisible]
);
// 스크롤 컨테이너의 클릭 이벤트 추적용 로깅
const handleScrollContainerClick = useCallback((e) => {
@@ -1010,7 +1056,10 @@ export default function ProductAllSection({
// TODO: 장바구니 추가 로직 구현
}, []);
const { revwGrd, orderPhnNo } = useMemo(() => extractProductMeta(productInfo), [productInfo]);
const { revwGrd, orderPhnNo } = useMemo(
() => extractProductMeta(productInfo),
[productInfo]
);
const [favoriteOverride, setFavoriteOverride] = useState(null);
const favoriteFlag = useMemo(
@@ -1019,7 +1068,8 @@ export default function ProductAllSection({
);
const [mobileSendPopupOpen, setMobileSendPopupOpen] = useState(false);
const [isShowUserReviewsFocused, setIsShowUserReviewsFocused] = useState(false);
const [isShowUserReviewsFocused, setIsShowUserReviewsFocused] =
useState(false);
// 🆕 [251210] patnrId=21 SEE MORE PRODUCTS 버튼 표시 여부
const [hasSeeMoreProducts, setHasSeeMoreProducts] = useState(false);
const [seeMoreProductsData, setSeeMoreProductsData] = useState([]);
@@ -1048,8 +1098,8 @@ export default function ProductAllSection({
const handleUserReviewsClick = useCallback(() => {
scrollToSection('scroll-marker-user-reviews');
setTimeout(() => {
Spotlight.focus("user-reviews-container");
},100)
Spotlight.focus('user-reviews-container');
}, 100);
}, [scrollToSection]);
// ProductVideo V1 전용 - MediaPanel minimize 포함
@@ -1125,7 +1175,10 @@ export default function ProductAllSection({
document.addEventListener('detailpanel-scroll-reset', handleScrollReset);
return () => {
document.removeEventListener('detailpanel-scroll-reset', handleScrollReset);
document.removeEventListener(
'detailpanel-scroll-reset',
handleScrollReset
);
};
}, []);
const productDetailRef = useRef(null); //높이값 변경때문
@@ -1150,7 +1203,11 @@ 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',
@@ -1170,7 +1227,9 @@ export default function ProductAllSection({
// renderItems에 Video가 존재하는지 확인하는 boolean 상태
const hasVideo = useMemo(() => {
return (
renderItems && renderItems.length > 0 && renderItems.some((item) => item.type === 'video')
renderItems &&
renderItems.length > 0 &&
renderItems.some((item) => item.type === 'video')
);
}, [renderItems]);
@@ -1182,10 +1241,11 @@ export default function ProductAllSection({
const handleShopByMobileOpen = useCallback(() => {
// sendLogShopByMobile - Source와 동일한 로깅 추가
if (productData && Object.keys(productData).length > 0) {
const { priceInfo, patncNm, patnrId, prdtId, prdtNm, brndNm, catNm } = productData;
const regularPrice = priceInfo?.split("|")[0];
const discountPrice = priceInfo?.split("|")[1];
const discountRate = priceInfo?.split("|")[4];
const { priceInfo, patncNm, patnrId, prdtId, prdtNm, brndNm, catNm } =
productData;
const regularPrice = priceInfo?.split('|')[0];
const discountPrice = priceInfo?.split('|')[1];
const discountRate = priceInfo?.split('|')[4];
const logParams = {
prdtId,
@@ -1233,7 +1293,8 @@ export default function ProductAllSection({
}, [promotions, isBillingProductVisible, shopByMobileId, stackOrder]);
const firstCouponId = useMemo(
() => (promotions && promotions.length > 0 ? 'detail-coupon-button-0' : null),
() =>
promotions && promotions.length > 0 ? 'detail-coupon-button-0' : null,
[promotions]
);
@@ -1242,7 +1303,8 @@ export default function ProductAllSection({
[]
);
const handleThemeItemButtonClick = useCallback((e) => {
const handleThemeItemButtonClick = useCallback(
(e) => {
e.stopPropagation();
dispatch(
showToast({
@@ -1269,7 +1331,9 @@ export default function ProductAllSection({
// },
})
);
}, [dispatch, themeProducts, setSelectedIndex, panelInfo]);
},
[dispatch, themeProducts, setSelectedIndex, panelInfo]
);
const handleProductDetailsClick = useCallback(() => {
dispatch(minimizeModalMedia());
@@ -1278,7 +1342,7 @@ export default function ProductAllSection({
// Source의 handleIndicatorOptions와 동일한 로깅 기능 추가
handleIndicatorOptions();
setTimeout(() => {
Spotlight.focus("product-description-content")
Spotlight.focus('product-description-content');
}, 100);
}, [scrollToSection, dispatch, handleIndicatorOptions]);
@@ -1286,7 +1350,7 @@ export default function ProductAllSection({
dispatch(minimizeModalMedia());
scrollToSection('scroll-marker-you-may-also-like');
setTimeout(() => {
Spotlight.focus("detail_youMayAlsoLike_area")
Spotlight.focus('detail_youMayAlsoLike_area');
}, 100);
}, [scrollToSection, dispatch]);
@@ -1295,16 +1359,21 @@ export default function ProductAllSection({
// 버튼 클릭 시 스크롤만 처리 (데이터는 useEffect에서 처리)
scrollToSection('scroll-marker-see-more-products');
setTimeout(() => {
Spotlight.focus("detail_seeMoreProducts_area");
Spotlight.focus('detail_seeMoreProducts_area');
}, 100);
}, [scrollToSection]);
// 🆕 [251210] patnrId=21인 경우 그룹 상품 데이터 미리 처리
useEffect(() => {
if (panelInfo?.patnrId === 21 || panelInfo?.patnrId === "21") {
console.log('[SEE MORE PRODUCTS] patnrId=21 detected - processing group data on panel mount');
if (panelInfo?.patnrId === 21 || panelInfo?.patnrId === '21') {
console.log(
'[SEE MORE PRODUCTS] patnrId=21 detected - processing group data on panel mount'
);
console.log('[SEE MORE PRODUCTS] panelInfo:', panelInfo);
console.log('[SEE MORE PRODUCTS] brandShopByShowCategoryGroups:', brandShopByShowCategoryGroups);
console.log(
'[SEE MORE PRODUCTS] brandShopByShowCategoryGroups:',
brandShopByShowCategoryGroups
);
const patnrIdString = String(panelInfo.patnrId);
const currentPrdtId = panelInfo.prdtId;
@@ -1323,16 +1392,25 @@ export default function ProductAllSection({
// 모든 contsId에서 현재 상품이 속한 그룹 찾기
for (const contsId in categoryGroups) {
const contsInfo = categoryGroups[contsId];
console.log(`[SEE MORE PRODUCTS] Checking contsId: ${contsId}, contsNm: ${contsInfo.contsNm}`);
console.log(
`[SEE MORE PRODUCTS] Checking contsId: ${contsId}, contsNm: ${contsInfo.contsNm}`
);
if (contsInfo.brandShopByShowClctInfos) {
for (const group of contsInfo.brandShopByShowClctInfos) {
console.log(`[SEE MORE PRODUCTS] Checking group: ${group.clctNm} (${group.clctId})`);
console.log(
`[SEE MORE PRODUCTS] Checking group: ${group.clctNm} (${group.clctId})`
);
if (group.brandProductInfos) {
const foundProduct = group.brandProductInfos.find(p => p.prdtId === currentPrdtId);
const foundProduct = group.brandProductInfos.find(
(p) => p.prdtId === currentPrdtId
);
if (foundProduct) {
console.log('[SEE MORE PRODUCTS] 🎯 Found current product:', foundProduct);
console.log(
'[SEE MORE PRODUCTS] 🎯 Found current product:',
foundProduct
);
foundGroup = group;
foundConts = contsInfo;
break;
@@ -1351,22 +1429,28 @@ export default function ProductAllSection({
console.log(' - Group ID:', foundGroup.clctId);
// 현재 상품을 제외한 다른 상품들 확인
const otherProducts = foundGroup.brandProductInfos.filter(p => p.prdtId !== currentPrdtId);
const otherProducts = foundGroup.brandProductInfos.filter(
(p) => p.prdtId !== currentPrdtId
);
console.log(' - Other products count:', otherProducts.length);
if (otherProducts.length > 0) {
// 다른 상품이 있을 때만 버튼 표시
shouldShowButton = true;
console.log('[SEE MORE PRODUCTS] 📦 Showing button - group has other products:');
console.log(
'[SEE MORE PRODUCTS] 📦 Showing button - group has other products:'
);
otherProducts.forEach((product, index) => {
console.log(` ${index + 1}. ${product.prdtNm} (${product.prdtId})`);
console.log(
` ${index + 1}. ${product.prdtNm} (${product.prdtId})`
);
console.log(` - Price: ${product.priceInfo}`);
console.log(` - Brand: ${product.brndNm || 'N/A'}`);
});
// 🆕 SeeMoreProducts 컴포넌트를 위한 데이터 변환
const formattedProducts = otherProducts.map(product => ({
const formattedProducts = otherProducts.map((product) => ({
prdtId: product.prdtId,
prdtNm: product.prdtNm,
priceInfo: product.priceInfo,
@@ -1382,14 +1466,20 @@ export default function ProductAllSection({
// YouMayAlsoLike 데이터 형식으로 맞추기
setSeeMoreProductsData(formattedProducts);
} else {
console.log('[SEE MORE PRODUCTS] ❌ No other products in group - hiding button');
console.log(
'[SEE MORE PRODUCTS] ❌ No other products in group - hiding button'
);
setSeeMoreProductsData([]);
}
} else {
console.log('[SEE MORE PRODUCTS] ❌ No group found for current product - hiding button');
console.log(
'[SEE MORE PRODUCTS] ❌ No group found for current product - hiding button'
);
}
} else {
console.log('[SEE MORE PRODUCTS] ❌ No category groups found for patnrId 21 - hiding button');
console.log(
'[SEE MORE PRODUCTS] ❌ No category groups found for patnrId 21 - hiding button'
);
}
// 버튼 표시 여부 상태 설정
@@ -1417,9 +1507,7 @@ export default function ProductAllSection({
const mediaMinimizedRef = useRef(false);
const getTotalContentHeight = useCallback(() => {
const measuredHeight =
contentHeightRef.current ||
scrollContainerRef.current?.scrollHeight ||
0;
contentHeightRef.current || scrollContainerRef.current?.scrollHeight || 0;
return measuredHeight + (youMayAlsoLikelRef.current?.scrollHeight || 0);
}, []);
@@ -1452,7 +1540,8 @@ export default function ProductAllSection({
const prevScrollTop = prevScrollTopRef.current;
scrollPositionRef.current = currentScrollTop;
contentHeightRef.current = e?.scrollHeight || contentHeightRef.current || 0;
contentHeightRef.current =
e?.scrollHeight || contentHeightRef.current || 0;
// 기존 bottom 체크 로직 유지
const totalHeight = getTotalContentHeight();
@@ -1510,7 +1599,13 @@ export default function ProductAllSection({
}
// v2: onScrollStop에서 처리 (기존 로직 유지)
},
[isBottom, productVideoVersion, isVideoPlaying, dispatch, getTotalContentHeight]
[
isBottom,
productVideoVersion,
isVideoPlaying,
dispatch,
getTotalContentHeight,
]
);
// 스크롤 멈추었을 때만 호출 (성능 최적화)
@@ -1518,7 +1613,8 @@ export default function ProductAllSection({
(e) => {
const currentScrollTop = e.scrollTop;
scrollPositionRef.current = currentScrollTop;
contentHeightRef.current = e?.scrollHeight || contentHeightRef.current || 0;
contentHeightRef.current =
e?.scrollHeight || contentHeightRef.current || 0;
const totalHeight = getTotalContentHeight();
if (totalHeight) {
const isAtBottom = currentScrollTop + 944 >= totalHeight;
@@ -1583,7 +1679,9 @@ export default function ProductAllSection({
// 초기 로딩 후 Skeleton 숨기기
useEffect(() => {
const hasDataReady =
productType === 'theme' ? hasThemeContents && !!productData : !!productData;
productType === 'theme'
? hasThemeContents && !!productData
: !!productData;
if (productType && hasDataReady && isInitialLoading) {
const timer = setTimeout(() => {
@@ -1693,7 +1791,11 @@ export default function ProductAllSection({
}
return (
<HorizontalContainer className={css.detailArea} onClick={handleCloseToast} onFocus={handleFocus}>
<HorizontalContainer
className={css.detailArea}
onClick={handleCloseToast}
onFocus={handleFocus}
>
{/* Left Margin Section - 60px */}
<div className={css.leftMarginSection}></div>
@@ -1727,7 +1829,10 @@ export default function ProductAllSection({
{isShowQRCode ? (
<>
{/* <QRCode productInfo={productData} productType={productType} kind={'detail'} /> */}
<QRCode productInfo={productData} productType={productType} />
<QRCode
productInfo={productData}
productType={productType}
/>
</>
) : (
<div className={css.qrRollingWrap}>
@@ -1763,7 +1868,9 @@ export default function ProductAllSection({
return (
<div className={css.couponContainer} key={idx}>
<div className={css.couponTitleText}>
<div className={css.firstTitle}>SPECIAL PROMOTION</div>
<div className={css.firstTitle}>
SPECIAL PROMOTION
</div>
<div className={css.secondTitle}>
Coupon only applicable to this product!
</div>
@@ -1815,7 +1922,9 @@ export default function ProductAllSection({
className={css.shopByMobileButton}
onClick={handleShopByMobileOpen}
>
<div className={css.shopByMobileText}>{$L('SHOP BY MOBILE')}</div>
<div className={css.shopByMobileText}>
{$L('SHOP BY MOBILE')}
</div>
</TButton>
{panelInfo && (
<div className={css.favoriteBtnWrapper}>
@@ -1835,7 +1944,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} />
@@ -1881,7 +1992,8 @@ export default function ProductAllSection({
</TButton>
</>
)}
{(panelInfo?.patnrId !== 21 || panelInfo?.patnrId !== "21") && hasYouMayAlsoLike && (
{(panelInfo?.patnrId !== 21 || panelInfo?.patnrId !== '21') &&
hasYouMayAlsoLike && (
<TButton
className={classNames(
css.youMayLikeButton,
@@ -1893,7 +2005,8 @@ export default function ProductAllSection({
</TButton>
)}
{/* 🆕 [251210] patnrId=21인 경우 SEE MORE PRODUCTS 버튼 */}
{(panelInfo?.patnrId === 21 || panelInfo?.patnrId === "21") && hasSeeMoreProducts && (
{(panelInfo?.patnrId === 21 || panelInfo?.patnrId === '21') &&
hasSeeMoreProducts && (
<TButton
className={classNames(
css.seeMoreProductButton,
@@ -1935,7 +2048,10 @@ export default function ProductAllSection({
}}
>
<div>{$L('THEME ITEM')}</div>
<img src={arrowDownIcon} className={css.themeButtonIcon} />
<img
src={arrowDownIcon}
className={css.themeButtonIcon}
/>
</TButton>
</Container>
)}
@@ -1981,7 +2097,9 @@ export default function ProductAllSection({
onBlur={handleButtonBlur}
>
{/* 비디오가 있으면 먼저 렌더링 (productVideoVersion이 3이 아닐 때만) */}
{hasVideo && renderItems[0].type === 'video' && productVideoVersion !== 3 && (
{hasVideo &&
renderItems[0].type === 'video' &&
productVideoVersion !== 3 && (
<>
{productVideoVersion === 1 ? (
<ProductVideo
@@ -2007,7 +2125,10 @@ export default function ProductAllSection({
onScrollToImages={handleScrollToImagesV2}
/>
)}
<div id="scroll-marker-after-video" className={css.scrollMarker}></div>
<div
id="scroll-marker-after-video"
className={css.scrollMarker}
></div>
</>
)}
@@ -2028,7 +2149,10 @@ export default function ProductAllSection({
))
: !hasVideo && <ProductDetail productInfo={productData} />}
</div>
<div id="scroll-marker-product-details" className={css.scrollMarker}></div>
<div
id="scroll-marker-product-details"
className={css.scrollMarker}
></div>
<div
id="product-description-section"
ref={descriptionRef}
@@ -2038,7 +2162,10 @@ export default function ProductAllSection({
<ProductDescription productInfo={productData} />
</div>
{/* 리뷰 데이터가 완전할 때만 UserReviews 섹션 표시 */}
<div id="scroll-marker-user-reviews" className={css.scrollMarker}></div>
<div
id="scroll-marker-user-reviews"
className={css.scrollMarker}
></div>
{isReviewDataComplete && (
<div
id="user-reviews-section"
@@ -2066,8 +2193,11 @@ export default function ProductAllSection({
)}
</div>
<div ref={youMayAlsoLikelRef}>
<div id="scroll-marker-you-may-also-like" className={css.scrollMarker}></div>
{(panelInfo?.patnrId !== 21 || panelInfo?.patnrId !== "21") && hasYouMayAlsoLike && (
<div
id="scroll-marker-you-may-also-like"
className={css.scrollMarker}
></div>
{panelInfo?.patnrId !== '21' && hasYouMayAlsoLike && (
<div id="you-may-also-like-section">
{/* {(() => {
console.log('[YouMayLike] YouMayAlsoLike 컴포넌트 렌더링:', {
@@ -2090,10 +2220,16 @@ export default function ProductAllSection({
</div>
{/* 🆕 [251210] patnrId=21인 경우 SEE MORE PRODUCTS 섹션 */}
{(panelInfo?.patnrId === 21 || panelInfo?.patnrId === "21") && hasSeeMoreProducts && (
{panelInfo?.patnrId === '21' && hasSeeMoreProducts && (
<div ref={seeMoreProductsRef}>
<div id="scroll-marker-see-more-products" className={css.scrollMarker}></div>
<div id="see-more-products-section" data-spotlight-id="see-more-products-area">
<div
id="scroll-marker-see-more-products"
className={css.scrollMarker}
></div>
<div
id="see-more-products-section"
data-spotlight-id="see-more-products-area"
>
<SeeMoreProducts
groupProducts={seeMoreProductsData}
sponserImage={sponserImage}
@@ -2156,7 +2292,9 @@ export default function ProductAllSection({
/>
)}
</Container>
<div className={css.couponRemain}>{`1/${selectedCoupon?.length}`}</div>
<div
className={css.couponRemain}
>{`1/${selectedCoupon?.length}`}</div>
</TPopUp>
)}
</HorizontalContainer>