From d5f5b9b1664fa1f0defd17bcadef93c40e35440c Mon Sep 17 00:00:00 2001 From: optrader Date: Thu, 6 Nov 2025 18:02:14 +0900 Subject: [PATCH] [251106] fix: BuyOption getProductOption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๐Ÿ• ์ปค๋ฐ‹ ์‹œ๊ฐ„: 2025. 11. 06. 18:02:13 ๐Ÿ“Š ๋ณ€๊ฒฝ ํ†ต๊ณ„: โ€ข ์ด ํŒŒ์ผ: 6๊ฐœ โ€ข ์ถ”๊ฐ€: +163์ค„ โ€ข ์‚ญ์ œ: -6์ค„ ๐Ÿ“ ์ˆ˜์ •๋œ ํŒŒ์ผ: ~ com.twin.app.shoptime/src/actions/productActions.js ~ com.twin.app.shoptime/src/actions/toastActions.js ~ com.twin.app.shoptime/src/components/TToast/TToastEnhanced.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/components/BuyOption.jsx ~ com.twin.app.shoptime/src/views/MainView/MainView.jsx ๐Ÿ”ง ์ฃผ์š” ๋ณ€๊ฒฝ ๋‚ด์šฉ: โ€ข ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ฐœ์„  โ€ข UI ์ปดํฌ๋„ŒํŠธ ์•„ํ‚คํ…์ฒ˜ ๊ฐœ์„  โ€ข ์ค‘๊ฐ„ ๊ทœ๋ชจ ๊ธฐ๋Šฅ ๊ฐœ์„  โ€ข ๋ชจ๋“ˆ ๊ตฌ์กฐ ๊ฐœ์„  --- .../src/actions/productActions.js | 49 ++++++++++- .../src/actions/toastActions.js | 8 ++ .../src/components/TToast/TToastEnhanced.jsx | 9 +- .../ProductAllSection/ProductAllSection.jsx | 14 ++- .../DetailPanel/components/BuyOption.jsx | 87 ++++++++++++++++++- .../src/views/MainView/MainView.jsx | 2 +- 6 files changed, 163 insertions(+), 6 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/productActions.js b/com.twin.app.shoptime/src/actions/productActions.js index ffb2a238..f2435c73 100644 --- a/com.twin.app.shoptime/src/actions/productActions.js +++ b/com.twin.app.shoptime/src/actions/productActions.js @@ -35,14 +35,59 @@ const createRequestThunk = const query = params(props); const body = data(props); + // ๐Ÿ“ก REQUEST ๋กœ๊ทธ: API ํ˜ธ์ถœ ์ „ (tag๋ณ„๋กœ ๋‹ค๋ฅด๊ฒŒ ํ‘œ์‹œ) + console.log( + `%c[${tag}] ๐Ÿ“ค REQUEST - ${method.toUpperCase()} ${url}`, + 'background: #4CAF50; color: white; font-weight: bold; padding: 3px;', + { + method: method.toUpperCase(), + url: url, + params: query, + body: body, + timestamp: new Date().toISOString(), + } + ); + const onSuccess = (response) => { - console.log(`${tag} onSuccess`, response.data); + // โœ… RESPONSE ๋กœ๊ทธ: API ํ˜ธ์ถœ ์„ฑ๊ณต (tag๋ณ„๋กœ ๋‹ค๋ฅด๊ฒŒ ํ‘œ์‹œ) + console.log( + `%c[${tag}] โœ… RESPONSE SUCCESS - ${method.toUpperCase()} ${url}`, + 'background: #2196F3; color: white; font-weight: bold; padding: 3px;', + { + method: method.toUpperCase(), + url: url, + httpStatus: response?.status, + httpStatusText: response?.statusText, + retCode: response?.data?.retCode, + retMsg: response?.data?.retMsg, + responseData: response?.data, + timestamp: new Date().toISOString(), + } + ); + dispatch({ type, payload: selectPayload(response) }); onSuccessExtra(props, dispatch, getState, response); }; const onFail = (error) => { - console.error(`${tag} onFail`, error); + // โŒ ERROR ๋กœ๊ทธ: API ํ˜ธ์ถœ ์‹คํŒจ (tag๋ณ„๋กœ ๋‹ค๋ฅด๊ฒŒ ํ‘œ์‹œ) + console.error( + `%c[${tag}] โŒ RESPONSE ERROR - ${method.toUpperCase()} ${url}`, + 'background: #F44336; color: white; font-weight: bold; padding: 3px;', + { + method: method.toUpperCase(), + url: url, + errorMessage: error?.message, + errorType: error?.type, + httpStatus: error?.response?.status, + httpStatusText: error?.response?.statusText, + responseRetCode: error?.response?.data?.retCode, + responseRetMsg: error?.response?.data?.retMsg, + responseData: error?.response?.data, + timestamp: new Date().toISOString(), + } + ); + onFailExtra(props, dispatch, getState, error); }; diff --git a/com.twin.app.shoptime/src/actions/toastActions.js b/com.twin.app.shoptime/src/actions/toastActions.js index 0c01ef11..0ff56bc7 100644 --- a/com.twin.app.shoptime/src/actions/toastActions.js +++ b/com.twin.app.shoptime/src/actions/toastActions.js @@ -18,6 +18,10 @@ export const showToast = curry( position = 'bottom-center', id, onToastClose, // Toast๊ฐ€ ๋‹ซํž ๋•Œ ํ˜ธ์ถœํ•  ์ฝœ๋ฐฑ + productInfo, // ๐Ÿš€ BuyOption์šฉ ์ƒํ’ˆ ์ •๋ณด + selectedPatnrId, // ๐Ÿš€ BuyOption์šฉ ํŒŒํŠธ๋„ˆ ID + selectedPrdtId, // ๐Ÿš€ BuyOption์šฉ ์ƒํ’ˆ ID + ...otherProps // ๐Ÿš€ ์ถ”๊ฐ€ props ์ „๋‹ฌ ์ง€์› }) => ({ type: TOAST_ACTIONS.ADD_TOAST, payload: { @@ -27,6 +31,10 @@ export const showToast = curry( duration, position, onToastClose, // ์ฝœ๋ฐฑ ์ „๋‹ฌ + productInfo, // ๐Ÿš€ BuyOption์— ์ „๋‹ฌํ•  ์ƒํ’ˆ ์ •๋ณด + selectedPatnrId, // ๐Ÿš€ BuyOption์— ์ „๋‹ฌํ•  ํŒŒํŠธ๋„ˆ ID + selectedPrdtId, // ๐Ÿš€ BuyOption์— ์ „๋‹ฌํ•  ์ƒํ’ˆ ID + ...otherProps, // ๐Ÿš€ ์ถ”๊ฐ€ props ์ง€์› timestamp: Date.now(), }, }) diff --git a/com.twin.app.shoptime/src/components/TToast/TToastEnhanced.jsx b/com.twin.app.shoptime/src/components/TToast/TToastEnhanced.jsx index feb50506..ef0c49fa 100644 --- a/com.twin.app.shoptime/src/components/TToast/TToastEnhanced.jsx +++ b/com.twin.app.shoptime/src/components/TToast/TToastEnhanced.jsx @@ -34,6 +34,9 @@ export default function TToastEnhanced({ id, onClose, // ToastContainer์—์„œ ์ „๋‹ฌํ•˜๋Š” toast ์ œ๊ฑฐ ์ฝœ๋ฐฑ onToastClose, // payload์˜ onClose - Toast ๋‹ซํž ๋•Œ ํ˜ธ์ถœํ•  ์ถ”๊ฐ€ ์ฝœ๋ฐฑ + productInfo, // ๐Ÿš€ BuyOption์— ์ „๋‹ฌํ•  ์ƒํ’ˆ ์ •๋ณด + selectedPatnrId, // ๐Ÿš€ BuyOption์— ์ „๋‹ฌํ•  ํŒŒํŠธ๋„ˆ ID + selectedPrdtId, // ๐Ÿš€ BuyOption์— ์ „๋‹ฌํ•  ์ƒํ’ˆ ID ...rest }) { const dispatch = useDispatch(); @@ -186,7 +189,11 @@ export default function TToastEnhanced({ > {type === 'buyOption' ? (
- +
) : (
diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx index c84441c8..2447300b 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx @@ -371,6 +371,14 @@ export default function ProductAllSection({ const handleBuyNowClick = useCallback((e) => { // console.log('[BuyNow] Buy Now button clicked'); e.stopPropagation(); + + console.log('[ProductAllSection] ๐Ÿ›’ BUY NOW clicked - productData:', { + prdtId: productData?.prdtId, + patnrId: productData?.patnrId, + prdtNm: productData?.prdtNm, + hasProductData: !!productData, + }); + dispatch( showToast({ id: productData.prdtId, @@ -378,6 +386,10 @@ export default function ProductAllSection({ type: 'buyOption', duration: 0, position: 'bottom-center', + // ๐Ÿš€ BuyOption์— ์ „๋‹ฌํ•  props ๋ฐ์ดํ„ฐ + productInfo: productData, + selectedPatnrId: productData?.patnrId, + selectedPrdtId: productData?.prdtId, // BuyOption Toast๊ฐ€ ๋‹ซํž ๋•Œ BUY NOW ๋ฒ„ํŠผ์œผ๋กœ ํฌ์ปค์Šค ๋ณต๊ตฌ onToastClose: () => { setTimeout(() => { @@ -386,7 +398,7 @@ export default function ProductAllSection({ }, }) ); - }, [dispatch]); + }, [dispatch, productData]); //๋‹ซํžˆ๋„๋ก const handleCloseToast = useCallback(() => { diff --git a/com.twin.app.shoptime/src/views/DetailPanel/components/BuyOption.jsx b/com.twin.app.shoptime/src/views/DetailPanel/components/BuyOption.jsx index 9311440f..5643bbaa 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/components/BuyOption.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/components/BuyOption.jsx @@ -74,7 +74,18 @@ const BuyOption = ({ type, }) => { // DEBUG_LOG ์„ค์ • - ์ด ๊ฐ’์ด true์ผ ๋•Œ๋งŒ console.log๊ฐ€ ์‹คํ–‰๋จ - const DEBUG_LOG = false; + const DEBUG_LOG = true; + + // ๐Ÿš€ ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ props ํ™•์ธ + useEffect(() => { + console.log('[BuyOption] ๐Ÿš€ COMPONENT MOUNTED - Props received:', { + propsProductInfo: !!propsProductInfo, + propsSelectedPatnrId, + propsSelectedPrdtId, + patncNm, + type, + }); + }, []); // console.log ์˜ค๋ฒ„๋ผ์ด๋“œ๋ฅผ ์œ„ํ•œ ref const originalConsoleLog = useRef(console.log); @@ -107,6 +118,16 @@ const BuyOption = ({ const productInfo = propsProductInfo || reduxProductInfo; const reduxProductOptionInfos = useSelector((state) => state.product.prdtOptInfo); const productData = useSelector((state) => state.main.productData); + + // ๐Ÿ”ด Redux productData ์ƒํƒœ ํ™•์ธ + useEffect(() => { + console.log('[BuyOption] ๐Ÿ”ด REDUX PRODUCT DATA STATUS:', { + hasReduxProductInfo: !!reduxProductInfo, + hasProductData: !!productData, + reduxProductInfoFull: reduxProductInfo, + productDataFull: productData, + }); + }, [reduxProductInfo, productData]); const { partnerCoupon } = useSelector( (state) => state.coupon.productCouponSearchData || {} ); @@ -137,6 +158,34 @@ const BuyOption = ({ const selectedPrdtId = propsSelectedPrdtId || productInfo?.prdtId; const isMockMode = BUYNOW_CONFIG.isMockMode(); + // ๐Ÿ”ด selectedPatnrId, selectedPrdtId ๋ณ€๊ฒฝ ๊ฐ์ง€ + useEffect(() => { + console.log('[BuyOption] ๐Ÿ”ด SELECTED IDS CHANGED:', { + selectedPatnrId, + selectedPrdtId, + propsSelectedPatnrId, + propsSelectedPrdtId, + }); + }, [selectedPatnrId, selectedPrdtId, propsSelectedPatnrId, propsSelectedPrdtId]); + + // ๐Ÿ” Redux ์ƒํƒœ์™€ ๊ณ„์‚ฐ๋œ ๊ฐ’ ํ™•์ธ + useEffect(() => { + console.log('[BuyOption] ๐Ÿ” REDUX STATE & CALCULATED VALUES:', { + isMockMode, + propsSelectedPatnrId, + propsSelectedPrdtId, + propsProductInfo: !!propsProductInfo, + reduxProductInfo: !!reduxProductInfo, + productInfo: !!productInfo, + reduxProductInfoPatnrId: productInfo?.patnrId, + reduxProductInfoPrdtId: productInfo?.prdtId, + finalSelectedPatnrId: selectedPatnrId, + finalSelectedPrdtId: selectedPrdtId, + reduxProductOptionInfos: reduxProductOptionInfos, + fullProductInfo: productInfo, + }); + }, [selectedPatnrId, selectedPrdtId, isMockMode, productInfo, reduxProductOptionInfos, reduxProductInfo, propsProductInfo]); + // Mock Mode์—์„œ ์˜ต์…˜ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ const productOptionInfos = useMemo(() => { console.log('[BuyOption] productOptionInfos useMemo - isMockMode:', isMockMode); @@ -402,8 +451,33 @@ const BuyOption = ({ // ํ•„์ˆ˜ ๋ฐ์ดํ„ฐ ๋กœ๋“œ (SingleOption๊ณผ ๋™์ผ) // Mock Mode: API ํ˜ธ์ถœ ์Šคํ‚ต (Mock ๋ฐ์ดํ„ฐ๋งŒ ์‚ฌ์šฉ) useEffect(() => { + // ๋””๋ฒ„๊ทธ ๋กœ๊ทธ: useEffect ์ง„์ž… + console.log('[BuyOption] ๐Ÿ“ DATA LOADING useEffect - Dependencies changed', { + isMockMode, + selectedPatnrId, + selectedPrdtId, + userNumber, + hasSelectedPatnrId: !!selectedPatnrId, + hasSelectedPrdtId: !!selectedPrdtId, + }); + // API Mode: ์‹ค์ œ API ํ˜ธ์ถœ if (!isMockMode) { + // โš ๏ธ ํ•„์ˆ˜ ๊ฐ’ ๊ฒ€์ฆ + if (!selectedPatnrId || !selectedPrdtId) { + console.warn('[BuyOption] โš ๏ธ [getProductOption] MISSING REQUIRED PARAMS', { + selectedPatnrId, + selectedPrdtId, + reason: 'selectedPatnrId or selectedPrdtId is missing', + }); + return; // API ํ˜ธ์ถœํ•˜์ง€ ์•Š์Œ + } + + console.log('[BuyOption] ๐Ÿ”„ [getProductOption] API CALL - Dispatching getProductOption', { + patnrId: selectedPatnrId, + prdtId: selectedPrdtId, + }); + dispatch( getProductOption({ patnrId: selectedPatnrId, @@ -411,6 +485,12 @@ const BuyOption = ({ }) ); + console.log('[BuyOption] ๐Ÿ”„ [getProductCouponSearch] API CALL - Dispatching getProductCouponSearch', { + patnrId: selectedPatnrId, + prdtId: selectedPrdtId, + mbrNo: userNumber, + }); + dispatch( getProductCouponSearch({ patnrId: selectedPatnrId, @@ -418,6 +498,11 @@ const BuyOption = ({ mbrNo: userNumber, }) ); + } else { + // Mock Mode ์ƒํƒœ ๋กœ๊ทธ + console.log('[BuyOption] ๐Ÿšซ Mock Mode Active - Skipping API calls'); + console.log('[BuyOption] ๐Ÿšซ [getProductOption] SKIPPED - Mock Mode enabled'); + console.log('[BuyOption] ๐Ÿšซ [getProductCouponSearch] SKIPPED - Mock Mode enabled'); } // Mock Mode: API ํ˜ธ์ถœ ํ•˜์ง€ ์•Š์Œ }, [dispatch, selectedPatnrId, selectedPrdtId, userNumber, isMockMode]); diff --git a/com.twin.app.shoptime/src/views/MainView/MainView.jsx b/com.twin.app.shoptime/src/views/MainView/MainView.jsx index f3bdffc7..69e112ea 100644 --- a/com.twin.app.shoptime/src/views/MainView/MainView.jsx +++ b/com.twin.app.shoptime/src/views/MainView/MainView.jsx @@ -167,7 +167,7 @@ export default function MainView({ className, initService }) { useEffect(() => { // TV ๋ฐฐํฌ์šฉ: Mock Mode ํ•˜๋“œ์ฝ”๋”ฉ ํ™œ์„ฑํ™” // ๋ชจ๋“  ์ƒํ’ˆ์—์„œ BUY NOW ๋ฒ„ํŠผ์ด ํ‘œ์‹œ๋จ - const mockMode = true; + const mockMode = false; // ๋ชจ๋“ˆ ๋ณ€์ˆ˜์— ์ €์žฅ (์ดํ›„ ProductAllSection ๋“ฑ์—์„œ ๋ฉ”๋ชจ๋ฆฌ์—์„œ๋งŒ ์ฝ์Œ) BUYNOW_CONFIG.init(mockMode);