diff --git a/com.twin.app.shoptime/src/App/deepLinkHandler.js b/com.twin.app.shoptime/src/App/deepLinkHandler.js index 8c7eaa94..6169c073 100644 --- a/com.twin.app.shoptime/src/App/deepLinkHandler.js +++ b/com.twin.app.shoptime/src/App/deepLinkHandler.js @@ -266,6 +266,11 @@ export const handleDeepLink = (contentTarget) => (dispatch, getState) => { deeplink: deeplinkPanel, curationId: curationId ? curationId : showId, productId: prdtId, + partnerID: patnrId, + showId: showId, + channelId: chanId, + category: lgCatNm, + linkTypeCode: linkTpCd, }) ); diff --git a/com.twin.app.shoptime/src/actions/commonActions.js b/com.twin.app.shoptime/src/actions/commonActions.js index 0d141e6d..0e7dcc34 100644 --- a/com.twin.app.shoptime/src/actions/commonActions.js +++ b/com.twin.app.shoptime/src/actions/commonActions.js @@ -3,6 +3,7 @@ import { Job } from '@enact/core/util'; import Spotlight from '@enact/spotlight'; +// <<<<<<< HEAD import appinfo from '../../webos-meta/appinfo.json'; import appinfo35 from '../../webos-meta/appinfo35.json'; import appinfo79 from '../../webos-meta/appinfo79.json'; @@ -10,7 +11,19 @@ import { handleBypassLink } from '../App/bypassLinkHandler'; import * as lunaSend from '../lunaSend'; import { initialLocalSettings } from '../reducers/localSettingsReducer'; import * as Config from '../utils/Config'; +import * as HelperMethods from '../utils/helperMethods'; import { types } from './actionTypes'; +// ======= +// import appinfo from "../../webos-meta/appinfo.json"; +// import appinfo35 from "../../webos-meta/appinfo35.json"; +// import appinfo79 from "../../webos-meta/appinfo79.json"; +// import { handleBypassLink } from "../App/bypassLinkHandler"; +// import * as lunaSend from "../lunaSend"; +// import { initialLocalSettings } from "../reducers/localSettingsReducer"; +// import * as Config from "../utils/Config"; +// import * as HelperMethods from "../utils/helperMethods"; +// import { types } from "./actionTypes"; +// >>>>>>> gitlab/develop export const changeAppStatus = (status) => ({ type: types.CHANGE_APP_STATUS, @@ -31,14 +44,19 @@ export const gnbOpened = (status) => ({ payload: status, }); +// <<<<<<< HEAD export const setShowPopup = (config, addPayload = {}) => { let payload; - if (typeof config === 'string') { + if (typeof config === 'string') { payload = { activePopup: config, ...addPayload }; - } else { + } else { payload = config; } - + +// ======= +// export const setShowPopup = (config) => { +// const payload = typeof config === "string" ? { activePopup: config } : config; +// >>>>>>> gitlab/develop return { type: types.SET_SHOW_POPUP, payload, @@ -295,25 +313,28 @@ export const getDeviceId = (onComplete) => (dispatch, getState) => { export const getTermsAgreeYn = () => (dispatch, getState) => { dispatch({ type: types.GET_TERMS_AGREE_YN_START }); - + try { const { terms } = getState().home.termsData.data; - console.log("getTermsAgreeYn", terms.map(term => ({ - trmsId: term.trmsId, - trmsTpCd: term.trmsTpCd, - trmsAgrFlag: term.trmsAgrFlag, - trmsPopFlag: term.trmsPopFlag, - }))); + console.log( + "getTermsAgreeYn", + terms.map((term) => ({ + trmsId: term.trmsId, + trmsTpCd: term.trmsTpCd, + trmsAgrFlag: term.trmsAgrFlag, + trmsPopFlag: term.trmsPopFlag, + })) + ); // MST00405 선택약관 정보만 따로 출력 - const optionalTerm = terms.find(term => term.trmsTpCd === 'MST00405'); + const optionalTerm = terms.find((term) => term.trmsTpCd === "MST00405"); if (optionalTerm) { console.log("getTermsAgreeYn MST00405 선택약관:", { trmsId: optionalTerm.trmsId, trmsTpCd: optionalTerm.trmsTpCd, trmsAgrFlag: optionalTerm.trmsAgrFlag, - trmsPopFlag: optionalTerm.trmsPopFlag + trmsPopFlag: optionalTerm.trmsPopFlag, }); } else { console.log("getTermsAgreeYn MST00405 선택약관을 찾을 수 없습니다."); @@ -340,7 +361,7 @@ export const getTermsAgreeYn = () => (dispatch, getState) => { break; } return acc; - }, {}); + }, {}); dispatch({ type: types.GET_TERMS_AGREE_YN_SUCCESS, @@ -507,10 +528,20 @@ export const requestLiveSubtitle = export const addReservation = (data) => (dispatch) => { lunaSend.addReservation(data, { onSuccess: (res) => { - console.log(res); + console.log("addReservation success:", res); + // Optionally show success toast + if (res && res.returnValue) { + dispatch(alertToast("Reminder set successfully")); + } }, onFailure: (err) => { - console.log(err); + console.error("addReservation failed:", err); + // Use the helper function for better error handling + const errorMessage = HelperMethods.getReservationErrorMessage(err); + dispatch(alertToast(errorMessage)); + }, + onComplete: () => { + console.log("addReservation completed"); }, }); }; @@ -594,7 +625,7 @@ export const showError = retDetailCode = null, returnBindStrings = null ) => - (dispatch) => { + (dispatch) => { dispatch( setShowPopup(Config.ACTIVE_POPUP.errorPopup, { data: { @@ -701,8 +732,8 @@ export const getConnectionInfo = () => (dispatch, getState) => { lunaSend.getConnectionInfo({ onSuccess: (res) => { console.log("lunasend getConnectionStatus", res); - if (res && res.retrunValue) { - const macAddress = res?.wiredInfo.macAddress; + if (res && res.returnValue) { + const macAddress = res?.wiredInfo?.macAddress; console.log("macAddress...........", macAddress, res); } }, @@ -764,35 +795,37 @@ export const resetOptionalTermsSession = () => ({ // 선택약관 동의 처리를 위한 헬퍼 함수 export const handleOptionalTermsAgree = () => (dispatch) => { - console.log('[CommonActions] 선택약관 동의 처리'); - dispatch(setOptionalTermsUserDecision('agreed')); + console.log("[CommonActions] 선택약관 동의 처리"); + dispatch(setOptionalTermsUserDecision("agreed")); dispatch(setOptionalTermsPopupShown(true)); }; // 선택약관 거절 처리를 위한 헬퍼 함수 export const handleOptionalTermsDecline = () => (dispatch) => { - console.log('[CommonActions] 선택약관 거절 처리'); - dispatch(setOptionalTermsUserDecision('declined')); + console.log("[CommonActions] 선택약관 거절 처리"); + dispatch(setOptionalTermsUserDecision("declined")); dispatch(setOptionalTermsPopupShown(true)); }; // 선택약관 상태 통합 업데이트 (TV 환경 최적화 - API 호출 없이 즉시 반영) -export const updateOptionalTermsAgreement = (agreed = true) => (dispatch) => { - console.log(`[CommonActions] 선택약관 통합 상태 업데이트: ${agreed}`); - - // 1. optionalTermsPopupFlow 업데이트 (TV 환경용) - dispatch(setOptionalTermsUserDecision(agreed ? 'agreed' : 'declined')); - dispatch(setOptionalTermsPopupShown(true)); - - // 2. 기본 optionalTermsAgree 상태 직접 업데이트 (API 호출 없이) - dispatch({ - type: types.UPDATE_OPTIONAL_TERMS_AGREE_DIRECT, - payload: agreed - }); - - // 3. termsAgreementStatus도 동기화 - dispatch({ - type: types.UPDATE_TERMS_AGREEMENT_STATUS_DIRECT, - payload: { MST00405: agreed } - }); -}; +export const updateOptionalTermsAgreement = + (agreed = true) => + (dispatch) => { + console.log(`[CommonActions] 선택약관 통합 상태 업데이트: ${agreed}`); + + // 1. optionalTermsPopupFlow 업데이트 (TV 환경용) + dispatch(setOptionalTermsUserDecision(agreed ? "agreed" : "declined")); + dispatch(setOptionalTermsPopupShown(true)); + + // 2. 기본 optionalTermsAgree 상태 직접 업데이트 (API 호출 없이) + dispatch({ + type: types.UPDATE_OPTIONAL_TERMS_AGREE_DIRECT, + payload: agreed, + }); + + // 3. termsAgreementStatus도 동기화 + dispatch({ + type: types.UPDATE_TERMS_AGREEMENT_STATUS_DIRECT, + payload: { MST00405: agreed }, + }); + }; diff --git a/com.twin.app.shoptime/src/actions/mainActions.js b/com.twin.app.shoptime/src/actions/mainActions.js index b11c1d06..398f2358 100644 --- a/com.twin.app.shoptime/src/actions/mainActions.js +++ b/com.twin.app.shoptime/src/actions/mainActions.js @@ -234,13 +234,23 @@ export const getSubCategory = export const continueGetSubCategory = (key, pageNo) => (dispatch, getState) => { if (!lastSubCategoryParams) { +// <<<<<<< HEAD console.warn('No previous category parameters found'); +// ======= +// console.warn("No previous category parameters found"); +// >>>>>>> gitlab/develop return; } const subCategoryData = getState().main.subCategoryData; const targetData = +// <<<<<<< HEAD subCategoryData[key]?.subCatItemList || subCategoryData[key]?.subCatShowList || []; +// ======= +// subCategoryData[key]?.subCatItemList || +// subCategoryData[key]?.subCatShowList || +// []; +// >>>>>>> gitlab/develop const totalCount = subCategoryData[key]?.total ?? 0; const startIndex = CATEGORY_DATA_MAX_RESULTS_LIMIT * (pageNo - 1); if ( @@ -251,7 +261,13 @@ export const continueGetSubCategory = (key, pageNo) => (dispatch, getState) => { //ignore query return; } +// <<<<<<< HEAD dispatch(getSubCategory({ ...lastSubCategoryParams }, pageNo, getSubCategoryKey)); +// ======= +// dispatch( +// getSubCategory({ ...lastSubCategoryParams }, pageNo, getSubCategoryKey) +// ); +// >>>>>>> gitlab/develop }; const clearSubCategory = () => ({ @@ -325,7 +341,11 @@ export const getMainYouMayLike = getState, 'get', URLS.GET_YOUMAYLIKE, +// <<<<<<< HEAD { lgCatCd, exclCurationId, exclPatnrId, exclPrdtId, catDpTh3, catDpTh4 }, +// ======= +// { lgCatCd, catDpTh3, catDpTh4, exclCurationId, exclPatnrId, exclPrdtId }, +// >>>>>>> gitlab/develop {}, onSuccess, onFail diff --git a/com.twin.app.shoptime/src/actions/myPageActions.js b/com.twin.app.shoptime/src/actions/myPageActions.js index b8fa6df7..dcfe3ffb 100644 --- a/com.twin.app.shoptime/src/actions/myPageActions.js +++ b/com.twin.app.shoptime/src/actions/myPageActions.js @@ -182,8 +182,22 @@ export const deleteMyFavorite = (params) => (dispatch, getState) => { // MyPage 약관 철회 (IF-LGSP-032) export const setMyTermsWithdraw = (params, callback) => (dispatch, getState) => { + let localMacAddress; const { mandatoryIncludeYn, termsList } = params; + // 약관철회 파라미터 추가 로그 요청 + const httpHeader = getState().common.httpHeader; + const macAddress = getState().common.macAddress; + const userNumber = getState().common.appStatus.loginUserData?.userNumber; + + const macAddr = macAddress?.wired || macAddress?.wifi || macAddress?.p2p; + + if (typeof window === "object" && !window.PalmSystem) { + localMacAddress = "00:1A:2B:3C:4D:5E"; + } + const logCreateTime = new Date().toISOString(); + const xDeviceProduct = httpHeader["X-Device-Product"] || httpHeader.prod_cd; + const onSuccess = (response) => { console.log("setMyTermsWithdraw onSuccess ", response.data); @@ -199,13 +213,22 @@ export const setMyTermsWithdraw = console.error("setMyTermsWithdraw onFail ", error); }; + const requestData = { + mandatoryIncludeYn, + termsList, + xDeviceProduct, + macAddr: macAddr ? macAddr : localMacAddress, + userNumber: userNumber || "", + requestTime: logCreateTime, + }; + TAxios( dispatch, getState, "post", URLS.SET_MY_TERMS_WITHDRAW, {}, - { mandatoryIncludeYn, termsList }, + requestData, onSuccess, onFail ); @@ -223,14 +246,17 @@ export const setMyPageTermsAgree = // 약관 ID를 약관 코드로 변환하기 위해 state에서 termsIdMap 조회 const termsIdMap = getState().home.termsIdMap || {}; - const idToCodeMap = Object.entries(termsIdMap).reduce((acc, [code, id]) => { - acc[id] = code; - return acc; - }, {}); + const idToCodeMap = Object.entries(termsIdMap).reduce( + (acc, [code, id]) => { + acc[id] = code; + return acc; + }, + {} + ); // 동의한 약관 ID 목록을 약관 코드로 변환 const agreedTermCodes = termsList - .map(id => idToCodeMap[id]) + .map((id) => idToCodeMap[id]) .filter(Boolean); dispatch({ diff --git a/com.twin.app.shoptime/src/components/MobileSend/MobileSendPopUp.jsx b/com.twin.app.shoptime/src/components/MobileSend/MobileSendPopUp.jsx index 3618a5e7..2dcd5eb6 100644 --- a/com.twin.app.shoptime/src/components/MobileSend/MobileSendPopUp.jsx +++ b/com.twin.app.shoptime/src/components/MobileSend/MobileSendPopUp.jsx @@ -176,7 +176,8 @@ export default function MobileSendPopUp({ if (rawPhoneNumber.length === getMaxNum(deviceCountryCode)) { Spotlight.focus("agreeAndSend"); } - if (rawPhoneNumber.length > getMaxNum(deviceCountryCode)) { + // 테스트용: 12자리까지 허용 + if (rawPhoneNumber.length > 12) { return; } const phoneUtil = PhoneNumberUtil.getInstance(); @@ -327,7 +328,12 @@ export default function MobileSendPopUp({ const handleAgreeSendClick = useCallback(() => { let naturalNumber = mobileNumber.replace(/\D/g, ""); - if (!mobileNumber || naturalNumber.length < getMaxNum(deviceCountryCode)) { + // 테스트용: 길이 체크를 더 유연하게 (10자리 또는 11자리 허용) + if ( + !mobileNumber || + naturalNumber.length < 10 || + naturalNumber.length > 12 + ) { setSmsRetCode(907); return; } @@ -405,7 +411,6 @@ export default function MobileSendPopUp({ if (smsTpCd === "APP00204") { params = { ...params, curationId }; } - dispatch(sendSms(params)); } // EVT00101 & APP00207(welcome) EVT00103 & APP00209 (welcome+Prizes) : smsTpCd 값을 받지 않음 diff --git a/com.twin.app.shoptime/src/components/TCheckBox/TCheckBoxSquare.module.less b/com.twin.app.shoptime/src/components/TCheckBox/TCheckBoxSquare.module.less index 0296bba3..ecbd3307 100644 --- a/com.twin.app.shoptime/src/components/TCheckBox/TCheckBoxSquare.module.less +++ b/com.twin.app.shoptime/src/components/TCheckBox/TCheckBoxSquare.module.less @@ -1,11 +1,9 @@ // src/components/TCheckBox/TCheckBoxSquare.module.less -@SQUARE_BORDER_DEFAULT: #CCCCCC; -@SQUARE_BORDER_ACTIVE: #C70850; -@SQUARE_BG_SELECTED: #7A808D; +@SQUARE_BORDER_DEFAULT: #cccccc; +@SQUARE_BORDER_ACTIVE: #c70850; +@SQUARE_BG_SELECTED: #7a808d; // @SQUARE_BG_SELECTED: #C70850; -; - .tCheckBoxSquare { min-width: 45px !important; min-height: 45px !important; @@ -17,17 +15,19 @@ position: relative; box-sizing: border-box; cursor: pointer; - transition: background 0.15s, border 0.15s !important; + transition: + background 0.15s, + border 0.15s !important; &:hover, &:focus, &.focus { border-color: @SQUARE_BORDER_ACTIVE !important; - border-width: 4px !important; // 🔥 포커스 시 굵은 테두리 + border-width: 4px !important; // 🔥 포커스 시 굵은 테두리 } &::before { - content: ''; + content: ""; position: absolute; top: 50%; left: 50%; @@ -52,7 +52,8 @@ &.selectedFocus { border-color: @SQUARE_BORDER_ACTIVE !important; border-width: 4px !important; - background-color: @SQUARE_BG_SELECTED !important; + background-color: @SQUARE_BG_SELECTED !important; + &::before { transform: translate(-50%, -70%) rotate(-45deg) scale(1); } diff --git a/com.twin.app.shoptime/src/components/TItemCard/TItemCard.jsx b/com.twin.app.shoptime/src/components/TItemCard/TItemCard.jsx index 09f6e37e..c9f2ade4 100644 --- a/com.twin.app.shoptime/src/components/TItemCard/TItemCard.jsx +++ b/com.twin.app.shoptime/src/components/TItemCard/TItemCard.jsx @@ -1,4 +1,11 @@ -import React, { memo, useCallback, useEffect, useMemo, useState } from "react"; +import React, { + memo, + use, + useCallback, + useEffect, + useMemo, + useState, +} from "react"; import classNames from "classnames"; import { useDispatch, useSelector } from "react-redux"; @@ -81,6 +88,8 @@ export default memo(function TItemCard({ nowProductId, nowCategory, nowProductTitle, + showId, + showTitle, contentId, version = 1, ...rest @@ -131,6 +140,8 @@ export default memo(function TItemCard({ shelfTitle: shelfTitle, productId: productId, productTitle: productName, + showId: showId, + showTitle: showTitle, nowProductId: nowProductId, nowCategory: nowCategory, nowProductTitle: nowProductTitle, @@ -144,7 +155,6 @@ export default memo(function TItemCard({ curationId: curationId, curationTitle: curationTitle, }; - console.log("###shelfContentClick", params); dispatch(sendLogTotalRecommend(params)); } } diff --git a/com.twin.app.shoptime/src/components/TPopUp/TNewPopUp.module.less b/com.twin.app.shoptime/src/components/TPopUp/TNewPopUp.module.less index b8b20206..4134cbfb 100644 --- a/com.twin.app.shoptime/src/components/TPopUp/TNewPopUp.module.less +++ b/com.twin.app.shoptime/src/components/TPopUp/TNewPopUp.module.less @@ -11,18 +11,18 @@ // bottom: unset !important; // transform: none !important; // overflow: unset; - + // > div { // overflow: unset; // } // } - + // // 다른 팝업들은 기존 TPopUp 방식 유지 // &:not(:has(.src_components_TPopUp_TNewPopUp_optionalConfirm)) { // bottom: 50%; // transform: translateY(50%); // overflow: unset; - + // > div { // overflow: unset; // } @@ -184,7 +184,7 @@ &.optionPopup { .default-style(); - + .optionInfo { width: 820px; background-color: @BG_COLOR_01; @@ -225,7 +225,7 @@ background: @PRIMARY_COLOR_RED; color: @COLOR_WHITE; } - + .optionImg { width: 60px; height: 60px; @@ -248,7 +248,7 @@ &.optionScroll { overflow-y: auto; } - + .selectedOption { box-sizing: border-box; background: @COLOR_WHITE; @@ -256,7 +256,7 @@ border: 4px solid @PRIMARY_COLOR_RED; } } - + .optionButtonContainer { margin: 30px 0 30px 0; display: flex; @@ -266,7 +266,7 @@ &.eventBannerPopup { .default-style(); - + .eventBannerInfo { width: 600px; height: 510px; @@ -277,7 +277,7 @@ font-weight: normal; box-sizing: border-box; border-radius: 4px; - + > p > img { width: 600px; height: 510px; @@ -291,7 +291,7 @@ left: 0; right: 0; bottom: 50px; - + > div { margin: 0 6px; min-width: 240px; @@ -302,7 +302,7 @@ &.supportPopup { .default-style(); - + .supportInfo { width: 960px; height: 640px; @@ -313,7 +313,7 @@ font-weight: normal; box-sizing: border-box; border-radius: 4px; - + .supportButtonContainer { position: absolute; right: 0; @@ -332,7 +332,7 @@ &.couponPopup { .default-style(); - + .couponInfo { width: 960px; height: 640px; @@ -343,7 +343,7 @@ font-weight: normal; box-sizing: border-box; border-radius: 4px; - + .couponButtonContainer { position: absolute; right: 0; @@ -362,7 +362,7 @@ &.mobileSendPopup { .default-style(); - + .mobileSendInfo { width: 960px; height: 640px; @@ -373,7 +373,7 @@ font-weight: normal; box-sizing: border-box; border-radius: 4px; - + .mobileSendButtonContainer { position: absolute; right: 0; @@ -392,7 +392,7 @@ &.qrPopup { .default-style(); - + .qrInfo { width: 960px; height: 640px; @@ -404,7 +404,7 @@ box-sizing: border-box; border-radius: 4px; } - + .qrButtonContainer { display: flex; justify-content: center; @@ -458,7 +458,7 @@ } } } - + .checkoutTermsButtonContainer { display: flex; justify-content: center; @@ -481,7 +481,7 @@ &.scrollPopup { .default-style(); - + .scrollInfo { width: 900px; background-color: @BG_COLOR_01; @@ -492,7 +492,7 @@ box-sizing: border-box; border-radius: 4px; } - + .scrollButtonContainer { display: flex; justify-content: center; @@ -517,7 +517,7 @@ position: absolute; right: 42px; bottom: -330px; - + .watchInfo { width: 1038px; height: 168px; @@ -567,7 +567,7 @@ .elip(@clamp:1); } } - + .watchButtonContainer { display: flex; flex-wrap: wrap; @@ -613,7 +613,7 @@ text-align: center; .flex(); } - + .setPinCodeButtonContainer { margin: 0 0 30px 0; display: flex; @@ -902,22 +902,22 @@ .default-style(); bottom: unset !important; - transform: none !important; + transform: none !important; top: 20% !important; - + // 기존 위치 스타일들... - + .optionalConfirmInfo { width: 100vw; height: 198px; - background-color: #E6EBF0; + background-color: #e6ebf0; border-radius: 4px; - box-shadow: 0px 20px 12px rgba(0, 0, 0, 0.30); + box-shadow: 0px 20px 12px rgba(0, 0, 0, 0.3); display: flex; flex-direction: column; box-sizing: border-box; // gap: 15px; - + .optionalConfirmContentContainer { width: 100%; height: 100%; @@ -927,7 +927,7 @@ box-sizing: border-box; justify-content: center; // gap: 20px; - + .optionalConfirmTextSection { // flex: 1; // 나머지 높이를 모두 차지 height: 30px; @@ -937,7 +937,7 @@ // border : 1px solid red; margin-bottom: 20px; } - + .optionalConfirmButtonSection { height: 60px; // margin-top: 15px; // gap 대신 margin으로 간격 처리 @@ -951,10 +951,10 @@ width: 320px; height: 60px; // 부모 높이(60px) 모두 사용 display: flex; - align-items: center; // 수직 중앙 정렬 + align-items: center; // 수직 중앙 정렬 display: flex; justify-content: space-between; - + .optionalTermsButton { width: 100% !important; height: 100% !important; @@ -963,25 +963,25 @@ padding: 0 20px !important; margin: 0 !important; background: white !important; - border: 1px solid #CFCFCF !important; + border: 1px solid #cfcfcf !important; border-radius: 4px !important; display: flex !important; align-items: center !important; justify-content: space-between !important; // 👈 flex-start → space-between 변경 flex-shrink: 0; box-sizing: border-box !important; - + // 포커스 스타일 &:focus { - outline: 2px solid #C70850 !important; - outline-offset: 1px !important; + outline: 2px solid #c70850; + outline-offset: -1px; } - + .optionalTermsTitle { - height: 100%; - color: #1A1A1A; + height: 100%; + color: #1a1a1a; font-size: 22px; - font-family: 'LG Smart UI'; + font-family: "LG Smart UI"; font-weight: 600; line-height: 22px; white-space: nowrap; @@ -989,35 +989,35 @@ text-overflow: ellipsis; flex: 1; } - + // 👈 '>' 아이콘 스타일 추가 .optionalTermsIcon { width: 24px; height: 24px; border-radius: 50%; - border: 2px solid #1A1A1A; + border: 2px solid #1a1a1a; display: flex; align-items: center; justify-content: center; flex-shrink: 0; margin-left: 8px; - + &::after { - content: '>'; + content: ">"; font-size: 14px; font-weight: bold; - color: #1A1A1A; + color: #1a1a1a; } } } } - + .optionalConfirmRightButtonSection { // width: 332px; height: 100%; // 부모 높이(60px) 모두 사용 display: flex; align-items: center; // 수직 중앙 정렬 - justify-content: space-between; + justify-content: space-between; // gap: 12px; .optionalConfirmButton { @@ -1037,37 +1037,37 @@ .figmaTermsInfo { .size(@w: 1064px, @h: 750px); padding: 60px 57px 40px; - background: #E6EBF0; - box-shadow: 0px 20px 12px rgba(0, 0, 0, 0.30); + background: #e6ebf0; + box-shadow: 0px 20px 12px rgba(0, 0, 0, 0.3); border-radius: 4px; } - + .figmaTermsContentContainer { display: flex; flex-direction: column; // gap: 40px; } - + .figmaTermsCard { background: white; border-radius: 4px; - border: 1px solid #CCCCCC; + border: 1px solid #cccccc; overflow: hidden; display: flex; flex-direction: column; } - + .figmaTermsTitleBar { padding: 17px 31px; - border-bottom: 1px solid #CCCCCC; + border-bottom: 1px solid #cccccc; } - + .figmaTermsTitleText { - color: #C70850; + color: #c70850; font-size: 30px; font-weight: 700; } - + .figmaTermsContentBody { flex-grow: 1; display: flex; @@ -1081,7 +1081,7 @@ line-height: 1.5; } } - + .figmaTermsButtonContainer { display: flex; justify-content: center; @@ -1089,13 +1089,13 @@ margin-top: 40px; // gap: 15px; // 버튼 사이 간격 } - + .figmaTermsAgreeButton { // 이제 TButton의 type="popup" 스타일을 사용하므로, // 여기서는 추가적인 스타일이 필요 없습니다. margin-right: 15px; } - + .figmaTermsCloseButton { // TButton의 type="popup" 스타일을 사용합니다. margin-left: 0px; // lint 오류 대비용용 @@ -1104,7 +1104,7 @@ } // optionalConfirm일 때만 기존 위치 스타일 무력화 - + // :global([id="floatLayer"]) :global(> div:not([id])) :global(> div) :global(> div:nth-child(2)) { // .tNewPopUp.optionalConfirm & { // bottom: unset !important; diff --git a/com.twin.app.shoptime/src/lunaSend/common.js b/com.twin.app.shoptime/src/lunaSend/common.js index 65a3db16..bdc3ba41 100644 --- a/com.twin.app.shoptime/src/lunaSend/common.js +++ b/com.twin.app.shoptime/src/lunaSend/common.js @@ -236,56 +236,108 @@ export const setSubtitleEnableOver5 = ( } }; -// system Alert +// system Alert with time validation export const addReservation = (data, { onSuccess, onFailure, onComplete }) => { if (typeof window === "object" && !window.PalmSystem) { console.log("LUNA SEND addReservation data", data); return; } - return new LS2Request().send({ - service: "luna://com.webos.service.tvReservationAgent", - method: "add", - parameters: { - scheduleType: "LGShopping", - startTime: { - year: data.startTime.year, - month: data.startTime.month, - day: data.startTime.day, - hour: data.startTime.hour, - minute: data.startTime.minute, - second: data.startTime.second, - }, - callback: { - method: "luna://com.webos.notification/createAlert", - params: { - message: data.params.message, - buttons: [ - { - label: data.params.buttons[0].label, - onclick: "luna://com.webos.applicationManager/launch", - params: { - id: window.PalmSystem.identifier ?? appinfo.id, - params: data.params.launch, + const createReservation = () => { + return new LS2Request().send({ + service: "luna://com.webos.service.tvReservationAgent", + method: "add", + parameters: { + scheduleType: "LGShopping", + startTime: { + year: data.startTime.year, + month: data.startTime.month, + day: data.startTime.day, + hour: data.startTime.hour, + minute: data.startTime.minute, + second: data.startTime.second, + }, + callback: { + method: "luna://com.webos.notification/createAlert", + params: { + message: data.params.message, + buttons: [ + { + label: data.params.buttons[0].label, + onclick: "luna://com.webos.applicationManager/launch", + params: { + id: window.PalmSystem.identifier ?? appinfo.id, + params: data.params.launch, + }, }, - }, - { - label: data.params.buttons[1].label, - }, - ], - - autoTimeout: 30, + { + label: data.params.buttons[1].label, + }, + ], + autoTimeout: 30, + }, + }, + information: { + showId: data.params.showId, + chanId: data.params.chanId, }, }, - information: { - showId: data.params.showId, - chanId: data.params.chanId, + onSuccess, + onFailure: (err) => { + console.log("LUNA SEND addReservation failed", err); + // Check if error is related to invalid current time + if ( + err && + err.errorText && + err.errorText.includes("Invalid current time") + ) { + console.log( + "Invalid current time error detected, will retry after time validation" + ); + // Don't call onFailure immediately, let the retry logic handle it + return; + } + onFailure(err); }, - }, - onSuccess, - onFailure, - onComplete, - }); + onComplete, + }); + }; + + // First, validate system time before creating reservation + const validateTimeAndCreateReservation = (retryCount = 0, maxRetries = 3) => { + console.log(`LUNA SEND validating system time, attempt ${retryCount + 1}`); + + getSystemTime({ + onSuccess: (timeRes) => { + console.log("LUNA SEND system time validation success", timeRes); + // Time is available, proceed with reservation + createReservation(); + }, + onFailure: (timeErr) => { + console.log("LUNA SEND system time validation failed", timeErr); + + if (retryCount < maxRetries) { + // Retry with exponential backoff + const delay = Math.min(1000 * Math.pow(2, retryCount), 5000); // Max 5 seconds + console.log(`LUNA SEND retrying time validation in ${delay}ms`); + + setTimeout(() => { + validateTimeAndCreateReservation(retryCount + 1, maxRetries); + }, delay); + } else { + console.log("LUNA SEND max retries exceeded for time validation"); + // Still try to create reservation as fallback + createReservation(); + } + }, + onComplete: () => { + console.log("LUNA SEND system time validation complete"); + }, + }); + }; + + // Start the validation and reservation process + validateTimeAndCreateReservation(); }; export const deleteReservationCallback = ( @@ -454,3 +506,48 @@ export const getConnectionInfo = ({ onSuccess, onFailure, onComplete }) => { }); } }; + +// Check system time availability +export const getSystemTime = ({ onSuccess, onFailure, onComplete }) => { + if (typeof window === "object" && !window.PalmSystem) { + console.log("LUNA SEND getSystemTime - mock environment"); + onSuccess({ returnValue: true, utc: Date.now() / 1000 }); + return; + } + + return new LS2Request().send({ + service: "luna://com.webos.settingsservice", + method: "getSystemSettings", + subscribe: false, + parameters: { + category: "time", + keys: ["autoClock"], + }, + onSuccess: (res) => { + console.log("LUNA SEND getSystemTime success", res); + if (res && res.returnValue) { + // If autoClock is available, try to get actual time + new LS2Request().send({ + service: "luna://com.webos.service.systemservice", + method: "clock/getTime", + subscribe: false, + parameters: {}, + onSuccess: (timeRes) => { + console.log("LUNA SEND clock/getTime success", timeRes); + onSuccess(timeRes); + }, + onFailure: (timeErr) => { + console.log("LUNA SEND clock/getTime failed", timeErr); + // Fallback to settings response if getTime fails + onSuccess(res); + }, + onComplete, + }); + } else { + onFailure(res); + } + }, + onFailure, + onComplete, + }); +}; diff --git a/com.twin.app.shoptime/src/reducers/commonReducer.js b/com.twin.app.shoptime/src/reducers/commonReducer.js index 59fabe75..a1f47261 100644 --- a/com.twin.app.shoptime/src/reducers/commonReducer.js +++ b/com.twin.app.shoptime/src/reducers/commonReducer.js @@ -11,7 +11,7 @@ const initialState = { serverHOST: "", //"US.nextlgsdp.com", mbr_no: "", //X-User-Number : "US2401051532595" deviceId: "", //d87cedca-84e7-c05e-613d-39739bb7941f - cursorVisible: false, + cursorVisible: false, loginUserData: {}, toast: false, toastText: null, @@ -20,7 +20,8 @@ const initialState = { }, broadcast: {}, httpHeader: null, - isGnbOpened: false, popup: { + isGnbOpened: false, + popup: { popupVisible: false, activePopup: null, secondaryPopup: null, @@ -32,7 +33,7 @@ const initialState = { optionalTermsConfirmSelected: false, }, termsFlag: null, - termsLoading: false, // 25.06.16 추가 + termsLoading: false, // 25.06.16 추가 introTermsAgree: undefined, // Y, N checkoutTermsAgree: undefined, useLog: true, @@ -85,9 +86,9 @@ const initialState = { // 선택약관 팝업 상태 관리 (TV 환경 최적화) optionalTermsPopupFlow: { - popupShown: false, // 팝업 표시 여부 - userDecision: null, // 'agreed' | 'declined' | null - agreedInSession: false, // 세션 내 동의 여부 (로컬 상태 기반) + popupShown: false, // 팝업 표시 여부 + userDecision: null, // 'agreed' | 'declined' | null + agreedInSession: false, // 세션 내 동의 여부 (로컬 상태 기반) }, }; @@ -184,7 +185,8 @@ export const commonReducer = (state = initialState, action) => { secondaryPopupVisible: false, secondaryPopup: null, }, - }; case types.SET_HIDE_SECONDARY_POPUP: + }; + case types.SET_HIDE_SECONDARY_POPUP: return { ...state, popup: { @@ -233,8 +235,13 @@ export const commonReducer = (state = initialState, action) => { } case types.GET_TERMS_AGREE_YN_SUCCESS: { - const { privacyTerms, serviceTerms, purchaseTerms, paymentTerms, optionalTerms } = - action.payload; + const { + privacyTerms, + serviceTerms, + purchaseTerms, + paymentTerms, + optionalTerms, + } = action.payload; const introTermsAgree = privacyTerms === "Y" && serviceTerms === "Y"; const checkoutTermsAgree = purchaseTerms === "Y" && paymentTerms === "Y"; @@ -262,9 +269,11 @@ export const commonReducer = (state = initialState, action) => { case types.GET_HOME_TERMS: { const newTermsStatus = { ...state.termsAgreementStatus }; if (action.payload?.data?.terms) { - action.payload.data.terms.forEach(term => { - if (Object.prototype.hasOwnProperty.call(newTermsStatus, term.trmsTpCd)) { - newTermsStatus[term.trmsTpCd] = term.trmsAgrFlag === 'Y'; + action.payload.data.terms.forEach((term) => { + if ( + Object.prototype.hasOwnProperty.call(newTermsStatus, term.trmsTpCd) + ) { + newTermsStatus[term.trmsTpCd] = term.trmsAgrFlag === "Y"; } }); } @@ -279,7 +288,7 @@ export const commonReducer = (state = initialState, action) => { const newTermsStatus = { ...state.termsAgreementStatus }; // action payload에 담겨온 동의한 약관 코드 리스트를 기반으로 상태 업데이트 if (action.payload?.agreedTermCodes) { - action.payload.agreedTermCodes.forEach(termCode => { + action.payload.agreedTermCodes.forEach((termCode) => { if (Object.prototype.hasOwnProperty.call(newTermsStatus, termCode)) { newTermsStatus[termCode] = true; } @@ -288,7 +297,7 @@ export const commonReducer = (state = initialState, action) => { return { ...state, termsLoading: false, - termsAgreementStatus: newTermsStatus + termsAgreementStatus: newTermsStatus, }; } case types.SET_MYPAGE_TERMS_AGREE_FAIL: @@ -310,7 +319,7 @@ export const commonReducer = (state = initialState, action) => { ...state.termsAgreementStatus, MST00401: true, MST00402: true, - } + }, }; } else { return state; @@ -398,7 +407,7 @@ export const commonReducer = (state = initialState, action) => { optionalTermsPopupFlow: { ...state.optionalTermsPopupFlow, userDecision: action.payload, - agreedInSession: action.payload === 'agreed', + agreedInSession: action.payload === "agreed", }, }; } diff --git a/com.twin.app.shoptime/src/utils/Config.js b/com.twin.app.shoptime/src/utils/Config.js index b0371e58..eaf9c51e 100644 --- a/com.twin.app.shoptime/src/utils/Config.js +++ b/com.twin.app.shoptime/src/utils/Config.js @@ -79,7 +79,7 @@ export const ACTIVE_POPUP = { exitPopup: 'exitPopup', favoritePopup: 'favoritePopup', loginPopup: 'loginPopup', - logoutPopup: 'logoutPopup', + logoutPopup: 'logoutPopup', noShowPopup: 'noShowPopup', optionPopup: 'optionPopup', qrPopup: 'qrPopup', @@ -113,7 +113,7 @@ export const ACTIVE_POPUP = { toast: 'toast', optionalConfirm: 'optionalConfirm', energyPopup: 'energyPopup', - addCartPopup: 'addCartPopup', + addCartPopup: 'addCartPopup', }; export const DEBUG_VIDEO_SUBTITLE_TEST = false; export const AUTO_SCROLL_DELAY = 600; @@ -587,6 +587,7 @@ export const ERROR_MESSAGES_GROUPS = [ ]; export const LOG_CONTEXT_NAME = { +// <<<<<<< HEAD SHOPTIME: 'shoptime', HOME: 'shoptime.home', CHECKOUT: 'shoptime.checkout', @@ -608,6 +609,29 @@ export const LOG_CONTEXT_NAME = { ENTRY: 'shoptime.entry', MYORDER: 'shoptime.myorder', DETAILPAGE: 'shoptime.detailpage', +// ======= +// SHOPTIME: "shoptime", +// HOME: "shoptime.home", +// CHECKOUT: "shoptime.checkout", +// PINCODE: "shoptime.pincode", +// YOUMAYLIKE: "shoptime.youmayalsolike", +// SHOW: "shoptime.show", +// SHOPBYMOBILE: "shoptime.shopbymobile", +// GNB: "shoptime.gnb", +// REMINDERS: "shoptime.reminders", +// MYPAGE: "shoptime.mypage", +// FEATURED_BRANDS: "shoptime.featuredpartner", +// MYINFO: "shoptime.myinfo", +// ON_SALE: "shoptime.onsale", +// TRENDING_NOW: "shoptime.trendingnow", +// HOT_PICKS: "shoptime.hotpicks", +// SEARCH: "shoptime.search", +// THEME_CURATION: "shoptime.themecuration", +// CATEGORY: "shoptime.category", +// ENTRY: "shoptime.entry", +// MYORDER: "shoptime.myorder", +// DETAILPAGE: "shoptime.detailpage", +// >>>>>>> gitlab/develop }; export const LOG_MESSAGE_ID = { diff --git a/com.twin.app.shoptime/src/utils/helperMethods.js b/com.twin.app.shoptime/src/utils/helperMethods.js index 387cc054..c6996563 100644 --- a/com.twin.app.shoptime/src/utils/helperMethods.js +++ b/com.twin.app.shoptime/src/utils/helperMethods.js @@ -530,3 +530,45 @@ export const getErrorMessage = (errorCode, retMsg, retDetailCode, returnBindStri return errorPrefix + 'An unknown error occurred. Please try again later.'; } }; + +/** + * Check if the reservation error is related to system time issues + * @param {Object} error - The error object from Luna service + * @returns {boolean} - True if error is time-related + */ +export const isTimeRelatedError = (error) => { + if (!error) return false; + + const timeErrorPatterns = [ + "Invalid current time", + "Fail to get Current Time", + "time not available", + "clock not set", + ]; + + const errorText = error.errorText || error.message || ""; + return timeErrorPatterns.some((pattern) => + errorText.toLowerCase().includes(pattern.toLowerCase()) + ); +}; + +/** + * Get user-friendly error message for reservation failures + * @param {Object} error - The error object from Luna service + * @returns {string} - User-friendly error message + */ +export const getReservationErrorMessage = (error) => { + if (!error) return $L("Failed to set reminder. Please try again."); + + if (isTimeRelatedError(error)) { + return $L( + "Unable to set reminder: System time not available. Please check your TV's time settings and try again." + ); + } + + if (error.errorText) { + return $L(`Failed to set reminder: ${error.errorText}`); + } + + return $L("Failed to set reminder. Please try again."); +}; diff --git a/com.twin.app.shoptime/src/views/CategoryPanel/CategoryPanel.jsx b/com.twin.app.shoptime/src/views/CategoryPanel/CategoryPanel.jsx index 77f06ac8..d336c31e 100644 --- a/com.twin.app.shoptime/src/views/CategoryPanel/CategoryPanel.jsx +++ b/com.twin.app.shoptime/src/views/CategoryPanel/CategoryPanel.jsx @@ -351,8 +351,8 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { ...params, category: categoryShowInfos?.catNm, partner: findPartnerName(patnrId), - contentId: showId, - contentTitle: showNm, + showId: showId, + showTitle: showNm, }); } @@ -365,8 +365,8 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { ...params, category: categoryShowInfos?.catNm, partner: findPartnerName(topShowInfo?.patnrId), - productId: prdtId, - productTitle: prdtNm, + showId: prdtId, + showTitle: prdtNm, price: discountRate ? discountPrice : regularPrice, discount: discountRate, }); @@ -379,8 +379,8 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { ...params, category: categoryShowInfos?.catNm, partner: findPartnerName(patnrId), - contentId: showId, - contentTitle: showNm, + showId: showId, + showTitle: showNm, }); } diff --git a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx index 5b05e028..f45f6d96 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx @@ -12,6 +12,7 @@ import { getMainCategoryDetail, getMainYouMayLike } from '../../actions/mainActi import { finishModalMediaForce } from '../../actions/mediaActions'; import { popPanel, updatePanel } from '../../actions/panelActions'; import { +// <<<<<<< HEAD finishVideoPreview, pauseFullscreenVideo, resumeFullscreenVideo, @@ -30,6 +31,45 @@ import THeaderCustom from './components/THeaderCustom'; import css from './DetailPanel.module.less'; import ProductAllSection from './ProductAllSection/ProductAllSection'; import ThemeItemListOverlay from './ThemeItemListOverlay/ThemeItemListOverlay'; +// ======= +// changeAppStatus, +// changeLocalSettings, +// setHidePopup, +// } from "../../actions/commonActions"; +// import { clearCouponInfo } from "../../actions/couponActions"; +// import { getDeviceAdditionInfo } from "../../actions/deviceActions"; +// import { +// clearThemeDetail, +// getThemeCurationDetailInfo, +// getThemeHotelDetailInfo, +// } from "../../actions/homeActions"; +// import { +// getMainCategoryDetail, +// getMainYouMayLike, +// } from "../../actions/mainActions"; +// import { popPanel, updatePanel } from "../../actions/panelActions"; +// import { finishVideoPreview } from "../../actions/playActions"; +// import { +// clearProductDetail, +// getProductGroup, +// getProductImageLength, +// getProductOptionId, +// } from "../../actions/productActions"; +// import MobileSendPopUp from "../../components/MobileSend/MobileSendPopUp"; +// import TBody from "../../components/TBody/TBody"; +// import THeader from "../../components/THeader/THeader"; +// import TPanel from "../../components/TPanel/TPanel"; +// import * as Config from "../../utils/Config"; +// import { panel_names } from "../../utils/Config"; +// import { $L, getQRCodeUrl } from "../../utils/helperMethods"; +// import css from "./DetailPanel.module.less"; +// import GroupProduct from "./GroupProduct/GroupProduct"; +// import SingleProduct from "./SingleProduct/SingleProduct"; +// import ThemeProduct from "./ThemeProduct/ThemeProduct"; +// import UnableProduct from "./UnableProduct/UnableProduct"; +// import YouMayLike from "./YouMayLike/YouMayLike"; +// import { now } from "lodash"; +// >>>>>>> gitlab/develop export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { const dispatch = useDispatch(); @@ -128,6 +168,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { const [productType, setProductType] = useState(null); const [openThemeItemOverlay, setOpenThemeItemOverlay] = useState(false); +// <<<<<<< HEAD const [scrollToSection, setScrollToSection] = useState(null); const [pendingScrollSection, setPendingScrollSection] = useState(null); const updateSelectedIndex = useCallback((newIndex) => { @@ -138,12 +179,79 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { )() ); }, []); +// ======= +// useEffect(() => { +// if (lgCatCd) { +// dispatch( +// getMainYouMayLike({ +// lgCatCd: lgCatCd, +// exclCurationId: panelInfo?.curationId, +// exclPatnrId: panelInfo?.patnrId, +// exclPrdtId: panelInfo?.prdtId, +// catDpTh3: +// panelInfo?.type === "theme" +// ? themeProductInfos[selectedIndex]?.catDpTh3 +// : productData?.catDpTh3, +// catDpTh4: +// panelInfo?.type === "theme" +// ? themeProductInfos[selectedIndex]?.catDpTh4 +// : productData?.catDpTh4, +// }) +// ); +// } +// }, [panelInfo?.curationId, panelInfo?.patnrId, panelInfo?.prdtId, lgCatCd]); +// >>>>>>> gitlab/develop const updateThemeItemOverlay = useCallback((isOpen) => { setOpenThemeItemOverlay(fp.pipe(() => isOpen, Boolean)()); }, []); +// <<<<<<< HEAD const onSpotlightUpTButton = useCallback((e) => { +// ======= +// useEffect(() => { +// if ( +// themeProductInfos && +// themeProductInfos.length > 0 && +// panelInfo?.themePrdtId +// ) { +// for (let i = 0; i < themeProductInfos.length; i++) { +// if (themeProductInfos[i].prdtId === panelInfo?.themePrdtId) { +// setSelectedIndex(i); +// } +// } +// } + +// if (hotelInfos && hotelInfos.length > 0 && panelInfo?.themeHotelId) { +// for (let i = 0; i < hotelInfos.length; i++) { +// if (hotelInfos[i].hotelId === panelInfo?.themeHotelId) { +// setSelectedIndex(i); +// } +// } +// } +// }, [ +// themeProductInfos, +// hotelInfos, +// panelInfo?.themePrdtId, +// panelInfo?.themeHotelId, +// ]); + +// const { detailUrl } = useMemo(() => { +// return getQRCodeUrl({ +// serverHOST, +// serverType, +// index: deviceInfo?.dvcIndex, +// patnrId: productInfo?.patnrId, +// prdtId: productInfo?.prdtId, +// entryMenu: entryMenu, +// nowMenu: nowMenu, +// liveFlag: "Y", +// qrType: "billingDetail", +// }); +// }, [serverHOST, serverType, deviceInfo, entryMenu, productInfo]); + +// const onSpotlightUpTButton = (e) => { +// >>>>>>> gitlab/develop e.stopPropagation(); Spotlight.focus('spotlightId_backBtn'); }, []); @@ -1041,6 +1149,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { productInfo={productDataSource} isOpen={openThemeItemOverlay} panelInfo={panelInfo} +// <<<<<<< HEAD productType={productType} setSelectedIndex={updateSelectedIndex} openThemeItemOverlay={openThemeItemOverlay} @@ -1048,5 +1157,55 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { /> +// ======= +// setSelectedIndex={setSelectedIndex} +// p +// roductInfo={productData || themeProductInfos[selectedIndex]} +// setIsYouMayLikeOpened={setIsYouMayLikeOpened} +// /> +// )} +// {activePopup === Config.ACTIVE_POPUP.smsPopup && ( +// +// )} +// +// >>>>>>> gitlab/develop ); } 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 502bf9ad..0368a627 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx @@ -1492,7 +1492,7 @@ export default function ProductAllSection({ - )} + )} dispatch(sendLogDetail(params)); + dispatch(sendLogDetail(params)); } }, [productData]); @@ -172,22 +172,24 @@ export default function ShowOption({ }, [productData]); const handleMobileSendPopupOpen = useCallback(() => { - if (productData && Object.keys(productData).length > 0) { - const regularPrice = productData?.priceInfo?.split("|")[0]; - const discountPrice = productData?.priceInfo?.split("|")[1]; - const discountRate = productData?.priceInfo?.split("|")[4]; + if (showProductInfo && Object.keys(showProductInfo).length > 0) { + const regularPrice = showProductInfo?.priceInfo?.split("|")[0]; + const discountPrice = showProductInfo?.priceInfo?.split("|")[1]; + const discountRate = showProductInfo?.priceInfo?.split("|")[4]; const logParams = { status: "open", nowMenu: nowMenu, - partner: productData?.patncNm, - productId: productData?.prdtId, - productTitle: productData?.prdtNm, + partner: showProductInfo?.patncNm, + productId: showProductInfo?.prdtId, + productTitle: showProductInfo?.prdtNm, price: discountRate ? discountPrice : regularPrice, - brand: productData?.brndNm, + brand: showProductInfo?.brndNm, discount: discountRate, - category: productData?.catNm, + category: showProductInfo?.catNm, contextName: LOG_CONTEXT_NAME.SHOPBYMOBILE, messageId: LOG_MESSAGE_ID.SMB, + showId: showProductInfo?.showId ?? "", + showNm: showProductInfo?.showNm ?? "", }; dispatch(sendLogTotalRecommend(logParams)); dispatch( @@ -276,7 +278,7 @@ export default function ShowOption({ isBillingProductVisible={isBillingProductVisible} isCall isFullOption={showProductInfo?.pmtSuptYn === "Y"} - isDescription={!showProductInfo?.pmtSuptYn === "Y"} + isDescription={showProductInfo?.pmtSuptYn !== "Y"} thumbnailUrl={showProductInfo?.imgUrls600[0]} productInfo={showProductInfo} /> diff --git a/com.twin.app.shoptime/src/views/DetailPanel/UnableProduct/UnableOption.jsx b/com.twin.app.shoptime/src/views/DetailPanel/UnableProduct/UnableOption.jsx index 3309f886..bd9b5ee1 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/UnableProduct/UnableOption.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/UnableProduct/UnableOption.jsx @@ -215,6 +215,21 @@ export default function UnableOption({ ); } else if (TYPE_CASE.case2) { + if ( + selectedPrdtId === "27LX6TYGA" && + offerInfo && + offerInfo?.length > 0 + ) { + return ( +
+ +
+ ); + } return (
diff --git a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedBrandsPanel.jsx b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedBrandsPanel.jsx index fccd11c2..598f6c4c 100644 --- a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedBrandsPanel.jsx +++ b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedBrandsPanel.jsx @@ -67,6 +67,7 @@ import Showroom from "./Showroom/Showroom"; import TodaysDeals from "./TodaysDeals/TodaysDeals"; import UpComing from "./UpComing/UpComing"; import { setContainerLastFocusedElement } from "@enact/spotlight/src/container"; +import { sortedIndexOf } from "lodash"; const STRING_CONF = { CANCEL: "CANCEL", @@ -318,29 +319,34 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => { return; } + const foundElement = sortedBrandLayoutInfo.find( + (el) => el.shptmBrndOptTpCd === containerId + ); + const actualShelfOrder = foundElement ? foundElement.expsOrd : null; + const selectedBrand = `${LOG_MENU.FEATURED_BRANDS}/${selectedPatncNm}`; const currentShelf = `${getMenuByContainerId(containerId)}`; + const menu = selectedBrand && currentShelf && `${selectedBrand} ${currentShelf}`; - dispatch(sendLogGNB(menu)); - dispatch( sendLogTotalRecommend({ contextName: LOG_CONTEXT_NAME.FEATURED_BRANDS, messageId: LOG_MESSAGE_ID.SHELF, partner: selectedPatncNm, - shelfLocation: shelfOrder, + shelfLocation: actualShelfOrder, shelfId: containerId, shelfTitle: currentShelf, }) ); + dispatch(sendLogGNB(menu)); setIsLogGNBSent(true); prevSelectedPatncNmRef.current = selectedPatncNm; lastMenuRef.current = getMenuByContainerId(containerId); }, - [selectedPatncNm, sortedBrandLayoutInfo, selectedPatncNm] + [selectedPatncNm, sortedBrandLayoutInfo] ); const focusOnMount = useCallback((targetId) => { diff --git a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedCategory/FeaturedCategoryContents/FeaturedCategoryContents.jsx b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedCategory/FeaturedCategoryContents/FeaturedCategoryContents.jsx index 3410960c..5dc74c8e 100644 --- a/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedCategory/FeaturedCategoryContents/FeaturedCategoryContents.jsx +++ b/com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedCategory/FeaturedCategoryContents/FeaturedCategoryContents.jsx @@ -46,6 +46,8 @@ const FeaturedCategoryContents = ({ spotlightId={spotlightId} shelfOrder={shelfOrder} shelfTitle={shelfTitle} + selectedPatncNm={selectedPatncNm} + catNm={catNm} /> ) : ( (e) => { const tItemCard = e.currentTarget; - const lastFocusedTarget = Spotlight.getCurrent(); const lastFocusedTargetId = lastFocusedTarget?.getAttribute("data-spotlight-id"); @@ -185,7 +186,8 @@ export default function FeaturedCategoryProductList({ contextName={LOG_CONTEXT_NAME.FEATURED_BRANDS} messageId={LOG_MESSAGE_ID.SHELF_CLICK} order={expsOrd} - category={selectedCatCdLv1} + category={catNm} + patnerName={selectedPatncNm} shelfLocation={shelfOrder} shelfTitle={shelfTitle} shelfId={spotlightId} diff --git a/com.twin.app.shoptime/src/views/HomePanel/EventPopUpBanner/EventPopUpBanner.jsx b/com.twin.app.shoptime/src/views/HomePanel/EventPopUpBanner/EventPopUpBanner.jsx index c2e32d6c..4d054a17 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/EventPopUpBanner/EventPopUpBanner.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/EventPopUpBanner/EventPopUpBanner.jsx @@ -81,8 +81,8 @@ export default function EventPopUpBanner() { pushPanel({ name: panel_names.HOT_PICKS_PANEL, panelInfo: { - curationId: eventPopData?.curationId, - patnrId: eventPopData?.patnrId, + curationId: eventPopData?.shptmLnkInfo?.lnkCurationId, + patnrId: eventPopData?.shptmLnkInfo?.lnkPatnrId, }, }) ); @@ -208,10 +208,14 @@ export default function EventPopUpBanner() { case 'EVT00203': dispatch(pushPanel({ name: panel_names.TRENDING_NOW_PANEL })); break; +// <<<<<<< HEAD case 'EVT00204': if (playerPanelInfo?.modal) { dispatch(finishVideoPreview()); } +// ======= +// case "EVT00204": +// >>>>>>> gitlab/develop dispatch( pushPanel({ name: panel_names.HOT_PICKS_PANEL, @@ -328,7 +332,7 @@ export default function EventPopUpBanner() { )} diff --git a/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RandomUnit.jsx b/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RandomUnit.jsx index 5a6396a2..002a2de5 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RandomUnit.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RandomUnit.jsx @@ -575,8 +575,8 @@ export default function RandomUnit({ // 비디오 클릭 const videoClick = useCallback(() => { - const lastFocusedTargetId = getContainerId(Spotlight.getCurrent()); const currentSpot = Spotlight.getCurrent(); +// <<<<<<< HEAD if (lastFocusedTargetId) { dispatch( updateHomeInfo({ @@ -589,6 +589,20 @@ export default function RandomUnit({ }) ); } +// ======= +// const currentSpotlightId = currentSpot?.getAttribute("data-spotlight-id") || spotlightId; + +// dispatch( +// updateHomeInfo({ +// name: panel_names.HOME_PANEL, +// panelInfo: { +// lastFocusedTargetId: currentSpotlightId, +// focusedContainerId: TEMPLATE_CODE_CONF.TOP, +// currentSpot: currentSpotlightId, +// }, +// }) +// ); +// >>>>>>> gitlab/develop // ✅ modal=true → modal=false로 전환 (또는 초기 로드 시 modal=false) // playActions의 shouldSkipVideoPlayback이 modal 상태를 확인하므로 @@ -631,9 +645,13 @@ export default function RandomUnit({ randomDataRef, sendBannerLog, onBlur, +// <<<<<<< HEAD playerPanelInfo?.modal, dispatch, handleStartVideo, +// ======= +// dispatch, +// >>>>>>> gitlab/develop ]); // 투데이즈 딜 가격 정보 diff --git a/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx b/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx index 97f995fe..dc1ae7e9 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx @@ -23,6 +23,7 @@ import { getHomeLayout, getHomeMainContents, updateHomeInfo, +// <<<<<<< HEAD } from '../../actions/homeActions'; import { sendLogGNB, sendLogTotalRecommend } from '../../actions/logActions'; import { getSubCategory, getTop20Show } from '../../actions/mainActions'; @@ -67,6 +68,20 @@ const BACKGROUND_IMAGES = { }; // [COMMENTED OUT] useVideoMove 관련 코드 주석 처리 - 향후 사용 검토 필요 // import { useVideoMove } from '../../hooks/useVideoTransition/useVideoMove'; +// ======= +// } from "../../actions/homeActions"; +// import { sendLogGNB, sendLogTotalRecommend } from "../../actions/logActions"; +// import { getSubCategory, getTop20Show } from "../../actions/mainActions"; +// import { getHomeOnSaleInfo } from "../../actions/onSaleActions"; +// import { finishVideoPreview } 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 useDebugKey from "../../hooks/useDebugKey"; +// >>>>>>> gitlab/develop import { ACTIVE_POPUP, LOG_CONTEXT_NAME, @@ -186,6 +201,9 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => { const isInitialRender = useRef(true); const verticalPagenatorRef = useRef(null); const currentSentMenuRef = useRef(null); + const lastRestoredIdRef = useRef(null); + const focusedContainerIdRef = useRef(null); + const prevIsOnTopRef = useRef(isOnTop); // ✅ [251119] DetailPanelBackground 이미지 프리로딩 // HomePanel 마운트 시 백그라운드로 모든 파트너사 배경 이미지를 미리 로드하여 @@ -250,8 +268,6 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => { const expandIntervalRef = useRef(null); // 최상단에서의 interval const expandAttemptRef = useRef(0); // 복구 시도 횟수 - const focusedContainerIdRef = usePrevious(focusedContainerId); - const loadingComplete = useSelector((state) => state.common?.loadingComplete); const isVideoTransitionLocked = useSelector((state) => state.home.videoTransitionLocked); @@ -757,6 +773,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => { // 비디오가 재생이 아니면 videoPlayIntentRef의 bannerId로 비디오 재생 // [251116] isHomeOnTop인 경우에는 비디오가 항상 재생되어야 함 useEffect(() => { +// <<<<<<< HEAD // console.log('[HomeActive] useEffect 실행 - isOnTop:', isOnTop); // console.log('[HomeActive] videoPlayIntentRef.current:', videoPlayIntentRef.current); // console.log( @@ -973,6 +990,23 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => { } } }, [detailPanelClosed, isOnTop, bannerDataList, dispatch]); +// ======= +// const justCameBack = !prevIsOnTopRef.current && isOnTop; + +// if ( +// justCameBack && +// panelInfo?.lastFocusedTargetId && +// panelInfo.lastFocusedTargetId !== lastRestoredIdRef.current +// ) { +// lastRestoredIdRef.current = panelInfo.lastFocusedTargetId; +// setTimeout(() => { +// Spotlight.focus(panelInfo.lastFocusedTargetId); +// }, 150); +// } + +// prevIsOnTopRef.current = isOnTop; +// }, [isOnTop, panelInfo?.lastFocusedTargetId]); +// >>>>>>> gitlab/develop useEffect(() => { return () => { @@ -997,13 +1031,17 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => { currentSpot: currentSpot, currentCatCd: targetSpotlightCatcd, currentCateName: targetSpotlightCateNm, +// <<<<<<< HEAD focusedContainerId: focusedContainerIdRef.current, lastFocusedTargetId: lastFocusedTargetRef.current || panelInfo.lastFocusedTargetId, +// ======= +// focusedContainerId: focusedContainerId, +// >>>>>>> gitlab/develop }, }) ); }; - }, [dispatch]); + }, [dispatch, focusedContainerId]); const handleArrowClick = useCallback(() => { if (verticalPagenatorRef.current) { 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 fc6503d4..0692ef2e 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/PopularShow/PopularShow.jsx @@ -73,7 +73,7 @@ const PopularShow = ({ const topInfos = useSelector((state) => state.main.top20ShowData.topInfos); const recommendInfo = useSelector((state) => state.foryou?.recommendInfo?.recommendShow); - + const orderStyle = useMemo(() => ({ order: order }), [order]); @@ -84,10 +84,10 @@ const PopularShow = ({ const [showNewInfos, setShowNewInfos] = useState([]); useEffect(() => { - setDrawChk(true); + setDrawChk(true); }, [topInfos]); - useEffect(()=>{ + useEffect(()=>{ setShowInfos( recommendInfo?.filter( (item) => item.recommendTpCd === "POPULARSHOW" @@ -96,7 +96,7 @@ const PopularShow = ({ },[recommendInfo]) useEffect(() => { - if (!showInfos || showInfos.length === 0) { + if (!showInfos || showInfos.length === 0) { const baseData = topInfos?.map((item) => ({ ...item, foryou: false, @@ -109,19 +109,19 @@ const PopularShow = ({ ...item, foryou: true, })) || []; - + const recommendedPrdtIds = new Set(recommendedData?.map(item => item.showId)); - + const baseData = topInfos?.map((item) => ({ ...item, foryou: recommendedPrdtIds.has(item.showId), - })) || []; - + })) || []; + setShowNewInfos([ ...baseData]); }, [topInfos, showInfos]); - + const handleCardClick = useCallback( (patnrId, showId, catCd, showUrl) => () => { @@ -234,7 +234,7 @@ const PopularShow = ({ if (handleShelfFocus) { handleShelfFocus(); } - }, [handleShelfFocus]); + }, [handleShelfFocus]); return ( >>>>>> gitlab/develop }, itemIndex ) => { @@ -286,8 +290,8 @@ const PopularShow = ({ shelfLocation={shelfLocation} shelfTitle={shelfTitle} patnerName={patncNm} - contentId={showId} - contentTitle={showNm} + showId={showId} + showTitle={showNm} imageSource={ (thumbnailUrl && thumbnailUrl960) ? thumbnailUrl !== thumbnailUrl960 @@ -296,7 +300,7 @@ const PopularShow = ({ : thumbnailUrl } imageAlt={showNm} - productName={showNm} + productName={productInfos[0].prdtNm} nonPosition={true} type={TYPES.videoShow} imgType={ @@ -305,7 +309,7 @@ const PopularShow = ({ : IMAGETYPES.imgVertical } logo={patncLogoPath} - productId={showId} + productId={productInfos[0].prdtId} onFocus={handleFocus(itemIndex)} onBlur={handleBlur(itemIndex)} onClick={handleCardClick(patnrId, showId, catCd, showUrl)} diff --git a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/CategoryNav/CategoryNavItem/CategoryNavItem.jsx b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/CategoryNav/CategoryNavItem/CategoryNavItem.jsx index 64004d1e..96e75f57 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/CategoryNav/CategoryNavItem/CategoryNavItem.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/CategoryNav/CategoryNavItem/CategoryNavItem.jsx @@ -1,13 +1,10 @@ -import React, { - memo, - useCallback, -} from 'react'; +import React, { memo, useCallback } from "react"; -import classNames from 'classnames'; +import classNames from "classnames"; -import Spottable from '@enact/spotlight/Spottable'; +import Spottable from "@enact/spotlight/Spottable"; -import css from './CategoryNavItem.module.less'; +import css from "./CategoryNavItem.module.less"; const SpottableComponent = Spottable("div"); diff --git a/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.jsx b/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.jsx index 5be3a6c9..04815dad 100644 --- a/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.jsx +++ b/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.jsx @@ -826,7 +826,7 @@ function IntroPanelWithOptional({ return shouldShowBenefitsView ? (
{$L( - 'By checking "Optional terms", you allow Shop Time to use your activity (views, purchases, searches, etc.) to show you more relevant content, product recommendations, special offers, and ads. If you do not check, you can still use all basic Shop Time features', + 'By checking Optional terms, you allow Shop Time to use your activity (views, purchases, searches, etc.) to show you more relevant content, product recommendations, special offers, and ads. If you do not check, you can still use all basic Shop Time features', )}
) : ( diff --git a/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.module.less b/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.module.less index a817ec3f..f9c4da6d 100644 --- a/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.module.less +++ b/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.module.less @@ -195,16 +195,12 @@ // &:focus-visible, &:hover { outline: 4px #c91d53 solid !important; - outline-offset: 2px !important; transform: translateY(-2px) !important; - box-shadow: 0 4px 12px rgba(201, 29, 83, 0.3) !important; - .termsText { font-weight: bold !important; - } - } + } + } } - } } .termsRightPanel { @@ -347,14 +343,12 @@ &.selected:before { background-color: #c91d53 !important; border: 4px solid #c91d53 !important; // 굵은 테두리로 변경 - box-shadow: 0 0 8px rgba(201, 29, 83, 0.3); // 약간의 그림자 효과 } // 포커스 받았지만 선택 안됨 &.focused:not(.selected):before { background-color: rgba(201, 29, 83, 0.1); border: 4px solid #c91d53 !important; - box-shadow: 0 0 10px rgba(199, 8, 80, 0.3) !important; } // 비활성화됨 @@ -367,7 +361,6 @@ // 포커스 받음 (선택된 상태가 아닌 경우에만 적용) &.focused:not(.selected):before { border: 4px solid #c91d53 !important; - box-shadow: 0 0 10px rgba(199, 8, 80, 0.3) !important; } // 체크마크 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 8f82caeb..4122bc5c 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 @@ -214,12 +214,15 @@ export default function Favorites({ title, panelInfo, isOnTop }) { }, [favoritesDatas, activeDelete]); const handleItemClick = useCallback( - (patnrId, prdtId, prdtNm, patncNm) => (ev) => { + (patnrId, prdtId, prdtNm, patncNm, showId, showNm, brndNm) => (ev) => { const params = { menu: "Favorite", productId: prdtId, productTitle: prdtNm, partner: patncNm, + showId: showId, + showTitle: showNm, + brand: brndNm, contextName: LOG_CONTEXT_NAME.MYPAGE, messageId: LOG_MESSAGE_ID.MYPAGE_CLICK, }; diff --git a/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/MyInfo/MyInfo.jsx b/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/MyInfo/MyInfo.jsx index d5ef76bd..0d0f6dd6 100644 --- a/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/MyInfo/MyInfo.jsx +++ b/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/MyInfo/MyInfo.jsx @@ -303,11 +303,6 @@ export default function MyInfo({ title, cbScrollTo }) { return ( <> - - {serverHOST && ( - [serverHost] {serverHOST} - )} -
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 ffe25236..aa41ecd1 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 @@ -64,38 +64,42 @@ export default function RecentlyViewedContents({ }, [mainContainerId, recentDataInfoItem, scrollLeft]); const handleItemClick = useCallback( - (showId, showNm, patnrId, lgCatCd, prdtId, prdtNm, patncNm) => () => { - const params = { - menu: "Recently Viewed", - partner: patncNm, - contentId: showId, - contentTitle: showNm, - productId: prdtId, - productTitle: prdtNm, - contextName: LOG_CONTEXT_NAME.MYPAGE, - messageId: LOG_MESSAGE_ID.MYPAGE_CLICK, - }; - dispatch(sendLogTotalRecommend(params)); + (showId, showNm, patnrId, lgCatCd, prdtId, prdtNm, patncNm, brndNm) => + () => { + const params = { + menu: "Recently Viewed", + partner: patncNm, + contentId: showId, + contentTitle: showNm, + productId: prdtId, + productTitle: prdtNm, + showId: showId, + showTitle: showNm, + brand: brndNm, + contextName: LOG_CONTEXT_NAME.MYPAGE, + messageId: LOG_MESSAGE_ID.MYPAGE_CLICK, + }; + dispatch(sendLogTotalRecommend(params)); - if (showId) { - dispatch( - startVideoPlayer({ - showId, - patnrId, - shptmBanrTpNm: "VOD", - lgCatCd, - modal: false, - }) - ); - } else { - dispatch( - pushPanel({ - name: panel_names.DETAIL_PANEL, - panelInfo: { patnrId, prdtId }, - }) - ); - } - }, + if (showId) { + dispatch( + startVideoPlayer({ + showId, + patnrId, + shptmBanrTpNm: "VOD", + lgCatCd, + modal: false, + }) + ); + } else { + dispatch( + pushPanel({ + name: panel_names.DETAIL_PANEL, + panelInfo: { patnrId, prdtId }, + }) + ); + } + }, [recentDataInfoItem] ); const _handleItemToggle = useCallback( 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 adb97173..405b92d2 100644 --- a/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleContents/OnSaleContents.jsx +++ b/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleContents/OnSaleContents.jsx @@ -39,7 +39,6 @@ export default memo(function OnSaleContents({ shelfId: selectedLgCatCd, shelfTitle: saleNm, }; - console.log("###shelfListShown", params); dispatch(sendLogTotalRecommend(params)); } }, [ diff --git a/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleNav/OnSaleNav.jsx b/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleNav/OnSaleNav.jsx index d0f23d6e..e78f955a 100644 --- a/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleNav/OnSaleNav.jsx +++ b/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleNav/OnSaleNav.jsx @@ -76,9 +76,9 @@ export default function OnSaleNav({ const containerId = "on-sale-nav"; setContainerLastFocusedElement(node, [containerId]); } - setTimeout(() => { - Spotlight.focus(node); - }, 100); + // setTimeout(() => { + // Spotlight.focus(node); + // }, 100); } }, [panelInfoLgCatCd]); diff --git a/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleNav/OnSaleNavItem/OnSaleNavItem.jsx b/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleNav/OnSaleNavItem/OnSaleNavItem.jsx index 296a078b..2e527a6a 100644 --- a/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleNav/OnSaleNavItem/OnSaleNavItem.jsx +++ b/com.twin.app.shoptime/src/views/OnSalePanel/OnSaleNav/OnSaleNavItem/OnSaleNavItem.jsx @@ -1,7 +1,7 @@ import React, { memo, useCallback, useEffect } from "react"; import classNames from "classnames"; -import { useDispatch } from "react-redux"; +import { connect, useDispatch } from "react-redux"; import Spottable from "@enact/spotlight/Spottable"; import { setContainerLastFocusedElement } from "@enact/spotlight/src/container"; @@ -32,8 +32,8 @@ export default memo(function OnSaleNavItem({ const selected = selectedLgCatCd ? selectedLgCatCd === lgCatCd && css.selected : panelInfoLgCatCd - ? panelInfoLgCatCd === lgCatCd && css.selected - : itemIndex === 0; + ? panelInfoLgCatCd === lgCatCd && css.selected + : itemIndex === 0; const selectedText = selected === true ? "Selected, " : ""; @@ -77,8 +77,8 @@ export default memo(function OnSaleNavItem({ selectedLgCatCd ? selectedLgCatCd === lgCatCd && css.selected : panelInfoLgCatCd - ? panelInfoLgCatCd === lgCatCd && css.selected - : itemIndex === 0 && css.selected + ? panelInfoLgCatCd === lgCatCd && css.selected + : itemIndex === 0 && css.selected )} onClick={handleClick} id={"spotlightId-" + lgCatCd} diff --git a/com.twin.app.shoptime/src/views/OnSalePanel/OnSalePanel.jsx b/com.twin.app.shoptime/src/views/OnSalePanel/OnSalePanel.jsx index 0e151653..6d27bef2 100644 --- a/com.twin.app.shoptime/src/views/OnSalePanel/OnSalePanel.jsx +++ b/com.twin.app.shoptime/src/views/OnSalePanel/OnSalePanel.jsx @@ -57,8 +57,8 @@ export default function OnSalePanel({ panelInfo, spotlightId }) { const enteredThroughEventPopup = Object.keys(panelInfo).length === 1; const enteredThroughGNB = Object.keys(panelInfo).length === 0; - const previousPanelIsHome = Object.keys(panelInfo).length === 3; - const previousPanelIsDetail = Object.keys(panelInfo).length > 4; + const previousPanelIsHome = panelInfo?.nowShelf !== undefined; + const previousPanelIsDetail = panelInfo?.noResetFlag === true; const cbChangePageRef = useRef(null); const focusedContainerIdRef = useRef(0); @@ -132,7 +132,6 @@ export default function OnSalePanel({ panelInfo, spotlightId }) { useEffect(() => { if (categories && saleInfos && Object.keys(saleInfos).length > 0) { const prdtId = saleInfos[0]?.saleProductInfos[0]?.prdtId; - if (prdtId) { setFirstFocusableTarget("spotlightId-" + removeDotAndColon(prdtId)); setIsReadyForInitialFocusTarget(true); @@ -149,9 +148,8 @@ export default function OnSalePanel({ panelInfo, spotlightId }) { } if (previousPanelIsHome) { - targetId = panelInfo?.linkTpCd - ? "spotlightId-" + panelInfo?.lgCatCd - : "spotlightId-" + panelInfo?.prdtId; + // 홈에서 온세일 아이템을 선택한 경우 해당 카테고리의 nav 아이템에 포커스 + targetId = "spotlightId-" + panelInfo?.lgCatCd; } if (enteredThroughEventPopup) { @@ -180,8 +178,6 @@ export default function OnSalePanel({ panelInfo, spotlightId }) { isInitialFocusOccurred, isReadyForInitialFocusTarget, panelInfo?.lgCatCd, - panelInfo?.linkTpCd, - panelInfo?.prdtId, panelInfo?.targetId, previousPanelIsDetail, previousPanelIsHome, @@ -300,7 +296,6 @@ export default function OnSalePanel({ panelInfo, spotlightId }) { cbChangePageRef.current(0); } }, []); - const handleShelfFocus = useCallback( (shelfOrder) => { // 현재 포커스된 shelf와 다른 shelf에 포커스될 때만 true 반환 diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx index 6621ccbe..a9fab64d 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx @@ -69,8 +69,15 @@ function PlayerOverlayContents({ }, [dispatch, captionEnable, setIsSubtitleActive]); const patncLogoPath = useMemo(() => { +// <<<<<<< HEAD let logo = playListInfo[selectedIndex]?.patncLogoPath; if (type === 'MEDIA') { +// ======= +// let logo = playListInfo[selectedIndex]?.patncLogoPath +// ? playListInfo[selectedIndex]?.patncLogoPath +// : playListInfo[selectedIndex]?.logoImgPath; +// if (type === "MEDIA") { +// >>>>>>> gitlab/develop logo = panelInfo?.patncLogoPath; } diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayQRCode.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayQRCode.jsx index e12a36ff..c308010a 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayQRCode.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayQRCode.jsx @@ -1,16 +1,18 @@ -import React, { useMemo } from 'react'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; import classNames from 'classnames'; import { useSelector } from 'react-redux'; import TQRCode from '../../../components/TQRCode/TQRCode'; import css from './PlayerOverlayQRCode.module.less'; -import { getQRCodeUrl, scaleH, scaleW } from '../../../utils/helperMethods'; +import { getQRCodeUrl, scaleH, scaleW, $L } from '../../../utils/helperMethods'; function PlayerOverlayQRCode({ qrCurrentItem, type, modalScale }) { const { cntry_cd } = useSelector((state) => state.common.httpHeader); const deviceInfo = useSelector((state) => state.device.deviceInfo); + const [isShowQRCode, setIsShowQRCode] = useState(true); + const timerRef = useRef(null); const serverHOST = useSelector((state) => state.common.appStatus.serverHOST); const serverType = useSelector((state) => state.localSettings.serverType); const { entryMenu, nowMenu } = useSelector((state) => state.common.menu); @@ -102,6 +104,28 @@ function PlayerOverlayQRCode({ qrCurrentItem, type, modalScale }) { return qrCurrentItem?.qrcodeUrl; }, [detailUrl, qrCurrentItem, type]); + useEffect(() => { + const toggleQRCode = () => { + if (isShowQRCode) { + timerRef.current = setTimeout(() => { + setIsShowQRCode(false); + }, 10000); + } else { + timerRef.current = setTimeout(() => { + setIsShowQRCode(true); + }, 5000); + } + }; + + toggleQRCode(); + + return () => { + if (timerRef.current) { + clearTimeout(timerRef.current); + } + }; + }, [isShowQRCode]); + return ( <> {innerStylePosition && QRCodeUrl && ( @@ -115,6 +139,7 @@ function PlayerOverlayQRCode({ qrCurrentItem, type, modalScale }) { )} style={innerStylePosition} > +{/* <<<<<<< HEAD */}
{label}
+{/* ======= + {isShowQRCode ? ( +
+ +
{label}
+
+ ) : ( +
+
+

{$L("Scan QR")}

+

{$L("with your phone, Check Product")}

+

{$L("info & Purchase easily")}

+
+
+ )} +>>>>>>> gitlab/develop */}
)} diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayQRCode.module.less b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayQRCode.module.less index 1d537521..f4b895ab 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayQRCode.module.less +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayQRCode.module.less @@ -68,4 +68,84 @@ } } } + + .qrRollingWrap { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + text-align: center; + width: 100%; + height: 100%; + background: @COLOR_WHITE; + + .innerText { + width: 100%; + padding: 0 10px; + + h3 { + word-break: break-word; + font-size: 24px; + font-weight: bold; + color: @PRIMARY_COLOR_RED; + + & + p { + margin-top: 10px; + } + } + + p { + font-size: 16px; + font-weight: bold; + line-height: 1.2; + color: @COLOR_GRAY05; + word-break: keep-all; + } + } + } + + // 국가별 롤링 텍스트 크기 조정 (폰트 사이즈만) + &.us .qrRollingWrap { + .innerText { + h3 { + font-size: 27px; + } + p { + font-size: 18px; + } + } + } + + &.ru .qrRollingWrap { + .innerText { + h3 { + font-size: 22px; + } + p { + font-size: 15px; + } + } + } + + &.de .qrRollingWrap { + .innerText { + h3 { + font-size: 26px; + } + p { + font-size: 17px; + } + } + } + + &.gb .qrRollingWrap { + .innerText { + h3 { + font-size: 23px; + } + p { + font-size: 16px; + } + } + } } diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx index 534cc4f7..05d765f8 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx @@ -28,9 +28,16 @@ import { getMainCategoryShowDetail, getMainLiveShow, getMainLiveShowNowProduct, +// <<<<<<< HEAD } from '../../actions/mainActions'; import * as PanelActions from '../../actions/panelActions'; import { updatePanel } from '../../actions/panelActions'; +// ======= +// } from "../../actions/mainActions"; +// import { getBrandLiveChannelInfo } from "../../actions/brandActions"; +// import * as PanelActions from "../../actions/panelActions"; +// import { updatePanel } from "../../actions/panelActions"; +// >>>>>>> gitlab/develop import { CLEAR_PLAYER_INFO, getChatLog, diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContainer.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContainer.jsx index e86a9add..6d083d2a 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContainer.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContainer.jsx @@ -33,16 +33,20 @@ export default function TabContainer({ prevChannelIndex, currentTime, spotlightId, + isFilteredByPatnr19, }) { const [tab, setTab] = useState(0); const tabList = [ $L("SHOP NOW"), panelInfo?.shptmBanrTpNm === "LIVE" - ? $L("LIVE CHANNEL") + ? isFilteredByPatnr19 + ? $L("VOD CHANNEL") + : $L("LIVE CHANNEL") : $L("FEATURED SHOWS"), ]; + // console.log("###liveChannelInfos", liveChannelInfos[selectedIndex]); const handleItemClick = useCallback( ({ index }) => { if (index === tab) return; @@ -101,7 +105,6 @@ export default function TabContainer({ }, [videoVerticalVisible] ); - return ( )} + {panelInfo?.shptmBanrTpNm === "VOD" && + panelInfo?.patnrId === "19" && + tab === 1 && ( + + )} {panelInfo?.shptmBanrTpNm === "VOD" && tab === 1 && ( )} diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/FeaturedShowContents.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/FeaturedShowContents.jsx index 0538c7b9..767a0f37 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/FeaturedShowContents.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/FeaturedShowContents.jsx @@ -4,6 +4,7 @@ import { useDispatch } from 'react-redux'; import Spotlight from '@enact/spotlight'; +// <<<<<<< HEAD import defaultImage from '../../../../../assets/images/img-thumb-empty-144@3x.png'; import { updatePanel } from '../../../../actions/panelActions'; import TVirtualGridList from '../../../../components/TVirtualGridList/TVirtualGridList'; @@ -14,6 +15,23 @@ import ListEmptyContents from '../TabContents/ListEmptyContents/ListEmptyContent import css from './LiveChannelContents.module.less'; import { getMainCategoryShowDetail } from '../../../../actions/mainActions'; import { sendLogTotalRecommend } from '../../../../actions/logActions'; +// ======= +// import defaultImage from "../../../../../assets/images/img-thumb-empty-144@3x.png"; +// import { updatePanel } from "../../../../actions/panelActions"; +// import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList"; +// import { +// LOG_CONTEXT_NAME, +// LOG_MENU, +// LOG_MESSAGE_ID, +// panel_names, +// } from "../../../../utils/Config"; +// import { $L, removeSpecificTags } from "../../../../utils/helperMethods"; +// import PlayerItemCard, { TYPES } from "../../PlayerItemCard/PlayerItemCard"; +// import ListEmptyContents from "../TabContents/ListEmptyContents/ListEmptyContents"; +// import css from "./LiveChannelContents.module.less"; +// import { getMainCategoryShowDetail } from "../../../../actions/mainActions"; +// import { sendLogTotalRecommend } from "../../../../actions/logActions"; +// >>>>>>> gitlab/develop export default function FeaturedShowContents({ featuredShowsInfos, @@ -44,6 +62,8 @@ export default function FeaturedShowContents({ ({ index, ...rest }) => { const { thumbnailUrl, + logoImgPath, + thumbnailImgPath, patncLogoPath, patnrId, showId, @@ -106,8 +126,14 @@ export default function FeaturedShowContents({ {...rest} key={prdtId} imageAlt={prdtId} - logo={patncLogoPath} - imageSource={thumbnailUrl ? thumbnailUrl : defaultImage} + logo={logoImgPath ? logoImgPath : patncLogoPath} + imageSource={ + thumbnailUrl + ? thumbnailUrl + : thumbnailImgPath + ? thumbnailImgPath + : defaultImage + } productName={showNameDangerouslySetInnerHTML} patnerName={patncNm} onClick={handleItemClick} diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/LiveChannelContents.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/LiveChannelContents.jsx index 009f4341..51734216 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/LiveChannelContents.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/LiveChannelContents.jsx @@ -4,6 +4,7 @@ import { useDispatch } from 'react-redux'; import Spotlight from '@enact/spotlight'; +// <<<<<<< HEAD import { updatePanel } from '../../../../actions/panelActions'; import TVirtualGridList from '../../../../components/TVirtualGridList/TVirtualGridList'; import { LOG_CONTEXT_NAME, LOG_MENU, LOG_MESSAGE_ID, panel_names } from '../../../../utils/Config'; @@ -13,6 +14,21 @@ import ListEmptyContents from '../TabContents/ListEmptyContents/ListEmptyContent import css from './LiveChannelContents.module.less'; import cssV2 from './LiveChannelContents.v2.module.less'; import { sendLogTotalRecommend } from '../../../../actions/logActions'; +// ======= +// import { updatePanel } from "../../../../actions/panelActions"; +// import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList"; +// import { +// LOG_CONTEXT_NAME, +// LOG_MENU, +// LOG_MESSAGE_ID, +// panel_names, +// } from "../../../../utils/Config"; +// import { $L } from "../../../../utils/helperMethods"; +// import PlayerItemCard, { TYPES } from "../../PlayerItemCard/PlayerItemCard"; +// import ListEmptyContents from "../TabContents/ListEmptyContents/ListEmptyContents"; +// import css from "./LiveChannelContents.module.less"; +// import { sendLogTotalRecommend } from "../../../../actions/logActions"; +// >>>>>>> gitlab/develop export default function LiveChannelContents({ liveInfos, @@ -24,13 +40,22 @@ export default function LiveChannelContents({ handleItemFocus, tabTitle, panelInfo, +// <<<<<<< HEAD direction = 'vertical', version = 1, + isFilteredByPatnr19, }) { const dispatch = useDispatch(); const isClickBlocked = useRef(false); const blockTimeoutRef = useRef(null); +// ======= +// isFilteredByPatnr19, +// }) { +// const dispatch = useDispatch(); +// const isClickBlocked = useRef(false); + const scrollToRef = useRef(null); +// >>>>>>> gitlab/develop const handleFocus = useCallback( () => () => { if (handleItemFocus) { @@ -40,6 +65,18 @@ export default function LiveChannelContents({ [handleItemFocus] ); + // cbScrollTo 콜백으로 scrollTo 함수 받기 + const handleScrollTo = useCallback((scrollToFn) => { + scrollToRef.current = scrollToFn; + }, []); + + // VOD Channel로 전환될 때 스크롤을 최상단으로 이동 + useEffect(() => { + if (isFilteredByPatnr19 && scrollToRef.current) { + scrollToRef.current({ index: 0, animate: false, focus: false }); + } + }, [isFilteredByPatnr19]); + const renderItem = useCallback( ({ index, ...rest }) => { const { @@ -144,7 +181,11 @@ export default function LiveChannelContents({ startDt={strtDt} endDt={endDt} currentTime={currentTime} +// <<<<<<< HEAD version={version} +// ======= +// currentVideoVisible={currentVideoShowId === liveInfos[index].showId} +// >>>>>>> gitlab/develop /> ); }, @@ -167,6 +208,7 @@ export default function LiveChannelContents({
{liveInfos && liveInfos.length > 0 ? ( state.main.youmaylikeInfos); const gridStyle = useMemo(() => ({ height: `${height}px` }), [height]); - useEffect(() => { if (shopNowInfo && shopNowInfo.length === 2) { setHeight(scaleH(300)); @@ -82,7 +81,12 @@ export default function YouMayLikeContents({ showNm: playListInfo?.showNm, showId: playListInfo?.showId, liveFlag: playListInfo?.liveFlag, +// <<<<<<< HEAD thumbnailUrl: playListInfo?.thumbnailUrl, +// ======= + catDpTh3: playListInfo?.catDpTh3, + catDpTh4: playListInfo?.catDpTh4, +// >>>>>>> gitlab/develop patnrId, prdtId, launchedFromPlayer: true, diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults/SearchCard/SearchShowCard.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults/SearchCard/SearchShowCard.jsx index 8bdf35ef..1c4b36d0 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults/SearchCard/SearchShowCard.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults/SearchCard/SearchShowCard.jsx @@ -43,7 +43,8 @@ export default memo(function SearchShowCard({ const sendLog = (newParams) => { const logParams = { ...newParams, - contentTitle: title, + showTitle: title, + showId: contentId.split("_").pop() || "", partner: patncNm, contextName: LOG_CONTEXT_NAME.SEARCH, messageId: LOG_MESSAGE_ID.SEARCH_RESULT_CLICK, diff --git a/com.twin.app.shoptime/src/views/TrendingNowPanel/PopularShow/PopularVideoCard/PopularVideoCard.jsx b/com.twin.app.shoptime/src/views/TrendingNowPanel/PopularShow/PopularVideoCard/PopularVideoCard.jsx index 7151b003..ecdf08fc 100644 --- a/com.twin.app.shoptime/src/views/TrendingNowPanel/PopularShow/PopularVideoCard/PopularVideoCard.jsx +++ b/com.twin.app.shoptime/src/views/TrendingNowPanel/PopularShow/PopularVideoCard/PopularVideoCard.jsx @@ -128,8 +128,8 @@ const PopularVideoCard = ({ shelfLocation: 1, shelfId: SpotlightIds.TRENDING_NOW_POPULAR_SHOW, shelfTitle: currentShelf, - contentId: showId, - contentTitle: showNm, + showId: showId, + showTitle: showNm, partner: patncNm, location: selectedIndex + 1, };