From 761796a78529448b3f07c99dbd6ef33b4409b5d7 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Mon, 10 Nov 2025 10:59:15 +0900 Subject: [PATCH 01/26] =?UTF-8?q?[=EA=B5=AC=EB=A7=A4=20=EC=98=B5=EC=85=98?= =?UTF-8?q?=20=EB=85=B8=EC=B6=9C=EA=B4=80=EB=A0=A8=20=EC=B2=98=EB=A6=AC]?= =?UTF-8?q?=20#1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - option노출부분에서의 hasMockOption부분 제거 - checkout넘어갔을시에 목데이터 노출되는부분 변경. --- .../container/InformationContainer.jsx | 36 ++++++++++++++----- .../DetailPanel/components/BuyOption.jsx | 13 ++++--- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/com.twin.app.shoptime/src/views/CheckOutPanel/container/InformationContainer.jsx b/com.twin.app.shoptime/src/views/CheckOutPanel/container/InformationContainer.jsx index 5cbdfebc..ede5c703 100644 --- a/com.twin.app.shoptime/src/views/CheckOutPanel/container/InformationContainer.jsx +++ b/com.twin.app.shoptime/src/views/CheckOutPanel/container/InformationContainer.jsx @@ -1,27 +1,42 @@ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { + useCallback, + useEffect, + useMemo, + useState, +} from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { + useDispatch, + useSelector, +} from 'react-redux'; import Spotlight from '@enact/spotlight'; -import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; +import SpotlightContainerDecorator + from '@enact/spotlight/SpotlightContainerDecorator'; import Spottable from '@enact/spotlight/Spottable'; -import { setHidePopup, setShowPopup } from '../../../actions/commonActions'; +import { + setHidePopup, + setShowPopup, +} from '../../../actions/commonActions'; +import { sendLogTotalRecommend } from '../../../actions/logActions'; import { popPanel } from '../../../actions/panelActions'; import TButton from '../../../components/TButton/TButton'; import TPopUp from '../../../components/TPopUp/TPopUp'; import TQRCode from '../../../components/TQRCode/TQRCode'; import useScrollTo from '../../../hooks/useScrollTo'; import useScrollTopByDistance from '../../../hooks/useScrollTopByDistance'; +import { BUYNOW_CONFIG } from '../../../utils/BuyNowConfig'; import * as Config from '../../../utils/Config'; -import { $L, getQRCodeUrl } from '../../../utils/helperMethods'; +import { + $L, + getQRCodeUrl, +} from '../../../utils/helperMethods'; import BillingAddressCard from '../components/BillingAddressCard'; import PaymentCard from '../components/PaymentCard'; import ShippingAddressCard from '../components/ShippingAddressCard'; import Subject from '../components/Subject'; import css from './InformationContainer.module.less'; -import { sendLogTotalRecommend } from '../../../actions/logActions'; -import { BUYNOW_CONFIG } from '../../../utils/BuyNowConfig'; const Container = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div'); @@ -282,9 +297,12 @@ export default function InformationContainer({ ADD/EDIT {/* BillingAddressCard disabled due to infinite render loop in Mock Mode */} -
+ {/*
Mock Billing Address -
+
*/} + {checkoutData?.billingAddressList && ( + + )}
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 7894469b..827b1610 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/components/BuyOption.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/components/BuyOption.jsx @@ -33,7 +33,10 @@ import { popPanel, pushPanel, } from '../../../actions/panelActions'; -import { clearAllVideoTimers, finishVideoPreview } from '../../../actions/playActions'; +import { + clearAllVideoTimers, + finishVideoPreview, +} from '../../../actions/playActions'; import { getProductOption, getProductOptionId, @@ -463,7 +466,7 @@ const BuyOption = ({ }); // API Mode: 실제 API 호출 - if (!isMockMode) { + if (!isMockMode) { // ⚠️ 필수 값 검증 if (!selectedPatnrId || !selectedPrdtId) { console.warn('[BuyOption] ⚠️ [getProductOption] MISSING REQUIRED PARAMS', { @@ -550,7 +553,7 @@ const BuyOption = ({ if (response) { if (response.retCode === 0) { - // 🔍 조건 체크 + // 🔍 조건 체크 const isCardInfoNull = response.data.cardInfo === null; const isBillingAddressEmpty = response.data.billingAddressList.length === 0; const isShippingAddressEmpty = response.data.shippingAddressList.length === 0; @@ -623,7 +626,7 @@ const BuyOption = ({ response.retDetailCode, response.returnBindStrings ) - ); + ); dispatch(changeAppStatus({ isLoading: false })); return; } @@ -1405,7 +1408,7 @@ const BuyOption = ({ {/* 동적 옵션 렌더링 */} {productOptionInfos && productOptionInfos?.length > 0 && - (productInfo?.optProdYn === 'Y' || hasMockOptions) && ( + productInfo?.optProdYn === 'Y' && ( <> {/* 첫번째 옵션 (여러 옵션이 있을 때만) */} {productOptionInfos?.length > 1 && ( From 3e547df1a45b05b55442e63711d37692a6d66a37 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Mon, 10 Nov 2025 12:14:12 +0900 Subject: [PATCH 02/26] =?UTF-8?q?[=EA=B5=AC=EB=A7=A4=20=EC=98=B5=EC=85=98?= =?UTF-8?q?=20=EB=85=B8=EC=B6=9C=EA=B4=80=EB=A0=A8=20=EC=B2=98=EB=A6=AC]#2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - productallsection 에서 토스트 열렸을때 다시 열리는 부분 방지 처리. --- .../ProductAllSection/ProductAllSection.jsx | 52 +++++++++++-------- 1 file changed, 30 insertions(+), 22 deletions(-) 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 2447300b..8dc569be 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx @@ -185,6 +185,9 @@ export default function ProductAllSection({ const [isShowQRCode, setIsShowQRCode] = useState(true); const timerRef = useRef(null); + //구매 하단 토스트 노출 확인을 위한 용도 + const [openToast, setOpenToast] = useState(false); + // 모든 timeout/timer를 추적하기 위한 ref const timersRef = useRef([]); @@ -378,31 +381,36 @@ export default function ProductAllSection({ prdtNm: productData?.prdtNm, hasProductData: !!productData, }); - - dispatch( - showToast({ - id: productData.prdtId, - message: '', - type: 'buyOption', - duration: 0, - position: 'bottom-center', - // 🚀 BuyOption에 전달할 props 데이터 - productInfo: productData, - selectedPatnrId: productData?.patnrId, - selectedPrdtId: productData?.prdtId, - // BuyOption Toast가 닫힐 때 BUY NOW 버튼으로 포커스 복구 - onToastClose: () => { - setTimeout(() => { - Spotlight.focus('detail-buy-now-button'); - }, 100); - }, - }) - ); - }, [dispatch, productData]); + if(openToast === false){ + dispatch( + showToast({ + id: productData.prdtId, + message: '', + type: 'buyOption', + duration: 0, + position: 'bottom-center', + // 🚀 BuyOption에 전달할 props 데이터 + productInfo: productData, + selectedPatnrId: productData?.patnrId, + selectedPrdtId: productData?.prdtId, + // BuyOption Toast가 닫힐 때 BUY NOW 버튼으로 포커스 복구 + onToastClose: () => { + setTimeout(() => { + setOpenToast(false); + Spotlight.focus('detail-buy-now-button'); + }, 100); + }, + }) + ); + + setOpenToast(true); + } + }, [dispatch, productData, openToast]); //닫히도록 const handleCloseToast = useCallback(() => { - dispatch(clearAllToasts()) + dispatch(clearAllToasts()); + setOpenToast(false); },[dispatch]) // ADD TO CART 버튼 클릭 핸들러 From 11582840b88845f6a84af7f04a96560ca363feec Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Mon, 10 Nov 2025 16:17:51 +0900 Subject: [PATCH 03/26] =?UTF-8?q?[=ED=8F=AC=EC=9C=A0=20=EC=9E=91=EC=97=85]?= =?UTF-8?q?#1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - action, reducer 에 recommendProduct 관련 추가. - 로그 관련으로 Config에 pickedforyou추가 - homepanel pickforyou노출 건으로 추가. - homepanel getSubCategory에 파라미터 추가. - bestseller,pickedforyou노출 변경.(foru api에서 내려주는걸로) - subCategory 노출 변경. foru api에서 내려주는 아이템 2개 추가및 기존 데이터 중복시 제거. --- .../src/actions/mainActions.js | 33 ++++++++-- .../src/reducers/mainReducer.js | 7 +++ com.twin.app.shoptime/src/utils/Config.js | 1 + .../views/HomePanel/BestSeller/BestSeller.jsx | 52 ++++++++-------- .../src/views/HomePanel/HomePanel.jsx | 60 ++++++++++++++++--- .../HomePanel/PickedForYou/PickedForYou.jsx | 23 +++++-- .../HomePanel/SubCategory/SubCategory.jsx | 47 ++++++++------- 7 files changed, 156 insertions(+), 67 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/mainActions.js b/com.twin.app.shoptime/src/actions/mainActions.js index e1469564..448b4f1d 100644 --- a/com.twin.app.shoptime/src/actions/mainActions.js +++ b/com.twin.app.shoptime/src/actions/mainActions.js @@ -1,10 +1,18 @@ import { URLS } from '../api/apiConfig'; import { TAxios } from '../api/TAxios'; import { convertUtcToLocal } from '../components/MediaPlayer/util'; -import { CATEGORY_DATA_MAX_RESULTS_LIMIT, LOG_CONTEXT_NAME, LOG_MESSAGE_ID } from '../utils/Config'; +import { + CATEGORY_DATA_MAX_RESULTS_LIMIT, + LOG_CONTEXT_NAME, + LOG_MESSAGE_ID, +} from '../utils/Config'; import * as HelperMethods from '../utils/helperMethods'; import { types } from './actionTypes'; -import { addReservation, changeAppStatus, deleteReservation } from './commonActions'; +import { + addReservation, + changeAppStatus, + deleteReservation, +} from './commonActions'; //IF-LGSP-007 export const getMainLiveShow = (props) => (dispatch, getState) => { @@ -155,7 +163,7 @@ let lastSubCategoryParams = {}; export const getSubCategory = (params, pageNo = 1, key = null, clear = false) => (dispatch, getState) => { - const { lgCatCd, patnrIdList, tabType, filterType } = params; + const { lgCatCd, patnrIdList, tabType, filterType, recommendIncFlag } = params; let pageSize = params.pageSize || CATEGORY_DATA_MAX_RESULTS_LIMIT; if (pageNo === 1) { @@ -179,21 +187,34 @@ export const getSubCategory = if (pageNo === 1) { getSubCategoryKey = new Date(); currentKey = getSubCategoryKey; + + // ✅ recommendProduct 분리 + const { recommendProduct, ...restData } = response.data.data; + dispatch({ type: types.GET_SUB_CATEGORY, - payload: response.data.data, + payload: { + ...restData, + recommendProduct, + }, categoryParams: { lgCatCd, patnrIdList, tabType, filterType, + recommendIncFlag, pageSize, }, }); } else if (getSubCategoryKey === currentKey) { + const { recommendProduct, ...restData } = response.data.data; + dispatch({ type: types.GET_SUB_CATEGORY, - payload: response.data.data, + payload: { + ...restData, + recommendProduct, + }, append: true, startIndex: (pageNo - 1) * pageSize, }); @@ -212,7 +233,7 @@ export const getSubCategory = getState, 'get', URLS.GET_SUB_CATEGORY, - { lgCatCd, patnrIdList, pageSize, pageNo, tabType, filterType }, + { lgCatCd, patnrIdList, pageSize, pageNo, tabType, filterType,recommendIncFlag }, {}, onSuccess, onFail diff --git a/com.twin.app.shoptime/src/reducers/mainReducer.js b/com.twin.app.shoptime/src/reducers/mainReducer.js index a66815c7..8143b9f5 100644 --- a/com.twin.app.shoptime/src/reducers/mainReducer.js +++ b/com.twin.app.shoptime/src/reducers/mainReducer.js @@ -10,11 +10,13 @@ const initialState = { showDetailInfo: [], showNowInfo: null, featuredShowsInfos: {}, + recommendProduct: null, categoryParams: { lgCatCd: null, patnrIdList: null, tabType: null, filterType: null, + recommendIncFlag: null, pageSize: CATEGORY_DATA_MAX_RESULTS_LIMIT, }, }; @@ -39,6 +41,7 @@ export const mainReducer = (state = initialState, action) => { categoryFilterCd: action.payload.categoryFilterCd, topShowInfo: action.payload.topShowInfo, partnerInfos: action.payload.partnerInfos, + recommendProduct: action.payload.recommendProduct, categoryParams: action.categoryParams, }; } @@ -63,6 +66,7 @@ export const mainReducer = (state = initialState, action) => { categoryFilterCd: action.payload.categoryFilterCd, topShowInfo: action.payload.topShowInfo, partnerInfos: action.payload.partnerInfos, + recommendProduct: action.payload.recommendProduct, categoryParams: action.categoryParams, }; } @@ -93,6 +97,7 @@ export const mainReducer = (state = initialState, action) => { categoryFilterCd: action.payload.categoryFilterCd, topShowInfo: action.payload.topShowInfo, partnerInfos: action.payload.partnerInfos, + recommendProduct: action.payload.recommendProduct, }; } else { return { @@ -107,6 +112,7 @@ export const mainReducer = (state = initialState, action) => { categoryFilterCd: action.payload.categoryFilterCd, topShowInfo: action.payload.topShowInfo, partnerInfos: action.payload.partnerInfos, + recommendProduct: action.payload.recommendProduct, categoryParams: action.categoryParams, }; } @@ -206,6 +212,7 @@ export const mainReducer = (state = initialState, action) => { return { ...state, subCategoryData: {}, + recommendProduct: null, }; default: diff --git a/com.twin.app.shoptime/src/utils/Config.js b/com.twin.app.shoptime/src/utils/Config.js index 9be17c52..9a7d1fb7 100644 --- a/com.twin.app.shoptime/src/utils/Config.js +++ b/com.twin.app.shoptime/src/utils/Config.js @@ -292,6 +292,7 @@ export const LOG_MENU = { HOME_ON_SALE: 'Home/On Sale', HOME_POPULAR_SHOWS: 'Home/Popular Shows', HOME_BEST_SELLER: 'Home/Best Sellers', + HOME_PICKED_FOR_YOU: 'Home/Picked For You', TRENDING_NOW_POPULAR_SHOWS: 'Trending Now/Popular Shows', TRENDING_NOW_BEST_SELLER: 'Trending Now/Best Sellers', diff --git a/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx b/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx index 7b224278..6640e283 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx @@ -67,18 +67,33 @@ const BestSeller = ({ const { cursorVisible } = useSelector((state) => state.common.appStatus); - const bestSellerDatas = useSelector( - (state) => state.product.bestSellerData?.bestSeller - ); + + + const bestSellerNewDatas = useSelector( + (state) => + state.foryou?.justForYouInfo?.shelfInfos + ); + + const [drawChk, setDrawChk] = useState(false); const [firstChk, setFirstChk] = useState(0); + const [bestInfos, setBestInfos] = useState(null); + + useEffect(()=>{ + setBestInfos( + bestSellerNewDatas?.filter( + (item) => item.recommendTpCd === "BESTSELLER" + ) + ) + },[bestSellerNewDatas]) + const orderStyle = useMemo(() => ({ order: order }), [order]); - useEffect(() => { + useEffect(() => { setDrawChk(true); - }, [bestSellerDatas]); + }, [bestSellerNewDatas]); const handleCardClick = useCallback( (patnrId, prdtId) => () => { @@ -176,22 +191,7 @@ const BestSeller = ({ handleShelfFocus(); } }, [handleShelfFocus]); - - const [bestSellerNewData, setBestSellerNewData] = useState([]); - - const _randomProduct = useCallback(() => { - const randomChk = Math.round(Math.random()) === 0 ? false : true; - return randomChk; - }, []); - - useEffect(() => { - setBestSellerNewData( - bestSellerDatas?.map((item) => ({ - ...item, - // foryou: _randomProduct(), - })) - ); - }, [bestSellerDatas]); + return ( - {bestSellerNewData && - bestSellerNewData.map( + {bestInfos && + bestInfos?.[0].productInfos.map( ( { prdtId, @@ -226,7 +226,7 @@ const BestSeller = ({ offerInfo, brndNm, patncNm, - catNm, + //catNm, 없음 //foryou, euEnrgLblInfos, }, @@ -251,7 +251,7 @@ const BestSeller = ({ shelfTitle={shelfTitle} patnerName={patncNm} brandName={brndNm} - catNm={catNm} + // catNm={catNm} imageAlt={prdtId} imageSource={imgUrl} priceInfo={priceInfo} @@ -265,7 +265,7 @@ const BestSeller = ({ offerInfo={offerInfo} spotlightId={"bestsellerItem" + itemIndex} firstLabel={rankText} - label={itemIndex * 1 + 1 + " of " + bestSellerNewData.length} + label={itemIndex * 1 + 1 + " of " + bestInfos?.[0].productInfos.length} lastLabel=" go to detail, button" euEnrgLblInfos={euEnrgLblInfos} > diff --git a/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx b/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx index 091e5598..123fdc68 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx @@ -1,7 +1,17 @@ -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; import classNames from 'classnames'; -import { useDispatch, useSelector } from 'react-redux'; +import { + useDispatch, + useSelector, +} from 'react-redux'; +import { applyMiddleware } from 'redux'; import Spotlight from '@enact/spotlight'; import { @@ -23,20 +33,31 @@ import { getHomeMainContents, updateHomeInfo, } from '../../actions/homeActions'; -import { sendLogGNB, sendLogTotalRecommend } from '../../actions/logActions'; -import { getSubCategory, getTop20Show } from '../../actions/mainActions'; +import { + sendLogGNB, + sendLogTotalRecommend, +} from '../../actions/logActions'; +import { + getSubCategory, + getTop20Show, +} from '../../actions/mainActions'; import { getHomeOnSaleInfo } from '../../actions/onSaleActions'; -import { finishVideoPreview, shrinkVideoTo1px, expandVideoFrom1px } from '../../actions/playActions'; import { updatePanel } from '../../actions/panelActions'; +import { + expandVideoFrom1px, + finishVideoPreview, + shrinkVideoTo1px, +} from '../../actions/playActions'; import { getBestSeller } from '../../actions/productActions'; import TBody from '../../components/TBody/TBody'; import TButton, { TYPES } from '../../components/TButton/TButton'; import TPanel from '../../components/TPanel/TPanel'; import TPopUp from '../../components/TPopUp/TPopUp'; -import TVerticalPagenator from '../../components/TVerticalPagenator/TVerticalPagenator'; +import TVerticalPagenator + from '../../components/TVerticalPagenator/TVerticalPagenator'; import useDebugKey from '../../hooks/useDebugKey'; -import usePrevious from '../../hooks/usePrevious'; import { useFocusHistory } from '../../hooks/useFocusHistory/useFocusHistory'; +import usePrevious from '../../hooks/usePrevious'; import { useVideoPlay } from '../../hooks/useVideoPlay/useVideoPlay'; import { useVideoMove } from '../../hooks/useVideoTransition/useVideoMove'; import { @@ -55,7 +76,7 @@ import css from '../HomePanel/HomePanel.module.less'; import PopularShow from '../HomePanel/PopularShow/PopularShow'; import SubCategory from '../HomePanel/SubCategory/SubCategory'; import EventPopUpBanner from './EventPopUpBanner/EventPopUpBanner'; -import { applyMiddleware } from 'redux'; +import PickedForYou from './PickedForYou/PickedForYou'; export const TEMPLATE_CODE_CONF = { TOP: 'DSP00101', @@ -63,6 +84,7 @@ export const TEMPLATE_CODE_CONF = { ON_SALE: 'DSP00103', POPULAR_SHOW: 'DSP00104', BEST_SELLER: 'DSP00105', + PICK_FOR_YOU: 'DSP00106', }; const HomePanel = ({ isOnTop }) => { @@ -251,6 +273,9 @@ const HomePanel = ({ isOnTop }) => { case TEMPLATE_CODE_CONF.BEST_SELLER: nowMenu = LOG_MENU.HOME_BEST_SELLER; break; + case TEMPLATE_CODE_CONF.PICK_FOR_YOU: + nowMenu = LOG_MENU.HOME_PICKED_FOR_YOU; + break; default: nowMenu = LOG_MENU.HOME_TOP; break; @@ -384,6 +409,24 @@ const HomePanel = ({ isOnTop }) => { ); } else break; } + case TEMPLATE_CODE_CONF.PICK_FOR_YOU: { + if (bestSellerDatas && bestSellerDatas.length > 0) { + return ( + + ); + } else break; + } } })} {loadingComplete && sortedHomeLayoutInfo && sortedHomeLayoutInfo.length > 0 && ( @@ -593,6 +636,7 @@ const HomePanel = ({ isOnTop }) => { pageSize: 10, tabType: 'CAT00102', filterType: 'CAT00202', + recommendIncFlag: 'Y', }, 1 ) diff --git a/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx b/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx index 9dbb6e57..f53a0f0a 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx @@ -52,7 +52,7 @@ const PickedForYou = ({ shelfLocation, shelfTitle, }) => { - console.log("###Test pjh 여기지 ?"); + const { getScrollTo, scrollLeft } = useScrollTo(); const { handleScrollReset, handleStopScrolling } = useScrollReset( scrollLeft, @@ -67,11 +67,26 @@ const PickedForYou = ({ (state) => state.product.bestSellerData?.bestSeller ); + const justForYouDatasNew = useSelector( + (state) => state.foryou?.justForYouInfo?.shelfInfos + ) + + const [drawChk, setDrawChk] = useState(false); const [firstChk, setFirstChk] = useState(0); + const [pickedForYou, setPickedForYou] = useState(null); + const orderStyle = useMemo(() => ({ order: order }), [order]); + useEffect(()=>{ + setPickedForYou( + justForYouDatasNew?.filter( + (item) => item.recommendTpCd === "PICKEDFORYOU" + ) + ) + },[justForYouDatasNew]) + useEffect(() => { setDrawChk(true); }, [justForYouDatas]); @@ -193,8 +208,8 @@ const PickedForYou = ({ cbScrollTo={getScrollTo} noScrollByWheel > - {justForYouDatas && - justForYouDatas.map( + {pickedForYou && + pickedForYou?.[0].productInfos.map( ( { prdtId, @@ -233,7 +248,7 @@ const PickedForYou = ({ onClick={handleCardClick(patnrId, prdtId)} offerInfo={offerInfo} spotlightId={"bestsellerItem" + itemIndex} - label={itemIndex * 1 + 1 + " of " + justForYouDatas.length} + label={itemIndex * 1 + 1 + " of " + pickedForYou?.[0].productInfos.length} lastLabel=" go to detail, button" /> ); diff --git a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx index f366aac2..16d31437 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx @@ -71,6 +71,10 @@ export default memo(function SubCategory({ (state) => state.main.subCategoryData?.categoryItemInfos ); + const foruItemInfos = useSelector( + (state) => state.main.recommendProduct[0]?.productInfos + ); + const nowMenu = useSelector((state) => state.common.menu.nowMenu); const [currentLgCatCd, setCurrentLgCatCd] = useState(catCd ? catCd : null); @@ -110,6 +114,7 @@ export default memo(function SubCategory({ pageSize: "10", tabType: "CAT00102", filterType: "CAT00202", + recommendIncFlag: 'Y', }, 1 ) @@ -222,27 +227,23 @@ export default memo(function SubCategory({ } }, [handleShelfFocus]); - const _randomProduct = useCallback(() => { - const randomChk = Math.round(Math.random()) === 0 ? false : true; - return randomChk; - }, []); - useEffect(() => { - setCategoryItemNewData( - categoryItemInfos?.subCatItemList?.map((item) => ({ - ...item, - foryou: _randomProduct(), - })) - ); - }, [categoryItemInfos?.subCatItemList]); - - useEffect(() => { - dispatch( - getRecentlySawItem( - categoryItemNewData.filter((item) => item.foryou === true) - ) - ); - }, [categoryItemNewData, dispatch]); + const recommendedData = foruItemInfos?.slice(0, 2).map((item) => ({ + ...item, + foryou: true, + })) || []; + + const recommendedPrdtIds = new Set(recommendedData.map(item => item.prdtId)); + + const baseData = categoryItemInfos?.subCatItemList?.filter( + (item) => !recommendedPrdtIds.has(item.prdtId) + ).map((item) => ({ + ...item, + foryou: false, + })) || []; + + setCategoryItemNewData([...recommendedData, ...baseData]); + }, [categoryItemInfos?.subCatItemList, foruItemInfos]); return ( { @@ -367,7 +368,7 @@ export default memo(function SubCategory({ } lastLabel=" go to detail, button" > - {/* {foryou === true && } */} + {foryou === true && } ); } From 0050f9043cba1746e0c1aebbcc7741e2b9de1679 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Mon, 10 Nov 2025 16:23:22 +0900 Subject: [PATCH 04/26] =?UTF-8?q?[=ED=8F=AC=EC=9C=A0=20=EC=9E=91=EC=97=85]?= =?UTF-8?q?#2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 롤링유닛에서 노출 관련 수정. --- .../src/views/HomePanel/HomeBanner/RollingUnit.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RollingUnit.jsx b/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RollingUnit.jsx index 185f058e..61ea8efb 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RollingUnit.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RollingUnit.jsx @@ -107,7 +107,7 @@ export default function RollingUnit({ const nowMenu = useSelector((state) => state.common.menu.nowMenu); const entryMenu = useSelector((state) => state.common.menu.entryMenu); const introTermsAgree = useSelector( - (state) => state.common.termsFlag.optionalTerms + (state) => state.common.optionalTermsAgree ); const homeCategory = useSelector( (state) => state.home.menuData?.data?.homeCategory @@ -120,7 +120,7 @@ export default function RollingUnit({ // 컴포넌트 상단에서 필터링 const filteredRollingData = useMemo(() => { return rollingData.filter( - (item) => introTermsAgree === "Y" || item.shptmLnkTpCd !== "DSP00510" + (item) => introTermsAgree === true || item.shptmLnkTpCd !== "DSP00510" ); }, [rollingData, introTermsAgree]); From bde1fb4eef5a1aba9fee317d253018e552e21376 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Mon, 10 Nov 2025 19:31:07 +0900 Subject: [PATCH 05/26] =?UTF-8?q?[=ED=8F=AC=EC=9C=A0=20=EC=9E=91=EC=97=85]?= =?UTF-8?q?#3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - foryouaction,reducer 받는부분 변경 및 추가 . - 베스트셀러,픽포유,파퓰러쇼,저스트포유패널 노출 변경 및 수정 작업 - 홈배너 데이터 불러오는부분 수정 및 변경. --- .../src/actions/actionTypes.js | 1 + .../src/actions/forYouActions.js | 31 +++++++++ com.twin.app.shoptime/src/api/apiConfig.js | 2 + .../src/reducers/forYouReducer.js | 6 ++ .../views/HomePanel/BestSeller/BestSeller.jsx | 33 +++++++-- .../views/HomePanel/HomeBanner/HomeBanner.jsx | 8 +-- .../HomePanel/PickedForYou/PickedForYou.jsx | 9 +-- .../HomePanel/PopularShow/PopularShow.jsx | 67 ++++++++++++------- .../JustForYouTestPanel.jsx | 42 +++++------- 9 files changed, 132 insertions(+), 67 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/actionTypes.js b/com.twin.app.shoptime/src/actions/actionTypes.js index ba5f877d..fe993c2b 100644 --- a/com.twin.app.shoptime/src/actions/actionTypes.js +++ b/com.twin.app.shoptime/src/actions/actionTypes.js @@ -313,6 +313,7 @@ export const types = { GET_LIKE_BRAND_PRODUCT: 'GET_LIKE_BRAND_PRODUCT', GET_MORE_TO_CONCIDER_AT_THIS_PRICE: 'GET_MORE_TO_CONCIDER_AT_THIS_PRICE', GET_JUSTFORYOU_INFO: 'GET_JUSTFORYOU_INFO', + JUSTFORYOU: 'JUSTFORYOU', // 🔽 Voice Conductor 관련 액션 타입 VOICE_REGISTER_SUCCESS: 'VOICE_REGISTER_SUCCESS', diff --git a/com.twin.app.shoptime/src/actions/forYouActions.js b/com.twin.app.shoptime/src/actions/forYouActions.js index 5844d7df..2caa8c99 100644 --- a/com.twin.app.shoptime/src/actions/forYouActions.js +++ b/com.twin.app.shoptime/src/actions/forYouActions.js @@ -54,3 +54,34 @@ export const getJustForYouInfo = (callback) => (dispatch, getState) => { onFail ); }; + +export const justForYou = (callback) => (dispatch, getState) => { + const macAddress = getState().common.macAddress; + const macAddr = macAddress?.wired || macAddress?.wifi || "00:1A:2B:3C:4D:5E"; + const onSuccess = (response) => { + console.log("JustForYou onSuccess", response.data); + dispatch({ + type: types.JUSTFORYOU, + payload: get("data.data", response), + }); + dispatch(changeAppStatus({ showLoadingPanel: { show: false } })); + callback && callback(); + }; + + const onFail = (error) => { + console.error("JustForYou onFail", error); + dispatch(changeAppStatus({ showLoadingPanel: { show: false } })); + callback && callback(); + }; + + TAxios( + dispatch, + getState, + "post", + URLS.JUSTFORYOU, + {}, + {macAddr}, + onSuccess, + onFail + ); +}; diff --git a/com.twin.app.shoptime/src/api/apiConfig.js b/com.twin.app.shoptime/src/api/apiConfig.js index b8e8d15f..270e3f98 100644 --- a/com.twin.app.shoptime/src/api/apiConfig.js +++ b/com.twin.app.shoptime/src/api/apiConfig.js @@ -143,6 +143,8 @@ export const URLS = { // foryou controller GET_JUSTFORYOU_INFO: "/lgsp/v1/justforyou/list.lge", + JUSTFORYOU: "/lgsp/v1/recommend/justforyou.lge", + // emp controller GET_SHOPTIME_TERMS: "/lgsp/v1/emp/shoptime/terms.lge", diff --git a/com.twin.app.shoptime/src/reducers/forYouReducer.js b/com.twin.app.shoptime/src/reducers/forYouReducer.js index c899f5d4..ffa540a3 100644 --- a/com.twin.app.shoptime/src/reducers/forYouReducer.js +++ b/com.twin.app.shoptime/src/reducers/forYouReducer.js @@ -13,6 +13,7 @@ import { // }; const initialState = { justForYouInfo: {}, + recommendInfo: {}, }; // const foryouReducer = (state = initialState, action) => { @@ -47,8 +48,13 @@ const justForYouInfo = curry((state, action) => set("justForYouInfo", get("payload", action), state) ); +const recommendInfo = curry((state, action) => + set("recommendInfo", get("payload", action), state) +); + const handlers = { [types.GET_JUSTFORYOU_INFO]: justForYouInfo, + [types.JUSTFORYOU]: recommendInfo, }; export const foryouReducer = (state = initialState, action = {}) => { diff --git a/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx b/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx index 6640e283..ad163fd4 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx @@ -67,11 +67,13 @@ const BestSeller = ({ const { cursorVisible } = useSelector((state) => state.common.appStatus); - + const bestSellerDatas = useSelector( + (state) => state.product.bestSellerData?.bestSeller + ); const bestSellerNewDatas = useSelector( (state) => - state.foryou?.justForYouInfo?.shelfInfos + state.foryou?.recommendInfo?.recommendProduct ); @@ -80,6 +82,7 @@ const BestSeller = ({ const [firstChk, setFirstChk] = useState(0); const [bestInfos, setBestInfos] = useState(null); + const [bestItemNewData, setBestItemNewData] = useState([]); useEffect(()=>{ setBestInfos( @@ -89,6 +92,24 @@ const BestSeller = ({ ) },[bestSellerNewDatas]) + useEffect(() => { + const recommendedData = bestInfos?.[0].productInfos?.slice(0, 2).map((item) => ({ + ...item, + foryou: true, + })) || []; + + const recommendedPrdtIds = new Set(recommendedData.map(item => item.prdtId)); + + const baseData = bestSellerDatas?.filter( + (item) => !recommendedPrdtIds.has(item.prdtId) + ).map((item) => ({ + ...item, + foryou: false, + })) || []; + + setBestItemNewData([...recommendedData, ...baseData]); + }, [bestSellerDatas, bestInfos?.[0].productInfos]); + const orderStyle = useMemo(() => ({ order: order }), [order]); useEffect(() => { @@ -213,8 +234,8 @@ const BestSeller = ({ cbScrollTo={getScrollTo} noScrollByWheel > - {bestInfos && - bestInfos?.[0].productInfos.map( + {bestItemNewData && + bestItemNewData.map( ( { prdtId, @@ -227,7 +248,7 @@ const BestSeller = ({ brndNm, patncNm, //catNm, 없음 - //foryou, + foryou, euEnrgLblInfos, }, itemIndex @@ -269,7 +290,7 @@ const BestSeller = ({ lastLabel=" go to detail, button" euEnrgLblInfos={euEnrgLblInfos} > - {/* {foryou === true && } */} + {foryou === true && } ); } diff --git a/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/HomeBanner.jsx b/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/HomeBanner.jsx index 182bf392..b57ed8e3 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/HomeBanner.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/HomeBanner.jsx @@ -28,7 +28,7 @@ import { setOptionalTermsUserDecision, updateOptionalTermsAgreement, } from '../../../actions/commonActions'; -import { getJustForYouInfo } from '../../../actions/forYouActions'; +import { justForYou } from '../../../actions/forYouActions'; import { fetchCurrentUserHomeTerms, setDefaultFocus, @@ -39,11 +39,11 @@ import { pushPanel, } from '../../../actions/panelActions'; import { + clearAllVideoTimers, releasePlayControl, requestPlayControl, startVideoPlayer, startVideoPlayerNew, - clearAllVideoTimers, } from '../../../actions/playActions'; import CustomImage from '../../../components/CustomImage/CustomImage'; // import TButtonScroller from "../../../components/TButtonScroller/TButtonScroller"; @@ -82,8 +82,8 @@ export default function HomeBanner({ handleShelfFocus, }) { const dispatch = useDispatch(); - useEffect(() => { - dispatch(getJustForYouInfo()); + useEffect(() => { + dispatch(justForYou()); }, [dispatch]); const homeTopDisplayInfo = useSelector( (state) => state.home.homeTopDisplayInfo diff --git a/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx b/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx index f53a0f0a..540935d3 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx @@ -63,14 +63,9 @@ const PickedForYou = ({ const { cursorVisible } = useSelector((state) => state.common.appStatus); - const justForYouDatas = useSelector( - (state) => state.product.bestSellerData?.bestSeller - ); - const justForYouDatasNew = useSelector( - (state) => state.foryou?.justForYouInfo?.shelfInfos + (state) => state.foryou?.recommendInfo?.recommendProduct ) - const [drawChk, setDrawChk] = useState(false); const [firstChk, setFirstChk] = useState(0); @@ -89,7 +84,7 @@ const PickedForYou = ({ useEffect(() => { setDrawChk(true); - }, [justForYouDatas]); + }, [justForYouDatasNew]); const handleCardClick = useCallback( (patnrId, prdtId) => () => { diff --git a/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx b/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx index 7e5e80f7..a677a14e 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx @@ -71,17 +71,48 @@ const PopularShow = ({ const { cursorVisible } = useSelector((state) => state.common.appStatus); const topInfos = useSelector((state) => state.main.top20ShowData.topInfos); + const recommendInfo = useSelector((state) => state.foryou?.recommendInfo?.recommendShow); + - const [drawChk, setDrawChk] = useState(false); const orderStyle = useMemo(() => ({ order: order }), [order]); - + const [drawChk, setDrawChk] = useState(false); const [firstChk, setFirstChk] = useState(0); + const [showInfos, setShowInfos] = useState(null); + const [showNewInfos, setShowNewInfos] = useState([]); + useEffect(() => { - setDrawChk(true); + setDrawChk(true); }, [topInfos]); + useEffect(()=>{ + setShowInfos( + recommendInfo?.filter( + (item) => item.recommendTpCd === "POPULARSHOW" + ) + ) + },[recommendInfo]) + + useEffect(() => { + const recommendedData = showInfos?.[0].showInfos?.slice(0, 2).map((item) => ({ + ...item, + foryou: true, + })) || []; + + const recommendedPrdtIds = new Set(recommendedData?.map(item => item.showId)); + + const baseData = topInfos?.filter( + (item) => !recommendedPrdtIds.has(item.showId) + ).map((item) => ({ + ...item, + foryou: false, + })) || []; + setShowNewInfos([...recommendedData, ...baseData]); + }, [topInfos, showInfos?.[0].showInfos]); + + + const handleCardClick = useCallback( (patnrId, showId, catCd, showUrl) => () => { dispatch( @@ -187,23 +218,7 @@ const PopularShow = ({ if (handleShelfFocus) { handleShelfFocus(); } - }, [handleShelfFocus]); - - const [topInfosNewData, setTopInfosNewData] = useState([]); - - const _randomProduct = useCallback(() => { - const randomChk = Math.round(Math.random()) === 0 ? false : true; - return randomChk; - }, []); - - useEffect(() => { - setTopInfosNewData( - topInfos?.map((item) => ({ - ...item, - // foryou: _randomProduct(), - })) - ); - }, [topInfos]); + }, [handleShelfFocus]); return ( - {topInfosNewData && - topInfosNewData.map( + {showNewInfos && + showNewInfos.map( ( { showId, @@ -240,7 +255,7 @@ const PopularShow = ({ patncNm, catCd, showUrl, - //foryou, + foryou, }, itemIndex ) => { @@ -258,9 +273,11 @@ const PopularShow = ({ contentId={showId} contentTitle={showNm} imageSource={ + (thumbnailUrl && thumbnailUrl960) ? thumbnailUrl !== thumbnailUrl960 ? thumbnailUrl960 : thumbnailUrl + : thumbnailUrl } imageAlt={showNm} productName={showNm} @@ -277,10 +294,10 @@ const PopularShow = ({ onBlur={handleBlur(itemIndex)} onClick={handleCardClick(patnrId, showId, catCd, showUrl)} firstLabel={patncNm + " "} - label={itemIndex * 1 + 1 + " of " + topInfos.length} + label={itemIndex * 1 + 1 + " of " + showNewInfos.length} lastLabel=" go to detail, button" > - {/* {foryou === true && } */} + {foryou === true && } ); } diff --git a/com.twin.app.shoptime/src/views/JustForYouTestPanel/JustForYouTestPanel.jsx b/com.twin.app.shoptime/src/views/JustForYouTestPanel/JustForYouTestPanel.jsx index 3ebef3e9..b9d5e928 100644 --- a/com.twin.app.shoptime/src/views/JustForYouTestPanel/JustForYouTestPanel.jsx +++ b/com.twin.app.shoptime/src/views/JustForYouTestPanel/JustForYouTestPanel.jsx @@ -47,11 +47,11 @@ const JustForYouTestPanel = ({ panelInfo, ...rest }) => { const cbChangePageRef = useRef(null); const shelfInfos = useSelector( - (state) => state.foryou?.justForYouInfo?.shelfInfos + (state) => state.foryou?.recommendInfo?.recommendProduct ); const justForYouInfo = useSelector( - (state) => state.foryou?.justForYouInfo?.justForYouInfo + (state) => state.foryou?.recommendInfo?.justForYouInfo ); const onClick = useCallback(() => { @@ -80,25 +80,19 @@ const JustForYouTestPanel = ({ panelInfo, ...rest }) => { } const product = productInfos[index]; - const { - contentId, - title, - thumbnail, - price, - dcPrice, - partnerName, - partnerLogo, + const { + prdtNm, + imgUrl, + priceInfo, + patncNm, + patnrId, + prdtId, } = product; const handleItemClick = () => { - // Extract product ID from contentId if needed - const tokens = contentId.split("_"); - const patnrId = tokens?.[4] || ""; - const prdtId = tokens?.[5] || ""; dispatch( pushPanel({ - name: panel_names.DETAIL_PANEL, - // panelInfo: { prdtId: contentId }, + name: panel_names.DETAIL_PANEL, panelInfo: { patnrId: patnrId, prdtId: prdtId, @@ -109,16 +103,14 @@ const JustForYouTestPanel = ({ panelInfo, ...rest }) => { return ( { key={shelf.shelfId} className={classNames( css.itemsContainer, - shelfIndex === 0 && css.itemsContinerFirst + shelfIndex === 1 && css.itemsContinerFirst )} spotlightId={`justForYouList_${shelf.shelfExpsOrd}`} data-wheel-point From d0e6b9f0bb263be3d699001536838b27afb784a3 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Mon, 10 Nov 2025 19:35:48 +0900 Subject: [PATCH 06/26] =?UTF-8?q?[=ED=8F=AC=EC=9C=A0=20=EC=9E=91=EC=97=85]?= =?UTF-8?q?#4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 이전 justforyou관련 삭제 --- .../src/actions/actionTypes.js | 6 +-- .../src/actions/forYouActions.js | 53 +------------------ com.twin.app.shoptime/src/api/apiConfig.js | 3 +- .../src/reducers/forYouReducer.js | 40 -------------- .../HomePanel/SubCategory/SubCategory.jsx | 1 - 5 files changed, 3 insertions(+), 100 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/actionTypes.js b/com.twin.app.shoptime/src/actions/actionTypes.js index fe993c2b..2cc6e5a3 100644 --- a/com.twin.app.shoptime/src/actions/actionTypes.js +++ b/com.twin.app.shoptime/src/actions/actionTypes.js @@ -308,11 +308,7 @@ export const types = { SET_MODAL_BORDER: 'SET_MODAL_BORDER', SET_BANNER_VISIBILITY: 'SET_BANNER_VISIBILITY', - // 🔽 [추가] JustForYou 상품 관리 부분 - GET_RECENTLY_SAW_ITEM: 'GET_RECENTLY_SAW_ITEM', - GET_LIKE_BRAND_PRODUCT: 'GET_LIKE_BRAND_PRODUCT', - GET_MORE_TO_CONCIDER_AT_THIS_PRICE: 'GET_MORE_TO_CONCIDER_AT_THIS_PRICE', - GET_JUSTFORYOU_INFO: 'GET_JUSTFORYOU_INFO', + // 🔽 [추가] JustForYou 상품 관리 부분 JUSTFORYOU: 'JUSTFORYOU', // 🔽 Voice Conductor 관련 액션 타입 diff --git a/com.twin.app.shoptime/src/actions/forYouActions.js b/com.twin.app.shoptime/src/actions/forYouActions.js index 2caa8c99..18445341 100644 --- a/com.twin.app.shoptime/src/actions/forYouActions.js +++ b/com.twin.app.shoptime/src/actions/forYouActions.js @@ -1,60 +1,9 @@ import { URLS } from '../api/apiConfig'; import { TAxios } from '../api/TAxios'; -import { - curry, - get, - set, -} from '../utils/fp'; +import { get } from '../utils/fp'; import { types } from './actionTypes'; import { changeAppStatus } from './commonActions'; -// 최근 본 아이템 관련 액션 -export const getRecentlySawItem = (data) => ({ - type: types.GET_RECENTLY_SAW_ITEM, - payload: data, -}); - -// 좋아하는 브랜드 제품 관련 액션 -export const getLikeBrandProduct = (data) => ({ - type: types.GET_LIKE_BRAND_PRODUCT, - payload: data, -}); - -// 이 가격대에서 고려할 만한 더 많은 제품 관련 액션 -export const getMoreToConciderAtThisPrice = (data) => ({ - type: types.GET_MORE_TO_CONCIDER_AT_THIS_PRICE, - payload: data, -}); - -export const getJustForYouInfo = (callback) => (dispatch, getState) => { - const onSuccess = (response) => { - console.log("getJustForYouInfo onSuccess", response.data); - dispatch({ - type: types.GET_JUSTFORYOU_INFO, - payload: get("data.data", response), - }); - dispatch(changeAppStatus({ showLoadingPanel: { show: false } })); - callback && callback(); - }; - - const onFail = (error) => { - console.error("getJustForYouInfo onFail", error); - dispatch(changeAppStatus({ showLoadingPanel: { show: false } })); - callback && callback(); - }; - - TAxios( - dispatch, - getState, - "get", - URLS.GET_JUSTFORYOU_INFO, - {}, - {}, - onSuccess, - onFail - ); -}; - export const justForYou = (callback) => (dispatch, getState) => { const macAddress = getState().common.macAddress; const macAddr = macAddress?.wired || macAddress?.wifi || "00:1A:2B:3C:4D:5E"; diff --git a/com.twin.app.shoptime/src/api/apiConfig.js b/com.twin.app.shoptime/src/api/apiConfig.js index 270e3f98..f37d181d 100644 --- a/com.twin.app.shoptime/src/api/apiConfig.js +++ b/com.twin.app.shoptime/src/api/apiConfig.js @@ -141,8 +141,7 @@ export const URLS = { UPDATE_ORDER_PARTIAL_CANCEL: "/lgsp/v1/myinfo/order/orderPartialCancel.lge", PAYMENT_TOTAL_CANCEL: "/lgsp/v1/myinfo/order/paymentTotalCancel.lge", - // foryou controller - GET_JUSTFORYOU_INFO: "/lgsp/v1/justforyou/list.lge", + // foryou controller JUSTFORYOU: "/lgsp/v1/recommend/justforyou.lge", diff --git a/com.twin.app.shoptime/src/reducers/forYouReducer.js b/com.twin.app.shoptime/src/reducers/forYouReducer.js index ffa540a3..bdd344c6 100644 --- a/com.twin.app.shoptime/src/reducers/forYouReducer.js +++ b/com.twin.app.shoptime/src/reducers/forYouReducer.js @@ -5,55 +5,15 @@ import { set, } from '../utils/fp'; -// 초기 상태 정의 -// const initialState = { -// recentlySawItems: [], -// likeBrandProducts: [], -// moreToConciderAtThisPrice: [], -// }; const initialState = { - justForYouInfo: {}, recommendInfo: {}, }; -// const foryouReducer = (state = initialState, action) => { -// switch (action.type) { -// // 최근 본 아이템 -// case types.GET_RECENTLY_SAW_ITEM: -// return { -// ...state, -// recentlySawItems: action.payload, -// }; - -// // 좋아하는 브랜드 제품 -// case types.GET_LIKE_BRAND_PRODUCT: -// return { -// ...state, -// likeBrandProducts: action.payload, -// }; - -// // 이 가격대에서 고려할 만한 더 많은 제품 -// case types.GET_MORE_TO_CONCIDER_AT_THIS_PRICE: -// return { -// ...state, -// moreToConciderAtThisPrice: action.payload, -// }; - -// default: -// return state; -// } -// }; - -const justForYouInfo = curry((state, action) => - set("justForYouInfo", get("payload", action), state) -); - const recommendInfo = curry((state, action) => set("recommendInfo", get("payload", action), state) ); const handlers = { - [types.GET_JUSTFORYOU_INFO]: justForYouInfo, [types.JUSTFORYOU]: recommendInfo, }; diff --git a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx index 16d31437..8a58ac48 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx @@ -16,7 +16,6 @@ import { import Spottable from '@enact/spotlight/Spottable'; import { setContainerLastFocusedElement } from '@enact/spotlight/src/container'; -import { getRecentlySawItem } from '../../../actions/forYouActions'; import { sendLogCuration } from '../../../actions/logActions'; import { getSubCategory } from '../../../actions/mainActions'; import { pushPanel } from '../../../actions/panelActions'; From 5700ff8de32532e5859a7414cab1893333aa7408 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Mon, 10 Nov 2025 19:51:36 +0900 Subject: [PATCH 07/26] =?UTF-8?q?[=EC=97=90=EB=84=88=EC=A7=80=20=EB=9D=BC?= =?UTF-8?q?=EB=B2=A8]#1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 빠진곳 추가. --- .../src/views/HomePanel/PickedForYou/PickedForYou.jsx | 2 ++ .../src/views/HomePanel/SubCategory/SubCategory.jsx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx b/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx index 540935d3..24097ef1 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx @@ -217,6 +217,7 @@ const PickedForYou = ({ brndNm, patncNm, catNm, + euEnrgLblInfos, }, itemIndex ) => { @@ -245,6 +246,7 @@ const PickedForYou = ({ spotlightId={"bestsellerItem" + itemIndex} label={itemIndex * 1 + 1 + " of " + pickedForYou?.[0].productInfos.length} lastLabel=" go to detail, button" + euEnrgLblInfos={euEnrgLblInfos} /> ); } diff --git a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx index 8a58ac48..d7b12e44 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx @@ -333,6 +333,7 @@ export default memo(function SubCategory({ brndNm, patncNm, foryou, + euEnrgLblInfos, }, itemIndex ) => { @@ -366,6 +367,7 @@ export default memo(function SubCategory({ categoryItemInfos?.subCatItemList.length } lastLabel=" go to detail, button" + euEnrgLblInfos={euEnrgLblInfos} > {foryou === true && } From 7a5627d213d0a16c7df178c5aa2e751607ed814c Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Mon, 10 Nov 2025 19:59:59 +0900 Subject: [PATCH 08/26] =?UTF-8?q?[=EC=97=90=EB=9F=AC=EC=88=98=EC=A0=95]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Pickforyou titemcard -> titemcardnew 변경 --- .../HomePanel/PickedForYou/PickedForYou.jsx | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx b/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx index 24097ef1..b6f3ccf4 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/PickedForYou/PickedForYou.jsx @@ -16,12 +16,9 @@ import { } from '@enact/spotlight/SpotlightContainerDecorator'; import Spottable from '@enact/spotlight/Spottable'; -import { - pushPanel, - updatePanel, -} from '../../../actions/panelActions'; +import { pushPanel } from '../../../actions/panelActions'; import SectionTitle from '../../../components/SectionTitle/SectionTitle'; -import TItemCard from '../../../components/TItemCard/TItemCard'; +import TItemCardNew from '../../../components/TItemCard/TItemCard.new'; import TScroller from '../../../components/TScroller/TScroller'; import useScrollReset from '../../../hooks/useScrollReset'; import useScrollTo from '../../../hooks/useScrollTo'; @@ -30,10 +27,7 @@ import { LOG_MESSAGE_ID, panel_names, } from '../../../utils/Config'; -import { - $L, - scaleW, -} from '../../../utils/helperMethods'; +import { $L } from '../../../utils/helperMethods'; import { SpotlightIds } from '../../../utils/SpotlightIds'; import css from './PickedForYou.module.less'; @@ -204,25 +198,25 @@ const PickedForYou = ({ noScrollByWheel > {pickedForYou && + pickedForYou?.[0] && pickedForYou?.[0].productInfos.map( ( { prdtId, imgUrl, priceInfo, - prdtNm, - rankOrd, + prdtNm, patnrId, offerInfo, brndNm, patncNm, catNm, - euEnrgLblInfos, + euEnrgLblInfos }, itemIndex ) => { return ( - Date: Tue, 11 Nov 2025 10:54:33 +0900 Subject: [PATCH 09/26] =?UTF-8?q?[=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88]=20?= =?UTF-8?q?=EA=B8=88=EC=95=A1=20=EB=85=B8=EC=B6=9C=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 계산했을때 맞지않던 부분, 옵션가 노출관련 처리. - 사이드바 부분에서도 계산 맞지않던 부분에 대하여 수정 --- .../src/views/CartPanel/CartProduct.jsx | 31 ++++++++++--------- .../src/views/CartPanel/CartSidebar.jsx | 10 +++--- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx b/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx index 299e3195..5a82fb49 100644 --- a/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx +++ b/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx @@ -138,12 +138,12 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { // 파트너사별 총합 계산 const calculatePartnerTotal = (items) => { const productTotal = items.reduce((sum, item) => - sum + (parseFloat(item.price3 || item.price2 || 0) * item.prodQty), 0 + sum + (parseFloat(Number(item.price3) !== 0 ? Number(item.price3) : Number(item.price2) !== 0 ? Number(item.price2) : 0) * item.prodQty), 0 ); - // const optionTotal = items.reduce((sum, item) => - // sum + (parseFloat(item.optPrc.replace("$","") || 0) * item.prodQty), 0 - // ); - const optionTotal = 0; + const optionTotal = items.reduce((sum, item) => + sum + (parseFloat(Number(item.price5) !== 0 ? Number(item.price5) : Number(item.optPrc) !== 0 ? Number(item.optPrc) : 0) * item.prodQty), 0 + ); + const shippingTotal = items.reduce((sum, item) => sum + parseFloat((item.shippingCharge) * item.prodQty || 0), 0 ); @@ -268,7 +268,6 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { <> {Object.entries(groupedCartData).map(([partnerKey, group], index) => { const totals = calculatePartnerTotal(group.items); - return ( {index === 0 && ( @@ -298,13 +297,15 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { Product Total ${totals.productTotal.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 - })} + - - {/* Option ${totals.optionTotal.toLocaleString('en-US', { + })} + + {totals.optionTotal > 0 && ( + <> + Option ${totals.optionTotal.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 - })} + */} - Option $0.00 + + })} + + + )} S&H ${totals.shippingTotal.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 @@ -372,20 +373,22 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { )}
- ${parseFloat(item.price3 || item.price2 || 0).toLocaleString('en-US', { + ${parseFloat(Number(item.price3) > 0 ? Number(item.price3) : Number(item.price2) > 0 ? Number(item.price2) : 0).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
- {item.price2 && ( + {item.price2 && (parseFloat(item.price2) > 0 && parseFloat(item.price3) > 0 && parseFloat(item.price2) !== parseFloat(item.price3)) && ( + <> ${parseFloat(item.price2).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} - + )} + {item.price5 && parseFloat(item.price5) > 0 && ( OPTION : ${parseFloat(item.price5).toLocaleString('en-US', { diff --git a/com.twin.app.shoptime/src/views/CartPanel/CartSidebar.jsx b/com.twin.app.shoptime/src/views/CartPanel/CartSidebar.jsx index 8c869a0a..b850ac53 100644 --- a/com.twin.app.shoptime/src/views/CartPanel/CartSidebar.jsx +++ b/com.twin.app.shoptime/src/views/CartPanel/CartSidebar.jsx @@ -175,16 +175,16 @@ const CartSidebar = ({ cartInfo }) => { // API Mode: 실제 장바구니 데이터로 계산 const itemCount = displayCartInfo.reduce((sum, item) => sum + (item.prodQty || 1), 0); const subtotal = displayCartInfo.reduce((sum, item) => { - const price = parseFloat(item.price3 || item.price2 || 0); + const price = parseFloat(Number(item.price3) !== 0 ? Number(item.price3) : Number(item.price2) !== 0 ? Number(item.price2) : 0); return sum + (price * (item.prodQty || 1)); }, 0); const optionTotal = displayCartInfo.reduce((sum, item) => { - const optionPrice = parseFloat(item.price5 || item.optPrc || 0); + const optionPrice = parseFloat(Number(item.price5) || Number(item.optPrc) || 0); return sum + (optionPrice * (item.prodQty || 1)); }, 0); - const shippingHandling = displayCartInfo.reduce((sum, item) => - sum + parseFloat(item.shippingCharge || 0), 0 - ); + const shippingHandling = displayCartInfo.reduce((sum, item) => { + return sum + parseFloat(Number(item.shippingCharge) * (item.prodQty || 1)) + }, 0); return { itemCount, From 25fee0bfb5854daf9b225df7cd4e61d508a9eb43 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Tue, 11 Nov 2025 14:42:37 +0900 Subject: [PATCH 10/26] =?UTF-8?q?[popularshow]=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - showInfos가 undefined 일때 처리 추가. --- .../HomePanel/PopularShow/PopularShow.jsx | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx b/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx index a677a14e..3cc95ec5 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx @@ -86,16 +86,25 @@ const PopularShow = ({ setDrawChk(true); }, [topInfos]); - useEffect(()=>{ + useEffect(()=>{ setShowInfos( recommendInfo?.filter( (item) => item.recommendTpCd === "POPULARSHOW" - ) + ) || [] ) },[recommendInfo]) useEffect(() => { - const recommendedData = showInfos?.[0].showInfos?.slice(0, 2).map((item) => ({ + if (!showInfos || showInfos.length === 0) { + const baseData = topInfos?.map((item) => ({ + ...item, + foryou: false, + })) || []; + setShowNewInfos(baseData); + return; + } + + const recommendedData = showInfos[0].showInfos?.slice(0, 2).map((item) => ({ ...item, foryou: true, })) || []; @@ -104,12 +113,14 @@ const PopularShow = ({ const baseData = topInfos?.filter( (item) => !recommendedPrdtIds.has(item.showId) - ).map((item) => ({ - ...item, - foryou: false, - })) || []; + ).map((item) => ({ + ...item, + foryou: false, + })) || []; + setShowNewInfos([...recommendedData, ...baseData]); - }, [topInfos, showInfos?.[0].showInfos]); + + }, [topInfos, showInfos]); From 8fc492eaf87d132d8ddf8e6b6925f7b6e3cdb023 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Tue, 11 Nov 2025 15:29:38 +0900 Subject: [PATCH 11/26] =?UTF-8?q?[=EC=98=A4=EB=A5=98=20=EC=B2=98=EB=A6=AC]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 혹시 모를 남은 추천 수정한 파일들에 대한 수정. - 없을때는 빈배열이나 기초값으로 가도록 수정. --- .../views/HomePanel/BestSeller/BestSeller.jsx | 57 ++++++------ .../HomePanel/SubCategory/SubCategory.jsx | 86 +++++-------------- 2 files changed, 53 insertions(+), 90 deletions(-) diff --git a/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx b/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx index ad163fd4..da67d568 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx @@ -85,30 +85,37 @@ const BestSeller = ({ const [bestItemNewData, setBestItemNewData] = useState([]); useEffect(()=>{ - setBestInfos( - bestSellerNewDatas?.filter( - (item) => item.recommendTpCd === "BESTSELLER" - ) - ) - },[bestSellerNewDatas]) + setBestInfos( + bestSellerNewDatas?.filter( + (item) => item.recommendTpCd === "BESTSELLER" + ) || [] // 기본값으로 빈 배열 설정 + ) +},[bestSellerNewDatas]) - useEffect(() => { - const recommendedData = bestInfos?.[0].productInfos?.slice(0, 2).map((item) => ({ - ...item, - foryou: true, - })) || []; - - const recommendedPrdtIds = new Set(recommendedData.map(item => item.prdtId)); - - const baseData = bestSellerDatas?.filter( - (item) => !recommendedPrdtIds.has(item.prdtId) - ).map((item) => ({ - ...item, - foryou: false, - })) || []; - - setBestItemNewData([...recommendedData, ...baseData]); - }, [bestSellerDatas, bestInfos?.[0].productInfos]); + useEffect(() => { + if (!bestInfos || bestInfos.length === 0) { + const baseData = bestSellerDatas?.map((item) => ({ + ...item, + foryou: false, + })) || []; + setBestItemNewData(baseData); + return; + } + + const recommendedData = bestInfos[0].productInfos?.slice(0, 20).map((item) => ({ + ...item, + foryou: true, + })) || []; + + const recommendedPrdtIds = new Set(recommendedData.map(item => item.prdtId)); + + const baseData = bestSellerDatas?.map((item) => ({ + ...item, + foryou: recommendedPrdtIds.has(item.prdtId), + })) || []; + + setBestItemNewData(baseData); + }, [bestSellerDatas, bestInfos]); const orderStyle = useMemo(() => ({ order: order }), [order]); @@ -286,7 +293,7 @@ const BestSeller = ({ offerInfo={offerInfo} spotlightId={"bestsellerItem" + itemIndex} firstLabel={rankText} - label={itemIndex * 1 + 1 + " of " + bestInfos?.[0].productInfos.length} + label={itemIndex * 1 + 1 + " of " + bestItemNewData.length} lastLabel=" go to detail, button" euEnrgLblInfos={euEnrgLblInfos} > @@ -311,4 +318,4 @@ const BestSeller = ({ ); }; -export default BestSeller; +export default BestSeller; \ No newline at end of file diff --git a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx index d7b12e44..3244ff02 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx @@ -121,7 +121,7 @@ export default memo(function SubCategory({ } setDrawChk(true); } - }, [currentLgCatCd, dispatch]); + }, [currentLgCatCd, dispatch, firstChk]); useEffect(() => { if (!nowMenuRef.current || !nowMenuRef.current.startsWith("Home")) { @@ -138,7 +138,7 @@ export default memo(function SubCategory({ dispatch(sendLogCuration(params)); } - }, [categoryInfos, currentLgCatCd, currentLgCatNm]); + }, [categoryInfos, currentLgCatCd, currentLgCatNm, dispatch, nowMenuRef]); const handleCategoryNav = useCallback( (lgCatCd, lgCatNm) => { @@ -153,7 +153,7 @@ export default memo(function SubCategory({ setContainerLastFocusedElement(null, [SpotlightIds.HOME_CATEGORY_NAV]); }, - [currentLgCatCd] + [currentLgCatCd, handleScrollReset] ); const handleFocus = useCallback( @@ -164,7 +164,7 @@ export default memo(function SubCategory({ handleScrollReset(); } }, - [_handleItemFocus] + [_handleItemFocus, handleScrollReset] ); const handleBlur = useCallback( @@ -173,7 +173,7 @@ export default memo(function SubCategory({ handleStopScrolling(); } }, - [] + [handleStopScrolling] ); const handleCardClick = useCallback( @@ -185,7 +185,7 @@ export default memo(function SubCategory({ }) ); }, - [] + [dispatch, spotlightId] ); const handleScrollRight = useCallback((e) => { @@ -193,7 +193,7 @@ export default memo(function SubCategory({ const x = container.scrollWidth - container.clientWidth; setTimeout(() => scrollLeft({ x, animate: true })); - }, []); + }, [scrollLeft]); const handleMoreCardClick = useCallback((e) => { const lgCatCd = e.currentTarget?.getAttribute("data-catcd-num"); @@ -212,7 +212,7 @@ export default memo(function SubCategory({ }) ); } - }, []); + }, [dispatch]); const _handleItemFocus = useCallback(() => { if (handleItemFocus) { @@ -227,7 +227,16 @@ export default memo(function SubCategory({ }, [handleShelfFocus]); useEffect(() => { - const recommendedData = foruItemInfos?.slice(0, 2).map((item) => ({ + if (!foruItemInfos || foruItemInfos.length === 0) { + const baseData = categoryItemInfos?.subCatItemList?.map((item) => ({ + ...item, + foryou: false, + })) || []; + setCategoryItemNewData(baseData); + return; + } + + const recommendedData = foruItemInfos?.slice(0, 10).map((item) => ({ ...item, foryou: true, })) || []; @@ -267,59 +276,6 @@ export default memo(function SubCategory({ cbScrollTo={getScrollTo} noScrollByWheel > - {/* {categoryItemInfos && - categoryItemInfos?.subCatItemList.map( - ( - { - prdtId, - imgUrl, - priceInfo, - prdtNm, - patnrId, - offerInfo, - brndNm, - patncNm, - }, - itemIndex - ) => { - return ( - - - - - - ); - } - )} 원본 보관*/} {categoryItemNewData && categoryItemNewData.slice(0, 10).map( ( @@ -342,7 +298,7 @@ export default memo(function SubCategory({ key={"subItem" + itemIndex} contextName={LOG_CONTEXT_NAME.HOME} messageId={LOG_MESSAGE_ID.SHELF_CLICK} - catNm={categoryItemInfos.catNm} + catNm={categoryItemInfos?.catNm} order={itemIndex + 1} shelfId={spotlightId} shelfLocation={shelfLocation} @@ -364,7 +320,7 @@ export default memo(function SubCategory({ itemIndex * 1 + 1 + " of " + - categoryItemInfos?.subCatItemList.length + (categoryItemNewData?.length || 0) } lastLabel=" go to detail, button" euEnrgLblInfos={euEnrgLblInfos} @@ -391,4 +347,4 @@ export default memo(function SubCategory({ ); -}); +}); \ No newline at end of file From 69659f301e42da33e83469aabc85dafa04f348ad Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Tue, 11 Nov 2025 15:50:44 +0900 Subject: [PATCH 12/26] =?UTF-8?q?[=EC=97=90=EB=84=88=EC=A7=80=20=EB=9D=BC?= =?UTF-8?q?=EB=B2=A8=20=EA=B4=80=EB=A0=A8]=20=EC=8A=A4=ED=83=80=EC=9D=BC?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Titemcard 노출부분 수정과 스타일 수정. --- .../TItemCard/TItemCard.module.less | 2 +- .../components/TItemCard/TItemCard.new.jsx | 32 ++++++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/com.twin.app.shoptime/src/components/TItemCard/TItemCard.module.less b/com.twin.app.shoptime/src/components/TItemCard/TItemCard.module.less index c3ad8c47..dee8ea6e 100644 --- a/com.twin.app.shoptime/src/components/TItemCard/TItemCard.module.less +++ b/com.twin.app.shoptime/src/components/TItemCard/TItemCard.module.less @@ -245,7 +245,7 @@ > p { font-weight: bold; - font-size: 30px; + font-size: 28px; color: @PRIMARY_COLOR_RED; margin-top: 8px; diff --git a/com.twin.app.shoptime/src/components/TItemCard/TItemCard.new.jsx b/com.twin.app.shoptime/src/components/TItemCard/TItemCard.new.jsx index 346c9372..bee18b35 100644 --- a/com.twin.app.shoptime/src/components/TItemCard/TItemCard.new.jsx +++ b/com.twin.app.shoptime/src/components/TItemCard/TItemCard.new.jsx @@ -86,7 +86,7 @@ export const removeDotAndColon = (string) => { }; const parsePrice = (price) => { - return parseFloat(price?.replace(/[^0-9.-]+/g, "") || "0"); + return parseFloat(price?.replace(/[^0-9.-]+/g, "").replace("£","") || "0"); }; const generateMockEnergyLabels = (productId) => { @@ -474,13 +474,19 @@ export default memo(function TItemCardNew({ className={classNames( css.descWrap, catNm && css.hstNmWrap, - parsePrice(originPrice) >= 1000 && - parsePrice(dcPrice) >= 1000 && - (countryCode === "GB" || countryCode === "DE") && + (parsePrice(originalPrice) >= 1000 || parsePrice(originPrice) >= 1000 ) && + (parsePrice(discountedPrice) >= 1000 || parsePrice(dcPrice) >= 1000 ) && + euEnrgLblInfos?.length > 0 && + euEnrgLblInfos[0]?.enrgLblIcnUrl !== null && + euEnrgLblInfos[0]?.enrgLblIcnUrl !== undefined && + countryCode === "GB" && css.labelBox, - parsePrice(originPrice) >= 10000 && - parsePrice(dcPrice) >= 10000 && - (countryCode === "GB" || countryCode === "DE") && + (parsePrice(originalPrice) >= 10000 || parsePrice(originPrice) >= 10000 ) && + (parsePrice(discountedPrice) >= 10000 || parsePrice(dcPrice) >= 10000 ) && + euEnrgLblInfos?.length > 0 && + euEnrgLblInfos[0]?.enrgLblIcnUrl !== null && + euEnrgLblInfos[0]?.enrgLblIcnUrl !== undefined && + countryCode === "GB" && css.labelOverBox )} > @@ -525,11 +531,11 @@ export default memo(function TItemCardNew({ )}
{(() => { - const hasValidApiData = + {/* const hasValidApiData = euEnrgLblInfos?.length > 0 && euEnrgLblInfos[0]?.enrgLblIcnUrl !== null && - euEnrgLblInfos[0]?.enrgLblIcnUrl !== undefined; - + euEnrgLblInfos[0]?.enrgLblIcnUrl !== undefined; */} + const hasValidApiData = true; let energyLabels; if (CURRENT_ENERGY_LABEL_MODE === ENERGY_LABEL_MODE.API_ONLY) { @@ -550,7 +556,11 @@ export default memo(function TItemCardNew({ } return ( - (countryCode === "GB" || countryCode === "DE") && ( + countryCode === "GB" && + (euEnrgLblInfos?.length > 0 && + euEnrgLblInfos[0]?.enrgLblIcnUrl !== null && + euEnrgLblInfos[0]?.enrgLblIcnUrl !== undefined) && + (
{type !== "videoShow" && energyLabels From 1b902b69ad7b4e80a3f52c3265001ca045cb3a30 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Tue, 11 Nov 2025 19:28:32 +0900 Subject: [PATCH 13/26] =?UTF-8?q?[=EC=97=90=EB=84=88=EC=A7=80=20=EB=9D=BC?= =?UTF-8?q?=EB=B2=A8=20=EB=85=B8=EC=B6=9C=20=EA=B4=80=EB=A0=A8=20=EC=9E=91?= =?UTF-8?q?=EC=97=85]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 상세 가격하단 노출 처리 및 스타일 수정 - youmayalsolike 부분에 노출 처리 및 스타일 수정 - 검색결과 아이템 부분에 노출 처리. --- .../YouMayAlsoLike/YouMayAlsoLike.jsx | 40 +++- .../YouMayAlsoLike/YouMayAlsoLike.module.less | 2 +- .../ProductPriceDisplay.jsx | 221 +++++++++++++++++- .../ProductPriceDisplay.module.less | 87 +++++++ .../SearchPanel/SearchResultsNew/ItemCard.jsx | 8 +- 5 files changed, 345 insertions(+), 13 deletions(-) diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx index 7c263bf4..3b6540a2 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx @@ -1,20 +1,40 @@ -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { + useDispatch, + useSelector, +} from 'react-redux'; import { Job } from '@enact/core/util'; -import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; +import SpotlightContainerDecorator + from '@enact/spotlight/SpotlightContainerDecorator'; import Spottable from '@enact/spotlight/Spottable'; import { clearThemeDetail } from '../../../../actions/homeActions'; -import { popPanel, pushPanel, updatePanel } from '../../../../actions/panelActions'; +import { + popPanel, + pushPanel, + updatePanel, +} from '../../../../actions/panelActions'; import { finishVideoPreview } from '../../../../actions/playActions'; import THeader from '../../../../components/THeader/THeader'; -import TItemCard from '../../../../components/TItemCard/TItemCard'; -import TVerticalPagenator from '../../../../components/TVerticalPagenator/TVerticalPagenator'; -import TVirtualGridList from '../../../../components/TVirtualGridList/TVirtualGridList'; +import TItemCardNew from '../../../../components/TItemCard/TItemCard.new'; +import TVerticalPagenator + from '../../../../components/TVerticalPagenator/TVerticalPagenator'; +import TVirtualGridList + from '../../../../components/TVirtualGridList/TVirtualGridList'; import useScrollTo from '../../../../hooks/useScrollTo'; -import { LOG_CONTEXT_NAME, LOG_MESSAGE_ID, panel_names } from '../../../../utils/Config'; +import { + LOG_CONTEXT_NAME, + LOG_MESSAGE_ID, + panel_names, +} from '../../../../utils/Config'; import { $L } from '../../../../utils/helperMethods'; import css from './YouMayAlsoLike.module.less'; @@ -136,6 +156,7 @@ export default function YouMayAlsoLike({ patncNm, brndNm, lgCatCd, + euEnrgLblInfos, } = product; const handleItemClick = () => { @@ -166,7 +187,7 @@ export default function YouMayAlsoLike({ cursorOpen.current.stop(); }; return ( - ); })} diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.module.less b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.module.less index 0906deeb..af050ff0 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.module.less +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.module.less @@ -81,7 +81,7 @@ > div:nth-child(2) { margin-top: 15px; /* desc wrapper */ - > div > h3 { + > div > div > h3 { /* title */ color: rgba(234, 234, 234, 1); .size(@w:100%,@h:64px); diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ProductPriceDisplay.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ProductPriceDisplay.jsx index 24f242b5..0ac0a91a 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ProductPriceDisplay.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ProductPriceDisplay.jsx @@ -1,19 +1,59 @@ import React, { useCallback, useMemo, + useState, } from 'react'; import classNames from 'classnames'; -import { useSelector } from 'react-redux'; +import { + useDispatch, + useSelector, +} from 'react-redux'; +import Spotlight from '@enact/spotlight'; +import Spottable from '@enact/spotlight/Spottable'; + +import { + setHidePopup, + setShowPopup, +} from '../../../../actions/commonActions'; +import { + clearConvertedImage, + convertPdfToImage, +} from '../../../../actions/convertActions'; +import CustomImage from '../../../../components/CustomImage/CustomImage'; +import TPopUp from '../../../../components/TPopUp/TPopUp'; import usePriceInfo from '../../../../hooks/usePriceInfo'; +import * as Config from '../../../../utils/Config'; import { $L } from '../../../../utils/helperMethods'; +import { SpotlightIds } from '../../../../utils/SpotlightIds'; import BuyNowPriceDisplay from './BuyNowPriceDisplay/BuyNowPriceDisplay'; import css from './ProductPriceDisplay.module.less'; import ShopByMobilePriceDisplay from './ShopByMobilePriceDisplay/ShopByMobilePriceDisplay'; +const SpottableComponent = Spottable("div"); + +const STRING_CONF = { + ENERGY_LOADING: "Loading energy label...", + ENERGY_ERROR: "Failed to load energy label", +}; + export default function ProductPriceDisplay({ productType, productInfo }) { + const dispatch = useDispatch(); + + const [currentPdfUrl, setCurrentPdfUrl] = useState(null); + + const cursorVisible = useSelector( + (state) => state.common.appStatus.cursorVisible + ); + const { activePopup, popupVisible } = useSelector( + (state) => state.common.popup + ); + + const convert = useSelector((state) => state.convert); + + const webOSVersion = useSelector( (state) => state.common.appStatus.webOSVersion ); @@ -27,6 +67,7 @@ export default function ProductPriceDisplay({ productType, productInfo }) { patnrName, installmentMonths, orderPhnNo, + euEnrgLblInfos, } = productInfo; const { @@ -65,6 +106,67 @@ export default function ProductPriceDisplay({ productType, productInfo }) { ); }, [productType, productInfo?.pmtSuptYn, webOSVersion]); + const handleClosePopup = useCallback(() => { + if (convert?.convertedImage && convert.convertedImage.startsWith("blob:")) { + URL.revokeObjectURL(convert.convertedImage); + } + + dispatch(setHidePopup()); + dispatch(clearConvertedImage()); + setCurrentPdfUrl(null); + }, [dispatch, convert?.convertedImage]); + + const onEnergyClick = useCallback( + (e, pdfUrl) => { + e.stopPropagation(); + setCurrentPdfUrl(pdfUrl); + + // PNG 이미지는 직접 표시 + if (pdfUrl.endsWith(".png")) { + // console.log(`📸 [EnergyLabel] Displaying PNG directly:`, pdfUrl); + dispatch({ + type: "CONVERT_PDF_TO_IMAGE_SUCCESS", + payload: { pdfUrl, imageUrl: pdfUrl }, + }); + dispatch(setShowPopup(Config.ACTIVE_POPUP.energyPopup)); + setTimeout(() => { + Spotlight.focus(SpotlightIds.TPOPUP); + }, 250); + return; + } + + // PDF 변환 시작 (최대 5회 재시도, 60초 타임아웃) + // console.log(`📄 [EnergyLabel] Starting PDF conversion:`, pdfUrl); + dispatch( + convertPdfToImage( + pdfUrl, + (error, imageUrl) => { + if (error) { + console.error( + "[EnergyLabel] 최종 변환 실패:", + error.message || error + ); + // 실패해도 팝업은 열어서 에러 메시지 표시 + dispatch(setShowPopup(Config.ACTIVE_POPUP.energyPopup)); + setTimeout(() => { + Spotlight.focus(SpotlightIds.TPOPUP); + }, 250); + } else { + console.log(`[EnergyLabel] PDF 변환 완료, 팝업 표시`); + dispatch(setShowPopup(Config.ACTIVE_POPUP.energyPopup)); + setTimeout(() => { + Spotlight.focus(SpotlightIds.TPOPUP); + }, 250); + } + }, + 5, // 최대 5회 재시도 + 60000 // 60초 타임아웃 + ) + ); + }, + [dispatch] + ); + return ( <> {productType && productInfo && ( @@ -91,8 +193,125 @@ export default function ProductPriceDisplay({ productType, productInfo }) { isDiscounted={isDiscounted} /> )} +
+ {euEnrgLblInfos && euEnrgLblInfos.map((item, index)=>{ + return( + onEnergyClick(e, item.enrgLblUrl)} + aria-label={`Energy Efficiency ${item.enrgGrade || ""}`} + className={css.enrgLbImg} + > + + + ) + })} +
)} + {(() => { + // 팝업이 표시되어야 하는 조건 검증 + const isEnergyPopup = activePopup === Config.ACTIVE_POPUP.energyPopup; + const hasPdfUrl = !!currentPdfUrl; + const shouldShowPopup = isEnergyPopup && hasPdfUrl; + + if (!shouldShowPopup) { + // console.log('[EnergyLabel] Popup not showing:', { + // isEnergyPopup, + // hasPdfUrl, + // popupVisible, + // }); + return null; + } + + // console.log('[EnergyLabel] Rendering popup:', { + // popupVisible, + // activePopup, + // currentPdfUrl, + // isConverting: convert?.isConverting, + // hasImage: !!convert?.convertedImage, + // hasError: !!convert?.error, + // }); + + return ( + +
+ {convert ? ( + <> +
+ {convert.convertedImage ? ( + Energy Label + ) : convert.error ? ( +
+

{$L(STRING_CONF.ENERGY_ERROR)}

+

+ {convert.error?.message || String(convert.error)} +

+
+ ) : convert.isConverting ? ( +
+

{$L(STRING_CONF.ENERGY_LOADING)}

+

+ Converting PDF to image... (attempt in progress) +

+
+ ) : ( +
+

{$L(STRING_CONF.ENERGY_ERROR)}

+

+ Unknown state - no image or error +

+
+ )} +
+ + ) : ( +
+

{$L(STRING_CONF.ENERGY_ERROR)}

+

+ Convert reducer state not found +

+
+ )} +
+
+ ); + })()} ); } diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ProductPriceDisplay.module.less b/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ProductPriceDisplay.module.less index ad2fc607..f608d8ae 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ProductPriceDisplay.module.less +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ProductPriceDisplay.module.less @@ -99,3 +99,90 @@ } } } + +.enrgLbImgBox { + display:flex; + justify-content: flex-start; + align-items: center; + .enrgLbImg { + width:62px; + height:38px; + border:4px solid transparent; + &:focus { + border: 4px solid @PRIMARY_COLOR_RED; + box-shadow: 0 0 22px 0 rgba(0, 0, 0, 0.5); + border-radius: 12px; + box-sizing: border-box; + } + > img { + width:100%; + } + } +} + +.popupContainer { + .header { + .size(@w: 780px , @h: 102px); + .flex(@display: flex, @justifyCenter: center, @alignCenter: center, @direction: row); + background-color: #e7ebef; + + > h3 { + font-size: 36px; + color: #222222; + font-weight: bold; + } + } + + .qrcodeContainer { + padding: 30px 0; + display: flex; + flex-direction: column; + align-items: center; + + .qrcode { + .size(@w: 360px , @h: 360px); + background-color: #ffffff; + border-radius: 12px; + box-shadow: 0 0 0 1px #dadada inset; + margin-bottom: 41px; + } + + > h3 { + display: flex; + text-align: center; + word-break: break-word; + line-height: 1.27; + } + + .popupBtn { + .size(@w: 300px , @h: 78px); + margin-top: 38px; + } + } +} + +// 🔽 에너지 라벨 팝업 스타일 (1920x1080 TV 화면 기준) +.energyPopupContent { + width: 100%; + max-height: 800px; // 팝업 타이틀/버튼 영역 제외한 콘텐츠 최대 높이 + overflow-y: auto; + display: flex; + justify-content: center; + align-items: center; + padding: 20px; +} + +.energyImagesContainer { + width: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.energyImage { + max-width: 100%; + max-height: 750px; // 1080px - 타이틀(~120px) - 버튼(~120px) - 여백(~90px) + width: auto; + height: auto; + object-fit: contain; // 비율 유지하면서 컨테이너에 맞춤 +} diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ItemCard.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ItemCard.jsx index 27319243..2a8aeb77 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ItemCard.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ItemCard.jsx @@ -4,7 +4,10 @@ import { useDispatch } from 'react-redux'; import Spotlight from '@enact/spotlight'; -import { pushPanel, updatePanel } from '../../../actions/panelActions'; +import { + pushPanel, + updatePanel, +} from '../../../actions/panelActions'; import { navigateToDetailPanel } from '../../../actions/panelNavigationActions'; import TItemCardNew from '../../../components/TItemCard/TItemCard.new'; import TScroller from '../../../components/TScroller/TScroller'; @@ -62,7 +65,7 @@ const ItemCard = ({ onClick, itemInfo, searchQuery }) => { <> {itemInfo.map((item, index) => { - const { thumbnail, title, dcPrice, price, soldout, contentId } = item; + const { thumbnail, title, dcPrice, price, soldout, contentId,euEnrgLblInfos } = item; const tokens = contentId && contentId.split('_'); const patnrId = tokens?.[4] || ''; const prdtId = tokens?.[5] || ''; @@ -83,6 +86,7 @@ const ItemCard = ({ onClick, itemInfo, searchQuery }) => { {...(index === 0 ? { 'data-spotlight-up': 'searchtabContainer' } : {})} label={index * 1 + 1 + ' of ' + itemInfo.length + 1} lastLabel=" go to detail, button" + euEnrgLblInfos={euEnrgLblInfos} /> ); })} From e2dff2e5b2fc400cf3fb49b57474c43015e53f27 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Tue, 11 Nov 2025 19:33:45 +0900 Subject: [PATCH 14/26] =?UTF-8?q?[=EC=97=90=EB=84=88=EC=A7=80=20=EB=9D=BC?= =?UTF-8?q?=EB=B2=A8=20=EB=85=B8=EC=B6=9C=20=EA=B4=80=EB=A0=A8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 상세 youmayalsolike 부분에서 에너지 라벨 클릭시 밀려나는 부분이 있어 수정. --- .../ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx | 1 + .../YouMayAlsoLike/YouMayAlsoLike.module.less | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx index 3b6540a2..36f8ae9e 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx @@ -189,6 +189,7 @@ export default function YouMayAlsoLike({ return ( div { + > div.itemCardNew { /* item card */ margin: 0 15px 15px 0; .size(@w:360px,@h:494px); From d4eec0b3920e74065c80e64c4d6f4e4bff0ab8b1 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Tue, 11 Nov 2025 19:38:00 +0900 Subject: [PATCH 15/26] =?UTF-8?q?[=EC=97=90=EB=84=88=EC=A7=80=20=EB=9D=BC?= =?UTF-8?q?=EB=B2=A8=20=EC=B6=94=EA=B0=80=EC=88=98=EC=A0=95]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 영국에만 데이터가 현재 존재해 영국만 노출시켰지만 기획상 유럽에 나와야하여 독일 다시 추가. - 영국, 독일에서만 노출되도록 수정. --- .../src/components/TItemCard/TItemCard.new.jsx | 6 +++--- .../ProductPriceDisplay/ProductPriceDisplay.jsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/com.twin.app.shoptime/src/components/TItemCard/TItemCard.new.jsx b/com.twin.app.shoptime/src/components/TItemCard/TItemCard.new.jsx index bee18b35..dd1792f3 100644 --- a/com.twin.app.shoptime/src/components/TItemCard/TItemCard.new.jsx +++ b/com.twin.app.shoptime/src/components/TItemCard/TItemCard.new.jsx @@ -479,14 +479,14 @@ export default memo(function TItemCardNew({ euEnrgLblInfos?.length > 0 && euEnrgLblInfos[0]?.enrgLblIcnUrl !== null && euEnrgLblInfos[0]?.enrgLblIcnUrl !== undefined && - countryCode === "GB" && + (countryCode === "GB" || countryCode === "DE") && css.labelBox, (parsePrice(originalPrice) >= 10000 || parsePrice(originPrice) >= 10000 ) && (parsePrice(discountedPrice) >= 10000 || parsePrice(dcPrice) >= 10000 ) && euEnrgLblInfos?.length > 0 && euEnrgLblInfos[0]?.enrgLblIcnUrl !== null && euEnrgLblInfos[0]?.enrgLblIcnUrl !== undefined && - countryCode === "GB" && + (countryCode === "GB" || countryCode === "DE") && css.labelOverBox )} > @@ -556,7 +556,7 @@ export default memo(function TItemCardNew({ } return ( - countryCode === "GB" && + (countryCode === "GB" || countryCode === "DE") && (euEnrgLblInfos?.length > 0 && euEnrgLblInfos[0]?.enrgLblIcnUrl !== null && euEnrgLblInfos[0]?.enrgLblIcnUrl !== undefined) && diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ProductPriceDisplay.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ProductPriceDisplay.jsx index 0ac0a91a..15031a90 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ProductPriceDisplay.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductOverview/ProductPriceDisplay/ProductPriceDisplay.jsx @@ -52,7 +52,7 @@ export default function ProductPriceDisplay({ productType, productInfo }) { ); const convert = useSelector((state) => state.convert); - + const countryCode = useSelector((state) => state.common.httpHeader.cntry_cd); const webOSVersion = useSelector( (state) => state.common.appStatus.webOSVersion @@ -194,7 +194,7 @@ export default function ProductPriceDisplay({ productType, productInfo }) { /> )}
- {euEnrgLblInfos && euEnrgLblInfos.map((item, index)=>{ + {euEnrgLblInfos && (countryCode === "GB" || countryCode === "DE") && euEnrgLblInfos.map((item, index)=>{ return( Date: Wed, 12 Nov 2025 09:32:55 +0900 Subject: [PATCH 16/26] =?UTF-8?q?[=EC=97=90=EB=84=88=EC=A7=80=20=ED=8C=9D?= =?UTF-8?q?=EC=97=85=20=EB=85=B8=EC=B6=9C=EC=8B=9C=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 팝업 노출시 div가 생성되어 margin이 잡히는 문제때문에 수정. --- .../CategoryContents/ItemContents/ItemContents.jsx | 1 + .../CategoryContents/ItemContents/ItemContents.module.less | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/com.twin.app.shoptime/src/views/CategoryPanel/CategoryContents/ItemContents/ItemContents.jsx b/com.twin.app.shoptime/src/views/CategoryPanel/CategoryContents/ItemContents/ItemContents.jsx index d4c980a3..42d8c1b6 100644 --- a/com.twin.app.shoptime/src/views/CategoryPanel/CategoryContents/ItemContents/ItemContents.jsx +++ b/com.twin.app.shoptime/src/views/CategoryPanel/CategoryContents/ItemContents/ItemContents.jsx @@ -79,6 +79,7 @@ export default function ItemContents({ onClick }) { lastLabel=" go to detail, button" data-wheel-point={index >= 5} euEnrgLblInfos={euEnrgLblInfos} + className={css.itemCardNewCate} /> ); })} diff --git a/com.twin.app.shoptime/src/views/CategoryPanel/CategoryContents/ItemContents/ItemContents.module.less b/com.twin.app.shoptime/src/views/CategoryPanel/CategoryContents/ItemContents/ItemContents.module.less index 7a15773a..d19d221d 100644 --- a/com.twin.app.shoptime/src/views/CategoryPanel/CategoryContents/ItemContents/ItemContents.module.less +++ b/com.twin.app.shoptime/src/views/CategoryPanel/CategoryContents/ItemContents/ItemContents.module.less @@ -6,7 +6,7 @@ display: flex; flex-wrap: wrap; margin-top: 34px; - > div { + > div.itemCardNewCate { margin: 0 15px 15px 0; } } From 1617da223b500c86c9d25bdf6cae54b5e602e2b7 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Wed, 12 Nov 2025 09:33:58 +0900 Subject: [PATCH 17/26] =?UTF-8?q?[=EB=A9=94=EC=9D=B8=20=EB=85=B8=EC=B6=9C]?= =?UTF-8?q?=20=EC=B6=94=EC=B2=9C=EC=83=81=ED=92=88=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 몇개가 들어올지 모른다하여 기존 slice로 잘라서 저장하는부분에 대하여 삭제. --- .../views/HomePanel/BestSeller/BestSeller.jsx | 36 +++++++++---------- .../HomePanel/PopularShow/PopularShow.jsx | 8 ++--- .../HomePanel/SubCategory/SubCategory.jsx | 8 ++--- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx b/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx index da67d568..ee16c131 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/BestSeller/BestSeller.jsx @@ -85,28 +85,28 @@ const BestSeller = ({ const [bestItemNewData, setBestItemNewData] = useState([]); useEffect(()=>{ - setBestInfos( - bestSellerNewDatas?.filter( - (item) => item.recommendTpCd === "BESTSELLER" - ) || [] // 기본값으로 빈 배열 설정 - ) -},[bestSellerNewDatas]) + setBestInfos( + bestSellerNewDatas?.filter( + (item) => item.recommendTpCd === "BESTSELLER" + ) || [] // 기본값으로 빈 배열 설정 + ) + },[bestSellerNewDatas]) useEffect(() => { if (!bestInfos || bestInfos.length === 0) { - const baseData = bestSellerDatas?.map((item) => ({ - ...item, - foryou: false, - })) || []; - setBestItemNewData(baseData); - return; - } + const baseData = bestSellerDatas?.map((item) => ({ + ...item, + foryou: false, + })) || []; + setBestItemNewData(baseData); + return; + } - const recommendedData = bestInfos[0].productInfos?.slice(0, 20).map((item) => ({ - ...item, - foryou: true, - })) || []; - + const recommendedData = bestInfos[0].productInfos?.map((item) => ({ + ...item, + foryou: true, + })) || []; + const recommendedPrdtIds = new Set(recommendedData.map(item => item.prdtId)); const baseData = bestSellerDatas?.map((item) => ({ diff --git a/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx b/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx index 3cc95ec5..4d5711db 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx @@ -104,18 +104,16 @@ const PopularShow = ({ return; } - const recommendedData = showInfos[0].showInfos?.slice(0, 2).map((item) => ({ + const recommendedData = showInfos[0].showInfos?.map((item) => ({ ...item, foryou: true, })) || []; const recommendedPrdtIds = new Set(recommendedData?.map(item => item.showId)); - const baseData = topInfos?.filter( - (item) => !recommendedPrdtIds.has(item.showId) - ).map((item) => ({ + const baseData = topInfos?.map((item) => ({ ...item, - foryou: false, + foryou: recommendedPrdtIds.has(item.showId), })) || []; setShowNewInfos([...recommendedData, ...baseData]); diff --git a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx index 3244ff02..5425bc94 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx @@ -236,18 +236,16 @@ export default memo(function SubCategory({ return; } - const recommendedData = foruItemInfos?.slice(0, 10).map((item) => ({ + const recommendedData = foruItemInfos?.map((item) => ({ ...item, foryou: true, })) || []; const recommendedPrdtIds = new Set(recommendedData.map(item => item.prdtId)); - const baseData = categoryItemInfos?.subCatItemList?.filter( - (item) => !recommendedPrdtIds.has(item.prdtId) - ).map((item) => ({ + const baseData = categoryItemInfos?.subCatItemList?.map((item) => ({ ...item, - foryou: false, + foryou: recommendedPrdtIds.has(item.prdtId), })) || []; setCategoryItemNewData([...recommendedData, ...baseData]); From fd5b9aab0e689f7d6b4d137ffab79b601051e074 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Wed, 12 Nov 2025 10:32:45 +0900 Subject: [PATCH 18/26] =?UTF-8?q?[=EC=B6=94=EC=B2=9C=EC=83=81=ED=92=88=20?= =?UTF-8?q?=EC=88=98=EC=A0=95]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 추천 상품부분을 더해주는부분을 빼지않아 그부분에 대한수정 --- .../src/views/HomePanel/PopularShow/PopularShow.jsx | 2 +- .../src/views/HomePanel/SubCategory/SubCategory.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx b/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx index 4d5711db..9305dbf4 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx @@ -116,7 +116,7 @@ const PopularShow = ({ foryou: recommendedPrdtIds.has(item.showId), })) || []; - setShowNewInfos([...recommendedData, ...baseData]); + setShowNewInfos([ ...baseData]); }, [topInfos, showInfos]); diff --git a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx index 5425bc94..20f95377 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx @@ -248,7 +248,7 @@ export default memo(function SubCategory({ foryou: recommendedPrdtIds.has(item.prdtId), })) || []; - setCategoryItemNewData([...recommendedData, ...baseData]); + setCategoryItemNewData([...baseData]); }, [categoryItemInfos?.subCatItemList, foruItemInfos]); return ( @@ -275,7 +275,7 @@ export default memo(function SubCategory({ noScrollByWheel > {categoryItemNewData && - categoryItemNewData.slice(0, 10).map( + categoryItemNewData.map( ( { prdtId, From 9b4b15f46e989c91685b4d5b0cf3f7ee9849d3cf Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Wed, 12 Nov 2025 12:46:50 +0900 Subject: [PATCH 19/26] =?UTF-8?q?[=EA=B2=80=EC=83=89=EA=B2=B0=EA=B3=BC=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=EC=88=98=EC=A0=95]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 일반 검색에서는 필터 노출하지않도록 --- .../SearchPanel/SearchResults.new.v2.jsx | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.v2.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.v2.jsx index b8947209..39c8c303 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.v2.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.v2.jsx @@ -1,10 +1,21 @@ -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; import classNames from 'classnames'; -import { useDispatch, useSelector } from 'react-redux'; +import { + useDispatch, + useSelector, +} from 'react-redux'; +import Dropdown from '@enact/sandstone/Dropdown'; import Spotlight from '@enact/spotlight'; -import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; +import SpotlightContainerDecorator + from '@enact/spotlight/SpotlightContainerDecorator'; import Spottable from '@enact/spotlight/Spottable'; import downBtnImg from '../../../assets/images/btn/search_btn_down_arrow.png'; @@ -14,7 +25,8 @@ import { hideShopperHouseError } from '../../actions/searchActions'; import CustomImage from '../../components/CustomImage/CustomImage'; import TButtonTab, { LIST_TYPE } from '../../components/TButtonTab/TButtonTab'; import TDropDown from '../../components/TDropDown/TDropDown'; -import TVirtualGridList from '../../components/TVirtualGridList/TVirtualGridList'; +import TVirtualGridList + from '../../components/TVirtualGridList/TVirtualGridList'; import { panel_names } from '../../utils/Config'; import { $L } from '../../utils/helperMethods'; import { SpotlightIds } from '../../utils/SpotlightIds'; @@ -24,8 +36,6 @@ import HowAboutTheseSmall from './HowAboutThese/HowAboutThese.small'; import css from './SearchResults.new.v2.module.less'; import ItemCard from './SearchResultsNew/ItemCard'; import ShowCard from './SearchResultsNew/ShowCard'; -import Dropdown from '@enact/sandstone/Dropdown'; - const ITEMS_PER_PAGE = 10; @@ -926,7 +936,7 @@ const SearchResultsNew = ({ No matches, Showing suggestions
)} - + {hasShopperHouseItems && ( {filterMethods} - + )} {/* 아이템/쇼 컨텐츠 */} From 5c833ad6b21b27b8b599f99cb9698fb5a926e299 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Wed, 12 Nov 2025 13:01:56 +0900 Subject: [PATCH 20/26] =?UTF-8?q?[logout]=20=EA=B4=80=EB=A0=A8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - config에 로그아웃 팝업 부분이 없어 처리. --- com.twin.app.shoptime/src/utils/Config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/com.twin.app.shoptime/src/utils/Config.js b/com.twin.app.shoptime/src/utils/Config.js index 9a7d1fb7..8d7bd238 100644 --- a/com.twin.app.shoptime/src/utils/Config.js +++ b/com.twin.app.shoptime/src/utils/Config.js @@ -79,6 +79,7 @@ export const ACTIVE_POPUP = { exitPopup: 'exitPopup', favoritePopup: 'favoritePopup', loginPopup: 'loginPopup', + logoutPopup: 'logoutPopup', noShowPopup: 'noShowPopup', optionPopup: 'optionPopup', qrPopup: 'qrPopup', From 2d2b438508d7297010b2dfcdc40416e5b9c563b0 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Wed, 12 Nov 2025 14:31:32 +0900 Subject: [PATCH 21/26] =?UTF-8?q?[=EB=94=94=ED=85=8C=EC=9D=BC]=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=ED=99=94=EB=A9=B4=20=EB=B0=B0=ED=8F=AC=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=EC=9A=A9=EB=8F=84=20=20-=20=EC=83=81=EC=84=B8?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EB=B9=84=EB=94=94=EC=98=A4=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=EC=9A=A9=EB=8F=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../views/DetailPanel/ProductAllSection/ProductAllSection.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8dc569be..0459300f 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx @@ -174,7 +174,7 @@ export default function ProductAllSection({ const youmaylikeData = useSelector((state) => state.main.youmaylikeData); // ProductVideo 버전 관리 (1: 기존 modal 방식, 2: 내장 방식 , 3: 비디오 생략) - const [productVideoVersion, setProductVideoVersion] = useState(3); + const [productVideoVersion, setProductVideoVersion] = useState(2); // const [currentHeight, setCurrentHeight] = useState(0); //하단부분까지 갔을때 체크용 From 693780298f527bcde0e245b6f4f6d7b6336cb62c Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Wed, 12 Nov 2025 17:41:00 +0900 Subject: [PATCH 22/26] =?UTF-8?q?[=EC=97=90=EB=84=88=EC=A7=80=20=EB=9D=BC?= =?UTF-8?q?=EB=B2=A8]#=EC=9E=84=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 토큰 만료일때 재처리 --- .../src/actions/convertActions.js | 105 ++++++++++-------- 1 file changed, 56 insertions(+), 49 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/convertActions.js b/com.twin.app.shoptime/src/actions/convertActions.js index afeccf8a..f75153fa 100644 --- a/com.twin.app.shoptime/src/actions/convertActions.js +++ b/com.twin.app.shoptime/src/actions/convertActions.js @@ -1,6 +1,7 @@ import { URLS } from '../api/apiConfig'; import { TAxios } from '../api/TAxios'; import { types } from './actionTypes'; +import { getReAuthenticationCode } from './deviceActions'; /** * PDF를 이미지로 변환 (재시도 로직 포함) @@ -52,7 +53,7 @@ export const convertPdfToImage = clearTimeout(timeoutId); timeoutId = null; } - + // retCode 체크 (프로젝트 API 규약: 200이어도 retCode로 성공/실패 구분) const retCode = response.headers?.retcode || response.headers?.retCode; @@ -79,56 +80,62 @@ export const convertPdfToImage = } return; } - - let imageUrl; - try { - if (response.data instanceof Blob) { - if (response.data.size === 0) { - throw new Error('Invalid image data (empty blob)'); - } - imageUrl = URL.createObjectURL(response.data); - } else if (response.data instanceof ArrayBuffer) { - if (response.data.byteLength === 0) { - throw new Error('Invalid image data (empty buffer)'); - } - const blob = new Blob([response.data], { type: 'image/png' }); - imageUrl = URL.createObjectURL(blob); - } else { - const blob = new Blob([response.data], { type: 'image/png' }); - if (blob.size === 0) { - throw new Error('Invalid image data (empty blob)'); - } - imageUrl = URL.createObjectURL(blob); - } - - console.log(`✅ [EnergyLabel] Conversion successful on attempt ${attempts}:`, pdfUrl); - dispatch({ - type: types.CONVERT_PDF_TO_IMAGE_SUCCESS, - payload: { pdfUrl, imageUrl }, - }); - - callback && callback(null, imageUrl); - } catch (error) { - console.error(`❌ [EnergyLabel] Image creation failed on attempt ${attempts}:`, error); - - // 이미지 생성 실패도 재시도 - if (attempts < maxRetries + 1) { - console.log( - `🔄 [EnergyLabel] Retrying due to image creation error... (${attempts}/${maxRetries + 1})` - ); + + if(response.data.size > 100 && response.data.type === "text/xml"){ + dispatch(getReAuthenticationCode()); attemptConversion(); - } else { - console.error( - `❌ [EnergyLabel] Final failure after ${attempts} attempts (image error):`, - pdfUrl - ); - dispatch({ - type: types.CONVERT_PDF_TO_IMAGE_FAILURE, - payload: { pdfUrl, error }, - }); - callback && callback(error, null); + return; + } + + let imageUrl; + try { + if (response.data instanceof Blob) { + if (response.data.size === 0) { + throw new Error('Invalid image data (empty blob)'); + } + imageUrl = URL.createObjectURL(response.data); + } else if (response.data instanceof ArrayBuffer) { + if (response.data.byteLength === 0) { + throw new Error('Invalid image data (empty buffer)'); + } + const blob = new Blob([response.data], { type: 'image/png' }); + imageUrl = URL.createObjectURL(blob); + } else { + const blob = new Blob([response.data], { type: 'image/png' }); + if (blob.size === 0) { + throw new Error('Invalid image data (empty blob)'); + } + imageUrl = URL.createObjectURL(blob); + } + + console.log(`✅ [EnergyLabel] Conversion successful on attempt ${attempts}:`, pdfUrl); + dispatch({ + type: types.CONVERT_PDF_TO_IMAGE_SUCCESS, + payload: { pdfUrl, imageUrl }, + }); + + callback && callback(null, imageUrl); + } catch (error) { + console.error(`❌ [EnergyLabel] Image creation failed on attempt ${attempts}:`, error); + + // 이미지 생성 실패도 재시도 + if (attempts < maxRetries + 1) { + console.log( + `🔄 [EnergyLabel] Retrying due to image creation error... (${attempts}/${maxRetries + 1})` + ); + attemptConversion(); + } else { + console.error( + `❌ [EnergyLabel] Final failure after ${attempts} attempts (image error):`, + pdfUrl + ); + dispatch({ + type: types.CONVERT_PDF_TO_IMAGE_FAILURE, + payload: { pdfUrl, error }, + }); + callback && callback(error, null); + } } - } }; const onFail = (error) => { From 5c8c67f666237f404c99f34c3efc2193d9d15b1a Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Wed, 12 Nov 2025 19:21:22 +0900 Subject: [PATCH 23/26] =?UTF-8?q?[=EC=97=90=EB=84=88=EC=A7=80=20=EB=9D=BC?= =?UTF-8?q?=EB=B2=A8]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2025년 11월 12일 김영진 부장과 통화로 image/png 경우가 아닐때 재인증 요청처리. --- com.twin.app.shoptime/src/actions/convertActions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/convertActions.js b/com.twin.app.shoptime/src/actions/convertActions.js index f75153fa..9b12062a 100644 --- a/com.twin.app.shoptime/src/actions/convertActions.js +++ b/com.twin.app.shoptime/src/actions/convertActions.js @@ -56,7 +56,7 @@ export const convertPdfToImage = // retCode 체크 (프로젝트 API 규약: 200이어도 retCode로 성공/실패 구분) const retCode = response.headers?.retcode || response.headers?.retCode; - + if (retCode !== undefined && retCode !== 0 && retCode !== '0') { const error = new Error(`API Error: retCode=${retCode}`); console.warn(`⚠️ [EnergyLabel] API returned error on attempt ${attempts}:`, retCode); @@ -81,7 +81,7 @@ export const convertPdfToImage = return; } - if(response.data.size > 100 && response.data.type === "text/xml"){ + if(response.data.type !== "image/png"){ dispatch(getReAuthenticationCode()); attemptConversion(); return; From 301e00298590d74d2029515b02e1ef4b9feeda1c Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Wed, 12 Nov 2025 19:40:55 +0900 Subject: [PATCH 24/26] =?UTF-8?q?[=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=B6=94=EA=B0=80]#1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 작업 진행중 - api로 데이터 보내도록 처리중. --- .../src/actions/actionTypes.js | 7 +- .../src/actions/cartActions.js | 145 ++++++++++++++++++ com.twin.app.shoptime/src/api/apiConfig.js | 9 +- .../src/reducers/cartReducer.js | 66 +++++++- .../src/views/CartPanel/CartPanel.jsx | 3 +- .../src/views/CartPanel/CartProduct.jsx | 18 ++- .../DetailPanel/components/BuyOption.jsx | 14 +- 7 files changed, 244 insertions(+), 18 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/actionTypes.js b/com.twin.app.shoptime/src/actions/actionTypes.js index 2cc6e5a3..cffa6b8b 100644 --- a/com.twin.app.shoptime/src/actions/actionTypes.js +++ b/com.twin.app.shoptime/src/actions/actionTypes.js @@ -76,11 +76,16 @@ export const types = { GET_MY_INFO_SHIPPING_SEARCH: 'GET_MY_INFO_SHIPPING_SEARCH', // cart actions - GET_MY_INFO_CART_SEARCH: 'GET_MY_INFO_CART_SEARCH', ADD_TO_CART: 'ADD_TO_CART', REMOVE_FROM_CART: 'REMOVE_FROM_CART', UPDATE_CART_ITEM: 'UPDATE_CART_ITEM', CLEAR_CART: 'CLEAR_CART', + //cart api action + GET_MY_INFO_CART_SEARCH: 'GET_MY_INFO_CART_SEARCH', + INSERT_MY_INFO_CART : "INSERT_MY_INFO_CART", + DELETE_MY_INFO_CART : "DELETE_MY_INFO_CART", + DELETE_ALL_MY_INFO_CART : "DELETE_ALL_MY_INFO_CART", + UPDATE_MY_INFO_CART : "UPDATE_MY_INFO_CART", // appData actions ADD_MAIN_INDEX: 'ADD_MAIN_INDEX', diff --git a/com.twin.app.shoptime/src/actions/cartActions.js b/com.twin.app.shoptime/src/actions/cartActions.js index 4f6f9c8b..f63c5ae5 100644 --- a/com.twin.app.shoptime/src/actions/cartActions.js +++ b/com.twin.app.shoptime/src/actions/cartActions.js @@ -50,6 +50,151 @@ export const getMyInfoCartSearch = (props) => (dispatch, getState) => { ); }; +/** + * 장바구니 상품 추가 API + */ +export const insertMyinfoCart = (props) => (dispatch, getState) => { + const { mbrNo, patnrId, prdtId, prdtOpt, prodQty } = props; + + const onSuccess = (response) => { + console.log("✅ insertMyinfoCart API 성공:", response.data); + if (response.data.retCode !== '0' && response.data.retCode !== 0) { + console.error("❌ retCode 에러:", response.data.retCode); + console.error("에러 메시지:", response.data.retMsg); + + return; + } + // response.data.data가 실제 상품 정보인지 확인 + if (!response.data.data) { + console.warn("⚠️ response.data.data가 undefined입니다"); + } + + dispatch({ + type: types.INSERT_MY_INFO_CART, + payload: response.data.data, + }); + + dispatch(getMyInfoCartSearch({ mbrNo })); + }; + + const onFail = (error) => { + console.error("insertMyinfoCart OnFail: ", error); + }; + + TAxios( + dispatch, + getState, + "post", + URLS.INSERT_MY_INFO_CART, + {}, + { mbrNo, patnrId, prdtId, prdtOpt, prodQty }, + onSuccess, + onFail + ); +}; + +/** + * 장바구니 상품 삭제 API + */ +export const deleteMyinfoCart = (props) => (dispatch, getState) => { + const { mbrNo, patnrId, prdtId, prodSno } = props; + + const onSuccess = (response) => { + console.log("deleteMyinfoCart onSuccess: ", response.data); + + dispatch({ + type: types.DELETE_MY_INFO_CART, + payload: response.data.data, + }); + + // 장바구니 목록 재조회 + dispatch(getMyInfoCartSearch({ mbrNo })); + }; + + const onFail = (error) => { + console.error("deleteMyinfoCart OnFail: ", error); + }; + + TAxios( + dispatch, + getState, + "post", + URLS.DELETE_MY_INFO_CART, + {}, + { mbrNo, patnrId, prdtId, prodSno }, + onSuccess, + onFail + ); +}; + +/** + * 장바구니 상품 전체 삭제 + */ +export const deleteAllMyinfoCart = (props) => (dispatch, getState) => { + const { mbrNo } = props; + + const onSuccess = (response) => { + console.log("deleteAllMyinfoCart onSuccess: ", response.data); + + dispatch({ + type: types.DELETE_ALL_MY_INFO_CART, + payload: response.data.data, + }); + + // 장바구니 목록 재조회 + dispatch(getMyInfoCartSearch({ mbrNo })); + }; + + const onFail = (error) => { + console.error("deleteAllMyinfoCart OnFail: ", error); + }; + + TAxios( + dispatch, + getState, + "post", + URLS.DELETE_ALL_MY_INFO_CART, + {}, + { mbrNo }, + onSuccess, + onFail + ); +}; + +/** + * 장바구니 상품 수정 + */ +export const updateMyinfoCart = (props) => (dispatch, getState) => { + const { mbrNo, patnrId, prdtId, prodQty, prodSno } = props; + + const onSuccess = (response) => { + console.log("updateMyinfoCart onSuccess: ", response.data); + + dispatch({ + type: types.UPDATE_MY_INFO_CART, + payload: response.data.data, + }); + + // 장바구니 목록 재조회 + dispatch(getMyInfoCartSearch({ mbrNo })); + }; + + const onFail = (error) => { + console.error("updateMyinfoCart OnFail: ", error); + }; + + TAxios( + dispatch, + getState, + "post", + URLS.UPDATE_MY_INFO_CART, + {}, + { mbrNo, patnrId, prdtId, prodQty, prodSno }, + onSuccess, + onFail + ); +}; + /** * 장바구니에 상품 추가 * @param {Object} props - 장바구니 상품 정보 diff --git a/com.twin.app.shoptime/src/api/apiConfig.js b/com.twin.app.shoptime/src/api/apiConfig.js index f37d181d..71fbec14 100644 --- a/com.twin.app.shoptime/src/api/apiConfig.js +++ b/com.twin.app.shoptime/src/api/apiConfig.js @@ -20,10 +20,15 @@ export const URLS = { GET_MY_INFO_CARD_SEARCH: "/lgsp/v1/myinfo/card/search.lge", // cart controller - GET_MY_INFO_CART_SEARCH: "/lgsp/v1/myinfo/cart/search.lge", ADD_TO_CART: "/lgsp/v1/myinfo/cart/add.lge", REMOVE_FROM_CART: "/lgsp/v1/myinfo/cart/remove.lge", - UPDATE_CART_ITEM: "/lgsp/v1/myinfo/cart/update.lge", + UPDATE_CART_ITEM: "/lgsp/v1/myinfo/cart/update.lge", + // cart api + GET_MY_INFO_CART_SEARCH: "/lgsp/v1/myinfo/cart/search.lge", + INSERT_MY_INFO_CART: "/lgsp/v1/myinfo/cart/add.lge", + DELETE_MY_INFO_CART : "/lgsp/v1/myinfo/cart/delete.lge", + DELETE_ALL_MY_INFO_CART : "/lgsp/v1/myinfo/cart/deleteAll.lge", + UPDATE_MY_INFO_CART : "/lgsp/v1/myinfo/cart/update.lge", // shipping controller GET_MY_INFO_SHIPPING_SEARCH: "/lgsp/v1/myinfo/address/shipping/search.lge", diff --git a/com.twin.app.shoptime/src/reducers/cartReducer.js b/com.twin.app.shoptime/src/reducers/cartReducer.js index d0d14f6d..b576a605 100644 --- a/com.twin.app.shoptime/src/reducers/cartReducer.js +++ b/com.twin.app.shoptime/src/reducers/cartReducer.js @@ -1,4 +1,4 @@ -import { types } from "../actions/actionTypes"; +import { types } from '../actions/actionTypes'; /** * Cart Reducer 초기 상태 @@ -18,9 +18,9 @@ const initialState = { * Cart Reducer * 장바구니 관련 상태를 관리합니다. */ -export const cartReducer = (state = initialState, action) => { +export const cartReducer = (state = initialState, action) => { switch (action.type) { - // 장바구니 조회 + // 장바구니 조회 - API에서 가져온 전체 목록 case types.GET_MY_INFO_CART_SEARCH: return { ...state, @@ -32,6 +32,56 @@ export const cartReducer = (state = initialState, action) => { }; // 장바구니에 상품 추가 + case types.INSERT_MY_INFO_CART: + return { + ...state, + getMyinfoCartSearch: { + ...state.getMyinfoCartSearch, + cartList: [...state.getMyinfoCartSearch.cartList, action.payload], + totalCount: (state.getMyinfoCartSearch.totalCount || 0) + 1, + }, + lastAction: { + type: "insert", + data: action.payload, + timestamp: Date.now(), + }, + error: null, + }; + + // 장바구니에서 상품 삭제 + case types.DELETE_MY_INFO_CART: + return { + ...state, + getMyinfoCartSearch: { + ...state.getMyinfoCartSearch, + cartList: state.getMyinfoCartSearch.cartList.filter( + item => item.prodSno !== action.payload.prodSno + ), + totalCount: Math.max(0, (state.getMyinfoCartSearch.totalCount || 0) - 1), + }, + lastAction: { + type: "delete", + data: action.payload, + timestamp: Date.now(), + }, + error: null, + }; + + case types.UPDATE_MY_INFO_CART: + return { + ...state, + getMyinfoCartSearch: { + ...state.getMyinfoCartSearch, + cartList: state.getMyinfoCartSearch.cartList.map(item => + item.prodSno === action.payload.prodSno + ? { ...item, ...action.payload } + : item + ), + }, + error: null, + }; + + // 장바구니에 상품 추가 (addToCart - 로컬 상태용) case types.ADD_TO_CART: return { ...state, @@ -43,7 +93,7 @@ export const cartReducer = (state = initialState, action) => { error: null, }; - // 장바구니에서 상품 제거 + // 장바구니에서 상품 제거 (removeFromCart) case types.REMOVE_FROM_CART: return { ...state, @@ -55,19 +105,19 @@ export const cartReducer = (state = initialState, action) => { error: null, }; - // 장바구니 상품 수량 업데이트 + // 장바구니 상품 수량 업데이트 (updateCartItem) case types.UPDATE_CART_ITEM: return { ...state, lastAction: { - type: "update", + type: "updateQty", data: action.payload, timestamp: Date.now(), }, error: null, }; - // 장바구니 전체 비우기 + // 장바구니 전체 비우기 (clearCart - 로컬 상태 전용) case types.CLEAR_CART: return { ...state, @@ -85,4 +135,4 @@ export const cartReducer = (state = initialState, action) => { default: return state; } -}; +}; \ No newline at end of file diff --git a/com.twin.app.shoptime/src/views/CartPanel/CartPanel.jsx b/com.twin.app.shoptime/src/views/CartPanel/CartPanel.jsx index ef78a4c1..a835bbd5 100644 --- a/com.twin.app.shoptime/src/views/CartPanel/CartPanel.jsx +++ b/com.twin.app.shoptime/src/views/CartPanel/CartPanel.jsx @@ -46,7 +46,8 @@ export default function CartPanel({ spotlightId, scrollOptions = [], panelInfo } ); // Mock Mode 여부 확인 및 적절한 데이터 선택 - const isMockMode = BUYNOW_CONFIG.isMockMode(); + // const isMockMode = BUYNOW_CONFIG.isMockMode(); + const isMockMode = false; const displayCartData = useMemo(() => { return isMockMode ? mockCartData : cartData; }, [isMockMode, mockCartData, cartData]); diff --git a/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx b/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx index 5a82fb49..5227dd52 100644 --- a/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx +++ b/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx @@ -18,6 +18,7 @@ import SpotlightContainerDecorator import logoImage from '../../../assets/images/ic-partners-qvc@3x.png'; import defaultImage from '../../../assets/images/img-thumb-empty-144@3x.png'; import { + deleteMyinfoCart, removeFromCart, updateCartItem, } from '../../actions/cartActions'; @@ -264,6 +265,21 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { [scrollTop] ); + //장바구니 삭제 + const deleteCart = (patnrId, prdtId, prodSno) => { + const { userNumber } = store.getState().common.appStatus.loginUserData; + console.log("###test",userNumber, + patnrId, + prdtId, + prodSno) + // dispatch(deleteMyinfoCart({ + // mbrNo : userNumber, + // patnrId, + // prdtId, + // prodSno + // })) + } + return ( <> {Object.entries(groupedCartData).map(([partnerKey, group], index) => { @@ -433,7 +449,7 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { handleDeleteClick(item.prodSno)} + onClick={() => deleteCart(item.patnrId, item.prdtId, item.prodSno)} />
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 827b1610..a53c9078 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/components/BuyOption.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/components/BuyOption.jsx @@ -15,7 +15,10 @@ import Spotlight from '@enact/spotlight'; import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; -import { addToCart } from '../../../actions/cartActions'; +import { + addToCart, + insertMyinfoCart, +} from '../../../actions/cartActions'; import { getMyInfoCheckoutInfo } from '../../../actions/checkoutActions'; import { changeAppStatus, @@ -1084,17 +1087,18 @@ const BuyOption = ({ if (!isMock) { dispatch( - addToCart({ + insertMyinfoCart({ mbrNo: userNumber, patnrId: selectedPatnrId, prdtId: selectedPrdtId, - prodQty: String(effectiveQuantity), + prodQty: Number(effectiveQuantity), prdtOpt: { - prodOptCdCval: optionForUse?.prodOptCdCval || '', - prodOptCval: optionLabel, prodOptSno: productOptionInfos?.[0]?.prodOptSno || '', + prodOptCdCval: optionForUse?.prodOptCdCval || '', prodOptTpCdCval: productOptionInfos?.[0]?.prodOptTpCdCval || '', + prodOptCval: optionLabel, }, + }) ); From 75ae1953453cdaf603fff236a10c6c30100bccd1 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Thu, 13 Nov 2025 09:52:14 +0900 Subject: [PATCH 25/26] =?UTF-8?q?[=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88]=20?= =?UTF-8?q?=EB=85=B8=EC=B6=9C=EA=B4=80=EB=A0=A8=20=EB=B0=8F=20api=EC=97=90?= =?UTF-8?q?=20=EB=A7=9E=EC=B6=B0=20=EC=9E=91=EC=97=85=20#1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 현재 추가는 안됌. - 삭제, 갯수 조절에 대해서는 정상작동. - 금액 노출 정상적이지 않는 부분에 대해서 수정 --- .../src/reducers/cartReducer.js | 19 ++----- .../src/views/CartPanel/CartProduct.jsx | 53 +++++++++---------- .../src/views/CheckOutPanel/CheckOutPanel.jsx | 17 +++--- .../components/OrderItemCard.jsx | 3 +- .../container/OrderItemsSideBar.jsx | 2 +- .../container/SummaryCotainer.jsx | 41 ++++++++------ 6 files changed, 67 insertions(+), 68 deletions(-) diff --git a/com.twin.app.shoptime/src/reducers/cartReducer.js b/com.twin.app.shoptime/src/reducers/cartReducer.js index b576a605..a4a7143c 100644 --- a/com.twin.app.shoptime/src/reducers/cartReducer.js +++ b/com.twin.app.shoptime/src/reducers/cartReducer.js @@ -40,31 +40,19 @@ export const cartReducer = (state = initialState, action) => { cartList: [...state.getMyinfoCartSearch.cartList, action.payload], totalCount: (state.getMyinfoCartSearch.totalCount || 0) + 1, }, - lastAction: { - type: "insert", - data: action.payload, - timestamp: Date.now(), - }, - error: null, }; // 장바구니에서 상품 삭제 - case types.DELETE_MY_INFO_CART: + case types.DELETE_MY_INFO_CART: return { ...state, getMyinfoCartSearch: { ...state.getMyinfoCartSearch, - cartList: state.getMyinfoCartSearch.cartList.filter( + cartList: (state.getMyinfoCartSearch.cartList || []).filter( item => item.prodSno !== action.payload.prodSno ), totalCount: Math.max(0, (state.getMyinfoCartSearch.totalCount || 0) - 1), }, - lastAction: { - type: "delete", - data: action.payload, - timestamp: Date.now(), - }, - error: null, }; case types.UPDATE_MY_INFO_CART: @@ -72,13 +60,12 @@ export const cartReducer = (state = initialState, action) => { ...state, getMyinfoCartSearch: { ...state.getMyinfoCartSearch, - cartList: state.getMyinfoCartSearch.cartList.map(item => + cartList: (state.getMyinfoCartSearch.cartList || []).map(item => item.prodSno === action.payload.prodSno ? { ...item, ...action.payload } : item ), }, - error: null, }; // 장바구니에 상품 추가 (addToCart - 로컬 상태용) diff --git a/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx b/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx index 5227dd52..8280d01e 100644 --- a/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx +++ b/com.twin.app.shoptime/src/views/CartPanel/CartProduct.jsx @@ -11,20 +11,17 @@ import { useSelector, } from 'react-redux'; -import Spotlight from '@enact/spotlight'; import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; -import logoImage from '../../../assets/images/ic-partners-qvc@3x.png'; import defaultImage from '../../../assets/images/img-thumb-empty-144@3x.png'; import { deleteMyinfoCart, removeFromCart, - updateCartItem, + updateMyinfoCart, } from '../../actions/cartActions'; import { removeFromMockCart, - setMockCartItemQuantity, updateSelectedItems, } from '../../actions/mockCartActions'; import CustomImage from '../../components/CustomImage/CustomImage'; @@ -98,6 +95,7 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { // 항상 호출되어야 하는 Hook들 const fallbackCartData = useSelector((state) => state.cart.getMyinfoCartSearch.cartInfo); const selectedItems = useSelector((state) => state.mockCart.selectedItems || []); + const userNumber = useSelector((state) => state.common.appStatus.loginUserData.userNumber); // 실제 장바구니 데이터와 Mock 데이터 중 선택 const cartData = cartInfo || fallbackCartData; @@ -158,32 +156,38 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { }; // 수량 조절 핸들러 - const handleDecreseClick = useCallback((prodSno, currentQty) => { + const handleDecreseClick = useCallback((prodSno, patnrId, prdtId, currentQty) => { if (currentQty > 1) { const newQty = currentQty - 1; if (isMockMode) { - dispatch(setMockCartItemQuantity(prodSno, newQty)); + // dispatch(setMockCartItemQuantity(prodSno, newQty)); } else { // 실제 API 호출을 위한 사용자 정보 필요 - const { userNumber } = store.getState().common.appStatus.loginUserData; + if (userNumber) { - dispatch(updateCartItem({ mbrNo: userNumber, cartSno: prodSno, prodQty: newQty })); + dispatch(updateMyinfoCart({ + mbrNo: userNumber, + patnrId, + prdtId, + prodSno, + prodQty: newQty + })); } } } }, [dispatch, isMockMode]); - const handleIncreseClick = useCallback((prodSno, currentQty) => { + const handleIncreseClick = useCallback((prodSno, patnrId, prdtId, currentQty) => { const newQty = currentQty + 1; if (isMockMode) { - dispatch(setMockCartItemQuantity(prodSno, newQty)); + // dispatch(setMockCartItemQuantity(prodSno, newQty)); } else { // 실제 API 호출을 위한 사용자 정보 필요 - const { userNumber } = store.getState().common.appStatus.loginUserData; + if (userNumber) { - dispatch(updateCartItem({ mbrNo: userNumber, cartSno: prodSno, prodQty: newQty })); + dispatch(updateMyinfoCart({ mbrNo: userNumber, patnrId, prdtId, prodSno, prodQty: newQty })); } } }, [dispatch, isMockMode]); @@ -266,19 +270,14 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { ); //장바구니 삭제 - const deleteCart = (patnrId, prdtId, prodSno) => { - const { userNumber } = store.getState().common.appStatus.loginUserData; - console.log("###test",userNumber, - patnrId, - prdtId, - prodSno) - // dispatch(deleteMyinfoCart({ - // mbrNo : userNumber, - // patnrId, - // prdtId, - // prodSno - // })) - } + const deleteCart = useCallback((patnrId, prdtId, prodSno) => { + dispatch(deleteMyinfoCart({ + mbrNo : userNumber, + patnrId: String(patnrId), + prdtId : String(prdtId), + prodSno : String(prodSno) + })) + },[dispatch]) return ( <> @@ -430,13 +429,13 @@ const CartProduct = ({ cartInfo, getScrollTo, scrollTop }) => { item.prodQty === 1 ? css.dimm : "" )} size="cartEa" - onClick={() => handleDecreseClick(item.prodSno, item.prodQty)} + onClick={() => handleDecreseClick(item.prodSno, item.patnrId, item.prdtId, item.prodQty)} spotlightId={"pd_ea_decrese"} spotlightDisabled={item.prodQty === 1} />
{item.prodQty}
handleIncreseClick(item.prodSno, item.prodQty)} + onClick={() => handleIncreseClick(item.prodSno, item.patnrId, item.prdtId, item.prodQty)} className={css.plusBox} spotlightId={"pd_ea_increse"} size="cartEa" diff --git a/com.twin.app.shoptime/src/views/CheckOutPanel/CheckOutPanel.jsx b/com.twin.app.shoptime/src/views/CheckOutPanel/CheckOutPanel.jsx index b9d43c1f..361a73eb 100644 --- a/com.twin.app.shoptime/src/views/CheckOutPanel/CheckOutPanel.jsx +++ b/com.twin.app.shoptime/src/views/CheckOutPanel/CheckOutPanel.jsx @@ -30,7 +30,10 @@ import { sendLogPaymentEntry, sendLogTotalRecommend, } from '../../actions/logActions'; -import { popPanel, updatePanel } from '../../actions/panelActions'; +import { + popPanel, + updatePanel, +} from '../../actions/panelActions'; import TBody from '../../components/TBody/TBody'; import TButton from '../../components/TButton/TButton'; import TButtonScroller from '../../components/TButtonScroller/TButtonScroller'; @@ -615,7 +618,7 @@ export default function CheckOutPanel({ panelInfo }) {
- {BUYNOW_CONFIG.isMockMode() ? ( + {/* {BUYNOW_CONFIG.isMockMode() ? ( - ) : ( + ) : ( */} - )} - {BUYNOW_CONFIG.isMockMode() ? ( + {/* )} */} + {/* {BUYNOW_CONFIG.isMockMode() ? ( - ) : ( + ) : ( */} - )} + {/* )} */}
diff --git a/com.twin.app.shoptime/src/views/CheckOutPanel/components/OrderItemCard.jsx b/com.twin.app.shoptime/src/views/CheckOutPanel/components/OrderItemCard.jsx index 1cc71093..3353f526 100644 --- a/com.twin.app.shoptime/src/views/CheckOutPanel/components/OrderItemCard.jsx +++ b/com.twin.app.shoptime/src/views/CheckOutPanel/components/OrderItemCard.jsx @@ -41,7 +41,6 @@ export default memo(function OrderItemCard({ const priceTotalData = useSelector( (state) => state.checkout?.checkoutTotalData ); - console.log("###priceTotalData",priceTotalData); const formattedPrices = useMemo(() => { return { @@ -83,7 +82,7 @@ export default memo(function OrderItemCard({

- $ {(price * prodQty).toLocaleString('en-US', { + $ {(Number(price) * Number(prodQty)).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} diff --git a/com.twin.app.shoptime/src/views/CheckOutPanel/container/OrderItemsSideBar.jsx b/com.twin.app.shoptime/src/views/CheckOutPanel/container/OrderItemsSideBar.jsx index 82838475..35700b0e 100644 --- a/com.twin.app.shoptime/src/views/CheckOutPanel/container/OrderItemsSideBar.jsx +++ b/com.twin.app.shoptime/src/views/CheckOutPanel/container/OrderItemsSideBar.jsx @@ -165,7 +165,7 @@ export default function OrderItemsSideBar({ patncLogPath={item.patncLogPath} prdtId={item.prdtId} expsPrdtNo={item.expsPrdtNo} - price={item.price >= item.originalPrice ? item.originalPrice : item.price} + price={item.price2 >= item.price3 ? item.price3 : item.price2} currSign={item.currSign} currSignLoc={item.currSignLoc} shippingCharge={item.shippingCharge} diff --git a/com.twin.app.shoptime/src/views/CheckOutPanel/container/SummaryCotainer.jsx b/com.twin.app.shoptime/src/views/CheckOutPanel/container/SummaryCotainer.jsx index 4d8c99f1..c803ac1c 100644 --- a/com.twin.app.shoptime/src/views/CheckOutPanel/container/SummaryCotainer.jsx +++ b/com.twin.app.shoptime/src/views/CheckOutPanel/container/SummaryCotainer.jsx @@ -1,21 +1,32 @@ -import React, { useCallback, useEffect, useMemo } from "react"; +import React, { + useCallback, + useEffect, + useMemo, +} from 'react'; -import { useDispatch, useSelector } from "react-redux"; +import { + useDispatch, + useSelector, +} from 'react-redux'; -import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator"; +import SpotlightContainerDecorator + from '@enact/spotlight/SpotlightContainerDecorator'; -import { setHidePopup, setShowPopup } from "../../../actions/commonActions"; -import { popPanel } from "../../../actions/panelActions"; -import TButton from "../../../components/TButton/TButton"; -import TPopUp from "../../../components/TPopUp/TPopUp"; -import * as Config from "../../../utils/Config"; +import { + setHidePopup, + setShowPopup, +} from '../../../actions/commonActions'; +import { sendLogTotalRecommend } from '../../../actions/logActions'; +import { popPanel } from '../../../actions/panelActions'; +import TButton from '../../../components/TButton/TButton'; +import TPopUp from '../../../components/TPopUp/TPopUp'; +import * as Config from '../../../utils/Config'; import { $L, formatCurrencyValue, getErrorMessage, -} from "../../../utils/helperMethods"; -import css from "./SummaryContainer.module.less"; -import { sendLogTotalRecommend } from "../../../actions/logActions"; +} from '../../../utils/helperMethods'; +import css from './SummaryContainer.module.less'; const Container = SpotlightContainerDecorator( { enterTo: "last-focused" }, @@ -51,12 +62,12 @@ export default function SummaryContainer({ // Mock Mode: priceTotalData가 없으면 가짜 데이터 제공 const effectivePriceTotalData = hasValidPriceTotalData ? priceTotalData : { - totProdPrc: 521.66, + totProdPrc: 0.00, totDcAmt: 0, totDlvrAmt: 0, - ordPmtNoTaxAmt: 521.66, - ordTotTaxAmt: 50, - ordPmtReqAmt: 571.66 + ordPmtNoTaxAmt: 0.0, + ordTotTaxAmt: 0, + ordPmtReqAmt: 0.00, }; const items = useMemo( From 81e537e39ba137842aade907232701f9eed772c2 Mon Sep 17 00:00:00 2001 From: "junghoon86.park" Date: Thu, 13 Nov 2025 13:29:12 +0900 Subject: [PATCH 26/26] =?UTF-8?q?[=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=20?= =?UTF-8?q?=EB=8B=B4=EA=B8=B0=20=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95]?= =?UTF-8?q?=20=20-=20=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=20=EB=8B=B4?= =?UTF-8?q?=EB=8A=94=EB=B6=80=EB=B6=84=EC=97=90=EC=84=9C=20=EB=B0=B0?= =?UTF-8?q?=EC=97=B4=EB=A1=9C=20=EC=98=B5=EC=85=98=EC=9D=84=20=EB=84=A3?= =?UTF-8?q?=EC=96=B4=EC=95=BC=ED=95=9C=EB=8B=A4=ED=95=98=EC=97=AC=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=EC=B2=98=EB=A6=AC.=20=20-=20cartaction?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=A0=95=EC=83=81=EC=A0=81=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=95=88=EB=93=A4=EC=96=B4=EC=99=94=EC=9D=84?= =?UTF-8?q?=EB=95=8C=EB=8A=94=20=EC=97=90=EB=9F=AC=EB=85=B8=EC=B6=9C?= =?UTF-8?q?=EB=90=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/actions/cartActions.js | 38 ++++++++++++------- .../DetailPanel/components/BuyOption.jsx | 4 +- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/cartActions.js b/com.twin.app.shoptime/src/actions/cartActions.js index f63c5ae5..70258e5e 100644 --- a/com.twin.app.shoptime/src/actions/cartActions.js +++ b/com.twin.app.shoptime/src/actions/cartActions.js @@ -1,6 +1,7 @@ import { URLS } from '../api/apiConfig'; import { TAxios } from '../api/TAxios'; import { types } from './actionTypes'; +import { showError } from './commonActions'; /** * 회원 장바구니 정보 조회 @@ -57,24 +58,33 @@ export const insertMyinfoCart = (props) => (dispatch, getState) => { const { mbrNo, patnrId, prdtId, prdtOpt, prodQty } = props; const onSuccess = (response) => { - console.log("✅ insertMyinfoCart API 성공:", response.data); - if (response.data.retCode !== '0' && response.data.retCode !== 0) { - console.error("❌ retCode 에러:", response.data.retCode); - console.error("에러 메시지:", response.data.retMsg); + console.log("✅ insertMyinfoCart API 성공:", response.data.retCode); + // if (response.data?.retCode !== '0' && response.data.retCode !== 0) { + // console.error("❌ retCode 에러:", response.data.retCode); + // console.error("에러 메시지:", response.data.retMsg); - return; - } - // response.data.data가 실제 상품 정보인지 확인 - if (!response.data.data) { - console.warn("⚠️ response.data.data가 undefined입니다"); - } - + // return; + // } + + if (response.data.retCode === 0) { dispatch({ type: types.INSERT_MY_INFO_CART, payload: response.data.data, - }); - - dispatch(getMyInfoCartSearch({ mbrNo })); + }); + dispatch(getMyInfoCartSearch({ mbrNo })); + } else { + dispatch( + showError( + response.data.retCode, + response.data.retMsg, + false, + null, + null + ) + ); + console.error("❌ retCode 에러:", response.data.retCode); + console.error("에러 메시지:", response.data.retMsg); + } }; const onFail = (error) => { 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 a53c9078..d2b4afa9 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/components/BuyOption.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/components/BuyOption.jsx @@ -1092,12 +1092,12 @@ const BuyOption = ({ patnrId: selectedPatnrId, prdtId: selectedPrdtId, prodQty: Number(effectiveQuantity), - prdtOpt: { + prdtOpt: [{ prodOptSno: productOptionInfos?.[0]?.prodOptSno || '', prodOptCdCval: optionForUse?.prodOptCdCval || '', prodOptTpCdCval: productOptionInfos?.[0]?.prodOptTpCdCval || '', prodOptCval: optionLabel, - }, + }], }) );