diff --git a/com.twin.app.shoptime/compare-branches.sh b/com.twin.app.shoptime/compare-branches.sh
new file mode 100755
index 00000000..795bcef1
--- /dev/null
+++ b/com.twin.app.shoptime/compare-branches.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+# 브랜치 비교 스크립트
+# 사용법: ./compare-branches.sh <파일경로> [브랜치1] [브랜치2]
+
+FILE_PATH=$1
+BRANCH1=${2:-develop}
+BRANCH2=${3:-feature/si_log}
+
+if [ -z "$FILE_PATH" ]; then
+ echo "❌ 사용법: ./compare-branches.sh <파일경로> [브랜치1] [브랜치2]"
+ echo ""
+ echo "예시:"
+ echo " ./compare-branches.sh src/App/deepLinkHandler.js"
+ echo " ./compare-branches.sh src/actions/logActions.js develop develop_si"
+ exit 1
+fi
+
+FILENAME=$(basename "$FILE_PATH")
+TEMP_DIR="/tmp/branch_compare"
+
+# 브랜치 이름에서 슬래시를 언더스코어로 변경
+BRANCH1_SAFE=$(echo "$BRANCH1" | sed 's/\//_/g')
+BRANCH2_SAFE=$(echo "$BRANCH2" | sed 's/\//_/g')
+
+mkdir -p "$TEMP_DIR"
+
+echo "🔍 비교 중..."
+echo " 📂 파일: $FILE_PATH"
+echo " 🌿 브랜치1: $BRANCH1"
+echo " 🌿 브랜치2: $BRANCH2"
+echo ""
+
+git show "$BRANCH1:com.twin.app.shoptime/$FILE_PATH" > "$TEMP_DIR/${FILENAME}_${BRANCH1_SAFE}" 2>/dev/null
+if [ $? -ne 0 ]; then
+ echo "❌ 오류: $BRANCH1 브랜치에서 파일을 찾을 수 없습니다."
+ exit 1
+fi
+
+git show "$BRANCH2:com.twin.app.shoptime/$FILE_PATH" > "$TEMP_DIR/${FILENAME}_${BRANCH2_SAFE}" 2>/dev/null
+if [ $? -ne 0 ]; then
+ echo "❌ 오류: $BRANCH2 브랜치에서 파일을 찾을 수 없습니다."
+ exit 1
+fi
+
+echo "✅ 파일 추출 완료!"
+echo "📊 라인 수:"
+wc -l "$TEMP_DIR/${FILENAME}_${BRANCH1_SAFE}" "$TEMP_DIR/${FILENAME}_${BRANCH2_SAFE}"
+echo ""
+echo "🎨 Cursor에서 비교 화면 열기..."
+
+code --diff "$TEMP_DIR/${FILENAME}_${BRANCH1_SAFE}" "$TEMP_DIR/${FILENAME}_${BRANCH2_SAFE}"
+
+echo "✨ 완료!"
+
diff --git a/com.twin.app.shoptime/src/App/deepLinkHandler.js b/com.twin.app.shoptime/src/App/deepLinkHandler.js
index 67f5e4c7..40c822d3 100644
--- a/com.twin.app.shoptime/src/App/deepLinkHandler.js
+++ b/com.twin.app.shoptime/src/App/deepLinkHandler.js
@@ -1,4 +1,3 @@
-
import { updateHomeInfo } from "../actions/homeActions";
import { pushPanel } from "../actions/panelActions";
import {
@@ -252,18 +251,22 @@ export const handleDeepLink = (contentTarget) => (dispatch, _getState) => {
// break;
}
+ // 251204 [통합로그] webOS 에서 shoptime 진입점 정보 수집
+ const isFirstLaunch = _getState().common.appStatus?.isFirstLaunch;
+
dispatch(
sendLogTotalRecommend({
contextName: LOG_CONTEXT_NAME.ENTRY,
messageId: LOG_MESSAGE_ID.ENTRY_INFO,
- deeplink: deeplinkPanel,
- curationId: curationId ? curationId : showId,
- productId: prdtId,
- partnerID: patnrId,
+ entryMenu: linkTpNm,
+ deeplink: type,
+ linkTypeCode: linkTpCd,
+ curationId: curationId,
showId: showId,
channelId: chanId,
+ productId: prdtId,
category: lgCatNm,
- linkTypeCode: linkTpCd,
+ firstYn: isFirstLaunch ? "Y" : "N",
})
);
diff --git a/com.twin.app.shoptime/src/components/MobileSend/MobileSendPopUp.jsx b/com.twin.app.shoptime/src/components/MobileSend/MobileSendPopUp.jsx
index 7c10576d..cf0f0aa4 100644
--- a/com.twin.app.shoptime/src/components/MobileSend/MobileSendPopUp.jsx
+++ b/com.twin.app.shoptime/src/components/MobileSend/MobileSendPopUp.jsx
@@ -4,72 +4,61 @@ import React, {
useMemo,
useRef,
useState,
-} from 'react';
+} from "react";
-import classNames from 'classnames';
+import classNames from "classnames";
import {
AsYouTypeFormatter,
PhoneNumberFormat,
PhoneNumberUtil,
-} from 'google-libphonenumber';
-import {
- useDispatch,
- useSelector,
-} from 'react-redux';
+} from "google-libphonenumber";
+import { useDispatch, useSelector } from "react-redux";
-import {
- off,
- on,
-} from '@enact/core/dispatcher';
-import spotlight, { Spotlight } from '@enact/spotlight';
-import {
- SpotlightContainerDecorator,
-} from '@enact/spotlight/SpotlightContainerDecorator';
-import { Spottable } from '@enact/spotlight/Spottable';
+import { off, on } from "@enact/core/dispatcher";
+import spotlight, { Spotlight } from "@enact/spotlight";
+import { SpotlightContainerDecorator } from "@enact/spotlight/SpotlightContainerDecorator";
+import { Spottable } from "@enact/spotlight/Spottable";
-import defaultImage from '../../../assets/images/img-thumb-empty-144@3x.png';
-import { types } from '../../actions/actionTypes';
-import {
- clearSMS,
- sendSms,
-} from '../../actions/appDataActions';
+import defaultImage from "../../../assets/images/img-thumb-empty-144@3x.png";
+import { types } from "../../actions/actionTypes";
+import { clearSMS, sendSms } from "../../actions/appDataActions";
import {
changeLocalSettings,
setHidePopup,
setShowPopup,
-} from '../../actions/commonActions';
+} from "../../actions/commonActions";
import {
clearRegisterDeviceInfo,
getDeviceAdditionInfo,
registerDeviceInfo,
-} from '../../actions/deviceActions';
+} from "../../actions/deviceActions";
import {
clearCurationCoupon,
setEventIssueReq,
-} from '../../actions/eventActions';
+} from "../../actions/eventActions";
import {
sendLogShopByMobile,
sendLogTotalRecommend,
-} from '../../actions/logActions';
+} from "../../actions/logActions";
import {
ACTIVE_POPUP,
LOG_CONTEXT_NAME,
LOG_MESSAGE_ID,
LOG_TP_NO,
-} from '../../utils/Config';
+} from "../../utils/Config";
import {
$L,
decryptPhoneNumber,
encryptPhoneNumber,
formatLocalDateTime,
-} from '../../utils/helperMethods';
-import CustomImage from '../CustomImage/CustomImage';
-import TButton from '../TButton/TButton';
-import TPopUp from '../TPopUp/TPopUp';
-import HistoryPhoneNumber from './HistoryPhoneNumber/HistoryPhoneNumber';
-import css from './MobileSendPopUp.module.less';
-import PhoneInputSection from './PhoneInputSection';
-import SMSNumKeyPad from './SMSNumKeyPad';
+} from "../../utils/helperMethods";
+import CustomImage from "../CustomImage/CustomImage";
+import TButton from "../TButton/TButton";
+import TPopUp from "../TPopUp/TPopUp";
+import HistoryPhoneNumber from "./HistoryPhoneNumber/HistoryPhoneNumber";
+import css from "./MobileSendPopUp.module.less";
+import PhoneInputSection from "./PhoneInputSection";
+import SMSNumKeyPad from "./SMSNumKeyPad";
const SECRET_KEY = "fy7BTKuM9eeTQqEC9sF3Iw5qG43Aaip";
@@ -463,7 +452,10 @@ export default function MobileSendPopUp({
const logParams = {
status: "send",
nowMenu: nowMenu,
- partner: patncNm,
+ partner: patncNm ?? shopByMobileLogRef?.current?.patncNm,
+ productId: prdtId ?? shopByMobileLogRef?.current?.prdtId,
+ productTitle: title ?? shopByMobileLogRef?.current?.prdtNm,
+ brand: shopByMobileLogRef?.current?.brndNm,
contextName: LOG_CONTEXT_NAME.SHOPBYMOBILE,
messageId: LOG_MESSAGE_ID.SMB,
};
@@ -652,7 +644,7 @@ export default function MobileSendPopUp({
)}
{mobileNumber}
-
+
{keyPadOff && recentSentNumber.length > 0 ? (
{
if (onFocus) {
diff --git a/com.twin.app.shoptime/src/views/DetailPanel/YouMayLike/YouMayLike.jsx b/com.twin.app.shoptime/src/views/DetailPanel/YouMayLike/YouMayLike.jsx
index 1f01a705..5172e143 100644
--- a/com.twin.app.shoptime/src/views/DetailPanel/YouMayLike/YouMayLike.jsx
+++ b/com.twin.app.shoptime/src/views/DetailPanel/YouMayLike/YouMayLike.jsx
@@ -173,8 +173,9 @@ export default memo(function YouMayLike({
productTitle={prdtNm}
nowProductId={productInfo?.prdtId}
nowProductTitle={productInfo?.prdtNm}
- nowCategory={productInfo?.catNm}
+ nowCategory={productInfo?.catNm ?? productInfo?.lgCatNm}
catNm={lgCatNm}
+ category={lgCatNm}
patnerName={patncNm}
brandName={brndNm}
imageAlt={prdtId}
diff --git a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedBrandsPanel.jsx b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedBrandsPanel.jsx
index 598f6c4c..72320b97 100644
--- a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedBrandsPanel.jsx
+++ b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedBrandsPanel.jsx
@@ -319,10 +319,11 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
return;
}
+ const templateCode = containerId?.split("-")[0] || containerId;
const foundElement = sortedBrandLayoutInfo.find(
- (el) => el.shptmBrndOptTpCd === containerId
+ (el) => el.shptmBrndOptTpCd === templateCode
);
- const actualShelfOrder = foundElement ? foundElement.expsOrd : null;
+ const actualShelfOrder = foundElement ? foundElement.expsOrd : 0;
const selectedBrand = `${LOG_MENU.FEATURED_BRANDS}/${selectedPatncNm}`;
const currentShelf = `${getMenuByContainerId(containerId)}`;
diff --git a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/LiveChannels/LiveChannelsVerticalContents/LiveChannelsVerticalContents.jsx b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/LiveChannels/LiveChannelsVerticalContents/LiveChannelsVerticalContents.jsx
index b961203f..e2f41402 100644
--- a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/LiveChannels/LiveChannelsVerticalContents/LiveChannelsVerticalContents.jsx
+++ b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/LiveChannels/LiveChannelsVerticalContents/LiveChannelsVerticalContents.jsx
@@ -25,7 +25,11 @@ import {
finishVideoPreview,
startVideoPlayer,
} from "../../../../actions/playActions";
-import { 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 "./LiveChannelsVerticalContents.module.less";
import LiveChannelsVerticalProductList from "./LiveChannelsVerticalProductList/LiveChannelsVerticalProductList";
@@ -175,10 +179,14 @@ const LiveChannelsVerticalContents = ({
dispatch(
sendLogTotalRecommend({
+ contextName: LOG_CONTEXT_NAME.FEATURED_BRANDS,
+ messageId: LOG_MESSAGE_ID.SHELF_CLICK,
partner: chanNm,
shelfLocation: shelfOrder,
shelfId: spotlightId,
shelfTitle: shelfTitle,
+ showId: showId,
+ showTitle: showNm,
contentId: showId,
contentTitle: showNm,
brand: brndNm,
diff --git a/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/Favorites/Favorites.jsx b/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/Favorites/Favorites.jsx
index 4122bc5c..ec7ee352 100644
--- a/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/Favorites/Favorites.jsx
+++ b/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/Favorites/Favorites.jsx
@@ -217,6 +217,8 @@ export default function Favorites({ title, panelInfo, isOnTop }) {
(patnrId, prdtId, prdtNm, patncNm, showId, showNm, brndNm) => (ev) => {
const params = {
menu: "Favorite",
+ contentId: showId ?? prdtId,
+ contentTitle: showNm ?? prdtNm,
productId: prdtId,
productTitle: prdtNm,
partner: patncNm,
@@ -340,7 +342,10 @@ export default function Favorites({ title, panelInfo, isOnTop }) {
item.patnrId,
item.prdtId,
item.prdtNm,
- item.patncNm
+ item.patncNm,
+ item.showId,
+ item.showNm,
+ item.brndNm
)}
onToggle={handleItemToggle(item.prdtId)}
length={favoritesDatas.length}
diff --git a/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/RecentlyViewed/RecentlyViewedContents.jsx b/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/RecentlyViewed/RecentlyViewedContents.jsx
index aa41ecd1..aa1432a8 100644
--- a/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/RecentlyViewed/RecentlyViewedContents.jsx
+++ b/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/RecentlyViewed/RecentlyViewedContents.jsx
@@ -145,6 +145,7 @@ export default function RecentlyViewedContents({
lgCatCd,
thumbnailUrl,
showNm,
+ brndNm,
} = item;
return (
() => {
+ const params = {
+ menu: "Reminders",
+ contentId: showId,
+ contentTitle: showNm,
+ showId: showId,
+ showTitle: showNm,
+ partner: patncNm,
+ brand: brndNm,
+ contextName: Config.LOG_CONTEXT_NAME.MYPAGE,
+ messageId: Config.LOG_MESSAGE_ID.MYPAGE_CLICK,
+ };
+ dispatch(sendLogTotalRecommend(params));
+ },
+ [dispatch]
+ );
const renderItem = useCallback(
({ index, ...rest }) => {
const sortedAlertShows = upComingAlertShow.alertShows
@@ -298,15 +315,29 @@ export default function Reminders({ title, cbScrollTo }) {
showNm={listItem.showNm}
strtDt={listItem.strtDt}
thumbnailUrl={listItem.thumbnailUrl}
+ brndNm={listItem.brndNm}
activeDelete={activeDelete}
selected={selectedItems[listItem.showId]}
onToggle={handleItemToggle(listItem.showId)}
+ onClick={handleItemClick(
+ listItem.showId,
+ listItem.showNm,
+ listItem.patncNm,
+ listItem.brndNm,
+ listItem.patnrId
+ )}
index={index}
length={upComingAlertShow.alertShows.length}
/>
);
},
- [upComingAlertShow, activeDelete, selectedItems, handleItemToggle]
+ [
+ upComingAlertShow,
+ activeDelete,
+ selectedItems,
+ handleItemToggle,
+ handleItemClick,
+ ]
);
return (
diff --git a/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleContents/OnSaleContents.jsx b/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleContents/OnSaleContents.jsx
index 405b92d2..e7fe7c72 100644
--- a/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleContents/OnSaleContents.jsx
+++ b/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleContents/OnSaleContents.jsx
@@ -36,7 +36,7 @@ export default memo(function OnSaleContents({
messageId: LOG_MESSAGE_ID.SHELF,
category: selectedLgCatNm,
shelfLocation: shelfOrder,
- shelfId: selectedLgCatCd,
+ shelfId: spotlightId,
shelfTitle: saleNm,
};
dispatch(sendLogTotalRecommend(params));
diff --git a/com.twin.app.shoptime/src/views/OnSalePanel/OnSalePanel.jsx b/com.twin.app.shoptime/src/views/OnSalePanel/OnSalePanel.jsx
index 6d27bef2..b440330a 100644
--- a/com.twin.app.shoptime/src/views/OnSalePanel/OnSalePanel.jsx
+++ b/com.twin.app.shoptime/src/views/OnSalePanel/OnSalePanel.jsx
@@ -108,8 +108,9 @@ export default function OnSalePanel({ panelInfo, spotlightId }) {
if (categoryInfos) {
dispatch(copyCategoryInfos(categoryInfos));
setCategories(categoryInfos);
- setSelectedLgCatCd(panelInfo?.lgCatCd);
- setSelectedLgCatNm(panelInfo?.lgCatNm);
+ // GNB 진입 시 panelInfo가 비어있으면 첫 번째 카테고리를 기본값으로 설정
+ setSelectedLgCatCd(panelInfo?.lgCatCd ?? categoryInfos[0]?.lgCatCd);
+ setSelectedLgCatNm(panelInfo?.lgCatNm ?? categoryInfos[0]?.lgCatNm);
}
}
}, [
diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx
index 440d6077..40af25e0 100644
--- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx
+++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx
@@ -1,38 +1,60 @@
-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 classNames from "classnames";
+import { useDispatch, useSelector } from "react-redux";
-import { Job } from '@enact/core/util';
-import Spotlight from '@enact/spotlight';
-import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
-import { getContainerNode, setContainerLastFocusedElement } from '@enact/spotlight/src/container';
+import { Job } from "@enact/core/util";
+import Spotlight from "@enact/spotlight";
+import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
+import {
+ getContainerNode,
+ setContainerLastFocusedElement,
+} from "@enact/spotlight/src/container";
-import { sendLogTotalRecommend } from '../../../../actions/logActions';
-import { navigateToDetail, SOURCE_MENUS, pushPanel } from '../../../../actions/panelActions';
-import { hidePlayerOverlays } from '../../../../actions/videoPlayActions';
-import TItemCard, { TYPES } from '../../../../components/TItemCard/TItemCard';
-import TVirtualGridList from '../../../../components/TVirtualGridList/TVirtualGridList';
-import useScrollTo from '../../../../hooks/useScrollTo';
-import { LOG_CONTEXT_NAME, LOG_MENU, LOG_MESSAGE_ID, panel_names } from '../../../../utils/Config';
-import { scaleH } from '../../../../utils/helperMethods';
-import ListEmptyContents from '../TabContents/ListEmptyContents/ListEmptyContents';
-import css1 from './ShopNowContents.module.less';
-import cssV2 from './ShopNowContents.v2.module.less';
+import { sendLogTotalRecommend } from "../../../../actions/logActions";
+import {
+ navigateToDetail,
+ SOURCE_MENUS,
+ pushPanel,
+} from "../../../../actions/panelActions";
+import { hidePlayerOverlays } from "../../../../actions/videoPlayActions";
+import TItemCard, { TYPES } from "../../../../components/TItemCard/TItemCard";
+import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList";
+import useScrollTo from "../../../../hooks/useScrollTo";
+import {
+ LOG_CONTEXT_NAME,
+ LOG_MENU,
+ LOG_MESSAGE_ID,
+ panel_names,
+} from "../../../../utils/Config";
+import { scaleH } from "../../../../utils/helperMethods";
+import ListEmptyContents from "../TabContents/ListEmptyContents/ListEmptyContents";
+import css1 from "./ShopNowContents.module.less";
+import cssV2 from "./ShopNowContents.v2.module.less";
const extractPriceInfo = (priceInfo) => {
- if (!priceInfo) return { originalPrice: '', discountedPrice: '', discountRate: '' };
+ if (!priceInfo)
+ return { originalPrice: "", discountedPrice: "", discountRate: "" };
- const parts = priceInfo.split('|').map((part) => part.trim());
+ const parts = priceInfo.split("|").map((part) => part.trim());
return {
- originalPrice: parts[0] || '',
- discountedPrice: parts[1] || '',
- discountRate: parts[4] || '',
+ originalPrice: parts[0] || "",
+ discountedPrice: parts[1] || "",
+ discountRate: parts[4] || "",
};
};
-const Container = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
+const Container = SpotlightContainerDecorator(
+ { enterTo: "last-focused" },
+ "div"
+);
export default function ShopNowContents({
shopNowInfo,
videoVerticalVisible,
@@ -42,7 +64,7 @@ export default function ShopNowContents({
panelInfo,
tabTitle,
version = 1,
- direction = 'vertical',
+ direction = "vertical",
}) {
const css = version === 2 ? cssV2 : css1;
const { getScrollTo, scrollTop } = useScrollTo();
@@ -54,12 +76,12 @@ export default function ShopNowContents({
const gridStyle = useMemo(() => ({ height: `${height}px` }), [height]);
useEffect(() => {
- console.log('=== [ShopNow] Component Rendered ===');
- console.log('[ShopNow] shopNowInfo:', shopNowInfo);
- console.log('[ShopNow] youmaylikeInfos:', youmaylikeInfos);
- console.log('[ShopNow] version:', version);
- console.log('[ShopNow] tabIndex:', tabIndex);
- console.log('=====================================');
+ console.log("=== [ShopNow] Component Rendered ===");
+ console.log("[ShopNow] shopNowInfo:", shopNowInfo);
+ console.log("[ShopNow] youmaylikeInfos:", youmaylikeInfos);
+ console.log("[ShopNow] version:", version);
+ console.log("[ShopNow] tabIndex:", tabIndex);
+ console.log("=====================================");
}, [shopNowInfo, youmaylikeInfos, version, tabIndex]);
// ShopNow + YouMayLike 통합 아이템 (v2이고 shopNow < 3일 때만)
@@ -69,17 +91,17 @@ export default function ShopNowContents({
// 기본: ShopNow 아이템
let items = shopNowInfo.map((item) => ({
...item,
- _type: 'shopnow',
+ _type: "shopnow",
}));
// v2 + ShopNow < 3 + YouMayLike 데이터 존재 시 통합
- // for Test =>
+ // for Test =>
if (version === 2 && youmaylikeInfos && youmaylikeInfos.length > 0) {
- // if (version === 2 && shopNowInfo.length < 3 && youmaylikeInfos && youmaylikeInfos.length > 0) {
+ // if (version === 2 && shopNowInfo.length < 3 && youmaylikeInfos && youmaylikeInfos.length > 0) {
items = items.concat(
youmaylikeInfos.map((item) => ({
...item,
- _type: 'youmaylike',
+ _type: "youmaylike",
}))
);
}
@@ -102,7 +124,7 @@ export default function ShopNowContents({
useEffect(() => {
return () => {
- const gridListId = 'playVideoShopNowBox';
+ const gridListId = "playVideoShopNowBox";
const girdList = getContainerNode(gridListId);
if (girdList) setContainerLastFocusedElement(null, [gridListId]);
@@ -144,14 +166,17 @@ export default function ShopNowContents({
const item = combinedItems[index];
// ===== YouMayLike 아이템 처리 =====
- if (item._type === 'youmaylike') {
+ if (item._type === "youmaylike") {
const { imgUrl, patnrId, prdtId, prdtNm, priceInfo, offerInfo } = item;
// YouMayLike 시작 지점 여부 (구분선 표시)
const isYouMayLikeStart = shopNowInfo && index === shopNowInfo.length;
const handleYouMayLikeItemClick = () => {
- console.log('[ShopNowContents] DetailPanel 진입 - sourceMenu:', SOURCE_MENUS.PLAYER_SHOP_NOW);
+ console.log(
+ "[ShopNowContents] DetailPanel 진입 - sourceMenu:",
+ SOURCE_MENUS.PLAYER_SHOP_NOW
+ );
dispatch(
navigateToDetail({
@@ -195,7 +220,7 @@ export default function ShopNowContents({
onSpotlightUp={(e) => {
e.stopPropagation();
e.preventDefault();
- Spotlight.focus('shownow_close_button');
+ Spotlight.focus("shownow_close_button");
}}
type={TYPES.horizontal}
version={version}
@@ -216,10 +241,12 @@ export default function ShopNowContents({
patncNm,
brndNm,
catNm,
+ lgCatNm,
} = item;
// 미리 계산된 가격 정보를 사용
- const { originalPrice, discountedPrice, discountRate } = priceInfoMap[index] || {};
+ const { originalPrice, discountedPrice, discountRate } =
+ priceInfoMap[index] || {};
const handleShopNowItemClick = () => {
// ===== 기존 코드 (코멘트 처리) =====
@@ -228,20 +255,20 @@ export default function ShopNowContents({
// const currentSpotlightId = currentFocusedElement?.getAttribute('data-spotlight-id');
// console.log('[ShopNowContents] 현재 포커스된 spotlightId:', currentSpotlightId);
- // const params = {
- // tabTitle: tabTitle[tabIndex],
- // productId: prdtId,
- // productTitle: prdtNm,
- // partner: patncNm,
- // brand: brndNm,
- // price: discountRate ? discountedPrice : originalPrice,
- // showType: panelInfo?.shptmBanrTpNm,
- // category: catNm,
- // discount: discountRate,
- // contextName: LOG_CONTEXT_NAME.SHOW,
- // messageId: LOG_MESSAGE_ID.CONTENTCLICK,
- // };
- // dispatch(sendLogTotalRecommend(params));
+ const params = {
+ tabTitle: tabTitle[tabIndex],
+ productId: prdtId,
+ productTitle: prdtNm,
+ partner: patncNm,
+ brand: brndNm,
+ price: discountRate ? discountedPrice : originalPrice,
+ showType: panelInfo?.shptmBanrTpNm,
+ category: catNm ?? lgCatNm,
+ discount: discountRate,
+ contextName: LOG_CONTEXT_NAME.SHOW,
+ messageId: LOG_MESSAGE_ID.CONTENTCLICK,
+ };
+ dispatch(sendLogTotalRecommend(params));
// // DetailPanel push 전에 VideoPlayer 오버레이 숨김
// dispatch(hidePlayerOverlays());
@@ -264,7 +291,10 @@ export default function ShopNowContents({
// );
// ===== navigateToDetail 방식 (handleYouMayLikeItemClick 참고) =====
- console.log('[ShopNowContents] ShopNow DetailPanel 진입 - sourceMenu:', SOURCE_MENUS.PLAYER_SHOP_NOW);
+ console.log(
+ "[ShopNowContents] ShopNow DetailPanel 진입 - sourceMenu:",
+ SOURCE_MENUS.PLAYER_SHOP_NOW
+ );
dispatch(
navigateToDetail({
@@ -276,7 +306,7 @@ export default function ShopNowContents({
showId: playListInfo?.showId,
liveFlag: playListInfo?.liveFlag,
thumbnailUrl: playListInfo?.thumbnailUrl,
- liveReqFlag: panelInfo?.shptmBanrTpNm === 'LIVE' && 'Y',
+ liveReqFlag: panelInfo?.shptmBanrTpNm === "LIVE" && "Y",
launchedFromPlayer: true,
},
})
@@ -304,7 +334,7 @@ export default function ShopNowContents({
// v2에서 첫 번째 아이템일 때 위로 가면 Close 버튼으로
e.stopPropagation();
e.preventDefault();
- Spotlight.focus('shownow_close_button');
+ Spotlight.focus("shownow_close_button");
}
: undefined
}
@@ -341,7 +371,9 @@ export default function ShopNowContents({
itemWidth={version === 2 ? 310 : videoVerticalVisible ? 540 : 600}
itemHeight={version === 2 ? 445 : 236}
spacing={version === 2 ? 30 : 12}
- className={videoVerticalVisible ? css.verticalItemList : css.itemList}
+ className={
+ videoVerticalVisible ? css.verticalItemList : css.itemList
+ }
noScrollByWheel={false}
spotlightId="playVideoShopNowBox"
/>
diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.jsx
index 2cdb026c..dbe94d8b 100644
--- a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.jsx
+++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.jsx
@@ -4,55 +4,41 @@ import React, {
useMemo,
useRef,
useState,
-} from 'react';
+} from "react";
-import {
- useDispatch,
- useSelector,
-} from 'react-redux';
+import { useDispatch, useSelector } from "react-redux";
-import { Job } from '@enact/core/util';
-import Spotlight from '@enact/spotlight';
-import SpotlightContainerDecorator
- from '@enact/spotlight/SpotlightContainerDecorator';
-import { setContainerLastFocusedElement } from '@enact/spotlight/src/container';
+import { Job } from "@enact/core/util";
+import Spotlight from "@enact/spotlight";
+import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
+import { setContainerLastFocusedElement } from "@enact/spotlight/src/container";
-import {
- sendLogGNB,
- sendLogTotalRecommend,
-} from '../../actions/logActions';
-import { getMyRecommandedKeyword } from '../../actions/myPageActions';
-import {
- popPanel,
- updatePanel,
-} from '../../actions/panelActions';
-import {
- getSearch,
- resetSearch,
-} from '../../actions/searchActions';
-import TBody from '../../components/TBody/TBody';
-import TInput, {
- ICONS,
- KINDS,
-} from '../../components/TInput/TInput';
-import TPanel from '../../components/TPanel/TPanel';
-import TVerticalPagenator
- from '../../components/TVerticalPagenator/TVerticalPagenator';
-import usePrevious from '../../hooks/usePrevious';
-import useSearchVoice from '../../hooks/useSearchVoice';
+import { sendLogGNB, sendLogTotalRecommend } from "../../actions/logActions";
+import { getMyRecommandedKeyword } from "../../actions/myPageActions";
+import { popPanel, updatePanel } from "../../actions/panelActions";
+import { getSearch, resetSearch } from "../../actions/searchActions";
+import TBody from "../../components/TBody/TBody";
+import TInput, { ICONS, KINDS } from "../../components/TInput/TInput";
+import TPanel from "../../components/TPanel/TPanel";
+import TVerticalPagenator from "../../components/TVerticalPagenator/TVerticalPagenator";
+import usePrevious from "../../hooks/usePrevious";
+import useSearchVoice from "../../hooks/useSearchVoice";
import {
LOG_CONTEXT_NAME,
LOG_MENU,
LOG_MESSAGE_ID,
panel_names,
-} from '../../utils/Config';
-import { SpotlightIds } from '../../utils/SpotlightIds';
-import NoSearchResults from './NoSearchResults/NoSearchResults';
-import RecommendedKeywords from './RecommendedKeywords/RecommendedKeywords';
-import css from './SearchPanel.module.less';
-import SearchResults from './SearchResults/SearchResults';
+} from "../../utils/Config";
+import { SpotlightIds } from "../../utils/SpotlightIds";
+import NoSearchResults from "./NoSearchResults/NoSearchResults";
+import RecommendedKeywords from "./RecommendedKeywords/RecommendedKeywords";
+import css from "./SearchPanel.module.less";
+import SearchResults from "./SearchResults/SearchResults";
-const ContainerBasic = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
+const ContainerBasic = SpotlightContainerDecorator(
+ { enterTo: "last-focused" },
+ "div"
+);
const ITEMS_PER_PAGE = 9;
export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
@@ -69,7 +55,9 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
const [currentPage, setCurrentPage] = useState(1);
const [paginatedKeywords, setPaginatedKeywords] = useState([]);
const [pageChanged, setPageChanged] = useState(false);
- const [searchQuery, setSearchQuery] = useState(panelInfo.searchVal ? panelInfo.searchVal : null);
+ const [searchQuery, setSearchQuery] = useState(
+ panelInfo.searchVal ? panelInfo.searchVal : null
+ );
const [position, setPosition] = useState(null);
let searchQueryRef = usePrevious(searchQuery);
@@ -77,12 +65,16 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
const isRecommendedSearchRef = useRef(false);
- const firstButtonSpotlightId = 'first-keyword-button';
+ const firstButtonSpotlightId = "first-keyword-button";
const focusJob = useRef(new Job((func) => func(), 100));
const cbChangePageRef = useRef(null);
- const [focusedContainerId, setFocusedContainerId] = useState(panelInfo?.focusedContainerId);
+ const [focusedContainerId, setFocusedContainerId] = useState(
+ panelInfo?.focusedContainerId
+ );
const focusedContainerIdRef = usePrevious(focusedContainerId);
- const bestSellerDatas = useSelector((state) => state.product.bestSellerData.bestSeller);
+ const bestSellerDatas = useSelector(
+ (state) => state.product.bestSellerData.bestSeller
+ );
useEffect(() => {
if (loadingComplete && !recommandedKeywords) {
@@ -145,7 +137,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// dispatch(
// sendLogTotalRecommend({
// query: searchQuery,
- // searchType: searchPerformed ? 'query' : 'keyword',
+ // searchType: searchPerformed ? "query" : "keyword",
// result: result,
// contextName: LOG_CONTEXT_NAME.SEARCH,
// messageId: LOG_MESSAGE_ID.SEARCH_ITEM,
@@ -160,9 +152,9 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
if (query.trim()) {
dispatch(
getSearch({
- service: 'com.lgshop.app',
+ service: "com.lgshop.app",
query: query,
- domain: 'theme,show,item',
+ domain: "theme,show,item",
})
);
} else {
@@ -176,7 +168,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// STT 텍스트 수신 핸들러
const handleSTTText = useCallback(
(sttText) => {
- console.log('[SearchPanel] STT text received:', sttText);
+ console.log("[SearchPanel] STT text received:", sttText);
// 1. searchQuery 업데이트
setSearchQuery(sttText);
@@ -185,9 +177,9 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
if (sttText && sttText.trim()) {
dispatch(
getSearch({
- service: 'com.lgshop.app',
+ service: "com.lgshop.app",
query: sttText.trim(),
- domain: 'theme,show,item',
+ domain: "theme,show,item",
})
);
}
@@ -215,7 +207,8 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
}, [currentPage]);
const hasPrevPage = currentPage > 1;
- const hasNextPage = currentPage * ITEMS_PER_PAGE < recommandedKeywords?.length;
+ const hasNextPage =
+ currentPage * ITEMS_PER_PAGE < recommandedKeywords?.length;
useEffect(() => {
if (panelInfo && isOnTop) {
@@ -244,19 +237,21 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
return;
}
- if (e.key === 'Enter') {
+ if (e.key === "Enter") {
handleSearchSubmit(searchQuery);
}
if (position === 0) {
- if (e.key === 'Left' || e.key === 'ArrowLeft') {
+ if (e.key === "Left" || e.key === "ArrowLeft") {
e.preventDefault();
}
}
};
const cursorPosition = () => {
- const input = document.querySelector(`[data-spotlight-id="input-field-box"] > input`);
+ const input = document.querySelector(
+ `[data-spotlight-id="input-field-box"] > input`
+ );
if (input) {
setPosition(input.selectionStart);
}
@@ -266,13 +261,13 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
if (!isOnTopRef.current) {
return;
}
- if (searchQuery === null || searchQuery === '') {
+ if (searchQuery === null || searchQuery === "") {
dispatch(popPanel(panel_names.SEARCH_PANEL));
} else {
- setSearchQuery('');
+ setSearchQuery("");
setCurrentPage(1);
dispatch(resetSearch());
- Spotlight.focus('search-input-box');
+ Spotlight.focus("search-input-box");
}
}, [searchQuery, dispatch]);
@@ -284,7 +279,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
Spotlight.resume();
setFirstSpot(true);
if (panelInfo.currentSpot) {
- if (panels[panels.length - 1]?.name === 'searchpanel') {
+ if (panels[panels.length - 1]?.name === "searchpanel") {
Spotlight.focus(panelInfo.currentSpot);
}
}
@@ -303,13 +298,21 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
}, [panelInfo, firstSpot]);
return (
-
-
+
+
{isOnTop && (
diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults/SearchCard/SearchItemCard.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults/SearchCard/SearchItemCard.jsx
index d69f81d5..50c41761 100644
--- a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults/SearchCard/SearchItemCard.jsx
+++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults/SearchCard/SearchItemCard.jsx
@@ -80,11 +80,20 @@ export default memo(function SearchItemCard({
const xContainer = tItemCard?.parentNode?.parentNode;
const yContainer = tBody?.children[0]?.children[0]?.children[0];
+ // 할인율 계산
+ const discountRate =
+ priceNumber > discountPriceNumber
+ ? Math.round(
+ ((priceNumber - discountPriceNumber) / priceNumber) * 100
+ ) + "%"
+ : "";
+
sendLog({
productId: prdtId,
productTitle: title,
partner: patncNm,
- price: dcPrice ? dcPrice : price,
+ price: price,
+ discount: discountRate,
resultType: "item",
});
if (xContainer && yContainer) {
diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults/SearchCard/SearchThemeCard.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults/SearchCard/SearchThemeCard.jsx
index f227e169..4c64435f 100644
--- a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults/SearchCard/SearchThemeCard.jsx
+++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults/SearchCard/SearchThemeCard.jsx
@@ -60,6 +60,8 @@ export default memo(function SearchThemeCard({
const yContainer = tBody?.children[0]?.children[0]?.children[0];
sendLog({
+ contentId: curationId,
+ contentTitle: title,
productId: prdtId,
productTitle: title,
partner: patncNm,