[251105] fix: BuyOption 동영상 정리 및 검색 썸네일 옵션 추가
- BuyOption 체크아웃 진입 시 동영상 및 플레이어 패널 정리 로직 추가 - 선택된 옵션 기본값 설정 로직 개선 - SearchResults 썸네일 최적화 옵션 필드 추가 Generated with coding tools Co-Authored-By: Dev Team <noreply@dev.team>
This commit is contained in:
@@ -29,12 +29,11 @@ import {
|
||||
sendLogTotalRecommend,
|
||||
} from '../../../actions/logActions';
|
||||
import { finishMediaPreview } from '../../../actions/mediaActions';
|
||||
import { addToMockCart } from '../../../actions/mockCartActions';
|
||||
import {
|
||||
popPanel,
|
||||
pushPanel,
|
||||
} from '../../../actions/panelActions';
|
||||
import { clearAllVideoTimers } from '../../../actions/playActions';
|
||||
import { clearAllVideoTimers, finishVideoPreview } from '../../../actions/playActions';
|
||||
import {
|
||||
getProductOption,
|
||||
getProductOptionId,
|
||||
@@ -163,9 +162,103 @@ const BuyOption = ({
|
||||
// Mock Mode이고 유효한 옵션 데이터가 있으면 그대로 사용
|
||||
console.log('[BuyOption] Mock Mode - using existing valid reduxProductOptionInfos');
|
||||
return reduxProductOptionInfos;
|
||||
}, [reduxProductOptionInfos, productData, isMockMode]); // logInfo 생성 (SingleOption과 동일한 로직, productData 우선 사용)
|
||||
}, [reduxProductOptionInfos, productData, productInfo, isMockMode]); // logInfo 생성 (SingleOption과 동일한 로직, productData 우선 사용)
|
||||
const hasMockOptions =
|
||||
isMockMode && Array.isArray(productOptionInfos) && productOptionInfos.length > 0;
|
||||
const cleanupVideoAndPlayerPanels = useCallback(() => {
|
||||
clearAllVideoTimers();
|
||||
|
||||
dispatch((dispatchFn, getState) => {
|
||||
const getPanels = () => getState().panels?.panels || [];
|
||||
const popIfTopMatches = (predicate, action) => {
|
||||
const panels = getPanels();
|
||||
if (!panels.length) {
|
||||
return;
|
||||
}
|
||||
const topPanel = panels[panels.length - 1];
|
||||
if (predicate(topPanel)) {
|
||||
action();
|
||||
}
|
||||
};
|
||||
|
||||
popIfTopMatches(
|
||||
(panel) =>
|
||||
panel?.name === Config.panel_names.MEDIA_PANEL &&
|
||||
panel.panelInfo?.modal,
|
||||
() => dispatchFn(finishMediaPreview())
|
||||
);
|
||||
|
||||
popIfTopMatches(
|
||||
(panel) =>
|
||||
panel &&
|
||||
(panel.name === Config.panel_names.PLAYER_PANEL ||
|
||||
panel.name === Config.panel_names.PLAYER_PANEL_NEW) &&
|
||||
panel.panelInfo?.modal,
|
||||
() => dispatchFn(finishVideoPreview())
|
||||
);
|
||||
});
|
||||
}, [dispatch]);
|
||||
|
||||
const selectDefaultOptionForMock = useCallback(() => {
|
||||
if (!isMockMode) {
|
||||
return selectedOptions;
|
||||
}
|
||||
|
||||
if (selectedOptions) {
|
||||
return selectedOptions;
|
||||
}
|
||||
|
||||
const firstGroup = Array.isArray(productOptionInfos)
|
||||
? productOptionInfos[0]
|
||||
: null;
|
||||
const firstDetail = firstGroup?.prdtOptDtl?.[0];
|
||||
|
||||
if (firstDetail) {
|
||||
const hasSecondDropdown = (firstGroup?.prdtOptDtl?.length || 0) > 1;
|
||||
const hasMultipleGroups = (productOptionInfos?.length || 0) > 1;
|
||||
|
||||
setSelectedOptions((prev) => prev || firstDetail);
|
||||
setIsOptionValue(true);
|
||||
setIsOptionSelect(true);
|
||||
setSelectedBtnOptIdx((prev) => prev || 0);
|
||||
setSelectedOptionItemIndex((prev) =>
|
||||
hasSecondDropdown ? (prev > 0 ? prev : 1) : 0
|
||||
);
|
||||
setSelectSecondOptionIndex((prev) =>
|
||||
hasSecondDropdown ? (prev > 0 ? prev : 1) : 0
|
||||
);
|
||||
if (hasMultipleGroups) {
|
||||
setSelectFirstOptionIndex((prev) => (prev > 0 ? prev : 1));
|
||||
}
|
||||
return firstDetail;
|
||||
}
|
||||
|
||||
const fallbackLabel =
|
||||
productInfo?.optNm || productInfo?.prdtNm || 'Mock Option';
|
||||
const fallbackPriceInfo =
|
||||
productInfo?.priceInfo || '999.99|999.99|0|0%|0';
|
||||
|
||||
const fallbackOption = {
|
||||
prodOptCdCval: 'MOCK_DEFAULT_OPT',
|
||||
prodOptCval: fallbackLabel,
|
||||
optNm: fallbackLabel,
|
||||
optPrc: productInfo?.price3 || productInfo?.price2 || '0.00',
|
||||
priceInfo: fallbackPriceInfo,
|
||||
};
|
||||
|
||||
setSelectedOptions((prev) => prev || fallbackOption);
|
||||
setIsOptionValue(true);
|
||||
setIsOptionSelect(true);
|
||||
setSelectedBtnOptIdx((prev) => prev || 0);
|
||||
setSelectedOptionItemIndex((prev) => (prev > 0 ? prev : 0));
|
||||
setSelectSecondOptionIndex((prev) => (prev > 0 ? prev : 0));
|
||||
return fallbackOption;
|
||||
}, [
|
||||
isMockMode,
|
||||
selectedOptions,
|
||||
productOptionInfos,
|
||||
productInfo,
|
||||
]);
|
||||
const logInfo = useMemo(() => {
|
||||
if (productData) {
|
||||
// productData가 있으면 SingleOption과 동일하게 처리
|
||||
@@ -375,9 +468,7 @@ const BuyOption = ({
|
||||
|
||||
// CheckOutPanel 이동 전에 ProductVideoV2 타이머 및 MediaPanel/PlayerPanel 정리
|
||||
console.log('[BuyOption] API Mode - Cleaning up media panels before checkout');
|
||||
clearAllVideoTimers(); // ProductVideoV2의 타이머 정리
|
||||
dispatch(finishMediaPreview()); // MediaPanel 정리
|
||||
dispatch(popPanel(Config.panel_names.PLAYER_PANEL)); // PlayerPanel 제거
|
||||
cleanupVideoAndPlayerPanels();
|
||||
|
||||
// 🔴 CRITICAL: 기존 CheckOutPanel 있으면 제거 후 새로 push (API Mode)
|
||||
dispatch((dispatchFn, getState) => {
|
||||
@@ -443,9 +534,11 @@ const BuyOption = ({
|
||||
return;
|
||||
}
|
||||
if (!userNumber || userNumber === '') {
|
||||
console.log('%c[BuyOption] ❌ User not logged in - showing login popup', 'background: red; color: white; padding: 3px;');
|
||||
dispatch(setShowPopup(Config.ACTIVE_POPUP.loginPopup));
|
||||
return;
|
||||
if (!isMockMode) {
|
||||
console.log('%c[BuyOption] ❌ User not logged in - showing login popup', 'background: red; color: white; padding: 3px;');
|
||||
dispatch(setShowPopup(Config.ACTIVE_POPUP.loginPopup));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// // 옵션 선택 검증 (SingleOption과 동일)
|
||||
@@ -459,7 +552,7 @@ const BuyOption = ({
|
||||
// }
|
||||
|
||||
// Mock Mode가 아닐 때만 옵션 선택 검증
|
||||
if (!BUYNOW_CONFIG.isMockMode()) {
|
||||
if (!isMockMode) {
|
||||
//옵션 선택 안하면 구매 안돼도록.
|
||||
if (
|
||||
productOptionInfos &&
|
||||
@@ -513,39 +606,37 @@ const BuyOption = ({
|
||||
dispatch(showError(null, 'Missing required information', false, null, null));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Mock Mode: 최소한의 검증만 수행
|
||||
console.log('%c[BuyOption] Mock Mode - Bypassing option validation', 'background: blue; color: white; padding: 3px;');
|
||||
if (!selectedPatnrId || !selectedPrdtId) {
|
||||
console.error('%c[BuyOption] ❌ Mock Mode - Missing critical IDs:', 'background: red; color: white; padding: 3px;', {
|
||||
selectedPatnrId: !!selectedPatnrId,
|
||||
selectedPrdtId: !!selectedPrdtId
|
||||
});
|
||||
dispatch(showError(null, 'Product ID is missing', false, null, null));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const effectivePatnrId =
|
||||
selectedPatnrId || productInfo?.patnrId || 'MOCK_PARTNER';
|
||||
const effectivePrdtId =
|
||||
selectedPrdtId || productInfo?.prdtId || 'MOCK_PRODUCT';
|
||||
const optionForUse = isMockMode
|
||||
? selectDefaultOptionForMock()
|
||||
: selectedOptions;
|
||||
const effectiveQuantity = quantity > 0 ? quantity : 1;
|
||||
|
||||
// Mock Mode: 조건 완화 (userNumber 체크 제외)
|
||||
const shouldProceed = BUYNOW_CONFIG.isMockMode()
|
||||
? (selectedPatnrId && selectedPrdtId && quantity)
|
||||
const shouldProceed = isMockMode
|
||||
? (effectivePatnrId && effectivePrdtId && effectiveQuantity)
|
||||
: (userNumber && selectedPatnrId && selectedPrdtId && quantity);
|
||||
|
||||
console.log('%c[BuyOption] shouldProceed check:', 'background: purple; color: white; padding: 3px;', {
|
||||
shouldProceed,
|
||||
isMockMode: BUYNOW_CONFIG.isMockMode(),
|
||||
isMockMode,
|
||||
userNumber: !!userNumber,
|
||||
selectedPatnrId: !!selectedPatnrId,
|
||||
selectedPrdtId: !!selectedPrdtId,
|
||||
selectedPatnrId: !!effectivePatnrId,
|
||||
selectedPrdtId: !!effectivePrdtId,
|
||||
quantity
|
||||
});
|
||||
|
||||
if (shouldProceed) {
|
||||
const { prodOptCval, priceInfo } = selectedOptions || {};
|
||||
const { prodOptCval, priceInfo } = optionForUse || {};
|
||||
const { patncNm, brndNm, catNm, prdtNm, prdtId } = productInfo;
|
||||
|
||||
console.log('[BuyOption] handleClickOrder - productInfo:', productInfo);
|
||||
console.log('[BuyOption] handleClickOrder - selectedOptions:', selectedOptions);
|
||||
console.log('[BuyOption] handleClickOrder - selectedOptions:', optionForUse);
|
||||
console.log('[BuyOption] handleClickOrder - priceInfo:', priceInfo);
|
||||
console.log('[BuyOption] handleClickOrder - logInfo:', logInfo);
|
||||
|
||||
@@ -579,7 +670,7 @@ const BuyOption = ({
|
||||
console.log('[BuyOption] handleClickOrder - Calculated prices - regularPrice:', regularPrice, 'discountPrice:', discountPrice);
|
||||
|
||||
// selectedOptions가 없고 logInfo가 있으면, logInfo의 가격도 고려
|
||||
if (!selectedOptions && logInfo) {
|
||||
if (!optionForUse && logInfo) {
|
||||
console.log('[BuyOption] handleClickOrder - selectedOptions is undefined, checking logInfo prices');
|
||||
// logInfo의 dcBefPrc와 dcAftrPrc는 "$ 521.66" 형식이므로 숫자만 추출 (소수점 포함)
|
||||
const dcBefPrcMatch = logInfo.dcBefPrc?.match(/[\d.]+/);
|
||||
@@ -606,7 +697,7 @@ const BuyOption = ({
|
||||
price: discountRate ? discountPrice : regularPrice,
|
||||
discount: discountRate,
|
||||
brand: brndNm,
|
||||
productOption: prodOptCval || '',
|
||||
productOption: prodOptCval || optionForUse?.optNm || optionForUse?.prodOptCval || '',
|
||||
category: catNm,
|
||||
contextName: Config.LOG_CONTEXT_NAME.DETAILPAGE,
|
||||
messageId: Config.LOG_MESSAGE_ID.BUY_NOW,
|
||||
@@ -624,8 +715,8 @@ const BuyOption = ({
|
||||
{
|
||||
patnrId: selectedPatnrId,
|
||||
prdtId: selectedPrdtId,
|
||||
prodOptCdCval: selectedOptions?.prodOptCdCval
|
||||
? selectedOptions.prodOptCdCval
|
||||
prodOptCdCval: optionForUse?.prodOptCdCval
|
||||
? optionForUse.prodOptCdCval
|
||||
: null,
|
||||
prodQty: String(quantity),
|
||||
prodOptTpCdCval: productOptionInfos[0]?.prodOptTpCdCval,
|
||||
@@ -644,9 +735,7 @@ const BuyOption = ({
|
||||
|
||||
// CheckOutPanel 이동 전에 ProductVideoV2 타이머 및 MediaPanel/PlayerPanel 정리
|
||||
console.log('[BuyOption] Mock Mode - Cleaning up media panels before checkout');
|
||||
clearAllVideoTimers(); // ProductVideoV2의 타이머 정리
|
||||
dispatch(finishMediaPreview()); // MediaPanel 정리
|
||||
dispatch(popPanel(Config.panel_names.PLAYER_PANEL)); // PlayerPanel 제거
|
||||
cleanupVideoAndPlayerPanels();
|
||||
|
||||
// Mock 모드: 선택 상품의 정보를 panelInfo에 담아서 전달
|
||||
// CheckOutPanel에서 이 정보로 Mock 상품 데이터 생성
|
||||
@@ -657,11 +746,11 @@ const BuyOption = ({
|
||||
'/mock/image.jpg';
|
||||
|
||||
const mockProductInfo = {
|
||||
prdtId: selectedPrdtId,
|
||||
prdtId: effectivePrdtId,
|
||||
prdtNm: productInfo?.prdtNm,
|
||||
patnrId: selectedPatnrId,
|
||||
patnrId: effectivePatnrId,
|
||||
patncNm: patncNm,
|
||||
prodQty: quantity,
|
||||
prodQty: effectiveQuantity,
|
||||
origPrice: regularPrice || 99999, // 원래 가격 (숫자)
|
||||
discountPrice: discountPrice || regularPrice || 99999, // 할인된 가격 (실제 판매 가격, 숫자)
|
||||
finalPrice: discountPrice || regularPrice || 99999, // 최종 가격 (숫자)
|
||||
@@ -681,11 +770,11 @@ const BuyOption = ({
|
||||
|
||||
const checkoutPanelInfo = {
|
||||
logInfo: { ...logInfo, cartTpSno: `MOCK_${Date.now()}` },
|
||||
productInfo: {
|
||||
prdtId: productInfo?.prdtId || selectedPrdtId || 'MOCK_PRODUCT',
|
||||
prdtNm: productInfo?.prdtNm || 'Mock Product',
|
||||
patnrId: selectedPatnrId || '1',
|
||||
patncNm: patncNm || 'Mock Partner',
|
||||
productInfo: {
|
||||
prdtId: productInfo?.prdtId || effectivePrdtId || 'MOCK_PRODUCT',
|
||||
prdtNm: productInfo?.prdtNm || 'Mock Product',
|
||||
patnrId: effectivePatnrId || '1',
|
||||
patncNm: patncNm || 'Mock Partner',
|
||||
// calculateOrderSummaryFromProductInfo 함수가 필요한 필드들
|
||||
// productInfo에서 직접 추출한 값을 전달
|
||||
price2: price3Value, // Items (상품 가격)
|
||||
@@ -694,7 +783,7 @@ const BuyOption = ({
|
||||
discount: price5Value,
|
||||
origPrice: regularPrice,
|
||||
discountPrice: discountPrice,
|
||||
prodQty:quantity,
|
||||
prodQty: quantity,
|
||||
// 추가 가격 필드들 (fallback용)
|
||||
price: discountPrice,
|
||||
originalPrice: regularPrice,
|
||||
@@ -730,9 +819,9 @@ const BuyOption = ({
|
||||
const fallbackPanelInfo = {
|
||||
logInfo: { cartTpSno: `MOCK_FALLBACK_${Date.now()}` },
|
||||
productInfo: {
|
||||
prdtId: selectedPrdtId || 'MOCK_PRODUCT',
|
||||
prdtId: effectivePrdtId || 'MOCK_PRODUCT',
|
||||
prdtNm: 'Mock Product',
|
||||
patnrId: selectedPatnrId || '1',
|
||||
patnrId: effectivePatnrId || '1',
|
||||
patncNm: 'Mock Partner',
|
||||
finalPrice: 99999,
|
||||
origPrice: 99999,
|
||||
@@ -805,308 +894,181 @@ const BuyOption = ({
|
||||
logInfo,
|
||||
selectFirstOptionIndex,
|
||||
selectSecondOptionIndex,
|
||||
nowMenu,
|
||||
isMockMode,
|
||||
selectDefaultOptionForMock,
|
||||
cleanupVideoAndPlayerPanels,
|
||||
]);
|
||||
|
||||
// ADD TO CART 버튼 클릭 핸들러
|
||||
const handleAddToCartClick = useCallback(() => {
|
||||
console.log('[BuyOption] ADD TO CART clicked');
|
||||
|
||||
// 상품 품절 체크
|
||||
if (productInfo && productInfo?.soldoutFlag === 'Y') {
|
||||
const isMock = isMockMode;
|
||||
|
||||
// 상품 품절 체크 (Mock Mode에서는 우회)
|
||||
if (productInfo && productInfo?.soldoutFlag === 'Y' && !isMock) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 로그인 체크
|
||||
if (!userNumber || userNumber === '') {
|
||||
// 로그인 체크 (Mock Mode에서는 우회)
|
||||
if ((!userNumber || userNumber === '') && !isMock) {
|
||||
return dispatch(setShowPopup(Config.ACTIVE_POPUP.loginPopup));
|
||||
}
|
||||
|
||||
// 장바구니에 상품 추가
|
||||
if (userNumber && selectedPatnrId && selectedPrdtId && quantity) {
|
||||
const { prodOptCval, priceInfo } = selectedOptions || {};
|
||||
const { patncNm, brndNm, catNm, prdtNm, prdtId } = productInfo;
|
||||
const regularPrice = priceInfo?.split('|')[0];
|
||||
const discountPrice = priceInfo?.split('|')[1];
|
||||
const discountRate = priceInfo?.split('|')[4];
|
||||
const effectivePatnrId =
|
||||
selectedPatnrId || productInfo?.patnrId || 'MOCK_PARTNER';
|
||||
const effectivePrdtId =
|
||||
selectedPrdtId || productInfo?.prdtId || 'MOCK_PRODUCT';
|
||||
const effectiveQuantity = quantity > 0 ? quantity : 1;
|
||||
const optionForUse = isMock ? selectDefaultOptionForMock() : selectedOptions;
|
||||
|
||||
// 로그 전송
|
||||
// dispatch(
|
||||
// sendLogTotalRecommend({
|
||||
// nowMenu: nowMenu,
|
||||
// productId: prdtId,
|
||||
// productTitle: prdtNm,
|
||||
// partner: patncNm,
|
||||
// price: discountRate ? discountPrice : regularPrice,
|
||||
// discount: discountRate,
|
||||
// brand: brndNm,
|
||||
// productOption: prodOptCval || '',
|
||||
// category: catNm,
|
||||
// contextName: Config.LOG_CONTEXT_NAME.DETAILPAGE,
|
||||
// messageId: Config.LOG_MESSAGE_ID.ADD_TO_CART,
|
||||
// })
|
||||
// );
|
||||
|
||||
// API Mode: 실제 API 호출 후 CartPanel로 이동
|
||||
if (!BUYNOW_CONFIG.isMockMode()) {
|
||||
// 장바구니에 추가
|
||||
dispatch(
|
||||
addToCart({
|
||||
mbrNo: userNumber,
|
||||
patnrId: selectedPatnrId,
|
||||
prdtId: selectedPrdtId,
|
||||
prodQty: String(quantity),
|
||||
prdtOpt: {
|
||||
prodOptCdCval: selectedOptions?.prodOptCdCval
|
||||
? selectedOptions.prodOptCdCval
|
||||
: "",
|
||||
prodOptCval:productOptionInfos[0]?.optNm,
|
||||
prodOptSno: productOptionInfos[0]?.prodOptSno,
|
||||
prodOptTpCdCval: productOptionInfos[0]?.prodOptTpCdCval,
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// CartPanel로 이동 (productInfo 포함) - API에서는 이미 addToCart 호출됨
|
||||
// 이미지 URL 구성 (CheckOutPanel과 동일한 방식)
|
||||
// ✅ 이미지 URL 추출 (ProductAllSection의 고품질 이미지 우선)
|
||||
const imgUrl = productInfo?.imgUrls600?.[0] || // ✅ ProductAllSection에서 사용하는 고품질 이미지
|
||||
productInfo?.thumbnailUrl960 || // ✅ 960px 썸네일
|
||||
productInfo?.imgList?.[0]?.imgUrl ||
|
||||
productInfo?.thumbnailUrl ||
|
||||
productInfo?.patncLogPath ||
|
||||
'/assets/images/img-thumb-empty-144@3x.png';
|
||||
|
||||
// ✅ 정확한 가격 추출 (Mock Mode와 동일한 로직)
|
||||
console.log('[BuyOption] API Mode ADD TO CART - Extracting accurate prices from productInfo');
|
||||
console.log('[BuyOption] API Mode ADD TO CART - productInfo.price2:', productInfo?.price2);
|
||||
console.log('[BuyOption] API Mode ADD TO CART - productInfo.price5:', productInfo?.price5);
|
||||
console.log('[BuyOption] API Mode ADD TO CART - productInfo.priceInfo:', productInfo?.priceInfo);
|
||||
|
||||
// 정확한 가격 추출 로직
|
||||
const extractNumericPrice = (value) => {
|
||||
if (typeof value === 'number') return value;
|
||||
if (typeof value === 'string') {
|
||||
const cleanedValue = value.replace(/,/g, '');
|
||||
const numMatch = cleanedValue.match(/[\d.]+/);
|
||||
return numMatch ? parseFloat(numMatch[0]) : 0;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
const price2Value = extractNumericPrice(productInfo?.price2);
|
||||
const price5Value = extractNumericPrice(productInfo?.price5);
|
||||
|
||||
console.log('[BuyOption] API Mode ADD TO CART - extracted price2Value:', price2Value);
|
||||
console.log('[BuyOption] API Mode ADD TO CART - extracted price5Value:', price5Value);
|
||||
|
||||
// 정확한 가격 계산 (ProductAllSection의 가격 정보 사용)
|
||||
let discountPrice = price2Value > 0 ? price2Value : 521.66; // ProductAllSection 가격 fallback
|
||||
let regularPrice = price2Value + price5Value;
|
||||
|
||||
// priceInfo에서 직접 가격 추출 시도
|
||||
if (productInfo?.priceInfo) {
|
||||
const priceParts = productInfo.priceInfo.split('|');
|
||||
if (priceParts.length >= 2) {
|
||||
const infoDiscountPrice = extractNumericPrice(priceParts[1]);
|
||||
const infoRegularPrice = extractNumericPrice(priceParts[0]);
|
||||
if (infoDiscountPrice > 0) {
|
||||
discountPrice = infoDiscountPrice;
|
||||
regularPrice = infoRegularPrice > 0 ? infoRegularPrice : discountPrice;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[BuyOption] API Mode ADD TO CART - Final calculated prices:', {
|
||||
discountPrice,
|
||||
regularPrice,
|
||||
price2Value,
|
||||
price5Value
|
||||
});
|
||||
|
||||
const productInfoForCart = {
|
||||
// 기본 정보
|
||||
prdtId: selectedPrdtId,
|
||||
prdtNm: productInfo?.prdtNm || 'Product',
|
||||
patnrId: selectedPatnrId,
|
||||
patncNm: productInfo?.patncNm || 'Partner',
|
||||
patncLogPath: productInfo?.patncLogPath || '',
|
||||
|
||||
// ✅ 이미지 정보 (ProductAllSection의 고품질 이미지 포함)
|
||||
imgUrl: imgUrl,
|
||||
thumbnailUrl: productInfo?.thumbnailUrl960 || imgUrl,
|
||||
thumbnailUrl960: productInfo?.thumbnailUrl960,
|
||||
imgList: productInfo?.imgList || [{ imgUrl: imgUrl }],
|
||||
imgUrls: productInfo?.imgUrls || [{ imgUrl: imgUrl }], // imgUrls 배열 구조 추가 (CheckOutPanel 호환성)
|
||||
imgUrls600: productInfo?.imgUrls600, // ✅ 고품질 이미지 배열 포함
|
||||
|
||||
// 가격 정보 (정확한 가격 정보 - 문자열 형식으로)
|
||||
price2: regularPrice.toFixed(2), // 원가 (ProductAllSection 가격)
|
||||
price3: discountPrice.toFixed(2), // 할인가/판매가 (ProductAllSection 가격)
|
||||
// 추가 가격 필드들 (다양한 fallback 지원)
|
||||
finalPrice: discountPrice,
|
||||
discountPrice: discountPrice,
|
||||
origPrice: regularPrice,
|
||||
discount: Math.max(0, regularPrice - discountPrice),
|
||||
priceInfo: productInfo?.priceInfo, // 원본 priceInfo 보존
|
||||
|
||||
// 수량 정보
|
||||
prodQty: quantity,
|
||||
|
||||
// 옵션 정보
|
||||
optNm: productOptionInfos[0]?.optNm || '',
|
||||
|
||||
// 배송비 정보
|
||||
shippingCharge: productInfo?.shippingFee || '12.99',
|
||||
|
||||
// 기타 정보
|
||||
soldoutFlag: productInfo?.soldoutFlag || 'N',
|
||||
};
|
||||
|
||||
const optionInfoForCart = {
|
||||
name: productOptionInfos[0]?.optNm || '',
|
||||
price: productOptionInfos[0]?.prdtOptDtl[0]?.optPrc || '0.00'
|
||||
};
|
||||
|
||||
console.log('[BuyOption] 🛒 API Mode - Pushing CART_PANEL with name:', Config.panel_names.CART_PANEL);
|
||||
console.log('[BuyOption] 🛒 API Mode - productInfoForCart:', productInfoForCart);
|
||||
console.log('[BuyOption] 🛒 API Mode - optionInfoForCart:', optionInfoForCart);
|
||||
console.log('[BuyOption] 🛒 API Mode - quantity:', quantity);
|
||||
|
||||
dispatch(
|
||||
pushPanel({
|
||||
name: Config.panel_names.CART_PANEL,
|
||||
panelInfo: {
|
||||
productInfo: productInfoForCart,
|
||||
optionInfo: optionInfoForCart,
|
||||
quantity: quantity
|
||||
}
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// Mock Mode: Mock 장바구니에 상품 추가 후 CartPanel로 이동
|
||||
console.log('[BuyOption] Mock Mode - Adding to cart (Mock)');
|
||||
|
||||
// ✅ 이미지 URL 구성 (ProductAllSection의 고품질 이미지 우선)
|
||||
const imgUrl = productInfo?.imgUrls600?.[0] || // ✅ ProductAllSection에서 사용하는 고품질 이미지
|
||||
productInfo?.thumbnailUrl960 || // ✅ 960px 썸네일
|
||||
productInfo?.imgList?.[0]?.imgUrl ||
|
||||
productInfo?.thumbnailUrl ||
|
||||
productInfo?.patncLogPath ||
|
||||
'/assets/images/img-thumb-empty-144@3x.png';
|
||||
|
||||
// ✅ 정확한 가격 추출 (handleBuyNowClick와 동일한 로직 사용)
|
||||
console.log('[BuyOption] Mock Mode ADD TO CART - Extracting accurate prices from productInfo');
|
||||
console.log('[BuyOption] Mock Mode ADD TO CART - productInfo.price2:', productInfo?.price2);
|
||||
console.log('[BuyOption] Mock Mode ADD TO CART - productInfo.price5:', productInfo?.price5);
|
||||
console.log('[BuyOption] Mock Mode ADD TO CART - productInfo.priceInfo:', productInfo?.priceInfo);
|
||||
|
||||
// handleBuyNowClick의 가격 추출 로직과 동일하게 적용
|
||||
const extractNumericPrice = (value) => {
|
||||
if (typeof value === 'number') return value;
|
||||
if (typeof value === 'string') {
|
||||
const cleanedValue = value.replace(/,/g, '');
|
||||
const numMatch = cleanedValue.match(/[\d.]+/);
|
||||
return numMatch ? parseFloat(numMatch[0]) : 0;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
const price2Value = extractNumericPrice(productInfo?.price2);
|
||||
const price5Value = extractNumericPrice(productInfo?.price5);
|
||||
|
||||
console.log('[BuyOption] Mock Mode ADD TO CART - extracted price2Value:', price2Value);
|
||||
console.log('[BuyOption] Mock Mode ADD TO CART - extracted price5Value:', price5Value);
|
||||
|
||||
// 정확한 가격 계산 (ProductAllSection의 가격 정보 사용)
|
||||
let discountPrice = price2Value > 0 ? price2Value : 521.66; // ProductAllSection 가격 fallback
|
||||
let regularPrice = price2Value + price5Value;
|
||||
|
||||
// priceInfo에서 직접 가격 추출 시도
|
||||
if (productInfo?.priceInfo) {
|
||||
const priceParts = productInfo.priceInfo.split('|');
|
||||
if (priceParts.length >= 2) {
|
||||
const infoDiscountPrice = extractNumericPrice(priceParts[1]);
|
||||
const infoRegularPrice = extractNumericPrice(priceParts[0]);
|
||||
if (infoDiscountPrice > 0) {
|
||||
discountPrice = infoDiscountPrice;
|
||||
regularPrice = infoRegularPrice > 0 ? infoRegularPrice : discountPrice;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[BuyOption] Mock Mode ADD TO CART - Final calculated prices:', {
|
||||
discountPrice,
|
||||
regularPrice,
|
||||
price2Value,
|
||||
price5Value
|
||||
});
|
||||
|
||||
// Mock 상품 정보 구성 (CheckOutPanel 구조 참고)
|
||||
const mockProductInfo = {
|
||||
// 기본 정보
|
||||
prdtId: selectedPrdtId,
|
||||
prdtNm: productInfo?.prdtNm || 'Mock Product',
|
||||
patnrId: selectedPatnrId,
|
||||
patncNm: productInfo?.patncNm || 'Mock Partner',
|
||||
patncLogPath: productInfo?.patncLogPath || '',
|
||||
|
||||
// ✅ 이미지 정보 (ProductAllSection의 고품질 이미지 포함)
|
||||
imgUrl: imgUrl,
|
||||
thumbnailUrl: productInfo?.thumbnailUrl960 || imgUrl,
|
||||
thumbnailUrl960: productInfo?.thumbnailUrl960,
|
||||
imgList: productInfo?.imgList || [{ imgUrl: imgUrl }], // imgList 배열 구조 추가
|
||||
imgUrls: productInfo?.imgUrls || [{ imgUrl: imgUrl }], // imgUrls 배열 구조 추가 (CheckOutPanel 호환성)
|
||||
imgUrls600: productInfo?.imgUrls600, // ✅ 고품질 이미지 배열 포함
|
||||
|
||||
// 가격 정보 (정확한 가격 정보 - 문자열 형식으로)
|
||||
price2: regularPrice.toFixed(2), // 원가 (ProductAllSection 가격)
|
||||
price3: discountPrice.toFixed(2), // 할인가/판매가 (ProductAllSection 가격)
|
||||
// 추가 가격 필드들 (다양한 fallback 지원)
|
||||
finalPrice: discountPrice,
|
||||
discountPrice: discountPrice,
|
||||
origPrice: regularPrice,
|
||||
discount: Math.max(0, regularPrice - discountPrice),
|
||||
priceInfo: productInfo?.priceInfo, // 원본 priceInfo 보존
|
||||
|
||||
// 수량 정보
|
||||
prodQty: quantity,
|
||||
|
||||
// 옵션 정보 (필요시)
|
||||
optNm: productOptionInfos[0]?.optNm || 'Default Option',
|
||||
|
||||
// 배송비 정보
|
||||
shippingCharge: productInfo?.shippingFee || '12.99',
|
||||
shippingFee: productInfo?.shippingFee || '12.99',
|
||||
|
||||
// 기타 정보
|
||||
soldoutFlag: productInfo?.soldoutFlag || 'N',
|
||||
};
|
||||
|
||||
// 옵션 정보 구성
|
||||
const optionInfo = {
|
||||
name: productOptionInfos[0]?.optNm || 'Default Option',
|
||||
price: productOptionInfos[0]?.prdtOptDtl[0]?.optPrc || '0.00'
|
||||
};
|
||||
|
||||
// CartPanel로 이동 (productInfo 포함) - CartPanel에서 직접 상품 추가
|
||||
console.log('[BuyOption] 🛒 Pushing CART_PANEL with name:', Config.panel_names.CART_PANEL);
|
||||
console.log('[BuyOption] 🛒 mockProductInfo:', mockProductInfo);
|
||||
console.log('[BuyOption] 🛒 optionInfo:', optionInfo);
|
||||
console.log('[BuyOption] 🛒 quantity:', quantity);
|
||||
|
||||
dispatch(
|
||||
pushPanel({
|
||||
name: Config.panel_names.CART_PANEL,
|
||||
panelInfo: {
|
||||
productInfo: mockProductInfo,
|
||||
optionInfo: optionInfo,
|
||||
quantity: quantity
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
// API Mode 조건 검증
|
||||
if (
|
||||
!isMock &&
|
||||
(!userNumber || !selectedPatnrId || !selectedPrdtId || !quantity)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parseNumericPrice = (value) => {
|
||||
if (typeof value === 'number') return value;
|
||||
if (!value) return 0;
|
||||
const cleaned = String(value).replace(/,/g, '');
|
||||
const match = cleaned.match(/-?[\d.]+/);
|
||||
return match ? parseFloat(match[0]) : 0;
|
||||
};
|
||||
|
||||
const priceInfoSource =
|
||||
optionForUse?.priceInfo ||
|
||||
productInfo?.priceInfo ||
|
||||
'0|0|0|0%|0';
|
||||
const priceParts = priceInfoSource.split('|');
|
||||
const regularPriceValue = parseNumericPrice(priceParts[0]);
|
||||
const discountPriceValue =
|
||||
priceParts.length > 1
|
||||
? parseNumericPrice(priceParts[1])
|
||||
: regularPriceValue;
|
||||
const optionLabel =
|
||||
optionForUse?.optNm || optionForUse?.prodOptCval || '';
|
||||
|
||||
if (!isMock) {
|
||||
dispatch(
|
||||
addToCart({
|
||||
mbrNo: userNumber,
|
||||
patnrId: selectedPatnrId,
|
||||
prdtId: selectedPrdtId,
|
||||
prodQty: String(effectiveQuantity),
|
||||
prdtOpt: {
|
||||
prodOptCdCval: optionForUse?.prodOptCdCval || '',
|
||||
prodOptCval: optionLabel,
|
||||
prodOptSno: productOptionInfos?.[0]?.prodOptSno || '',
|
||||
prodOptTpCdCval: productOptionInfos?.[0]?.prodOptTpCdCval || '',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const imgUrl =
|
||||
productInfo?.imgUrls600?.[0] ||
|
||||
productInfo?.thumbnailUrl960 ||
|
||||
productInfo?.imgList?.[0]?.imgUrl ||
|
||||
productInfo?.thumbnailUrl ||
|
||||
productInfo?.patncLogPath ||
|
||||
'/assets/images/img-thumb-empty-144@3x.png';
|
||||
|
||||
const productInfoForCart = {
|
||||
prdtId: effectivePrdtId,
|
||||
prdtNm: productInfo?.prdtNm || 'Product',
|
||||
patnrId: effectivePatnrId,
|
||||
patncNm: productInfo?.patncNm || 'Partner',
|
||||
patncLogPath: productInfo?.patncLogPath || '',
|
||||
imgUrl,
|
||||
thumbnailUrl: productInfo?.thumbnailUrl960 || imgUrl,
|
||||
thumbnailUrl960: productInfo?.thumbnailUrl960,
|
||||
imgList: productInfo?.imgList || [{ imgUrl }],
|
||||
imgUrls: productInfo?.imgUrls || [{ imgUrl }],
|
||||
imgUrls600: productInfo?.imgUrls600,
|
||||
price2: regularPriceValue.toFixed(2),
|
||||
price3: discountPriceValue.toFixed(2),
|
||||
finalPrice: discountPriceValue,
|
||||
discountPrice: discountPriceValue,
|
||||
origPrice: regularPriceValue,
|
||||
discount: Math.max(0, regularPriceValue - discountPriceValue),
|
||||
priceInfo: priceInfoSource,
|
||||
prodQty: effectiveQuantity,
|
||||
optNm: optionLabel,
|
||||
shippingCharge: productInfo?.shippingFee || '12.99',
|
||||
soldoutFlag: productInfo?.soldoutFlag || 'N',
|
||||
};
|
||||
|
||||
const optionInfoForCart = {
|
||||
name: optionLabel,
|
||||
price: optionForUse?.optPrc || '0.00',
|
||||
};
|
||||
|
||||
dispatch(
|
||||
pushPanel({
|
||||
name: Config.panel_names.CART_PANEL,
|
||||
panelInfo: {
|
||||
productInfo: productInfoForCart,
|
||||
optionInfo: optionInfoForCart,
|
||||
quantity: effectiveQuantity,
|
||||
},
|
||||
})
|
||||
);
|
||||
} else {
|
||||
console.log('[BuyOption] Mock Mode - Adding to cart (Mock)');
|
||||
|
||||
const imgUrl =
|
||||
productInfo?.imgUrls600?.[0] ||
|
||||
productInfo?.thumbnailUrl960 ||
|
||||
productInfo?.imgList?.[0]?.imgUrl ||
|
||||
productInfo?.thumbnailUrl ||
|
||||
productInfo?.patncLogPath ||
|
||||
'/assets/images/img-thumb-empty-144@3x.png';
|
||||
|
||||
const mockProductInfo = {
|
||||
prdtId: effectivePrdtId,
|
||||
prdtNm: productInfo?.prdtNm || 'Mock Product',
|
||||
patnrId: effectivePatnrId,
|
||||
patncNm: productInfo?.patncNm || 'Mock Partner',
|
||||
patncLogPath: productInfo?.patncLogPath || '',
|
||||
imgUrl,
|
||||
thumbnailUrl: productInfo?.thumbnailUrl960 || imgUrl,
|
||||
thumbnailUrl960: productInfo?.thumbnailUrl960,
|
||||
imgList: productInfo?.imgList || [{ imgUrl }],
|
||||
imgUrls: productInfo?.imgUrls || [{ imgUrl }],
|
||||
imgUrls600: productInfo?.imgUrls600,
|
||||
price2: regularPriceValue.toFixed(2),
|
||||
price3: discountPriceValue.toFixed(2),
|
||||
finalPrice: discountPriceValue,
|
||||
discountPrice: discountPriceValue,
|
||||
origPrice: regularPriceValue,
|
||||
discount: Math.max(0, regularPriceValue - discountPriceValue),
|
||||
priceInfo: priceInfoSource,
|
||||
prodQty: effectiveQuantity,
|
||||
optNm: optionLabel || 'Default Option',
|
||||
shippingCharge: productInfo?.shippingFee || '12.99',
|
||||
shippingFee: productInfo?.shippingFee || '12.99',
|
||||
soldoutFlag: productInfo?.soldoutFlag || 'N',
|
||||
};
|
||||
|
||||
const optionInfo = {
|
||||
name: optionLabel || 'Default Option',
|
||||
price: optionForUse?.optPrc || discountPriceValue.toFixed(2),
|
||||
};
|
||||
|
||||
dispatch(
|
||||
pushPanel({
|
||||
name: Config.panel_names.CART_PANEL,
|
||||
panelInfo: {
|
||||
productInfo: mockProductInfo,
|
||||
optionInfo,
|
||||
quantity: effectiveQuantity,
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
dispatch(clearAllToasts());
|
||||
}, [
|
||||
dispatch,
|
||||
@@ -1117,7 +1079,8 @@ const BuyOption = ({
|
||||
productInfo,
|
||||
productOptionInfos,
|
||||
quantity,
|
||||
nowMenu,
|
||||
isMockMode,
|
||||
selectDefaultOptionForMock,
|
||||
]);
|
||||
|
||||
const handleFirstOptionSelect = (selected) => {
|
||||
|
||||
@@ -312,6 +312,7 @@ const SearchResultsNew = ({
|
||||
return {
|
||||
// 기본 정보
|
||||
thumbnail: doc.thumbnail || doc.imgPath || '', // 이미지 경로
|
||||
thumbnailOptYn: doc.thumbnailOptYn || 'Y', // 썸네일 최적화 옵션 (Y/N)
|
||||
title: doc.title || doc.prdtName || '', // 제목
|
||||
contentId, // 콘텐트 아이디
|
||||
patnrId, // 파트너 아이디
|
||||
|
||||
Reference in New Issue
Block a user