[251123] Merge: develop_si base로 develop을 merge함

This commit is contained in:
2025-11-23 18:45:09 +09:00
45 changed files with 1059 additions and 315 deletions

View File

@@ -266,6 +266,11 @@ export const handleDeepLink = (contentTarget) => (dispatch, getState) => {
deeplink: deeplinkPanel, deeplink: deeplinkPanel,
curationId: curationId ? curationId : showId, curationId: curationId ? curationId : showId,
productId: prdtId, productId: prdtId,
partnerID: patnrId,
showId: showId,
channelId: chanId,
category: lgCatNm,
linkTypeCode: linkTpCd,
}) })
); );

View File

@@ -3,6 +3,7 @@
import { Job } from '@enact/core/util'; import { Job } from '@enact/core/util';
import Spotlight from '@enact/spotlight'; import Spotlight from '@enact/spotlight';
// <<<<<<< HEAD
import appinfo from '../../webos-meta/appinfo.json'; import appinfo from '../../webos-meta/appinfo.json';
import appinfo35 from '../../webos-meta/appinfo35.json'; import appinfo35 from '../../webos-meta/appinfo35.json';
import appinfo79 from '../../webos-meta/appinfo79.json'; import appinfo79 from '../../webos-meta/appinfo79.json';
@@ -10,7 +11,19 @@ import { handleBypassLink } from '../App/bypassLinkHandler';
import * as lunaSend from '../lunaSend'; import * as lunaSend from '../lunaSend';
import { initialLocalSettings } from '../reducers/localSettingsReducer'; import { initialLocalSettings } from '../reducers/localSettingsReducer';
import * as Config from '../utils/Config'; import * as Config from '../utils/Config';
import * as HelperMethods from '../utils/helperMethods';
import { types } from './actionTypes'; 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) => ({ export const changeAppStatus = (status) => ({
type: types.CHANGE_APP_STATUS, type: types.CHANGE_APP_STATUS,
@@ -31,14 +44,19 @@ export const gnbOpened = (status) => ({
payload: status, payload: status,
}); });
// <<<<<<< HEAD
export const setShowPopup = (config, addPayload = {}) => { export const setShowPopup = (config, addPayload = {}) => {
let payload; let payload;
if (typeof config === 'string') { if (typeof config === 'string') {
payload = { activePopup: config, ...addPayload }; payload = { activePopup: config, ...addPayload };
} else { } else {
payload = config; payload = config;
} }
// =======
// export const setShowPopup = (config) => {
// const payload = typeof config === "string" ? { activePopup: config } : config;
// >>>>>>> gitlab/develop
return { return {
type: types.SET_SHOW_POPUP, type: types.SET_SHOW_POPUP,
payload, payload,
@@ -295,25 +313,28 @@ export const getDeviceId = (onComplete) => (dispatch, getState) => {
export const getTermsAgreeYn = () => (dispatch, getState) => { export const getTermsAgreeYn = () => (dispatch, getState) => {
dispatch({ type: types.GET_TERMS_AGREE_YN_START }); dispatch({ type: types.GET_TERMS_AGREE_YN_START });
try { try {
const { terms } = getState().home.termsData.data; const { terms } = getState().home.termsData.data;
console.log("getTermsAgreeYn", terms.map(term => ({ console.log(
trmsId: term.trmsId, "getTermsAgreeYn",
trmsTpCd: term.trmsTpCd, terms.map((term) => ({
trmsAgrFlag: term.trmsAgrFlag, trmsId: term.trmsId,
trmsPopFlag: term.trmsPopFlag, trmsTpCd: term.trmsTpCd,
}))); trmsAgrFlag: term.trmsAgrFlag,
trmsPopFlag: term.trmsPopFlag,
}))
);
// MST00405 선택약관 정보만 따로 출력 // MST00405 선택약관 정보만 따로 출력
const optionalTerm = terms.find(term => term.trmsTpCd === 'MST00405'); const optionalTerm = terms.find((term) => term.trmsTpCd === "MST00405");
if (optionalTerm) { if (optionalTerm) {
console.log("getTermsAgreeYn MST00405 선택약관:", { console.log("getTermsAgreeYn MST00405 선택약관:", {
trmsId: optionalTerm.trmsId, trmsId: optionalTerm.trmsId,
trmsTpCd: optionalTerm.trmsTpCd, trmsTpCd: optionalTerm.trmsTpCd,
trmsAgrFlag: optionalTerm.trmsAgrFlag, trmsAgrFlag: optionalTerm.trmsAgrFlag,
trmsPopFlag: optionalTerm.trmsPopFlag trmsPopFlag: optionalTerm.trmsPopFlag,
}); });
} else { } else {
console.log("getTermsAgreeYn MST00405 선택약관을 찾을 수 없습니다."); console.log("getTermsAgreeYn MST00405 선택약관을 찾을 수 없습니다.");
@@ -340,7 +361,7 @@ export const getTermsAgreeYn = () => (dispatch, getState) => {
break; break;
} }
return acc; return acc;
}, {}); }, {});
dispatch({ dispatch({
type: types.GET_TERMS_AGREE_YN_SUCCESS, type: types.GET_TERMS_AGREE_YN_SUCCESS,
@@ -507,10 +528,20 @@ export const requestLiveSubtitle =
export const addReservation = (data) => (dispatch) => { export const addReservation = (data) => (dispatch) => {
lunaSend.addReservation(data, { lunaSend.addReservation(data, {
onSuccess: (res) => { 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) => { 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, retDetailCode = null,
returnBindStrings = null returnBindStrings = null
) => ) =>
(dispatch) => { (dispatch) => {
dispatch( dispatch(
setShowPopup(Config.ACTIVE_POPUP.errorPopup, { setShowPopup(Config.ACTIVE_POPUP.errorPopup, {
data: { data: {
@@ -701,8 +732,8 @@ export const getConnectionInfo = () => (dispatch, getState) => {
lunaSend.getConnectionInfo({ lunaSend.getConnectionInfo({
onSuccess: (res) => { onSuccess: (res) => {
console.log("lunasend getConnectionStatus", res); console.log("lunasend getConnectionStatus", res);
if (res && res.retrunValue) { if (res && res.returnValue) {
const macAddress = res?.wiredInfo.macAddress; const macAddress = res?.wiredInfo?.macAddress;
console.log("macAddress...........", macAddress, res); console.log("macAddress...........", macAddress, res);
} }
}, },
@@ -764,35 +795,37 @@ export const resetOptionalTermsSession = () => ({
// 선택약관 동의 처리를 위한 헬퍼 함수 // 선택약관 동의 처리를 위한 헬퍼 함수
export const handleOptionalTermsAgree = () => (dispatch) => { export const handleOptionalTermsAgree = () => (dispatch) => {
console.log('[CommonActions] 선택약관 동의 처리'); console.log("[CommonActions] 선택약관 동의 처리");
dispatch(setOptionalTermsUserDecision('agreed')); dispatch(setOptionalTermsUserDecision("agreed"));
dispatch(setOptionalTermsPopupShown(true)); dispatch(setOptionalTermsPopupShown(true));
}; };
// 선택약관 거절 처리를 위한 헬퍼 함수 // 선택약관 거절 처리를 위한 헬퍼 함수
export const handleOptionalTermsDecline = () => (dispatch) => { export const handleOptionalTermsDecline = () => (dispatch) => {
console.log('[CommonActions] 선택약관 거절 처리'); console.log("[CommonActions] 선택약관 거절 처리");
dispatch(setOptionalTermsUserDecision('declined')); dispatch(setOptionalTermsUserDecision("declined"));
dispatch(setOptionalTermsPopupShown(true)); dispatch(setOptionalTermsPopupShown(true));
}; };
// 선택약관 상태 통합 업데이트 (TV 환경 최적화 - API 호출 없이 즉시 반영) // 선택약관 상태 통합 업데이트 (TV 환경 최적화 - API 호출 없이 즉시 반영)
export const updateOptionalTermsAgreement = (agreed = true) => (dispatch) => { export const updateOptionalTermsAgreement =
console.log(`[CommonActions] 선택약관 통합 상태 업데이트: ${agreed}`); (agreed = true) =>
(dispatch) => {
// 1. optionalTermsPopupFlow 업데이트 (TV 환경용) console.log(`[CommonActions] 선택약관 통합 상태 업데이트: ${agreed}`);
dispatch(setOptionalTermsUserDecision(agreed ? 'agreed' : 'declined'));
dispatch(setOptionalTermsPopupShown(true)); // 1. optionalTermsPopupFlow 업데이트 (TV 환경용)
dispatch(setOptionalTermsUserDecision(agreed ? "agreed" : "declined"));
// 2. 기본 optionalTermsAgree 상태 직접 업데이트 (API 호출 없이) dispatch(setOptionalTermsPopupShown(true));
dispatch({
type: types.UPDATE_OPTIONAL_TERMS_AGREE_DIRECT, // 2. 기본 optionalTermsAgree 상태 직접 업데이트 (API 호출 없이)
payload: agreed dispatch({
}); type: types.UPDATE_OPTIONAL_TERMS_AGREE_DIRECT,
payload: agreed,
// 3. termsAgreementStatus도 동기화 });
dispatch({
type: types.UPDATE_TERMS_AGREEMENT_STATUS_DIRECT, // 3. termsAgreementStatus도 동기화
payload: { MST00405: agreed } dispatch({
}); type: types.UPDATE_TERMS_AGREEMENT_STATUS_DIRECT,
}; payload: { MST00405: agreed },
});
};

View File

@@ -234,13 +234,23 @@ export const getSubCategory =
export const continueGetSubCategory = (key, pageNo) => (dispatch, getState) => { export const continueGetSubCategory = (key, pageNo) => (dispatch, getState) => {
if (!lastSubCategoryParams) { if (!lastSubCategoryParams) {
// <<<<<<< HEAD
console.warn('No previous category parameters found'); console.warn('No previous category parameters found');
// =======
// console.warn("No previous category parameters found");
// >>>>>>> gitlab/develop
return; return;
} }
const subCategoryData = getState().main.subCategoryData; const subCategoryData = getState().main.subCategoryData;
const targetData = const targetData =
// <<<<<<< HEAD
subCategoryData[key]?.subCatItemList || subCategoryData[key]?.subCatShowList || []; subCategoryData[key]?.subCatItemList || subCategoryData[key]?.subCatShowList || [];
// =======
// subCategoryData[key]?.subCatItemList ||
// subCategoryData[key]?.subCatShowList ||
// [];
// >>>>>>> gitlab/develop
const totalCount = subCategoryData[key]?.total ?? 0; const totalCount = subCategoryData[key]?.total ?? 0;
const startIndex = CATEGORY_DATA_MAX_RESULTS_LIMIT * (pageNo - 1); const startIndex = CATEGORY_DATA_MAX_RESULTS_LIMIT * (pageNo - 1);
if ( if (
@@ -251,7 +261,13 @@ export const continueGetSubCategory = (key, pageNo) => (dispatch, getState) => {
//ignore query //ignore query
return; return;
} }
// <<<<<<< HEAD
dispatch(getSubCategory({ ...lastSubCategoryParams }, pageNo, getSubCategoryKey)); dispatch(getSubCategory({ ...lastSubCategoryParams }, pageNo, getSubCategoryKey));
// =======
// dispatch(
// getSubCategory({ ...lastSubCategoryParams }, pageNo, getSubCategoryKey)
// );
// >>>>>>> gitlab/develop
}; };
const clearSubCategory = () => ({ const clearSubCategory = () => ({
@@ -325,7 +341,11 @@ export const getMainYouMayLike =
getState, getState,
'get', 'get',
URLS.GET_YOUMAYLIKE, URLS.GET_YOUMAYLIKE,
// <<<<<<< HEAD
{ lgCatCd, exclCurationId, exclPatnrId, exclPrdtId, catDpTh3, catDpTh4 }, { lgCatCd, exclCurationId, exclPatnrId, exclPrdtId, catDpTh3, catDpTh4 },
// =======
// { lgCatCd, catDpTh3, catDpTh4, exclCurationId, exclPatnrId, exclPrdtId },
// >>>>>>> gitlab/develop
{}, {},
onSuccess, onSuccess,
onFail onFail

View File

@@ -182,8 +182,22 @@ export const deleteMyFavorite = (params) => (dispatch, getState) => {
// MyPage 약관 철회 (IF-LGSP-032) // MyPage 약관 철회 (IF-LGSP-032)
export const setMyTermsWithdraw = export const setMyTermsWithdraw =
(params, callback) => (dispatch, getState) => { (params, callback) => (dispatch, getState) => {
let localMacAddress;
const { mandatoryIncludeYn, termsList } = params; 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) => { const onSuccess = (response) => {
console.log("setMyTermsWithdraw onSuccess ", response.data); console.log("setMyTermsWithdraw onSuccess ", response.data);
@@ -199,13 +213,22 @@ export const setMyTermsWithdraw =
console.error("setMyTermsWithdraw onFail ", error); console.error("setMyTermsWithdraw onFail ", error);
}; };
const requestData = {
mandatoryIncludeYn,
termsList,
xDeviceProduct,
macAddr: macAddr ? macAddr : localMacAddress,
userNumber: userNumber || "",
requestTime: logCreateTime,
};
TAxios( TAxios(
dispatch, dispatch,
getState, getState,
"post", "post",
URLS.SET_MY_TERMS_WITHDRAW, URLS.SET_MY_TERMS_WITHDRAW,
{}, {},
{ mandatoryIncludeYn, termsList }, requestData,
onSuccess, onSuccess,
onFail onFail
); );
@@ -223,14 +246,17 @@ export const setMyPageTermsAgree =
// 약관 ID를 약관 코드로 변환하기 위해 state에서 termsIdMap 조회 // 약관 ID를 약관 코드로 변환하기 위해 state에서 termsIdMap 조회
const termsIdMap = getState().home.termsIdMap || {}; const termsIdMap = getState().home.termsIdMap || {};
const idToCodeMap = Object.entries(termsIdMap).reduce((acc, [code, id]) => { const idToCodeMap = Object.entries(termsIdMap).reduce(
acc[id] = code; (acc, [code, id]) => {
return acc; acc[id] = code;
}, {}); return acc;
},
{}
);
// 동의한 약관 ID 목록을 약관 코드로 변환 // 동의한 약관 ID 목록을 약관 코드로 변환
const agreedTermCodes = termsList const agreedTermCodes = termsList
.map(id => idToCodeMap[id]) .map((id) => idToCodeMap[id])
.filter(Boolean); .filter(Boolean);
dispatch({ dispatch({

View File

@@ -176,7 +176,8 @@ export default function MobileSendPopUp({
if (rawPhoneNumber.length === getMaxNum(deviceCountryCode)) { if (rawPhoneNumber.length === getMaxNum(deviceCountryCode)) {
Spotlight.focus("agreeAndSend"); Spotlight.focus("agreeAndSend");
} }
if (rawPhoneNumber.length > getMaxNum(deviceCountryCode)) { // 테스트용: 12자리까지 허용
if (rawPhoneNumber.length > 12) {
return; return;
} }
const phoneUtil = PhoneNumberUtil.getInstance(); const phoneUtil = PhoneNumberUtil.getInstance();
@@ -327,7 +328,12 @@ export default function MobileSendPopUp({
const handleAgreeSendClick = useCallback(() => { const handleAgreeSendClick = useCallback(() => {
let naturalNumber = mobileNumber.replace(/\D/g, ""); let naturalNumber = mobileNumber.replace(/\D/g, "");
if (!mobileNumber || naturalNumber.length < getMaxNum(deviceCountryCode)) { // 테스트용: 길이 체크를 더 유연하게 (10자리 또는 11자리 허용)
if (
!mobileNumber ||
naturalNumber.length < 10 ||
naturalNumber.length > 12
) {
setSmsRetCode(907); setSmsRetCode(907);
return; return;
} }
@@ -405,7 +411,6 @@ export default function MobileSendPopUp({
if (smsTpCd === "APP00204") { if (smsTpCd === "APP00204") {
params = { ...params, curationId }; params = { ...params, curationId };
} }
dispatch(sendSms(params)); dispatch(sendSms(params));
} }
// EVT00101 & APP00207(welcome) EVT00103 & APP00209 (welcome+Prizes) : smsTpCd 값을 받지 않음 // EVT00101 & APP00207(welcome) EVT00103 & APP00209 (welcome+Prizes) : smsTpCd 값을 받지 않음

View File

@@ -1,11 +1,9 @@
// src/components/TCheckBox/TCheckBoxSquare.module.less // src/components/TCheckBox/TCheckBoxSquare.module.less
@SQUARE_BORDER_DEFAULT: #CCCCCC; @SQUARE_BORDER_DEFAULT: #cccccc;
@SQUARE_BORDER_ACTIVE: #C70850; @SQUARE_BORDER_ACTIVE: #c70850;
@SQUARE_BG_SELECTED: #7A808D; @SQUARE_BG_SELECTED: #7a808d;
// @SQUARE_BG_SELECTED: #C70850; // @SQUARE_BG_SELECTED: #C70850;
;
.tCheckBoxSquare { .tCheckBoxSquare {
min-width: 45px !important; min-width: 45px !important;
min-height: 45px !important; min-height: 45px !important;
@@ -17,17 +15,19 @@
position: relative; position: relative;
box-sizing: border-box; box-sizing: border-box;
cursor: pointer; cursor: pointer;
transition: background 0.15s, border 0.15s !important; transition:
background 0.15s,
border 0.15s !important;
&:hover, &:hover,
&:focus, &:focus,
&.focus { &.focus {
border-color: @SQUARE_BORDER_ACTIVE !important; border-color: @SQUARE_BORDER_ACTIVE !important;
border-width: 4px !important; // 🔥 포커스 시 굵은 테두리 border-width: 4px !important; // 🔥 포커스 시 굵은 테두리
} }
&::before { &::before {
content: ''; content: "";
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
@@ -52,7 +52,8 @@
&.selectedFocus { &.selectedFocus {
border-color: @SQUARE_BORDER_ACTIVE !important; border-color: @SQUARE_BORDER_ACTIVE !important;
border-width: 4px !important; border-width: 4px !important;
background-color: @SQUARE_BG_SELECTED !important; background-color: @SQUARE_BG_SELECTED !important;
&::before { &::before {
transform: translate(-50%, -70%) rotate(-45deg) scale(1); transform: translate(-50%, -70%) rotate(-45deg) scale(1);
} }

View File

@@ -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 classNames from "classnames";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
@@ -81,6 +88,8 @@ export default memo(function TItemCard({
nowProductId, nowProductId,
nowCategory, nowCategory,
nowProductTitle, nowProductTitle,
showId,
showTitle,
contentId, contentId,
version = 1, version = 1,
...rest ...rest
@@ -131,6 +140,8 @@ export default memo(function TItemCard({
shelfTitle: shelfTitle, shelfTitle: shelfTitle,
productId: productId, productId: productId,
productTitle: productName, productTitle: productName,
showId: showId,
showTitle: showTitle,
nowProductId: nowProductId, nowProductId: nowProductId,
nowCategory: nowCategory, nowCategory: nowCategory,
nowProductTitle: nowProductTitle, nowProductTitle: nowProductTitle,
@@ -144,7 +155,6 @@ export default memo(function TItemCard({
curationId: curationId, curationId: curationId,
curationTitle: curationTitle, curationTitle: curationTitle,
}; };
console.log("###shelfContentClick", params);
dispatch(sendLogTotalRecommend(params)); dispatch(sendLogTotalRecommend(params));
} }
} }

View File

@@ -11,18 +11,18 @@
// bottom: unset !important; // bottom: unset !important;
// transform: none !important; // transform: none !important;
// overflow: unset; // overflow: unset;
// > div { // > div {
// overflow: unset; // overflow: unset;
// } // }
// } // }
// // 다른 팝업들은 기존 TPopUp 방식 유지 // // 다른 팝업들은 기존 TPopUp 방식 유지
// &:not(:has(.src_components_TPopUp_TNewPopUp_optionalConfirm)) { // &:not(:has(.src_components_TPopUp_TNewPopUp_optionalConfirm)) {
// bottom: 50%; // bottom: 50%;
// transform: translateY(50%); // transform: translateY(50%);
// overflow: unset; // overflow: unset;
// > div { // > div {
// overflow: unset; // overflow: unset;
// } // }
@@ -184,7 +184,7 @@
&.optionPopup { &.optionPopup {
.default-style(); .default-style();
.optionInfo { .optionInfo {
width: 820px; width: 820px;
background-color: @BG_COLOR_01; background-color: @BG_COLOR_01;
@@ -225,7 +225,7 @@
background: @PRIMARY_COLOR_RED; background: @PRIMARY_COLOR_RED;
color: @COLOR_WHITE; color: @COLOR_WHITE;
} }
.optionImg { .optionImg {
width: 60px; width: 60px;
height: 60px; height: 60px;
@@ -248,7 +248,7 @@
&.optionScroll { &.optionScroll {
overflow-y: auto; overflow-y: auto;
} }
.selectedOption { .selectedOption {
box-sizing: border-box; box-sizing: border-box;
background: @COLOR_WHITE; background: @COLOR_WHITE;
@@ -256,7 +256,7 @@
border: 4px solid @PRIMARY_COLOR_RED; border: 4px solid @PRIMARY_COLOR_RED;
} }
} }
.optionButtonContainer { .optionButtonContainer {
margin: 30px 0 30px 0; margin: 30px 0 30px 0;
display: flex; display: flex;
@@ -266,7 +266,7 @@
&.eventBannerPopup { &.eventBannerPopup {
.default-style(); .default-style();
.eventBannerInfo { .eventBannerInfo {
width: 600px; width: 600px;
height: 510px; height: 510px;
@@ -277,7 +277,7 @@
font-weight: normal; font-weight: normal;
box-sizing: border-box; box-sizing: border-box;
border-radius: 4px; border-radius: 4px;
> p > img { > p > img {
width: 600px; width: 600px;
height: 510px; height: 510px;
@@ -291,7 +291,7 @@
left: 0; left: 0;
right: 0; right: 0;
bottom: 50px; bottom: 50px;
> div { > div {
margin: 0 6px; margin: 0 6px;
min-width: 240px; min-width: 240px;
@@ -302,7 +302,7 @@
&.supportPopup { &.supportPopup {
.default-style(); .default-style();
.supportInfo { .supportInfo {
width: 960px; width: 960px;
height: 640px; height: 640px;
@@ -313,7 +313,7 @@
font-weight: normal; font-weight: normal;
box-sizing: border-box; box-sizing: border-box;
border-radius: 4px; border-radius: 4px;
.supportButtonContainer { .supportButtonContainer {
position: absolute; position: absolute;
right: 0; right: 0;
@@ -332,7 +332,7 @@
&.couponPopup { &.couponPopup {
.default-style(); .default-style();
.couponInfo { .couponInfo {
width: 960px; width: 960px;
height: 640px; height: 640px;
@@ -343,7 +343,7 @@
font-weight: normal; font-weight: normal;
box-sizing: border-box; box-sizing: border-box;
border-radius: 4px; border-radius: 4px;
.couponButtonContainer { .couponButtonContainer {
position: absolute; position: absolute;
right: 0; right: 0;
@@ -362,7 +362,7 @@
&.mobileSendPopup { &.mobileSendPopup {
.default-style(); .default-style();
.mobileSendInfo { .mobileSendInfo {
width: 960px; width: 960px;
height: 640px; height: 640px;
@@ -373,7 +373,7 @@
font-weight: normal; font-weight: normal;
box-sizing: border-box; box-sizing: border-box;
border-radius: 4px; border-radius: 4px;
.mobileSendButtonContainer { .mobileSendButtonContainer {
position: absolute; position: absolute;
right: 0; right: 0;
@@ -392,7 +392,7 @@
&.qrPopup { &.qrPopup {
.default-style(); .default-style();
.qrInfo { .qrInfo {
width: 960px; width: 960px;
height: 640px; height: 640px;
@@ -404,7 +404,7 @@
box-sizing: border-box; box-sizing: border-box;
border-radius: 4px; border-radius: 4px;
} }
.qrButtonContainer { .qrButtonContainer {
display: flex; display: flex;
justify-content: center; justify-content: center;
@@ -458,7 +458,7 @@
} }
} }
} }
.checkoutTermsButtonContainer { .checkoutTermsButtonContainer {
display: flex; display: flex;
justify-content: center; justify-content: center;
@@ -481,7 +481,7 @@
&.scrollPopup { &.scrollPopup {
.default-style(); .default-style();
.scrollInfo { .scrollInfo {
width: 900px; width: 900px;
background-color: @BG_COLOR_01; background-color: @BG_COLOR_01;
@@ -492,7 +492,7 @@
box-sizing: border-box; box-sizing: border-box;
border-radius: 4px; border-radius: 4px;
} }
.scrollButtonContainer { .scrollButtonContainer {
display: flex; display: flex;
justify-content: center; justify-content: center;
@@ -517,7 +517,7 @@
position: absolute; position: absolute;
right: 42px; right: 42px;
bottom: -330px; bottom: -330px;
.watchInfo { .watchInfo {
width: 1038px; width: 1038px;
height: 168px; height: 168px;
@@ -567,7 +567,7 @@
.elip(@clamp:1); .elip(@clamp:1);
} }
} }
.watchButtonContainer { .watchButtonContainer {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@@ -613,7 +613,7 @@
text-align: center; text-align: center;
.flex(); .flex();
} }
.setPinCodeButtonContainer { .setPinCodeButtonContainer {
margin: 0 0 30px 0; margin: 0 0 30px 0;
display: flex; display: flex;
@@ -902,22 +902,22 @@
.default-style(); .default-style();
bottom: unset !important; bottom: unset !important;
transform: none !important; transform: none !important;
top: 20% !important; top: 20% !important;
// 기존 위치 스타일들... // 기존 위치 스타일들...
.optionalConfirmInfo { .optionalConfirmInfo {
width: 100vw; width: 100vw;
height: 198px; height: 198px;
background-color: #E6EBF0; background-color: #e6ebf0;
border-radius: 4px; 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; display: flex;
flex-direction: column; flex-direction: column;
box-sizing: border-box; box-sizing: border-box;
// gap: 15px; // gap: 15px;
.optionalConfirmContentContainer { .optionalConfirmContentContainer {
width: 100%; width: 100%;
height: 100%; height: 100%;
@@ -927,7 +927,7 @@
box-sizing: border-box; box-sizing: border-box;
justify-content: center; justify-content: center;
// gap: 20px; // gap: 20px;
.optionalConfirmTextSection { .optionalConfirmTextSection {
// flex: 1; // 나머지 높이를 모두 차지 // flex: 1; // 나머지 높이를 모두 차지
height: 30px; height: 30px;
@@ -937,7 +937,7 @@
// border : 1px solid red; // border : 1px solid red;
margin-bottom: 20px; margin-bottom: 20px;
} }
.optionalConfirmButtonSection { .optionalConfirmButtonSection {
height: 60px; height: 60px;
// margin-top: 15px; // gap 대신 margin으로 간격 처리 // margin-top: 15px; // gap 대신 margin으로 간격 처리
@@ -951,10 +951,10 @@
width: 320px; width: 320px;
height: 60px; // 부모 높이(60px) 모두 사용 height: 60px; // 부모 높이(60px) 모두 사용
display: flex; display: flex;
align-items: center; // 수직 중앙 정렬 align-items: center; // 수직 중앙 정렬
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.optionalTermsButton { .optionalTermsButton {
width: 100% !important; width: 100% !important;
height: 100% !important; height: 100% !important;
@@ -963,25 +963,25 @@
padding: 0 20px !important; padding: 0 20px !important;
margin: 0 !important; margin: 0 !important;
background: white !important; background: white !important;
border: 1px solid #CFCFCF !important; border: 1px solid #cfcfcf !important;
border-radius: 4px !important; border-radius: 4px !important;
display: flex !important; display: flex !important;
align-items: center !important; align-items: center !important;
justify-content: space-between !important; // 👈 flex-start → space-between 변경 justify-content: space-between !important; // 👈 flex-start → space-between 변경
flex-shrink: 0; flex-shrink: 0;
box-sizing: border-box !important; box-sizing: border-box !important;
// 포커스 스타일 // 포커스 스타일
&:focus { &:focus {
outline: 2px solid #C70850 !important; outline: 2px solid #c70850;
outline-offset: 1px !important; outline-offset: -1px;
} }
.optionalTermsTitle { .optionalTermsTitle {
height: 100%; height: 100%;
color: #1A1A1A; color: #1a1a1a;
font-size: 22px; font-size: 22px;
font-family: 'LG Smart UI'; font-family: "LG Smart UI";
font-weight: 600; font-weight: 600;
line-height: 22px; line-height: 22px;
white-space: nowrap; white-space: nowrap;
@@ -989,35 +989,35 @@
text-overflow: ellipsis; text-overflow: ellipsis;
flex: 1; flex: 1;
} }
// 👈 '>' 아이콘 스타일 추가 // 👈 '>' 아이콘 스타일 추가
.optionalTermsIcon { .optionalTermsIcon {
width: 24px; width: 24px;
height: 24px; height: 24px;
border-radius: 50%; border-radius: 50%;
border: 2px solid #1A1A1A; border: 2px solid #1a1a1a;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-shrink: 0; flex-shrink: 0;
margin-left: 8px; margin-left: 8px;
&::after { &::after {
content: '>'; content: ">";
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
color: #1A1A1A; color: #1a1a1a;
} }
} }
} }
} }
.optionalConfirmRightButtonSection { .optionalConfirmRightButtonSection {
// width: 332px; // width: 332px;
height: 100%; // 부모 높이(60px) 모두 사용 height: 100%; // 부모 높이(60px) 모두 사용
display: flex; display: flex;
align-items: center; // 수직 중앙 정렬 align-items: center; // 수직 중앙 정렬
justify-content: space-between; justify-content: space-between;
// gap: 12px; // gap: 12px;
.optionalConfirmButton { .optionalConfirmButton {
@@ -1037,37 +1037,37 @@
.figmaTermsInfo { .figmaTermsInfo {
.size(@w: 1064px, @h: 750px); .size(@w: 1064px, @h: 750px);
padding: 60px 57px 40px; padding: 60px 57px 40px;
background: #E6EBF0; background: #e6ebf0;
box-shadow: 0px 20px 12px rgba(0, 0, 0, 0.30); box-shadow: 0px 20px 12px rgba(0, 0, 0, 0.3);
border-radius: 4px; border-radius: 4px;
} }
.figmaTermsContentContainer { .figmaTermsContentContainer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
// gap: 40px; // gap: 40px;
} }
.figmaTermsCard { .figmaTermsCard {
background: white; background: white;
border-radius: 4px; border-radius: 4px;
border: 1px solid #CCCCCC; border: 1px solid #cccccc;
overflow: hidden; overflow: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.figmaTermsTitleBar { .figmaTermsTitleBar {
padding: 17px 31px; padding: 17px 31px;
border-bottom: 1px solid #CCCCCC; border-bottom: 1px solid #cccccc;
} }
.figmaTermsTitleText { .figmaTermsTitleText {
color: #C70850; color: #c70850;
font-size: 30px; font-size: 30px;
font-weight: 700; font-weight: 700;
} }
.figmaTermsContentBody { .figmaTermsContentBody {
flex-grow: 1; flex-grow: 1;
display: flex; display: flex;
@@ -1081,7 +1081,7 @@
line-height: 1.5; line-height: 1.5;
} }
} }
.figmaTermsButtonContainer { .figmaTermsButtonContainer {
display: flex; display: flex;
justify-content: center; justify-content: center;
@@ -1089,13 +1089,13 @@
margin-top: 40px; margin-top: 40px;
// gap: 15px; // 버튼 사이 간격 // gap: 15px; // 버튼 사이 간격
} }
.figmaTermsAgreeButton { .figmaTermsAgreeButton {
// 이제 TButton의 type="popup" 스타일을 사용하므로, // 이제 TButton의 type="popup" 스타일을 사용하므로,
// 여기서는 추가적인 스타일이 필요 없습니다. // 여기서는 추가적인 스타일이 필요 없습니다.
margin-right: 15px; margin-right: 15px;
} }
.figmaTermsCloseButton { .figmaTermsCloseButton {
// TButton의 type="popup" 스타일을 사용합니다. // TButton의 type="popup" 스타일을 사용합니다.
margin-left: 0px; // lint 오류 대비용용 margin-left: 0px; // lint 오류 대비용용
@@ -1104,7 +1104,7 @@
} }
// optionalConfirm일 때만 기존 위치 스타일 무력화 // optionalConfirm일 때만 기존 위치 스타일 무력화
// :global([id="floatLayer"]) :global(> div:not([id])) :global(> div) :global(> div:nth-child(2)) { // :global([id="floatLayer"]) :global(> div:not([id])) :global(> div) :global(> div:nth-child(2)) {
// .tNewPopUp.optionalConfirm & { // .tNewPopUp.optionalConfirm & {
// bottom: unset !important; // bottom: unset !important;

View File

@@ -236,56 +236,108 @@ export const setSubtitleEnableOver5 = (
} }
}; };
// system Alert // system Alert with time validation
export const addReservation = (data, { onSuccess, onFailure, onComplete }) => { export const addReservation = (data, { onSuccess, onFailure, onComplete }) => {
if (typeof window === "object" && !window.PalmSystem) { if (typeof window === "object" && !window.PalmSystem) {
console.log("LUNA SEND addReservation data", data); console.log("LUNA SEND addReservation data", data);
return; return;
} }
return new LS2Request().send({ const createReservation = () => {
service: "luna://com.webos.service.tvReservationAgent", return new LS2Request().send({
method: "add", service: "luna://com.webos.service.tvReservationAgent",
parameters: { method: "add",
scheduleType: "LGShopping", parameters: {
startTime: { scheduleType: "LGShopping",
year: data.startTime.year, startTime: {
month: data.startTime.month, year: data.startTime.year,
day: data.startTime.day, month: data.startTime.month,
hour: data.startTime.hour, day: data.startTime.day,
minute: data.startTime.minute, hour: data.startTime.hour,
second: data.startTime.second, minute: data.startTime.minute,
}, second: data.startTime.second,
callback: { },
method: "luna://com.webos.notification/createAlert", callback: {
params: { method: "luna://com.webos.notification/createAlert",
message: data.params.message, params: {
buttons: [ message: data.params.message,
{ buttons: [
label: data.params.buttons[0].label, {
onclick: "luna://com.webos.applicationManager/launch", label: data.params.buttons[0].label,
params: { onclick: "luna://com.webos.applicationManager/launch",
id: window.PalmSystem.identifier ?? appinfo.id, params: {
params: data.params.launch, id: window.PalmSystem.identifier ?? appinfo.id,
params: data.params.launch,
},
}, },
}, {
{ label: data.params.buttons[1].label,
label: data.params.buttons[1].label, },
}, ],
], autoTimeout: 30,
},
autoTimeout: 30, },
information: {
showId: data.params.showId,
chanId: data.params.chanId,
}, },
}, },
information: { onSuccess,
showId: data.params.showId, onFailure: (err) => {
chanId: data.params.chanId, 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);
}, },
}, onComplete,
onSuccess, });
onFailure, };
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 = ( 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,
});
};

View File

@@ -11,7 +11,7 @@ const initialState = {
serverHOST: "", //"US.nextlgsdp.com", serverHOST: "", //"US.nextlgsdp.com",
mbr_no: "", //X-User-Number : "US2401051532595" mbr_no: "", //X-User-Number : "US2401051532595"
deviceId: "", //d87cedca-84e7-c05e-613d-39739bb7941f deviceId: "", //d87cedca-84e7-c05e-613d-39739bb7941f
cursorVisible: false, cursorVisible: false,
loginUserData: {}, loginUserData: {},
toast: false, toast: false,
toastText: null, toastText: null,
@@ -20,7 +20,8 @@ const initialState = {
}, },
broadcast: {}, broadcast: {},
httpHeader: null, httpHeader: null,
isGnbOpened: false, popup: { isGnbOpened: false,
popup: {
popupVisible: false, popupVisible: false,
activePopup: null, activePopup: null,
secondaryPopup: null, secondaryPopup: null,
@@ -32,7 +33,7 @@ const initialState = {
optionalTermsConfirmSelected: false, optionalTermsConfirmSelected: false,
}, },
termsFlag: null, termsFlag: null,
termsLoading: false, // 25.06.16 추가 termsLoading: false, // 25.06.16 추가
introTermsAgree: undefined, // Y, N introTermsAgree: undefined, // Y, N
checkoutTermsAgree: undefined, checkoutTermsAgree: undefined,
useLog: true, useLog: true,
@@ -85,9 +86,9 @@ const initialState = {
// 선택약관 팝업 상태 관리 (TV 환경 최적화) // 선택약관 팝업 상태 관리 (TV 환경 최적화)
optionalTermsPopupFlow: { optionalTermsPopupFlow: {
popupShown: false, // 팝업 표시 여부 popupShown: false, // 팝업 표시 여부
userDecision: null, // 'agreed' | 'declined' | null userDecision: null, // 'agreed' | 'declined' | null
agreedInSession: false, // 세션 내 동의 여부 (로컬 상태 기반) agreedInSession: false, // 세션 내 동의 여부 (로컬 상태 기반)
}, },
}; };
@@ -184,7 +185,8 @@ export const commonReducer = (state = initialState, action) => {
secondaryPopupVisible: false, secondaryPopupVisible: false,
secondaryPopup: null, secondaryPopup: null,
}, },
}; case types.SET_HIDE_SECONDARY_POPUP: };
case types.SET_HIDE_SECONDARY_POPUP:
return { return {
...state, ...state,
popup: { popup: {
@@ -233,8 +235,13 @@ export const commonReducer = (state = initialState, action) => {
} }
case types.GET_TERMS_AGREE_YN_SUCCESS: { case types.GET_TERMS_AGREE_YN_SUCCESS: {
const { privacyTerms, serviceTerms, purchaseTerms, paymentTerms, optionalTerms } = const {
action.payload; privacyTerms,
serviceTerms,
purchaseTerms,
paymentTerms,
optionalTerms,
} = action.payload;
const introTermsAgree = privacyTerms === "Y" && serviceTerms === "Y"; const introTermsAgree = privacyTerms === "Y" && serviceTerms === "Y";
const checkoutTermsAgree = purchaseTerms === "Y" && paymentTerms === "Y"; const checkoutTermsAgree = purchaseTerms === "Y" && paymentTerms === "Y";
@@ -262,9 +269,11 @@ export const commonReducer = (state = initialState, action) => {
case types.GET_HOME_TERMS: { case types.GET_HOME_TERMS: {
const newTermsStatus = { ...state.termsAgreementStatus }; const newTermsStatus = { ...state.termsAgreementStatus };
if (action.payload?.data?.terms) { if (action.payload?.data?.terms) {
action.payload.data.terms.forEach(term => { action.payload.data.terms.forEach((term) => {
if (Object.prototype.hasOwnProperty.call(newTermsStatus, term.trmsTpCd)) { if (
newTermsStatus[term.trmsTpCd] = term.trmsAgrFlag === 'Y'; 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 }; const newTermsStatus = { ...state.termsAgreementStatus };
// action payload에 담겨온 동의한 약관 코드 리스트를 기반으로 상태 업데이트 // action payload에 담겨온 동의한 약관 코드 리스트를 기반으로 상태 업데이트
if (action.payload?.agreedTermCodes) { if (action.payload?.agreedTermCodes) {
action.payload.agreedTermCodes.forEach(termCode => { action.payload.agreedTermCodes.forEach((termCode) => {
if (Object.prototype.hasOwnProperty.call(newTermsStatus, termCode)) { if (Object.prototype.hasOwnProperty.call(newTermsStatus, termCode)) {
newTermsStatus[termCode] = true; newTermsStatus[termCode] = true;
} }
@@ -288,7 +297,7 @@ export const commonReducer = (state = initialState, action) => {
return { return {
...state, ...state,
termsLoading: false, termsLoading: false,
termsAgreementStatus: newTermsStatus termsAgreementStatus: newTermsStatus,
}; };
} }
case types.SET_MYPAGE_TERMS_AGREE_FAIL: case types.SET_MYPAGE_TERMS_AGREE_FAIL:
@@ -310,7 +319,7 @@ export const commonReducer = (state = initialState, action) => {
...state.termsAgreementStatus, ...state.termsAgreementStatus,
MST00401: true, MST00401: true,
MST00402: true, MST00402: true,
} },
}; };
} else { } else {
return state; return state;
@@ -398,7 +407,7 @@ export const commonReducer = (state = initialState, action) => {
optionalTermsPopupFlow: { optionalTermsPopupFlow: {
...state.optionalTermsPopupFlow, ...state.optionalTermsPopupFlow,
userDecision: action.payload, userDecision: action.payload,
agreedInSession: action.payload === 'agreed', agreedInSession: action.payload === "agreed",
}, },
}; };
} }

View File

@@ -79,7 +79,7 @@ export const ACTIVE_POPUP = {
exitPopup: 'exitPopup', exitPopup: 'exitPopup',
favoritePopup: 'favoritePopup', favoritePopup: 'favoritePopup',
loginPopup: 'loginPopup', loginPopup: 'loginPopup',
logoutPopup: 'logoutPopup', logoutPopup: 'logoutPopup',
noShowPopup: 'noShowPopup', noShowPopup: 'noShowPopup',
optionPopup: 'optionPopup', optionPopup: 'optionPopup',
qrPopup: 'qrPopup', qrPopup: 'qrPopup',
@@ -113,7 +113,7 @@ export const ACTIVE_POPUP = {
toast: 'toast', toast: 'toast',
optionalConfirm: 'optionalConfirm', optionalConfirm: 'optionalConfirm',
energyPopup: 'energyPopup', energyPopup: 'energyPopup',
addCartPopup: 'addCartPopup', addCartPopup: 'addCartPopup',
}; };
export const DEBUG_VIDEO_SUBTITLE_TEST = false; export const DEBUG_VIDEO_SUBTITLE_TEST = false;
export const AUTO_SCROLL_DELAY = 600; export const AUTO_SCROLL_DELAY = 600;
@@ -587,6 +587,7 @@ export const ERROR_MESSAGES_GROUPS = [
]; ];
export const LOG_CONTEXT_NAME = { export const LOG_CONTEXT_NAME = {
// <<<<<<< HEAD
SHOPTIME: 'shoptime', SHOPTIME: 'shoptime',
HOME: 'shoptime.home', HOME: 'shoptime.home',
CHECKOUT: 'shoptime.checkout', CHECKOUT: 'shoptime.checkout',
@@ -608,6 +609,29 @@ export const LOG_CONTEXT_NAME = {
ENTRY: 'shoptime.entry', ENTRY: 'shoptime.entry',
MYORDER: 'shoptime.myorder', MYORDER: 'shoptime.myorder',
DETAILPAGE: 'shoptime.detailpage', 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 = { export const LOG_MESSAGE_ID = {

View File

@@ -530,3 +530,45 @@ export const getErrorMessage = (errorCode, retMsg, retDetailCode, returnBindStri
return errorPrefix + 'An unknown error occurred. Please try again later.'; 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.");
};

View File

@@ -351,8 +351,8 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => {
...params, ...params,
category: categoryShowInfos?.catNm, category: categoryShowInfos?.catNm,
partner: findPartnerName(patnrId), partner: findPartnerName(patnrId),
contentId: showId, showId: showId,
contentTitle: showNm, showTitle: showNm,
}); });
} }
@@ -365,8 +365,8 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => {
...params, ...params,
category: categoryShowInfos?.catNm, category: categoryShowInfos?.catNm,
partner: findPartnerName(topShowInfo?.patnrId), partner: findPartnerName(topShowInfo?.patnrId),
productId: prdtId, showId: prdtId,
productTitle: prdtNm, showTitle: prdtNm,
price: discountRate ? discountPrice : regularPrice, price: discountRate ? discountPrice : regularPrice,
discount: discountRate, discount: discountRate,
}); });
@@ -379,8 +379,8 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => {
...params, ...params,
category: categoryShowInfos?.catNm, category: categoryShowInfos?.catNm,
partner: findPartnerName(patnrId), partner: findPartnerName(patnrId),
contentId: showId, showId: showId,
contentTitle: showNm, showTitle: showNm,
}); });
} }

View File

@@ -12,6 +12,7 @@ import { getMainCategoryDetail, getMainYouMayLike } from '../../actions/mainActi
import { finishModalMediaForce } from '../../actions/mediaActions'; import { finishModalMediaForce } from '../../actions/mediaActions';
import { popPanel, updatePanel } from '../../actions/panelActions'; import { popPanel, updatePanel } from '../../actions/panelActions';
import { import {
// <<<<<<< HEAD
finishVideoPreview, finishVideoPreview,
pauseFullscreenVideo, pauseFullscreenVideo,
resumeFullscreenVideo, resumeFullscreenVideo,
@@ -30,6 +31,45 @@ import THeaderCustom from './components/THeaderCustom';
import css from './DetailPanel.module.less'; import css from './DetailPanel.module.less';
import ProductAllSection from './ProductAllSection/ProductAllSection'; import ProductAllSection from './ProductAllSection/ProductAllSection';
import ThemeItemListOverlay from './ThemeItemListOverlay/ThemeItemListOverlay'; 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 }) { export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
const dispatch = useDispatch(); const dispatch = useDispatch();
@@ -128,6 +168,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
const [productType, setProductType] = useState(null); const [productType, setProductType] = useState(null);
const [openThemeItemOverlay, setOpenThemeItemOverlay] = useState(false); const [openThemeItemOverlay, setOpenThemeItemOverlay] = useState(false);
// <<<<<<< HEAD
const [scrollToSection, setScrollToSection] = useState(null); const [scrollToSection, setScrollToSection] = useState(null);
const [pendingScrollSection, setPendingScrollSection] = useState(null); const [pendingScrollSection, setPendingScrollSection] = useState(null);
const updateSelectedIndex = useCallback((newIndex) => { 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) => { const updateThemeItemOverlay = useCallback((isOpen) => {
setOpenThemeItemOverlay(fp.pipe(() => isOpen, Boolean)()); setOpenThemeItemOverlay(fp.pipe(() => isOpen, Boolean)());
}, []); }, []);
// <<<<<<< HEAD
const onSpotlightUpTButton = useCallback((e) => { 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(); e.stopPropagation();
Spotlight.focus('spotlightId_backBtn'); Spotlight.focus('spotlightId_backBtn');
}, []); }, []);
@@ -1041,6 +1149,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
productInfo={productDataSource} productInfo={productDataSource}
isOpen={openThemeItemOverlay} isOpen={openThemeItemOverlay}
panelInfo={panelInfo} panelInfo={panelInfo}
// <<<<<<< HEAD
productType={productType} productType={productType}
setSelectedIndex={updateSelectedIndex} setSelectedIndex={updateSelectedIndex}
openThemeItemOverlay={openThemeItemOverlay} openThemeItemOverlay={openThemeItemOverlay}
@@ -1048,5 +1157,55 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
/> />
</TPanel> </TPanel>
</div> </div>
// =======
// setSelectedIndex={setSelectedIndex}
// p
// roductInfo={productData || themeProductInfos[selectedIndex]}
// setIsYouMayLikeOpened={setIsYouMayLikeOpened}
// />
// )}
// {activePopup === Config.ACTIVE_POPUP.smsPopup && (
// <MobileSendPopUp
// open={popupVisible}
// onClose={handleSMSonClose}
// title={$L("Send a purchase link for this item via SMS")}
// subTitle={mobileSendPopUpSubtitle}
// patncNm={
// panelInfo?.type === "theme" &&
// themeProductInfos &&
// themeProductInfos[selectedIndex]
// ? themeProductInfos[selectedIndex].patncNm
// : productData?.patncNm
// }
// productImg={mobileSendPopUpProductImg}
// patnrId={panelInfo?.patnrId}
// prdtId={
// panelInfo?.type === "theme" &&
// themeProductInfos &&
// themeProductInfos[selectedIndex]
// ? themeProductInfos[selectedIndex].prdtId
// : panelInfo?.prdtId
// }
// smsTpCd={panelInfo?.type === "hotel" ? "APP00205" : "APP00201"}
// curationId={panelInfo?.curationId}
// curationNm={panelInfo?.curationNm}
// hotelId={
// panelInfo?.type === "hotel" && hotelInfos[selectedIndex]?.hotelId
// }
// hotelNm={
// panelInfo?.type === "hotel" && hotelInfos[selectedIndex]?.hotelNm
// }
// hotelDtlUrl={
// panelInfo?.type === "hotel" &&
// hotelInfos[selectedIndex]?.hotelDetailInfo?.hotelDtlUrl
// }
// productPrice={panelInfo?.type === "hotel" && Price()}
// shopByMobileLogRef={shopByMobileLogRef}
// spotlightId="shopbymobile_Btn"
// smsText={productInfo?.pmtSuptYn === "Y" ? detailUrl : undefined}
// />
// )}
// </>
// >>>>>>> gitlab/develop
); );
} }

View File

@@ -1492,7 +1492,7 @@ export default function ProductAllSection({
<img src={arrowDownIcon} className={css.themeButtonIcon} /> <img src={arrowDownIcon} className={css.themeButtonIcon} />
</TButton> </TButton>
</Container> </Container>
)} )}
<DetailMobileSendPopUp <DetailMobileSendPopUp
ismobileSendPopupOpen={mobileSendPopupOpen} ismobileSendPopupOpen={mobileSendPopupOpen}

View File

@@ -453,7 +453,8 @@ export default function SingleOption({
} }
if (userNumber && selectedPatnrId && selectedPrdtId && quantity) { if (userNumber && selectedPatnrId && selectedPrdtId && quantity) {
const { prodOptCval, priceInfo } = selectedOptions || {}; const { prodOptCval, priceInfo } = selectedOptions || {};
const { patncNm, brndNm, catNm, prdtNm, prdtId } = productInfo; const { patncNm, brndNm, catNm, prdtNm, prdtId, showId, showNm } =
productInfo;
const regularPrice = priceInfo?.split("|")[0]; const regularPrice = priceInfo?.split("|")[0];
const discountPrice = priceInfo?.split("|")[1]; const discountPrice = priceInfo?.split("|")[1];
const discountRate = priceInfo?.split("|")[4]; const discountRate = priceInfo?.split("|")[4];
@@ -470,6 +471,8 @@ export default function SingleOption({
category: catNm, category: catNm,
contextName: Config.LOG_CONTEXT_NAME.DETAILPAGE, contextName: Config.LOG_CONTEXT_NAME.DETAILPAGE,
messageId: Config.LOG_MESSAGE_ID.BUY_NOW, messageId: Config.LOG_MESSAGE_ID.BUY_NOW,
showId: showId ?? "",
showNm: showNm ?? "",
}) })
); );
dispatch( dispatch(

View File

@@ -96,13 +96,13 @@ export default function ShowOption({
inDt: formatGMTString(new Date()), inDt: formatGMTString(new Date()),
linkTpCd: panelInfo?.linkTpCd ?? "", linkTpCd: panelInfo?.linkTpCd ?? "",
logTpNo: LOG_TP_NO.DETAIL.THEME_DETAIL, logTpNo: LOG_TP_NO.DETAIL.THEME_DETAIL,
patncNm: themeInfo?.patncNm ?? "", patncNm: themeInfo?.productInfos[selectedIndex]?.patncNm ?? "",
patnrId: themeInfo?.patnrId ?? "", patnrId: themeInfo?.productInfos[selectedIndex]?.patnrId ?? "",
}; };
detailLogParamsRef.current = params; detailLogParamsRef.current = params;
return () => dispatch(sendLogDetail(params)); dispatch(sendLogDetail(params));
} }
}, [productData]); }, [productData]);
@@ -172,22 +172,24 @@ export default function ShowOption({
}, [productData]); }, [productData]);
const handleMobileSendPopupOpen = useCallback(() => { const handleMobileSendPopupOpen = useCallback(() => {
if (productData && Object.keys(productData).length > 0) { if (showProductInfo && Object.keys(showProductInfo).length > 0) {
const regularPrice = productData?.priceInfo?.split("|")[0]; const regularPrice = showProductInfo?.priceInfo?.split("|")[0];
const discountPrice = productData?.priceInfo?.split("|")[1]; const discountPrice = showProductInfo?.priceInfo?.split("|")[1];
const discountRate = productData?.priceInfo?.split("|")[4]; const discountRate = showProductInfo?.priceInfo?.split("|")[4];
const logParams = { const logParams = {
status: "open", status: "open",
nowMenu: nowMenu, nowMenu: nowMenu,
partner: productData?.patncNm, partner: showProductInfo?.patncNm,
productId: productData?.prdtId, productId: showProductInfo?.prdtId,
productTitle: productData?.prdtNm, productTitle: showProductInfo?.prdtNm,
price: discountRate ? discountPrice : regularPrice, price: discountRate ? discountPrice : regularPrice,
brand: productData?.brndNm, brand: showProductInfo?.brndNm,
discount: discountRate, discount: discountRate,
category: productData?.catNm, category: showProductInfo?.catNm,
contextName: LOG_CONTEXT_NAME.SHOPBYMOBILE, contextName: LOG_CONTEXT_NAME.SHOPBYMOBILE,
messageId: LOG_MESSAGE_ID.SMB, messageId: LOG_MESSAGE_ID.SMB,
showId: showProductInfo?.showId ?? "",
showNm: showProductInfo?.showNm ?? "",
}; };
dispatch(sendLogTotalRecommend(logParams)); dispatch(sendLogTotalRecommend(logParams));
dispatch( dispatch(
@@ -276,7 +278,7 @@ export default function ShowOption({
isBillingProductVisible={isBillingProductVisible} isBillingProductVisible={isBillingProductVisible}
isCall isCall
isFullOption={showProductInfo?.pmtSuptYn === "Y"} isFullOption={showProductInfo?.pmtSuptYn === "Y"}
isDescription={!showProductInfo?.pmtSuptYn === "Y"} isDescription={showProductInfo?.pmtSuptYn !== "Y"}
thumbnailUrl={showProductInfo?.imgUrls600[0]} thumbnailUrl={showProductInfo?.imgUrls600[0]}
productInfo={showProductInfo} productInfo={showProductInfo}
/> />

View File

@@ -215,6 +215,21 @@ export default function UnableOption({
</div> </div>
); );
} else if (TYPE_CASE.case2) { } else if (TYPE_CASE.case2) {
if (
selectedPrdtId === "27LX6TYGA" &&
offerInfo &&
offerInfo?.length > 0
) {
return (
<div className={css.wrapper}>
<span
dangerouslySetInnerHTML={{
__html: offerInfo && offerInfo,
}}
/>
</div>
);
}
return ( return (
<div className={css.wrapper}> <div className={css.wrapper}>
<div className={css.topLayer}> <div className={css.topLayer}>

View File

@@ -67,6 +67,7 @@ import Showroom from "./Showroom/Showroom";
import TodaysDeals from "./TodaysDeals/TodaysDeals"; import TodaysDeals from "./TodaysDeals/TodaysDeals";
import UpComing from "./UpComing/UpComing"; import UpComing from "./UpComing/UpComing";
import { setContainerLastFocusedElement } from "@enact/spotlight/src/container"; import { setContainerLastFocusedElement } from "@enact/spotlight/src/container";
import { sortedIndexOf } from "lodash";
const STRING_CONF = { const STRING_CONF = {
CANCEL: "CANCEL", CANCEL: "CANCEL",
@@ -318,29 +319,34 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
return; return;
} }
const foundElement = sortedBrandLayoutInfo.find(
(el) => el.shptmBrndOptTpCd === containerId
);
const actualShelfOrder = foundElement ? foundElement.expsOrd : null;
const selectedBrand = `${LOG_MENU.FEATURED_BRANDS}/${selectedPatncNm}`; const selectedBrand = `${LOG_MENU.FEATURED_BRANDS}/${selectedPatncNm}`;
const currentShelf = `${getMenuByContainerId(containerId)}`; const currentShelf = `${getMenuByContainerId(containerId)}`;
const menu = const menu =
selectedBrand && currentShelf && `${selectedBrand} ${currentShelf}`; selectedBrand && currentShelf && `${selectedBrand} ${currentShelf}`;
dispatch(sendLogGNB(menu));
dispatch( dispatch(
sendLogTotalRecommend({ sendLogTotalRecommend({
contextName: LOG_CONTEXT_NAME.FEATURED_BRANDS, contextName: LOG_CONTEXT_NAME.FEATURED_BRANDS,
messageId: LOG_MESSAGE_ID.SHELF, messageId: LOG_MESSAGE_ID.SHELF,
partner: selectedPatncNm, partner: selectedPatncNm,
shelfLocation: shelfOrder, shelfLocation: actualShelfOrder,
shelfId: containerId, shelfId: containerId,
shelfTitle: currentShelf, shelfTitle: currentShelf,
}) })
); );
dispatch(sendLogGNB(menu));
setIsLogGNBSent(true); setIsLogGNBSent(true);
prevSelectedPatncNmRef.current = selectedPatncNm; prevSelectedPatncNmRef.current = selectedPatncNm;
lastMenuRef.current = getMenuByContainerId(containerId); lastMenuRef.current = getMenuByContainerId(containerId);
}, },
[selectedPatncNm, sortedBrandLayoutInfo, selectedPatncNm] [selectedPatncNm, sortedBrandLayoutInfo]
); );
const focusOnMount = useCallback((targetId) => { const focusOnMount = useCallback((targetId) => {

View File

@@ -46,6 +46,8 @@ const FeaturedCategoryContents = ({
spotlightId={spotlightId} spotlightId={spotlightId}
shelfOrder={shelfOrder} shelfOrder={shelfOrder}
shelfTitle={shelfTitle} shelfTitle={shelfTitle}
selectedPatncNm={selectedPatncNm}
catNm={catNm}
/> />
) : ( ) : (
<FeaturedCategoryProductGrid <FeaturedCategoryProductGrid

View File

@@ -57,6 +57,8 @@ export default function FeaturedCategoryProductList({
spotlightId, spotlightId,
shelfTitle, shelfTitle,
shelfOrder, shelfOrder,
selectedPatncNm,
catNm,
}) { }) {
const { getScrollTo, scrollLeft } = useScrollTo(); const { getScrollTo, scrollLeft } = useScrollTo();
@@ -105,7 +107,6 @@ export default function FeaturedCategoryProductList({
const handleClick = useCallback( const handleClick = useCallback(
(prdtId) => (e) => { (prdtId) => (e) => {
const tItemCard = e.currentTarget; const tItemCard = e.currentTarget;
const lastFocusedTarget = Spotlight.getCurrent(); const lastFocusedTarget = Spotlight.getCurrent();
const lastFocusedTargetId = const lastFocusedTargetId =
lastFocusedTarget?.getAttribute("data-spotlight-id"); lastFocusedTarget?.getAttribute("data-spotlight-id");
@@ -185,7 +186,8 @@ export default function FeaturedCategoryProductList({
contextName={LOG_CONTEXT_NAME.FEATURED_BRANDS} contextName={LOG_CONTEXT_NAME.FEATURED_BRANDS}
messageId={LOG_MESSAGE_ID.SHELF_CLICK} messageId={LOG_MESSAGE_ID.SHELF_CLICK}
order={expsOrd} order={expsOrd}
category={selectedCatCdLv1} category={catNm}
patnerName={selectedPatncNm}
shelfLocation={shelfOrder} shelfLocation={shelfOrder}
shelfTitle={shelfTitle} shelfTitle={shelfTitle}
shelfId={spotlightId} shelfId={spotlightId}

View File

@@ -81,8 +81,8 @@ export default function EventPopUpBanner() {
pushPanel({ pushPanel({
name: panel_names.HOT_PICKS_PANEL, name: panel_names.HOT_PICKS_PANEL,
panelInfo: { panelInfo: {
curationId: eventPopData?.curationId, curationId: eventPopData?.shptmLnkInfo?.lnkCurationId,
patnrId: eventPopData?.patnrId, patnrId: eventPopData?.shptmLnkInfo?.lnkPatnrId,
}, },
}) })
); );
@@ -208,10 +208,14 @@ export default function EventPopUpBanner() {
case 'EVT00203': case 'EVT00203':
dispatch(pushPanel({ name: panel_names.TRENDING_NOW_PANEL })); dispatch(pushPanel({ name: panel_names.TRENDING_NOW_PANEL }));
break; break;
// <<<<<<< HEAD
case 'EVT00204': case 'EVT00204':
if (playerPanelInfo?.modal) { if (playerPanelInfo?.modal) {
dispatch(finishVideoPreview()); dispatch(finishVideoPreview());
} }
// =======
// case "EVT00204":
// >>>>>>> gitlab/develop
dispatch( dispatch(
pushPanel({ pushPanel({
name: panel_names.HOT_PICKS_PANEL, name: panel_names.HOT_PICKS_PANEL,
@@ -328,7 +332,7 @@ export default function EventPopUpBanner() {
<TPopUp <TPopUp
kind="textPopup" kind="textPopup"
open={popupVisible} open={popupVisible}
hasText hasText
text={$L('Downloading coupon complete.')} text={$L('Downloading coupon complete.')}
/> />
)} )}

View File

@@ -575,8 +575,8 @@ export default function RandomUnit({
// 비디오 클릭 // 비디오 클릭
const videoClick = useCallback(() => { const videoClick = useCallback(() => {
const lastFocusedTargetId = getContainerId(Spotlight.getCurrent());
const currentSpot = Spotlight.getCurrent(); const currentSpot = Spotlight.getCurrent();
// <<<<<<< HEAD
if (lastFocusedTargetId) { if (lastFocusedTargetId) {
dispatch( dispatch(
updateHomeInfo({ 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) // ✅ modal=true → modal=false로 전환 (또는 초기 로드 시 modal=false)
// playActions의 shouldSkipVideoPlayback이 modal 상태를 확인하므로 // playActions의 shouldSkipVideoPlayback이 modal 상태를 확인하므로
@@ -631,9 +645,13 @@ export default function RandomUnit({
randomDataRef, randomDataRef,
sendBannerLog, sendBannerLog,
onBlur, onBlur,
// <<<<<<< HEAD
playerPanelInfo?.modal, playerPanelInfo?.modal,
dispatch, dispatch,
handleStartVideo, handleStartVideo,
// =======
// dispatch,
// >>>>>>> gitlab/develop
]); ]);
// 투데이즈 딜 가격 정보 // 투데이즈 딜 가격 정보

View File

@@ -23,6 +23,7 @@ import {
getHomeLayout, getHomeLayout,
getHomeMainContents, getHomeMainContents,
updateHomeInfo, updateHomeInfo,
// <<<<<<< HEAD
} from '../../actions/homeActions'; } from '../../actions/homeActions';
import { sendLogGNB, sendLogTotalRecommend } from '../../actions/logActions'; import { sendLogGNB, sendLogTotalRecommend } from '../../actions/logActions';
import { getSubCategory, getTop20Show } from '../../actions/mainActions'; import { getSubCategory, getTop20Show } from '../../actions/mainActions';
@@ -67,6 +68,20 @@ const BACKGROUND_IMAGES = {
}; };
// [COMMENTED OUT] useVideoMove 관련 코드 주석 처리 - 향후 사용 검토 필요 // [COMMENTED OUT] useVideoMove 관련 코드 주석 처리 - 향후 사용 검토 필요
// import { useVideoMove } from '../../hooks/useVideoTransition/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 { import {
ACTIVE_POPUP, ACTIVE_POPUP,
LOG_CONTEXT_NAME, LOG_CONTEXT_NAME,
@@ -186,6 +201,9 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
const isInitialRender = useRef(true); const isInitialRender = useRef(true);
const verticalPagenatorRef = useRef(null); const verticalPagenatorRef = useRef(null);
const currentSentMenuRef = useRef(null); const currentSentMenuRef = useRef(null);
const lastRestoredIdRef = useRef(null);
const focusedContainerIdRef = useRef(null);
const prevIsOnTopRef = useRef(isOnTop);
// ✅ [251119] DetailPanelBackground 이미지 프리로딩 // ✅ [251119] DetailPanelBackground 이미지 프리로딩
// HomePanel 마운트 시 백그라운드로 모든 파트너사 배경 이미지를 미리 로드하여 // HomePanel 마운트 시 백그라운드로 모든 파트너사 배경 이미지를 미리 로드하여
@@ -250,8 +268,6 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
const expandIntervalRef = useRef(null); // 최상단에서의 interval const expandIntervalRef = useRef(null); // 최상단에서의 interval
const expandAttemptRef = useRef(0); // 복구 시도 횟수 const expandAttemptRef = useRef(0); // 복구 시도 횟수
const focusedContainerIdRef = usePrevious(focusedContainerId);
const loadingComplete = useSelector((state) => state.common?.loadingComplete); const loadingComplete = useSelector((state) => state.common?.loadingComplete);
const isVideoTransitionLocked = useSelector((state) => state.home.videoTransitionLocked); const isVideoTransitionLocked = useSelector((state) => state.home.videoTransitionLocked);
@@ -757,6 +773,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
// 비디오가 재생이 아니면 videoPlayIntentRef의 bannerId로 비디오 재생 // 비디오가 재생이 아니면 videoPlayIntentRef의 bannerId로 비디오 재생
// [251116] isHomeOnTop인 경우에는 비디오가 항상 재생되어야 함 // [251116] isHomeOnTop인 경우에는 비디오가 항상 재생되어야 함
useEffect(() => { useEffect(() => {
// <<<<<<< HEAD
// console.log('[HomeActive] useEffect 실행 - isOnTop:', isOnTop); // console.log('[HomeActive] useEffect 실행 - isOnTop:', isOnTop);
// console.log('[HomeActive] videoPlayIntentRef.current:', videoPlayIntentRef.current); // console.log('[HomeActive] videoPlayIntentRef.current:', videoPlayIntentRef.current);
// console.log( // console.log(
@@ -973,6 +990,23 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
} }
} }
}, [detailPanelClosed, isOnTop, bannerDataList, dispatch]); }, [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(() => { useEffect(() => {
return () => { return () => {
@@ -997,13 +1031,17 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
currentSpot: currentSpot, currentSpot: currentSpot,
currentCatCd: targetSpotlightCatcd, currentCatCd: targetSpotlightCatcd,
currentCateName: targetSpotlightCateNm, currentCateName: targetSpotlightCateNm,
// <<<<<<< HEAD
focusedContainerId: focusedContainerIdRef.current, focusedContainerId: focusedContainerIdRef.current,
lastFocusedTargetId: lastFocusedTargetRef.current || panelInfo.lastFocusedTargetId, lastFocusedTargetId: lastFocusedTargetRef.current || panelInfo.lastFocusedTargetId,
// =======
// focusedContainerId: focusedContainerId,
// >>>>>>> gitlab/develop
}, },
}) })
); );
}; };
}, [dispatch]); }, [dispatch, focusedContainerId]);
const handleArrowClick = useCallback(() => { const handleArrowClick = useCallback(() => {
if (verticalPagenatorRef.current) { if (verticalPagenatorRef.current) {

View File

@@ -73,7 +73,7 @@ const PopularShow = ({
const topInfos = useSelector((state) => state.main.top20ShowData.topInfos); const topInfos = useSelector((state) => state.main.top20ShowData.topInfos);
const recommendInfo = useSelector((state) => state.foryou?.recommendInfo?.recommendShow); const recommendInfo = useSelector((state) => state.foryou?.recommendInfo?.recommendShow);
const orderStyle = useMemo(() => ({ order: order }), [order]); const orderStyle = useMemo(() => ({ order: order }), [order]);
@@ -84,10 +84,10 @@ const PopularShow = ({
const [showNewInfos, setShowNewInfos] = useState([]); const [showNewInfos, setShowNewInfos] = useState([]);
useEffect(() => { useEffect(() => {
setDrawChk(true); setDrawChk(true);
}, [topInfos]); }, [topInfos]);
useEffect(()=>{ useEffect(()=>{
setShowInfos( setShowInfos(
recommendInfo?.filter( recommendInfo?.filter(
(item) => item.recommendTpCd === "POPULARSHOW" (item) => item.recommendTpCd === "POPULARSHOW"
@@ -96,7 +96,7 @@ const PopularShow = ({
},[recommendInfo]) },[recommendInfo])
useEffect(() => { useEffect(() => {
if (!showInfos || showInfos.length === 0) { if (!showInfos || showInfos.length === 0) {
const baseData = topInfos?.map((item) => ({ const baseData = topInfos?.map((item) => ({
...item, ...item,
foryou: false, foryou: false,
@@ -109,19 +109,19 @@ const PopularShow = ({
...item, ...item,
foryou: true, foryou: true,
})) || []; })) || [];
const recommendedPrdtIds = new Set(recommendedData?.map(item => item.showId)); const recommendedPrdtIds = new Set(recommendedData?.map(item => item.showId));
const baseData = topInfos?.map((item) => ({ const baseData = topInfos?.map((item) => ({
...item, ...item,
foryou: recommendedPrdtIds.has(item.showId), foryou: recommendedPrdtIds.has(item.showId),
})) || []; })) || [];
setShowNewInfos([ ...baseData]); setShowNewInfos([ ...baseData]);
}, [topInfos, showInfos]); }, [topInfos, showInfos]);
const handleCardClick = useCallback( const handleCardClick = useCallback(
(patnrId, showId, catCd, showUrl) => () => { (patnrId, showId, catCd, showUrl) => () => {
@@ -234,7 +234,7 @@ const PopularShow = ({
if (handleShelfFocus) { if (handleShelfFocus) {
handleShelfFocus(); handleShelfFocus();
} }
}, [handleShelfFocus]); }, [handleShelfFocus]);
return ( return (
<Container <Container
@@ -271,7 +271,11 @@ const PopularShow = ({
patncNm, patncNm,
catCd, catCd,
showUrl, showUrl,
// <<<<<<< HEAD
foryou, foryou,
// =======
productInfos,
// >>>>>>> gitlab/develop
}, },
itemIndex itemIndex
) => { ) => {
@@ -286,8 +290,8 @@ const PopularShow = ({
shelfLocation={shelfLocation} shelfLocation={shelfLocation}
shelfTitle={shelfTitle} shelfTitle={shelfTitle}
patnerName={patncNm} patnerName={patncNm}
contentId={showId} showId={showId}
contentTitle={showNm} showTitle={showNm}
imageSource={ imageSource={
(thumbnailUrl && thumbnailUrl960) ? (thumbnailUrl && thumbnailUrl960) ?
thumbnailUrl !== thumbnailUrl960 thumbnailUrl !== thumbnailUrl960
@@ -296,7 +300,7 @@ const PopularShow = ({
: thumbnailUrl : thumbnailUrl
} }
imageAlt={showNm} imageAlt={showNm}
productName={showNm} productName={productInfos[0].prdtNm}
nonPosition={true} nonPosition={true}
type={TYPES.videoShow} type={TYPES.videoShow}
imgType={ imgType={
@@ -305,7 +309,7 @@ const PopularShow = ({
: IMAGETYPES.imgVertical : IMAGETYPES.imgVertical
} }
logo={patncLogoPath} logo={patncLogoPath}
productId={showId} productId={productInfos[0].prdtId}
onFocus={handleFocus(itemIndex)} onFocus={handleFocus(itemIndex)}
onBlur={handleBlur(itemIndex)} onBlur={handleBlur(itemIndex)}
onClick={handleCardClick(patnrId, showId, catCd, showUrl)} onClick={handleCardClick(patnrId, showId, catCd, showUrl)}

View File

@@ -1,13 +1,10 @@
import React, { import React, { memo, useCallback } from "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"); const SpottableComponent = Spottable("div");

View File

@@ -826,7 +826,7 @@ function IntroPanelWithOptional({
return shouldShowBenefitsView ? ( return shouldShowBenefitsView ? (
<div className={css.optionalDescription}> <div className={css.optionalDescription}>
{$L( {$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',
)} )}
</div> </div>
) : ( ) : (

View File

@@ -195,16 +195,12 @@
// &:focus-visible, // &:focus-visible,
&:hover { &:hover {
outline: 4px #c91d53 solid !important; outline: 4px #c91d53 solid !important;
outline-offset: 2px !important;
transform: translateY(-2px) !important; transform: translateY(-2px) !important;
box-shadow: 0 4px 12px rgba(201, 29, 83, 0.3) !important;
.termsText { .termsText {
font-weight: bold !important; font-weight: bold !important;
} }
} }
} }
} }
} }
.termsRightPanel { .termsRightPanel {
@@ -347,14 +343,12 @@
&.selected:before { &.selected:before {
background-color: #c91d53 !important; background-color: #c91d53 !important;
border: 4px solid #c91d53 !important; // 굵은 테두리로 변경 border: 4px solid #c91d53 !important; // 굵은 테두리로 변경
box-shadow: 0 0 8px rgba(201, 29, 83, 0.3); // 약간의 그림자 효과
} }
// 포커스 받았지만 선택 안됨 // 포커스 받았지만 선택 안됨
&.focused:not(.selected):before { &.focused:not(.selected):before {
background-color: rgba(201, 29, 83, 0.1); background-color: rgba(201, 29, 83, 0.1);
border: 4px solid #c91d53 !important; 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 { &.focused:not(.selected):before {
border: 4px solid #c91d53 !important; border: 4px solid #c91d53 !important;
box-shadow: 0 0 10px rgba(199, 8, 80, 0.3) !important;
} }
// 체크마크 // 체크마크

View File

@@ -214,12 +214,15 @@ export default function Favorites({ title, panelInfo, isOnTop }) {
}, [favoritesDatas, activeDelete]); }, [favoritesDatas, activeDelete]);
const handleItemClick = useCallback( const handleItemClick = useCallback(
(patnrId, prdtId, prdtNm, patncNm) => (ev) => { (patnrId, prdtId, prdtNm, patncNm, showId, showNm, brndNm) => (ev) => {
const params = { const params = {
menu: "Favorite", menu: "Favorite",
productId: prdtId, productId: prdtId,
productTitle: prdtNm, productTitle: prdtNm,
partner: patncNm, partner: patncNm,
showId: showId,
showTitle: showNm,
brand: brndNm,
contextName: LOG_CONTEXT_NAME.MYPAGE, contextName: LOG_CONTEXT_NAME.MYPAGE,
messageId: LOG_MESSAGE_ID.MYPAGE_CLICK, messageId: LOG_MESSAGE_ID.MYPAGE_CLICK,
}; };

View File

@@ -303,11 +303,6 @@ export default function MyInfo({ title, cbScrollTo }) {
return ( return (
<> <>
<THeader title={title} aria-label={title + " Heading 1"}>
{serverHOST && (
<span className={css.serverHostBadge}>[serverHost] {serverHOST}</span>
)}
</THeader>
<TBody className={css.tBody} cbScrollTo={cbScrollTo}> <TBody className={css.tBody} cbScrollTo={cbScrollTo}>
<Container className={css.myInfoContainer}> <Container className={css.myInfoContainer}>
<div className={css.contentsBox}> <div className={css.contentsBox}>

View File

@@ -64,38 +64,42 @@ export default function RecentlyViewedContents({
}, [mainContainerId, recentDataInfoItem, scrollLeft]); }, [mainContainerId, recentDataInfoItem, scrollLeft]);
const handleItemClick = useCallback( const handleItemClick = useCallback(
(showId, showNm, patnrId, lgCatCd, prdtId, prdtNm, patncNm) => () => { (showId, showNm, patnrId, lgCatCd, prdtId, prdtNm, patncNm, brndNm) =>
const params = { () => {
menu: "Recently Viewed", const params = {
partner: patncNm, menu: "Recently Viewed",
contentId: showId, partner: patncNm,
contentTitle: showNm, contentId: showId,
productId: prdtId, contentTitle: showNm,
productTitle: prdtNm, productId: prdtId,
contextName: LOG_CONTEXT_NAME.MYPAGE, productTitle: prdtNm,
messageId: LOG_MESSAGE_ID.MYPAGE_CLICK, showId: showId,
}; showTitle: showNm,
dispatch(sendLogTotalRecommend(params)); brand: brndNm,
contextName: LOG_CONTEXT_NAME.MYPAGE,
messageId: LOG_MESSAGE_ID.MYPAGE_CLICK,
};
dispatch(sendLogTotalRecommend(params));
if (showId) { if (showId) {
dispatch( dispatch(
startVideoPlayer({ startVideoPlayer({
showId, showId,
patnrId, patnrId,
shptmBanrTpNm: "VOD", shptmBanrTpNm: "VOD",
lgCatCd, lgCatCd,
modal: false, modal: false,
}) })
); );
} else { } else {
dispatch( dispatch(
pushPanel({ pushPanel({
name: panel_names.DETAIL_PANEL, name: panel_names.DETAIL_PANEL,
panelInfo: { patnrId, prdtId }, panelInfo: { patnrId, prdtId },
}) })
); );
} }
}, },
[recentDataInfoItem] [recentDataInfoItem]
); );
const _handleItemToggle = useCallback( const _handleItemToggle = useCallback(

View File

@@ -39,7 +39,6 @@ export default memo(function OnSaleContents({
shelfId: selectedLgCatCd, shelfId: selectedLgCatCd,
shelfTitle: saleNm, shelfTitle: saleNm,
}; };
console.log("###shelfListShown", params);
dispatch(sendLogTotalRecommend(params)); dispatch(sendLogTotalRecommend(params));
} }
}, [ }, [

View File

@@ -76,9 +76,9 @@ export default function OnSaleNav({
const containerId = "on-sale-nav"; const containerId = "on-sale-nav";
setContainerLastFocusedElement(node, [containerId]); setContainerLastFocusedElement(node, [containerId]);
} }
setTimeout(() => { // setTimeout(() => {
Spotlight.focus(node); // Spotlight.focus(node);
}, 100); // }, 100);
} }
}, [panelInfoLgCatCd]); }, [panelInfoLgCatCd]);

View File

@@ -1,7 +1,7 @@
import React, { memo, useCallback, useEffect } from "react"; import React, { memo, useCallback, useEffect } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { useDispatch } from "react-redux"; import { connect, useDispatch } from "react-redux";
import Spottable from "@enact/spotlight/Spottable"; import Spottable from "@enact/spotlight/Spottable";
import { setContainerLastFocusedElement } from "@enact/spotlight/src/container"; import { setContainerLastFocusedElement } from "@enact/spotlight/src/container";
@@ -32,8 +32,8 @@ export default memo(function OnSaleNavItem({
const selected = selectedLgCatCd const selected = selectedLgCatCd
? selectedLgCatCd === lgCatCd && css.selected ? selectedLgCatCd === lgCatCd && css.selected
: panelInfoLgCatCd : panelInfoLgCatCd
? panelInfoLgCatCd === lgCatCd && css.selected ? panelInfoLgCatCd === lgCatCd && css.selected
: itemIndex === 0; : itemIndex === 0;
const selectedText = selected === true ? "Selected, " : ""; const selectedText = selected === true ? "Selected, " : "";
@@ -77,8 +77,8 @@ export default memo(function OnSaleNavItem({
selectedLgCatCd selectedLgCatCd
? selectedLgCatCd === lgCatCd && css.selected ? selectedLgCatCd === lgCatCd && css.selected
: panelInfoLgCatCd : panelInfoLgCatCd
? panelInfoLgCatCd === lgCatCd && css.selected ? panelInfoLgCatCd === lgCatCd && css.selected
: itemIndex === 0 && css.selected : itemIndex === 0 && css.selected
)} )}
onClick={handleClick} onClick={handleClick}
id={"spotlightId-" + lgCatCd} id={"spotlightId-" + lgCatCd}

View File

@@ -57,8 +57,8 @@ export default function OnSalePanel({ panelInfo, spotlightId }) {
const enteredThroughEventPopup = Object.keys(panelInfo).length === 1; const enteredThroughEventPopup = Object.keys(panelInfo).length === 1;
const enteredThroughGNB = Object.keys(panelInfo).length === 0; const enteredThroughGNB = Object.keys(panelInfo).length === 0;
const previousPanelIsHome = Object.keys(panelInfo).length === 3; const previousPanelIsHome = panelInfo?.nowShelf !== undefined;
const previousPanelIsDetail = Object.keys(panelInfo).length > 4; const previousPanelIsDetail = panelInfo?.noResetFlag === true;
const cbChangePageRef = useRef(null); const cbChangePageRef = useRef(null);
const focusedContainerIdRef = useRef(0); const focusedContainerIdRef = useRef(0);
@@ -132,7 +132,6 @@ export default function OnSalePanel({ panelInfo, spotlightId }) {
useEffect(() => { useEffect(() => {
if (categories && saleInfos && Object.keys(saleInfos).length > 0) { if (categories && saleInfos && Object.keys(saleInfos).length > 0) {
const prdtId = saleInfos[0]?.saleProductInfos[0]?.prdtId; const prdtId = saleInfos[0]?.saleProductInfos[0]?.prdtId;
if (prdtId) { if (prdtId) {
setFirstFocusableTarget("spotlightId-" + removeDotAndColon(prdtId)); setFirstFocusableTarget("spotlightId-" + removeDotAndColon(prdtId));
setIsReadyForInitialFocusTarget(true); setIsReadyForInitialFocusTarget(true);
@@ -149,9 +148,8 @@ export default function OnSalePanel({ panelInfo, spotlightId }) {
} }
if (previousPanelIsHome) { if (previousPanelIsHome) {
targetId = panelInfo?.linkTpCd // 홈에서 온세일 아이템을 선택한 경우 해당 카테고리의 nav 아이템에 포커스
? "spotlightId-" + panelInfo?.lgCatCd targetId = "spotlightId-" + panelInfo?.lgCatCd;
: "spotlightId-" + panelInfo?.prdtId;
} }
if (enteredThroughEventPopup) { if (enteredThroughEventPopup) {
@@ -180,8 +178,6 @@ export default function OnSalePanel({ panelInfo, spotlightId }) {
isInitialFocusOccurred, isInitialFocusOccurred,
isReadyForInitialFocusTarget, isReadyForInitialFocusTarget,
panelInfo?.lgCatCd, panelInfo?.lgCatCd,
panelInfo?.linkTpCd,
panelInfo?.prdtId,
panelInfo?.targetId, panelInfo?.targetId,
previousPanelIsDetail, previousPanelIsDetail,
previousPanelIsHome, previousPanelIsHome,
@@ -300,7 +296,6 @@ export default function OnSalePanel({ panelInfo, spotlightId }) {
cbChangePageRef.current(0); cbChangePageRef.current(0);
} }
}, []); }, []);
const handleShelfFocus = useCallback( const handleShelfFocus = useCallback(
(shelfOrder) => { (shelfOrder) => {
// 현재 포커스된 shelf와 다른 shelf에 포커스될 때만 true 반환 // 현재 포커스된 shelf와 다른 shelf에 포커스될 때만 true 반환

View File

@@ -69,8 +69,15 @@ function PlayerOverlayContents({
}, [dispatch, captionEnable, setIsSubtitleActive]); }, [dispatch, captionEnable, setIsSubtitleActive]);
const patncLogoPath = useMemo(() => { const patncLogoPath = useMemo(() => {
// <<<<<<< HEAD
let logo = playListInfo[selectedIndex]?.patncLogoPath; let logo = playListInfo[selectedIndex]?.patncLogoPath;
if (type === 'MEDIA') { if (type === 'MEDIA') {
// =======
// let logo = playListInfo[selectedIndex]?.patncLogoPath
// ? playListInfo[selectedIndex]?.patncLogoPath
// : playListInfo[selectedIndex]?.logoImgPath;
// if (type === "MEDIA") {
// >>>>>>> gitlab/develop
logo = panelInfo?.patncLogoPath; logo = panelInfo?.patncLogoPath;
} }

View File

@@ -1,16 +1,18 @@
import React, { useMemo } from 'react'; import React, { useEffect, useMemo, useRef, useState } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import TQRCode from '../../../components/TQRCode/TQRCode'; import TQRCode from '../../../components/TQRCode/TQRCode';
import css from './PlayerOverlayQRCode.module.less'; 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 }) { function PlayerOverlayQRCode({ qrCurrentItem, type, modalScale }) {
const { cntry_cd } = useSelector((state) => state.common.httpHeader); const { cntry_cd } = useSelector((state) => state.common.httpHeader);
const deviceInfo = useSelector((state) => state.device.deviceInfo); 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 serverHOST = useSelector((state) => state.common.appStatus.serverHOST);
const serverType = useSelector((state) => state.localSettings.serverType); const serverType = useSelector((state) => state.localSettings.serverType);
const { entryMenu, nowMenu } = useSelector((state) => state.common.menu); const { entryMenu, nowMenu } = useSelector((state) => state.common.menu);
@@ -102,6 +104,28 @@ function PlayerOverlayQRCode({ qrCurrentItem, type, modalScale }) {
return qrCurrentItem?.qrcodeUrl; return qrCurrentItem?.qrcodeUrl;
}, [detailUrl, qrCurrentItem, type]); }, [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 ( return (
<> <>
{innerStylePosition && QRCodeUrl && ( {innerStylePosition && QRCodeUrl && (
@@ -115,6 +139,7 @@ function PlayerOverlayQRCode({ qrCurrentItem, type, modalScale }) {
)} )}
style={innerStylePosition} style={innerStylePosition}
> >
{/* <<<<<<< HEAD */}
<div> <div>
<TQRCode <TQRCode
text={QRCodeUrl} text={QRCodeUrl}
@@ -124,6 +149,27 @@ function PlayerOverlayQRCode({ qrCurrentItem, type, modalScale }) {
/> />
<div className={css.text}>{label}</div> <div className={css.text}>{label}</div>
</div> </div>
{/* =======
{isShowQRCode ? (
<div>
<TQRCode
text={QRCodeUrl}
width={width}
height={height}
ariaLabel='QR CODE, "SCAN TO SHOP" go to Shoptime App'
/>
<div className={css.text}>{label}</div>
</div>
) : (
<div className={css.qrRollingWrap}>
<div className={css.innerText}>
<h3>{$L("Scan QR")}</h3>
<p>{$L("with your phone, Check Product")}</p>
<p>{$L("info & Purchase easily")}</p>
</div>
</div>
)}
>>>>>>> gitlab/develop */}
</div> </div>
)} )}
</> </>

View File

@@ -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;
}
}
}
} }

View File

@@ -28,9 +28,16 @@ import {
getMainCategoryShowDetail, getMainCategoryShowDetail,
getMainLiveShow, getMainLiveShow,
getMainLiveShowNowProduct, getMainLiveShowNowProduct,
// <<<<<<< HEAD
} from '../../actions/mainActions'; } from '../../actions/mainActions';
import * as PanelActions from '../../actions/panelActions'; import * as PanelActions from '../../actions/panelActions';
import { updatePanel } 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 { import {
CLEAR_PLAYER_INFO, CLEAR_PLAYER_INFO,
getChatLog, getChatLog,

View File

@@ -33,16 +33,20 @@ export default function TabContainer({
prevChannelIndex, prevChannelIndex,
currentTime, currentTime,
spotlightId, spotlightId,
isFilteredByPatnr19,
}) { }) {
const [tab, setTab] = useState(0); const [tab, setTab] = useState(0);
const tabList = [ const tabList = [
$L("SHOP NOW"), $L("SHOP NOW"),
panelInfo?.shptmBanrTpNm === "LIVE" panelInfo?.shptmBanrTpNm === "LIVE"
? $L("LIVE CHANNEL") ? isFilteredByPatnr19
? $L("VOD CHANNEL")
: $L("LIVE CHANNEL")
: $L("FEATURED SHOWS"), : $L("FEATURED SHOWS"),
]; ];
// console.log("###liveChannelInfos", liveChannelInfos[selectedIndex]);
const handleItemClick = useCallback( const handleItemClick = useCallback(
({ index }) => { ({ index }) => {
if (index === tab) return; if (index === tab) return;
@@ -101,7 +105,6 @@ export default function TabContainer({
}, },
[videoVerticalVisible] [videoVerticalVisible]
); );
return ( return (
<Container <Container
className={classNames( className={classNames(
@@ -121,7 +124,7 @@ export default function TabContainer({
{tab === 0 && ( {tab === 0 && (
<ShopNowContents <ShopNowContents
tabTitle = {tabList} tabTitle={tabList}
shopNowInfo={shopNowInfo} shopNowInfo={shopNowInfo}
playListInfo={playListInfo && playListInfo[selectedIndex]} playListInfo={playListInfo && playListInfo[selectedIndex]}
videoVerticalVisible={videoVerticalVisible} videoVerticalVisible={videoVerticalVisible}
@@ -130,9 +133,25 @@ export default function TabContainer({
handleItemFocus={_handleItemFocus} handleItemFocus={_handleItemFocus}
/> />
)} )}
{panelInfo?.shptmBanrTpNm === "VOD" &&
panelInfo?.patnrId === "19" &&
tab === 1 && (
<FeaturedShowContents
tabTitle={tabList}
featuredShowsInfos={playListInfo}
currentVideoInfo={playListInfo[selectedIndex]}
setSelectedIndex={setSelectedIndex}
selectedIndex={selectedIndex}
videoVerticalVisible={videoVerticalVisible}
currentVideoShowId={playListInfo[selectedIndex]?.showId}
tabIndex={tab}
panelInfo={panelInfo}
handleItemFocus={_handleItemFocus}
/>
)}
{panelInfo?.shptmBanrTpNm === "VOD" && tab === 1 && ( {panelInfo?.shptmBanrTpNm === "VOD" && tab === 1 && (
<FeaturedShowContents <FeaturedShowContents
tabTitle = {tabList} tabTitle={tabList}
featuredShowsInfos={playListInfo} featuredShowsInfos={playListInfo}
currentVideoInfo={playListInfo[selectedIndex]} currentVideoInfo={playListInfo[selectedIndex]}
setSelectedIndex={setSelectedIndex} setSelectedIndex={setSelectedIndex}
@@ -146,7 +165,7 @@ export default function TabContainer({
)} )}
{panelInfo?.shptmBanrTpNm === "LIVE" && tab === 1 && liveChannelInfos && ( {panelInfo?.shptmBanrTpNm === "LIVE" && tab === 1 && liveChannelInfos && (
<LiveChannelContents <LiveChannelContents
tabTitle = {tabList} tabTitle={tabList}
selectedIndex={selectedIndex} selectedIndex={selectedIndex}
setSelectedIndex={setSelectedIndex} setSelectedIndex={setSelectedIndex}
videoVerticalVisible={videoVerticalVisible} videoVerticalVisible={videoVerticalVisible}
@@ -156,6 +175,7 @@ export default function TabContainer({
handleItemFocus={_handleItemFocus} handleItemFocus={_handleItemFocus}
panelInfo={panelInfo} panelInfo={panelInfo}
currentTime={currentTime} currentTime={currentTime}
isFilteredByPatnr19={isFilteredByPatnr19}
/> />
)} )}

View File

@@ -4,6 +4,7 @@ import { useDispatch } from 'react-redux';
import Spotlight from '@enact/spotlight'; import Spotlight from '@enact/spotlight';
// <<<<<<< HEAD
import defaultImage from '../../../../../assets/images/img-thumb-empty-144@3x.png'; import defaultImage from '../../../../../assets/images/img-thumb-empty-144@3x.png';
import { updatePanel } from '../../../../actions/panelActions'; import { updatePanel } from '../../../../actions/panelActions';
import TVirtualGridList from '../../../../components/TVirtualGridList/TVirtualGridList'; import TVirtualGridList from '../../../../components/TVirtualGridList/TVirtualGridList';
@@ -14,6 +15,23 @@ import ListEmptyContents from '../TabContents/ListEmptyContents/ListEmptyContent
import css from './LiveChannelContents.module.less'; import css from './LiveChannelContents.module.less';
import { getMainCategoryShowDetail } from '../../../../actions/mainActions'; import { getMainCategoryShowDetail } from '../../../../actions/mainActions';
import { sendLogTotalRecommend } from '../../../../actions/logActions'; 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({ export default function FeaturedShowContents({
featuredShowsInfos, featuredShowsInfos,
@@ -44,6 +62,8 @@ export default function FeaturedShowContents({
({ index, ...rest }) => { ({ index, ...rest }) => {
const { const {
thumbnailUrl, thumbnailUrl,
logoImgPath,
thumbnailImgPath,
patncLogoPath, patncLogoPath,
patnrId, patnrId,
showId, showId,
@@ -106,8 +126,14 @@ export default function FeaturedShowContents({
{...rest} {...rest}
key={prdtId} key={prdtId}
imageAlt={prdtId} imageAlt={prdtId}
logo={patncLogoPath} logo={logoImgPath ? logoImgPath : patncLogoPath}
imageSource={thumbnailUrl ? thumbnailUrl : defaultImage} imageSource={
thumbnailUrl
? thumbnailUrl
: thumbnailImgPath
? thumbnailImgPath
: defaultImage
}
productName={showNameDangerouslySetInnerHTML} productName={showNameDangerouslySetInnerHTML}
patnerName={patncNm} patnerName={patncNm}
onClick={handleItemClick} onClick={handleItemClick}

View File

@@ -4,6 +4,7 @@ import { useDispatch } from 'react-redux';
import Spotlight from '@enact/spotlight'; import Spotlight from '@enact/spotlight';
// <<<<<<< HEAD
import { updatePanel } from '../../../../actions/panelActions'; import { updatePanel } from '../../../../actions/panelActions';
import TVirtualGridList from '../../../../components/TVirtualGridList/TVirtualGridList'; import TVirtualGridList from '../../../../components/TVirtualGridList/TVirtualGridList';
import { LOG_CONTEXT_NAME, LOG_MENU, LOG_MESSAGE_ID, panel_names } from '../../../../utils/Config'; 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 css from './LiveChannelContents.module.less';
import cssV2 from './LiveChannelContents.v2.module.less'; import cssV2 from './LiveChannelContents.v2.module.less';
import { sendLogTotalRecommend } from '../../../../actions/logActions'; 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({ export default function LiveChannelContents({
liveInfos, liveInfos,
@@ -24,13 +40,22 @@ export default function LiveChannelContents({
handleItemFocus, handleItemFocus,
tabTitle, tabTitle,
panelInfo, panelInfo,
// <<<<<<< HEAD
direction = 'vertical', direction = 'vertical',
version = 1, version = 1,
isFilteredByPatnr19,
}) { }) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const isClickBlocked = useRef(false); const isClickBlocked = useRef(false);
const blockTimeoutRef = useRef(null); const blockTimeoutRef = useRef(null);
// =======
// isFilteredByPatnr19,
// }) {
// const dispatch = useDispatch();
// const isClickBlocked = useRef(false);
const scrollToRef = useRef(null);
// >>>>>>> gitlab/develop
const handleFocus = useCallback( const handleFocus = useCallback(
() => () => { () => () => {
if (handleItemFocus) { if (handleItemFocus) {
@@ -40,6 +65,18 @@ export default function LiveChannelContents({
[handleItemFocus] [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( const renderItem = useCallback(
({ index, ...rest }) => { ({ index, ...rest }) => {
const { const {
@@ -144,7 +181,11 @@ export default function LiveChannelContents({
startDt={strtDt} startDt={strtDt}
endDt={endDt} endDt={endDt}
currentTime={currentTime} currentTime={currentTime}
// <<<<<<< HEAD
version={version} version={version}
// =======
// currentVideoVisible={currentVideoShowId === liveInfos[index].showId}
// >>>>>>> gitlab/develop
/> />
); );
}, },
@@ -167,6 +208,7 @@ export default function LiveChannelContents({
<div className={containerClass}> <div className={containerClass}>
{liveInfos && liveInfos.length > 0 ? ( {liveInfos && liveInfos.length > 0 ? (
<TVirtualGridList <TVirtualGridList
cbScrollTo={handleScrollTo}
dataSize={liveInfos.length} dataSize={liveInfos.length}
direction={direction} direction={direction}
renderItem={renderItem} renderItem={renderItem}

View File

@@ -27,7 +27,6 @@ export default function YouMayLikeContents({
const youmaylikeInfos = useSelector((state) => state.main.youmaylikeInfos); const youmaylikeInfos = useSelector((state) => state.main.youmaylikeInfos);
const gridStyle = useMemo(() => ({ height: `${height}px` }), [height]); const gridStyle = useMemo(() => ({ height: `${height}px` }), [height]);
useEffect(() => { useEffect(() => {
if (shopNowInfo && shopNowInfo.length === 2) { if (shopNowInfo && shopNowInfo.length === 2) {
setHeight(scaleH(300)); setHeight(scaleH(300));
@@ -82,7 +81,12 @@ export default function YouMayLikeContents({
showNm: playListInfo?.showNm, showNm: playListInfo?.showNm,
showId: playListInfo?.showId, showId: playListInfo?.showId,
liveFlag: playListInfo?.liveFlag, liveFlag: playListInfo?.liveFlag,
// <<<<<<< HEAD
thumbnailUrl: playListInfo?.thumbnailUrl, thumbnailUrl: playListInfo?.thumbnailUrl,
// =======
catDpTh3: playListInfo?.catDpTh3,
catDpTh4: playListInfo?.catDpTh4,
// >>>>>>> gitlab/develop
patnrId, patnrId,
prdtId, prdtId,
launchedFromPlayer: true, launchedFromPlayer: true,

View File

@@ -43,7 +43,8 @@ export default memo(function SearchShowCard({
const sendLog = (newParams) => { const sendLog = (newParams) => {
const logParams = { const logParams = {
...newParams, ...newParams,
contentTitle: title, showTitle: title,
showId: contentId.split("_").pop() || "",
partner: patncNm, partner: patncNm,
contextName: LOG_CONTEXT_NAME.SEARCH, contextName: LOG_CONTEXT_NAME.SEARCH,
messageId: LOG_MESSAGE_ID.SEARCH_RESULT_CLICK, messageId: LOG_MESSAGE_ID.SEARCH_RESULT_CLICK,

View File

@@ -128,8 +128,8 @@ const PopularVideoCard = ({
shelfLocation: 1, shelfLocation: 1,
shelfId: SpotlightIds.TRENDING_NOW_POPULAR_SHOW, shelfId: SpotlightIds.TRENDING_NOW_POPULAR_SHOW,
shelfTitle: currentShelf, shelfTitle: currentShelf,
contentId: showId, showId: showId,
contentTitle: showNm, showTitle: showNm,
partner: patncNm, partner: patncNm,
location: selectedIndex + 1, location: selectedIndex + 1,
}; };