diff --git a/com.twin.app.shoptime/[251013]_RollingUnit_리렌더링_분석_및_해결방법.md b/com.twin.app.shoptime/[251013]_RollingUnit_리렌더링_분석_및_해결방법.md
new file mode 100644
index 00000000..cba0d1bb
--- /dev/null
+++ b/com.twin.app.shoptime/[251013]_RollingUnit_리렌더링_분석_및_해결방법.md
@@ -0,0 +1,416 @@
+# [251013] RollingUnit 리렌더링 분석 및 해결방법
+
+## 📋 문제 요약
+- **증상**: HomeBanner의 RollingUnit 컴포넌트가 계속 리렌더링됨
+- **특이사항**:
+ - RandomUnit은 정상 작동
+ - JustForYou 배너 관련 위치에서 특히 심함
+ - RollingUnit의 자동 순환(10초 롤링)이 제대로 작동하지 않음
+- **원인**: OptionalTerms(선택약관) 관련 코드 추가 후 발생
+
+---
+
+## 🔍 근본 원인 분석
+
+### 1. 불안정한 Props Chain (HomePanel → HomeBanner → RollingUnit)
+
+**문제 흐름:**
+```
+HomePanel.jsx
+ ↓ nowShelf 상태 변경
+ ↓ doSendLogGNB 재생성 (의존성: nowShelf, panelInfo.nowShelf, pageSpotIds)
+ ↓ handleItemFocus 재생성 (의존성: doSendLogGNB)
+ ↓ handleItemFocus(el.shptmApphmDspyOptCd) 호출 → 매번 새 함수 생성
+HomeBanner.jsx
+ ↓ _handleItemFocus 재생성 (의존성: handleItemFocus)
+ ↓ renderItem 재생성 (의존성: _handleItemFocus, _handleShelfFocus, bannerDataList)
+RollingUnit.jsx
+ ↓ 새로운 props 수신
+ ↓ 리렌더링 발생!
+```
+
+**코드 위치:**
+- `HomePanel.jsx` 라인 220-270
+- `HomeBanner.jsx` 라인 81-85, 348-352, 497-542
+
+---
+
+### 2. OptionalTerms 상태와 조건부 렌더링 문제 ⚠️ **핵심 원인**
+
+**문제 코드:** `HomeBanner.jsx` 라인 628-680
+
+```javascript
+const renderLayout = useCallback(() => {
+ switch (selectTemplate) {
+ case 'DSP00201': {
+ return (
+ <>
+
+ {renderItem(0, true, true)}
+ {renderItem(1, true, true)}
+
+ {renderItem(2, false, false)}
+
+ {/* ⚠️ 문제 부분: introTermsAgree 상태에 의존 */}
+ {introTermsAgree === 'Y' ? (
+
+
+
+ ) : (
+ renderItem(3, false, false)
+ )}
+ >
+ );
+ }
+ }
+ return null;
+}, [selectTemplate, renderItem, renderSimpleVideoContainer]);
+// ❌ 문제: introTermsAgree가 의존성 배열에 없음!
+```
+
+**문제점:**
+1. `introTermsAgree`가 JSX 내부에서 참조되지만 의존성 배열에 없음
+2. `introTermsAgree` 변경 시 React가 최적화를 제대로 하지 못함
+3. 클로저 문제로 인해 예상치 못한 리렌더링 발생
+
+---
+
+### 3. JustForSwitchBanner의 구조적 문제
+
+**문제 코드:** `JustForYouBanner.jsx` 라인 154-230
+
+```javascript
+export default function JustForSwitchBanner({
+ renderItem, // ← HomeBanner에서 받은 renderItem
+ handleShelfFocus, // ← 계속 변하는 함수
+ handleItemFocus, // ← 계속 변하는 함수
+ isHorizontal,
+ spotlightId,
+}) {
+ const [currentIndex, setCurrentIndex] = useState(0);
+
+ const onFocus = useCallback(() => {
+ if (handleItemFocus) {
+ handleItemFocus(); // ⚠️ 매번 새로운 함수 참조!
+ }
+ }, [handleItemFocus]); // ← 의존성: 계속 변경됨
+
+ return (
+ <>
+
+
+ {currentIndex === 0 ? (
+
+ ) : (
+ renderItem(3, false) // ⚠️ RollingUnit 렌더링!
+ )}
+
+
+ >
+ );
+}
+```
+
+**문제의 연쇄 반응:**
+```
+handleItemFocus 변경
+→ JustForSwitchBanner의 onFocus 재생성
+→ JustForYouBanner 리렌더링
+→ currentIndex === 1일 때 renderItem(3) 호출
+→ RollingUnit 리렌더링!
+```
+
+---
+
+### 4. RollingUnit 자동 롤링이 작동하지 않는 이유
+
+**코드 위치:** `RollingUnit.jsx` 라인 463-487
+
+```javascript
+// 10초 롤링
+useEffect(() => {
+ lastIndexRef.current = rollingDataLength - 1;
+ previousTimeRef.current = undefined; // ⚠️ 타이머 리셋!
+
+ if (rollingDataLength <= 1 || unitHasFocus) {
+ doRollingRef.current = false;
+ window.cancelAnimationFrame(requestRef.current);
+ return;
+ }
+
+ doRollingRef.current = true;
+ requestRef.current = window.requestAnimationFrame(animate);
+
+ return () => {
+ doRollingRef.current = false;
+ window.cancelAnimationFrame(requestRef.current);
+ };
+}, [rollingDataLength, unitHasFocus]);
+```
+
+**문제:**
+- RollingUnit이 계속 리렌더링되면 이 `useEffect`가 계속 실행됨
+- `previousTimeRef.current = undefined`로 타이머가 계속 리셋됨
+- `requestAnimationFrame`이 취소되고 다시 시작됨
+- **결과: 10초 타이머가 초기화되어 자동 롤링이 작동하지 않음**
+
+---
+
+### 5. RandomUnit은 왜 괜찮은가?
+
+**RandomUnit의 경우:**
+```javascript
+// HomeBanner.jsx - renderLayout (DSP00201)
+
+ {renderItem(0, true, true)} // ← Rolling 또는 Random
+ {renderItem(1, true, true)} // ← 주로 Random (고정 위치)
+
+```
+
+**RandomUnit은:**
+- ✅ 고정된 위치(index 0, 1)에서 렌더링
+- ✅ 조건부 렌더링 없음
+- ✅ `introTermsAgree` 상태와 무관
+- ✅ JustForSwitchBanner를 통하지 않음
+- ✅ 안정적인 props만 받음
+
+---
+
+## 💡 해결방법
+
+### ✅ 해결방법 1: renderLayout 의존성 배열에 introTermsAgree 추가 (적용됨)
+
+**파일:** `HomeBanner.jsx` 라인 514
+
+**변경 전:**
+```javascript
+}, [selectTemplate, renderItem, renderSimpleVideoContainer]);
+```
+
+**변경 후:**
+```javascript
+}, [selectTemplate, renderItem, renderSimpleVideoContainer, introTermsAgree]);
+```
+
+**효과:**
+- `introTermsAgree` 변경 시 `renderLayout`이 명시적으로 재생성됨
+- React가 변경사항을 정확히 추적할 수 있음
+- 클로저 문제 해결
+
+---
+
+### 🔧 추가 권장 해결방법
+
+#### 해결방법 2: HomePanel의 handleItemFocus 최적화
+
+**파일:** `HomePanel.jsx` 라인 265-270
+
+**현재 문제:**
+```javascript
+const handleItemFocus = useCallback(
+ (containerId, location, title) => () => {
+ doSendLogGNB(containerId, location, title);
+ },
+ [doSendLogGNB]
+);
+
+// 렌더링 시 매번 새 함수 생성
+
+```
+
+**해결방법:**
+```javascript
+// 1. 함수를 직접 전달하지 말고 파라미터를 전달
+
+
+// 2. HomeBanner에서 필요할 때 호출
+const _handleItemFocus = useCallback(() => {
+ if (onItemFocus) {
+ onItemFocus(containerId, location, title);
+ }
+}, [onItemFocus, containerId, location, title]);
+```
+
+---
+
+#### 해결방법 3: JustForSwitchBanner 최적화
+
+**파일:** `JustForYouBanner.jsx` 라인 189-195
+
+**현재 문제:**
+```javascript
+const onFocus = useCallback(() => {
+ if (handleItemFocus) {
+ handleItemFocus();
+ }
+}, [handleItemFocus]); // ← 계속 변경됨
+```
+
+**해결방법 A: useRef 사용**
+```javascript
+const handleItemFocusRef = useRef(handleItemFocus);
+
+useEffect(() => {
+ handleItemFocusRef.current = handleItemFocus;
+}, [handleItemFocus]);
+
+const onFocus = useCallback(() => {
+ if (handleItemFocusRef.current) {
+ handleItemFocusRef.current();
+ }
+}, []); // ← 의존성 없음, 안정적
+```
+
+**해결방법 B: React.memo로 JustForYouBanner 감싸기**
+```javascript
+const JustForYouBanner = React.memo(function JustForYouBanner({
+ onClick,
+ spotlightId,
+ onFocus,
+ isHorizontal,
+ popupVisible,
+ activePopup,
+}) {
+ // ... 기존 코드
+}, (prevProps, nextProps) => {
+ // onFocus가 변경되어도 리렌더링하지 않음
+ return (
+ prevProps.spotlightId === nextProps.spotlightId &&
+ prevProps.isHorizontal === nextProps.isHorizontal &&
+ prevProps.popupVisible === nextProps.popupVisible &&
+ prevProps.activePopup === nextProps.activePopup
+ );
+});
+```
+
+---
+
+#### 해결방법 4: doSendLogGNB 의존성 최적화
+
+**파일:** `HomePanel.jsx` 라인 220-263
+
+**현재 문제:**
+```javascript
+const doSendLogGNB = useCallback(
+ (containerId, location = null, title = null) => {
+ // ... 로직
+ },
+ [pageSpotIds, nowShelf, panelInfo.nowShelf] // ← 자주 변경됨
+);
+```
+
+**해결방법: useRef 사용**
+```javascript
+const nowShelfRef = useRef(nowShelf);
+const panelInfoRef = useRef(panelInfo.nowShelf);
+
+useEffect(() => {
+ nowShelfRef.current = nowShelf;
+ panelInfoRef.current = panelInfo.nowShelf;
+}, [nowShelf, panelInfo.nowShelf]);
+
+const doSendLogGNB = useCallback(
+ (containerId, location = null, title = null) => {
+ // nowShelfRef.current 사용
+ if (containerId !== nowShelfRef.current && location && title) {
+ // ... 로직
+ }
+ },
+ [pageSpotIds] // ← 의존성 감소
+);
+```
+
+---
+
+#### 해결방법 5: RollingUnit을 React.memo로 감싸기
+
+**파일:** `RollingUnit.jsx` 마지막 줄
+
+**현재:**
+```javascript
+export default function RollingUnit({ ... }) {
+ // ... 코드
+}
+```
+
+**해결방법:**
+```javascript
+function RollingUnit({ ... }) {
+ // ... 기존 코드
+}
+
+export default React.memo(RollingUnit, (prevProps, nextProps) => {
+ // props가 실제로 변경되었을 때만 리렌더링
+ return (
+ prevProps.bannerData === nextProps.bannerData &&
+ prevProps.spotlightId === nextProps.spotlightId &&
+ prevProps.isHorizontal === nextProps.isHorizontal &&
+ prevProps.videoPlayerable === nextProps.videoPlayerable
+ // handleItemFocus, handleShelfFocus는 비교하지 않음
+ );
+});
+```
+
+---
+
+## 📊 우선순위별 적용 순서
+
+### 1단계 (필수) ✅ 완료
+- [x] `renderLayout` 의존성 배열에 `introTermsAgree` 추가
+
+### 2단계 (권장)
+- [ ] `doSendLogGNB` 의존성 최적화 (useRef 사용)
+- [ ] `handleItemFocus` 구조 개선 (파라미터 전달 방식)
+
+### 3단계 (선택)
+- [ ] `JustForSwitchBanner` 최적화 (useRef 또는 React.memo)
+- [ ] `RollingUnit`을 React.memo로 감싸기
+
+---
+
+## 🎯 예상 효과
+
+### 1단계 적용 후:
+- ✅ `introTermsAgree` 변경 시 명시적 리렌더링
+- ✅ 클로저 문제 해결
+- ⚠️ 여전히 props chain으로 인한 불필요한 리렌더링 가능
+
+### 2-3단계 적용 후:
+- ✅ 불필요한 리렌더링 대폭 감소
+- ✅ RollingUnit 자동 롤링 정상 작동
+- ✅ 성능 개선
+- ✅ 안정적인 컴포넌트 동작
+
+---
+
+## 📝 테스트 체크리스트
+
+- [ ] RollingUnit이 불필요하게 리렌더링되지 않는지 확인
+- [ ] RollingUnit의 10초 자동 롤링이 정상 작동하는지 확인
+- [ ] OptionalTerms 동의 전/후 배너 전환이 정상적인지 확인
+- [ ] JustForYou 배너와 RollingUnit 간 전환이 부드러운지 확인
+- [ ] RandomUnit이 여전히 정상 작동하는지 확인
+- [ ] 포커스 이동 시 로그가 정상적으로 전송되는지 확인
+
+---
+
+## 📅 작성 정보
+- **날짜**: 2025-10-13
+- **분석 대상**: RollingUnit 리렌더링 문제
+- **주요 원인**: OptionalTerms 상태 + JustForSwitchBanner 조건부 렌더링
+- **적용된 해결방법**: renderLayout 의존성 배열에 introTermsAgree 추가
diff --git a/com.twin.app.shoptime/src/actions/actionTypes.js b/com.twin.app.shoptime/src/actions/actionTypes.js
index 6be957df..b9c8d5e1 100644
--- a/com.twin.app.shoptime/src/actions/actionTypes.js
+++ b/com.twin.app.shoptime/src/actions/actionTypes.js
@@ -2,218 +2,219 @@
export const types = {
// panel actions
- PUSH_PANEL: "PUSH_PANEL",
- POP_PANEL: "POP_PANEL",
- UPDATE_PANEL: "UPDATE_PANEL",
- RESET_PANELS: "RESET_PANELS",
+ PUSH_PANEL: 'PUSH_PANEL',
+ POP_PANEL: 'POP_PANEL',
+ UPDATE_PANEL: 'UPDATE_PANEL',
+ RESET_PANELS: 'RESET_PANELS',
// device actions
- GET_AUTHENTICATION_CODE: "GET_AUTHENTICATION_CODE",
- REGISTER_DEVICE: "REGISTER_DEVICE",
- REGISTER_DEVICE_INFO: "REGISTER_DEVICE_INFO",
- GET_DEVICE_INFO: "GET_DEVICE_INFO",
- CLEAR_REGISTER_DEVICE_INFO: "CLEAR_REGISTER_DEVICE_INFO",
- REGISTER_DEVICE_RESET: "REGISTER_DEVICE_RESET",
+ GET_AUTHENTICATION_CODE: 'GET_AUTHENTICATION_CODE',
+ REGISTER_DEVICE: 'REGISTER_DEVICE',
+ REGISTER_DEVICE_INFO: 'REGISTER_DEVICE_INFO',
+ GET_DEVICE_INFO: 'GET_DEVICE_INFO',
+ CLEAR_REGISTER_DEVICE_INFO: 'CLEAR_REGISTER_DEVICE_INFO',
+ REGISTER_DEVICE_RESET: 'REGISTER_DEVICE_RESET',
// common actions
- GET_HTTP_HEADER: "GET_HTTP_HEADER",
- CHANGE_APP_STATUS: "CHANGE_APP_STATUS",
- SEND_BROADCAST: "SEND_BROADCAST",
- CHANGE_LOCAL_SETTINGS: "CHANGE_LOCAL_SETTINGS",
- GNB_OPENED: "GNB_OPENED",
- SET_SHOW_POPUP: "SET_SHOW_POPUP",
- SET_SHOW_SECONDARY_POPUP: "SET_SHOW_SECONDARY_POPUP",
- SET_HIDE_POPUP: "SET_HIDE_POPUP",
- SET_HIDE_SECONDARY_POPUP: "SET_HIDE_SECONDARY_POPUP",
- SHOW_OPTIONAL_TERMS_CONFIRM_POPUP: "SHOW_OPTIONAL_TERMS_CONFIRM_POPUP",
- HIDE_OPTIONAL_TERMS_CONFIRM_POPUP: "HIDE_OPTIONAL_TERMS_CONFIRM_POPUP",
- TOGGLE_OPTIONAL_TERMS_CONFIRM: "TOGGLE_OPTIONAL_TERMS_CONFIRM",
+ GET_HTTP_HEADER: 'GET_HTTP_HEADER',
+ CHANGE_APP_STATUS: 'CHANGE_APP_STATUS',
+ SEND_BROADCAST: 'SEND_BROADCAST',
+ CHANGE_LOCAL_SETTINGS: 'CHANGE_LOCAL_SETTINGS',
+ GNB_OPENED: 'GNB_OPENED',
+ SET_SHOW_POPUP: 'SET_SHOW_POPUP',
+ SET_SHOW_SECONDARY_POPUP: 'SET_SHOW_SECONDARY_POPUP',
+ SET_HIDE_POPUP: 'SET_HIDE_POPUP',
+ SET_HIDE_SECONDARY_POPUP: 'SET_HIDE_SECONDARY_POPUP',
+ SHOW_OPTIONAL_TERMS_CONFIRM_POPUP: 'SHOW_OPTIONAL_TERMS_CONFIRM_POPUP',
+ HIDE_OPTIONAL_TERMS_CONFIRM_POPUP: 'HIDE_OPTIONAL_TERMS_CONFIRM_POPUP',
+ TOGGLE_OPTIONAL_TERMS_CONFIRM: 'TOGGLE_OPTIONAL_TERMS_CONFIRM',
// 선택약관 팝업 상태 관리
- SET_OPTIONAL_TERMS_POPUP_SHOWN: "SET_OPTIONAL_TERMS_POPUP_SHOWN",
- SET_OPTIONAL_TERMS_USER_DECISION: "SET_OPTIONAL_TERMS_USER_DECISION",
- RESET_OPTIONAL_TERMS_SESSION: "RESET_OPTIONAL_TERMS_SESSION",
+ SET_OPTIONAL_TERMS_POPUP_SHOWN: 'SET_OPTIONAL_TERMS_POPUP_SHOWN',
+ SET_OPTIONAL_TERMS_USER_DECISION: 'SET_OPTIONAL_TERMS_USER_DECISION',
+ RESET_OPTIONAL_TERMS_SESSION: 'RESET_OPTIONAL_TERMS_SESSION',
// 선택약관 직접 상태 업데이트 (API 호출 없이)
- UPDATE_OPTIONAL_TERMS_AGREE_DIRECT: "UPDATE_OPTIONAL_TERMS_AGREE_DIRECT",
- UPDATE_TERMS_AGREEMENT_STATUS_DIRECT: "UPDATE_TERMS_AGREEMENT_STATUS_DIRECT",
- SET_EXIT_APP: "SET_EXIT_APP",
- GET_LOGIN_USER_DATA: "GET_LOGIN_USER_DATA",
- GET_TERMS_AGREE_YN: "GET_TERMS_AGREE_YN",
- LAUNCH_MEMBERSHIP_APP: "LAUNCH_MEMBERSHIP_APP",
- SET_FOCUS: "SET_FOCUS",
- SET_GNB_MENU: "SET_GNB_MENU",
- SET_SYSTEM_NOTICE: "SET_SYSTEM_NOTICE",
- SET_SYSTEM_TERMINATION: "SET_SYSTEM_TERMINATION",
- SET_DEEP_LINK: "SET_DEEP_LINK",
- SET_SECOND_LAYER_INFO: "SET_SECOND_LAYER_INFO",
- SET_ERROR_MESSAGE: "SET_ERROR_MESSAGE",
- CLEAR_ERROR_MESSAGE: "CLEAR_ERROR_MESSAGE",
- GET_DEVICE_MACADDRESS: "GET_DEVICE_MACADDRESS",
- SET_DEVICE_REGISTERED: "SET_DEVICE_REGISTERED",
+ UPDATE_OPTIONAL_TERMS_AGREE_DIRECT: 'UPDATE_OPTIONAL_TERMS_AGREE_DIRECT',
+ UPDATE_TERMS_AGREEMENT_STATUS_DIRECT: 'UPDATE_TERMS_AGREEMENT_STATUS_DIRECT',
+ SET_EXIT_APP: 'SET_EXIT_APP',
+ GET_LOGIN_USER_DATA: 'GET_LOGIN_USER_DATA',
+ GET_TERMS_AGREE_YN: 'GET_TERMS_AGREE_YN',
+ LAUNCH_MEMBERSHIP_APP: 'LAUNCH_MEMBERSHIP_APP',
+ SET_FOCUS: 'SET_FOCUS',
+ SET_GNB_MENU: 'SET_GNB_MENU',
+ SET_SYSTEM_NOTICE: 'SET_SYSTEM_NOTICE',
+ SET_SYSTEM_TERMINATION: 'SET_SYSTEM_TERMINATION',
+ SET_DEEP_LINK: 'SET_DEEP_LINK',
+ SET_SECOND_LAYER_INFO: 'SET_SECOND_LAYER_INFO',
+ SET_ERROR_MESSAGE: 'SET_ERROR_MESSAGE',
+ CLEAR_ERROR_MESSAGE: 'CLEAR_ERROR_MESSAGE',
+ GET_DEVICE_MACADDRESS: 'GET_DEVICE_MACADDRESS',
+ SET_DEVICE_REGISTERED: 'SET_DEVICE_REGISTERED',
// billing actions
- GET_MY_INFO_BILLING_SEARCH: "GET_MY_INFO_BILLING_SEARCH",
+ GET_MY_INFO_BILLING_SEARCH: 'GET_MY_INFO_BILLING_SEARCH',
// card actions
- GET_MY_INFO_CARD_SEARCH: "GET_MY_INFO_CARD_SEARCH",
+ GET_MY_INFO_CARD_SEARCH: 'GET_MY_INFO_CARD_SEARCH',
// shipping actions
- GET_MY_INFO_SHIPPING_SEARCH: "GET_MY_INFO_SHIPPING_SEARCH",
+ GET_MY_INFO_SHIPPING_SEARCH: 'GET_MY_INFO_SHIPPING_SEARCH',
// cart actions
- GET_MY_INFO_CART_SEARCH: "GET_MY_INFO_CART_SEARCH",
- ADD_TO_CART: "ADD_TO_CART",
- REMOVE_FROM_CART: "REMOVE_FROM_CART",
- UPDATE_CART_ITEM: "UPDATE_CART_ITEM",
- CLEAR_CART: "CLEAR_CART",
+ GET_MY_INFO_CART_SEARCH: 'GET_MY_INFO_CART_SEARCH',
+ ADD_TO_CART: 'ADD_TO_CART',
+ REMOVE_FROM_CART: 'REMOVE_FROM_CART',
+ UPDATE_CART_ITEM: 'UPDATE_CART_ITEM',
+ CLEAR_CART: 'CLEAR_CART',
// appData actions
- ADD_MAIN_INDEX: "ADD_MAIN_INDEX",
- SEND_SMS: "SEND_SMS",
- CLEAR_SMS: "CLEAR_SMS",
+ ADD_MAIN_INDEX: 'ADD_MAIN_INDEX',
+ SEND_SMS: 'SEND_SMS',
+ CLEAR_SMS: 'CLEAR_SMS',
// home actions
- GET_HOME_TERMS: "GET_HOME_TERMS",
- SET_TERMS_ID_MAP: "SET_TERMS_ID_MAP",
- SET_OPTIONAL_TERMS_AVAILABILITY: "SET_OPTIONAL_TERMS_AVAILABILITY",
- GET_HOME_MENU: "GET_HOME_MENU",
- GET_HOME_LAYOUT: "GET_HOME_LAYOUT",
- GET_HOME_MAIN_CONTENTS: "GET_HOME_MAIN_CONTENTS",
- GET_HOME_FULL_VIDEO_INFO: "GET_HOME_FULL_VIDEO_INFO",
- GET_THEME_CURATION_INFO: "GET_THEME_CURATION_INFO",
- GET_THEME_CURATION_DETAIL_INFO: "GET_THEME_CURATION_DETAIL_INFO",
- GET_THEME_HOTEL_DETAIL_INFO: "GET_THEME_HOTEL_DETAIL_INFO",
- GET_THEME_MENU_SHELF_INFO: "GET_THEME_MENU_SHELF_INFO",
- CLEAR_THEME_MENU_SHELF_INFO: "CLEAR_THEME_MENU_SHELF_INFO",
- CLEAR_THEME_DETAIL: "CLEAR_THEME_DETAIL",
- CHECK_ENTER_THROUGH_GNB: "CHECK_ENTER_THROUGH_GNB",
- SET_DEFAULT_FOCUS: "SET_DEFAULT_FOCUS",
- SET_BANNER_INDEX: "SET_BANNER_INDEX",
- RESET_HOME_INFO: "RESET_HOME_INFO",
- UPDATE_HOME_INFO: "UPDATE_HOME_INFO",
+ GET_HOME_TERMS: 'GET_HOME_TERMS',
+ SET_TERMS_ID_MAP: 'SET_TERMS_ID_MAP',
+ SET_OPTIONAL_TERMS_AVAILABILITY: 'SET_OPTIONAL_TERMS_AVAILABILITY',
+ GET_HOME_MENU: 'GET_HOME_MENU',
+ GET_HOME_LAYOUT: 'GET_HOME_LAYOUT',
+ GET_HOME_MAIN_CONTENTS: 'GET_HOME_MAIN_CONTENTS',
+ GET_HOME_FULL_VIDEO_INFO: 'GET_HOME_FULL_VIDEO_INFO',
+ GET_THEME_CURATION_INFO: 'GET_THEME_CURATION_INFO',
+ GET_THEME_CURATION_DETAIL_INFO: 'GET_THEME_CURATION_DETAIL_INFO',
+ GET_THEME_HOTEL_DETAIL_INFO: 'GET_THEME_HOTEL_DETAIL_INFO',
+ GET_THEME_MENU_SHELF_INFO: 'GET_THEME_MENU_SHELF_INFO',
+ CLEAR_THEME_MENU_SHELF_INFO: 'CLEAR_THEME_MENU_SHELF_INFO',
+ CLEAR_THEME_DETAIL: 'CLEAR_THEME_DETAIL',
+ CHECK_ENTER_THROUGH_GNB: 'CHECK_ENTER_THROUGH_GNB',
+ SET_DEFAULT_FOCUS: 'SET_DEFAULT_FOCUS',
+ SET_BANNER_INDEX: 'SET_BANNER_INDEX',
+ RESET_HOME_INFO: 'RESET_HOME_INFO',
+ UPDATE_HOME_INFO: 'UPDATE_HOME_INFO',
// brand actions
- GET_BRAND_LIST: "GET_BRAND_LIST",
- GET_BRAND_LAYOUT_INFO: "GET_BRAND_LAYOUT_INFO",
- GET_BRAND_LIVE_CHANNEL_INFO: "GET_BRAND_LIVE_CHANNEL_INFO",
- GET_BRAND_CHAN_INFO: "GET_BRAND_CHAN_INFO",
- GET_BRAND_TSV_INFO: "GET_BRAND_TSV_INFO",
- GET_BRAND_RECOMMENDED_SHOW_INFO: "GET_BRAND_RECOMMENDED_SHOW_INFO",
- GET_BRAND_SERIES_INFO: "GET_BRAND_SERIES_INFO",
- GET_BRAND_CATEGORY_INFO: "GET_BRAND_CATEGORY_INFO",
- GET_BRAND_CATEGORY_PRODUCT_INFO: "GET_BRAND_CATEGORY_PRODUCT_INFO",
- GET_BRAND_BEST_SELLER: "GET_BRAND_BEST_SELLER",
- GET_BRAND_CREATORS_INFO: "GET_BRAND_CREATORS_INFO",
- GET_BRAND_SHOWROOM: "GET_BRAND_SHOWROOM",
- GET_BRAND_RECENTLY_AIRED: "GET_BRAND_RECENTLY_AIRED",
- SET_BRAND_LIVE_CHANNEL_UPCOMING: "SET_BRAND_LIVE_CHANNEL_UPCOMING",
- SET_BRAND_CHAN_INFO: "SET_BRAND_CHAN_INFO",
- RESET_BRAND_STATE: "RESET_BRAND_STATE",
- RESET_BRAND_STATE_EXCEPT_BRAND_INFO: "RESET_BRAND_STATE_EXCEPT_BRAND_INFO",
- RESET_BRAND_LAYOUT_INFO: "RESET_BRAND_LAYOUT_INFO",
+ GET_BRAND_LIST: 'GET_BRAND_LIST',
+ GET_BRAND_LAYOUT_INFO: 'GET_BRAND_LAYOUT_INFO',
+ GET_BRAND_LIVE_CHANNEL_INFO: 'GET_BRAND_LIVE_CHANNEL_INFO',
+ GET_BRAND_CHAN_INFO: 'GET_BRAND_CHAN_INFO',
+ GET_BRAND_TSV_INFO: 'GET_BRAND_TSV_INFO',
+ GET_BRAND_RECOMMENDED_SHOW_INFO: 'GET_BRAND_RECOMMENDED_SHOW_INFO',
+ GET_BRAND_SERIES_INFO: 'GET_BRAND_SERIES_INFO',
+ GET_BRAND_CATEGORY_INFO: 'GET_BRAND_CATEGORY_INFO',
+ GET_BRAND_CATEGORY_PRODUCT_INFO: 'GET_BRAND_CATEGORY_PRODUCT_INFO',
+ GET_BRAND_BEST_SELLER: 'GET_BRAND_BEST_SELLER',
+ GET_BRAND_CREATORS_INFO: 'GET_BRAND_CREATORS_INFO',
+ GET_BRAND_SHOWROOM: 'GET_BRAND_SHOWROOM',
+ GET_BRAND_RECENTLY_AIRED: 'GET_BRAND_RECENTLY_AIRED',
+ SET_BRAND_LIVE_CHANNEL_UPCOMING: 'SET_BRAND_LIVE_CHANNEL_UPCOMING',
+ SET_BRAND_CHAN_INFO: 'SET_BRAND_CHAN_INFO',
+ RESET_BRAND_STATE: 'RESET_BRAND_STATE',
+ RESET_BRAND_STATE_EXCEPT_BRAND_INFO: 'RESET_BRAND_STATE_EXCEPT_BRAND_INFO',
+ RESET_BRAND_LAYOUT_INFO: 'RESET_BRAND_LAYOUT_INFO',
// main actions
- GET_SUB_CATEGORY: "GET_SUB_CATEGORY",
- APPEND_SUB_CATEGORY: "APPEND_SUB_CATEGORY",
- GET_TOP_20_SHOW: "GET_TOP_20_SHOW",
- GET_PRODUCT_DETAIL: "GET_PRODUCT_DETAIL",
- GET_YOUMAYLIKE: "GET_YOUMAYLIKE",
- SET_MAIN_LIKE_CATEGORY: "SET_MAIN_LIKE_CATEGORY",
- SET_MAIN_LIVE_UPCOMING_ALARM: "SET_MAIN_LIVE_UPCOMING_ALARM",
- GET_MAIN_LIVE_SHOW_NOW_PRODUCT: "GET_MAIN_LIVE_SHOW_NOW_PRODUCT",
- GET_MAIN_LIVE_SHOW: "GET_MAIN_LIVE_SHOW",
- GET_MAIN_CATEGORY_SHOW_DETAIL: "GET_MAIN_CATEGORY_SHOW_DETAIL",
- CLEAR_PRODUCT_DETAIL: "CLEAR_PRODUCT_DETAIL",
- CLEAR_SUB_CATEGORY: "CLEAR_SUB_CATEGORY",
- CLEAR_SHOPNOW_INFO: "CLEAR_SHOPNOW_INFO",
+ GET_SUB_CATEGORY: 'GET_SUB_CATEGORY',
+ APPEND_SUB_CATEGORY: 'APPEND_SUB_CATEGORY',
+ GET_TOP_20_SHOW: 'GET_TOP_20_SHOW',
+ GET_PRODUCT_DETAIL: 'GET_PRODUCT_DETAIL',
+ GET_YOUMAYLIKE: 'GET_YOUMAYLIKE',
+ SET_MAIN_LIKE_CATEGORY: 'SET_MAIN_LIKE_CATEGORY',
+ SET_MAIN_LIVE_UPCOMING_ALARM: 'SET_MAIN_LIVE_UPCOMING_ALARM',
+ GET_MAIN_LIVE_SHOW_NOW_PRODUCT: 'GET_MAIN_LIVE_SHOW_NOW_PRODUCT',
+ GET_MAIN_LIVE_SHOW: 'GET_MAIN_LIVE_SHOW',
+ GET_MAIN_CATEGORY_SHOW_DETAIL: 'GET_MAIN_CATEGORY_SHOW_DETAIL',
+ CLEAR_PRODUCT_DETAIL: 'CLEAR_PRODUCT_DETAIL',
+ CLEAR_SUB_CATEGORY: 'CLEAR_SUB_CATEGORY',
+ CLEAR_SHOPNOW_INFO: 'CLEAR_SHOPNOW_INFO',
// myPage actions
- GET_MY_RECOMMANDED_KEYWORD: "GET_MY_RECOMMANDED_KEYWORD",
- GET_MY_FAQ_INFO: "GET_MY_FAQ_INFO",
- GET_NOTICE: "GET_NOTICE",
- GET_MY_CUSTOMERS: "GET_MY_CUSTOMERS",
- GET_MY_FAVORITE: "GET_MY_FAVORITE",
- DELETE_MY_FAVORITE: "DELETE_MY_FAVORITE",
- GET_MY_FAVORITE_FLAG: "GET_MY_FAVORITE_FLAG",
- SET_MY_TERMS_WITHDRAW: "SET_MY_TERMS_WITHDRAW",
- GET_MY_UPCOMING_CHANGE_INFO: "GET_MY_UPCOMING_CHANGE_INFO",
- GET_MY_UPCOMING_ALERT_SHOW: "GET_MY_UPCOMING_ALERT_SHOW",
- DELETE_MY_UPCOMING_ALERT_SHOW: "DELETE_MY_UPCOMING_ALERT_SHOW",
- GET_MY_UPCOMING_ALERT_SHOW_KEYS: "GET_MY_UPCOMING_ALERT_SHOW_KEYS",
- SET_MY_UPCOMING_USE_ALERT: "SET_MY_UPCOMING_USE_ALERT",
- GET_UPCOMING_ALERT_SHOW_CHANGE_INFO: "GET_UPCOMING_ALERT_SHOW_CHANGE_INFO",
- GET_MY_RECENTLY_VIEWED_INFO: "GET_MY_RECENTLY_VIEWED_INFO",
- CLEAR_RECENTLY_VIEWED_INFO: "CLEAR_RECENTLY_VIEWED_INFO",
- CLEAR_FAVORITES: "CLEAR_FAVORITES",
- SET_MYPAGE_TERMS_AGREE: "SET_MYPAGE_TERMS_AGREE",
- SET_MYPAGE_TERMS_AGREE_SUCCESS: "SET_MYPAGE_TERMS_AGREE_SUCCESS",
- SET_MYPAGE_TERMS_AGREE_FAIL: "SET_MYPAGE_TERMS_AGREE_FAIL",
+ GET_MY_RECOMMANDED_KEYWORD: 'GET_MY_RECOMMANDED_KEYWORD',
+ GET_MY_FAQ_INFO: 'GET_MY_FAQ_INFO',
+ GET_NOTICE: 'GET_NOTICE',
+ GET_MY_CUSTOMERS: 'GET_MY_CUSTOMERS',
+ GET_MY_FAVORITE: 'GET_MY_FAVORITE',
+ DELETE_MY_FAVORITE: 'DELETE_MY_FAVORITE',
+ GET_MY_FAVORITE_FLAG: 'GET_MY_FAVORITE_FLAG',
+ SET_MY_TERMS_WITHDRAW: 'SET_MY_TERMS_WITHDRAW',
+ GET_MY_UPCOMING_CHANGE_INFO: 'GET_MY_UPCOMING_CHANGE_INFO',
+ GET_MY_UPCOMING_ALERT_SHOW: 'GET_MY_UPCOMING_ALERT_SHOW',
+ DELETE_MY_UPCOMING_ALERT_SHOW: 'DELETE_MY_UPCOMING_ALERT_SHOW',
+ GET_MY_UPCOMING_ALERT_SHOW_KEYS: 'GET_MY_UPCOMING_ALERT_SHOW_KEYS',
+ SET_MY_UPCOMING_USE_ALERT: 'SET_MY_UPCOMING_USE_ALERT',
+ GET_UPCOMING_ALERT_SHOW_CHANGE_INFO: 'GET_UPCOMING_ALERT_SHOW_CHANGE_INFO',
+ GET_MY_RECENTLY_VIEWED_INFO: 'GET_MY_RECENTLY_VIEWED_INFO',
+ CLEAR_RECENTLY_VIEWED_INFO: 'CLEAR_RECENTLY_VIEWED_INFO',
+ CLEAR_FAVORITES: 'CLEAR_FAVORITES',
+ SET_MYPAGE_TERMS_AGREE: 'SET_MYPAGE_TERMS_AGREE',
+ SET_MYPAGE_TERMS_AGREE_SUCCESS: 'SET_MYPAGE_TERMS_AGREE_SUCCESS',
+ SET_MYPAGE_TERMS_AGREE_FAIL: 'SET_MYPAGE_TERMS_AGREE_FAIL',
// onSale actions
- GET_HOME_ON_SALE_INFO: "GET_HOME_ON_SALE_INFO",
- GET_ON_SALE_INFO: "GET_ON_SALE_INFO",
- COPY_CATEGORY_INFO: "COPY_CATEGORY_INFO",
- RESET_ON_SALE_STATE: "RESET_ON_SALE_STATE",
+ GET_HOME_ON_SALE_INFO: 'GET_HOME_ON_SALE_INFO',
+ GET_ON_SALE_INFO: 'GET_ON_SALE_INFO',
+ COPY_CATEGORY_INFO: 'COPY_CATEGORY_INFO',
+ RESET_ON_SALE_STATE: 'RESET_ON_SALE_STATE',
// product actions
- GET_BEST_SELLER: "GET_BEST_SELLER",
- GET_PRODUCT_GROUP: "GET_PRODUCT_GROUP",
- GET_PRODUCT_OPTION: "GET_PRODUCT_OPTION",
- GET_PRODUCT_IMAGE_LENGTH: "GET_PRODUCT_IMAGE_LENGTH",
- GET_VIDEO_INDECATOR_FOCUS: "GET_VIDEO_INDECATOR_FOCUS",
- GET_PRODUCT_OPTION_ID: "GET_PRODUCT_OPTION_ID",
- CLEAR_PRODUCT_OPTIONS: "CLEAR_PRODUCT_OPTIONS",
- GET_USER_REVIEW: "GET_USER_REVIEW",
- TOGGLE_SHOW_ALL_REVIEWS: "TOGGLE_SHOW_ALL_REVIEWS",
- RESET_SHOW_ALL_REVIEWS: "RESET_SHOW_ALL_REVIEWS",
+ GET_BEST_SELLER: 'GET_BEST_SELLER',
+ GET_PRODUCT_GROUP: 'GET_PRODUCT_GROUP',
+ GET_PRODUCT_OPTION: 'GET_PRODUCT_OPTION',
+ GET_PRODUCT_IMAGE_LENGTH: 'GET_PRODUCT_IMAGE_LENGTH',
+ GET_VIDEO_INDECATOR_FOCUS: 'GET_VIDEO_INDECATOR_FOCUS',
+ GET_PRODUCT_OPTION_ID: 'GET_PRODUCT_OPTION_ID',
+ CLEAR_PRODUCT_OPTIONS: 'CLEAR_PRODUCT_OPTIONS',
+ GET_USER_REVIEW: 'GET_USER_REVIEW',
+ TOGGLE_SHOW_ALL_REVIEWS: 'TOGGLE_SHOW_ALL_REVIEWS',
+ RESET_SHOW_ALL_REVIEWS: 'RESET_SHOW_ALL_REVIEWS',
// search actions
- GET_SEARCH: "GET_SEARCH",
- RESET_SEARCH: "RESET_SEARCH",
- GET_SEARCH_PROCESSED: "GET_SEARCH_PROCESSED",
- SET_SEARCH_INIT_PERFORMED: "SET_SEARCH_INIT_PERFORMED",
- UPDATE_SEARCH_TIMESTAMP: "UPDATE_SEARCH_TIMESTAMP",
+ GET_SEARCH: 'GET_SEARCH',
+ RESET_SEARCH: 'RESET_SEARCH',
+ GET_SEARCH_PROCESSED: 'GET_SEARCH_PROCESSED',
+ SET_SEARCH_INIT_PERFORMED: 'SET_SEARCH_INIT_PERFORMED',
+ UPDATE_SEARCH_TIMESTAMP: 'UPDATE_SEARCH_TIMESTAMP',
// event actions
- GET_WELCOME_EVENT_INFO: "GET_WELCOME_EVENT_INFO",
- GET_EVENT_ISSUED_STATUS: "GET_EVENT_ISSUED_STATUS",
- SET_EVENT_ISSUE_REQ: "SET_EVENT_ISSUE_REQ",
- SET_EVENT_POP_CLICK_INFO: "SET_EVENT_POP_CLICK_INFO",
- CLEAR_EVENT_INFO: "CLEAR_EVENT_INFO",
- SKIP_CLICK_INFO: "SKIP_CLICK_INFO",
- CLEAR_CURATION_COUPON: "CLEAR_CURATION_COUPON",
- CLEAR_EVENT_ISSUED_STATUS_SUCCEESS: "CLEAR_EVENT_ISSUED_STATUS_SUCCEESS",
+ GET_WELCOME_EVENT_INFO: 'GET_WELCOME_EVENT_INFO',
+ GET_EVENT_ISSUED_STATUS: 'GET_EVENT_ISSUED_STATUS',
+ SET_EVENT_ISSUE_REQ: 'SET_EVENT_ISSUE_REQ',
+ SET_EVENT_POP_CLICK_INFO: 'SET_EVENT_POP_CLICK_INFO',
+ CLEAR_EVENT_INFO: 'CLEAR_EVENT_INFO',
+ SKIP_CLICK_INFO: 'SKIP_CLICK_INFO',
+ CLEAR_CURATION_COUPON: 'CLEAR_CURATION_COUPON',
+ CLEAR_EVENT_ISSUED_STATUS_SUCCEESS: 'CLEAR_EVENT_ISSUED_STATUS_SUCCEESS',
// coupon actions
- GET_PRODUCT_COUPON_INFO: "GET_PRODUCT_COUPON_INFO",
- GET_PRODUCT_COUPON_SEARCH: "GET_PRODUCT_COUPON_SEARCH",
- GET_PRODUCT_COUPON_DOWNLOAD: "GET_PRODUCT_COUPON_DOWNLOAD",
- GET_PRODUCT_COUPON_TOTDOWNLOAD: "GET_PRODUCT_COUPON_TOTDOWNLOAD",
- CLEAR_COUPON_INFO: "CLEAR_COUPON_INFO",
- CLEAR_GET_PRODUCT_COUPON_DOWNLOAD: "CLEAR_GET_PRODUCT_COUPON_DOWNLOAD",
+ GET_PRODUCT_COUPON_INFO: 'GET_PRODUCT_COUPON_INFO',
+ GET_PRODUCT_COUPON_SEARCH: 'GET_PRODUCT_COUPON_SEARCH',
+ GET_PRODUCT_COUPON_DOWNLOAD: 'GET_PRODUCT_COUPON_DOWNLOAD',
+ GET_PRODUCT_COUPON_TOTDOWNLOAD: 'GET_PRODUCT_COUPON_TOTDOWNLOAD',
+ CLEAR_COUPON_INFO: 'CLEAR_COUPON_INFO',
+ CLEAR_GET_PRODUCT_COUPON_DOWNLOAD: 'CLEAR_GET_PRODUCT_COUPON_DOWNLOAD',
// checkout actions
- GET_CHECKOUT_INFO: "GET_CHECKOUT_INFO",
- INSERT_MY_INFO_CHECKOUT_ORDER: "INSERT_MY_INFO_CHECKOUT_ORDER",
- GET_TAX_INFOS: "GET_TAX_INFOS",
- UPDATE_SELECTED_SHIPPING_ADDR: "UPDATE_SELECTED_SHIPPING_ADDR",
- UPDATE_SELECTED_BILLING_ADDR: "UPDATE_SELECTED_BILLING_ADDR",
- UPDATE_SELECTED_COUPON: "UPDATE_SELECTED_COUPON",
- GET_CHECKOUT_TOTAL_AMT: "GET_CHECKOUT_TOTAL_AMT",
- CHECKOUT_DATA_RESET: "CHECKOUT_DATA_RESET",
+ GET_CHECKOUT_INFO: 'GET_CHECKOUT_INFO',
+ INSERT_MY_INFO_CHECKOUT_ORDER: 'INSERT_MY_INFO_CHECKOUT_ORDER',
+ GET_TAX_INFOS: 'GET_TAX_INFOS',
+ UPDATE_SELECTED_SHIPPING_ADDR: 'UPDATE_SELECTED_SHIPPING_ADDR',
+ UPDATE_SELECTED_BILLING_ADDR: 'UPDATE_SELECTED_BILLING_ADDR',
+ UPDATE_SELECTED_COUPON: 'UPDATE_SELECTED_COUPON',
+ GET_CHECKOUT_TOTAL_AMT: 'GET_CHECKOUT_TOTAL_AMT',
+ CHECKOUT_DATA_RESET: 'CHECKOUT_DATA_RESET',
// order actions
- SET_PURCHASE_TERMS_AGREE: "SET_PURCHASE_TERMS_AGREE",
- SET_PURCHASE_TERMS_WITHDRAW: "SET_PURCHASE_TERMS_WITHDRAW",
- GET_MY_INFO_ORDER_SEARCH: "GET_MY_INFO_ORDER_SEARCH",
- GET_MY_INFO_ORDER_SEARCH_CANCEL: "GET_MY_INFO_ORDER_SEARCH_CANCEL",
- GET_MY_INFO_ORDER_DETAIL_SEARCH: "GET_MY_INFO_ORDER_DETAIL_SEARCH",
- GET_MY_INFO_ORDER_SHIPPING_SEARCH: "GET_MY_INFO_ORDER_SHIPPING_SEARCH",
- CLEAR_MY_INFO_ORDER_SEARCH: "CLEAR_MY_INFO_ORDER_SEARCH",
+ SET_PURCHASE_TERMS_AGREE: 'SET_PURCHASE_TERMS_AGREE',
+ SET_PURCHASE_TERMS_WITHDRAW: 'SET_PURCHASE_TERMS_WITHDRAW',
+ GET_MY_INFO_ORDER_SEARCH: 'GET_MY_INFO_ORDER_SEARCH',
+ GET_MY_INFO_ORDER_SEARCH_CANCEL: 'GET_MY_INFO_ORDER_SEARCH_CANCEL',
+ GET_MY_INFO_ORDER_DETAIL_SEARCH: 'GET_MY_INFO_ORDER_DETAIL_SEARCH',
+ GET_MY_INFO_ORDER_SHIPPING_SEARCH: 'GET_MY_INFO_ORDER_SHIPPING_SEARCH',
+ CLEAR_MY_INFO_ORDER_SEARCH: 'CLEAR_MY_INFO_ORDER_SEARCH',
// play controller
- GET_CHAT_LOG: "GET_CHAT_LOG",
- GET_SUBTITLE: "GET_SUBTITLE",
- CLEAR_PLAYER_INFO: "CLEAR_PLAYER_INFO",
+ GET_CHAT_LOG: 'GET_CHAT_LOG',
+ GET_SUBTITLE: 'GET_SUBTITLE',
+ CLEAR_PLAYER_INFO: 'CLEAR_PLAYER_INFO',
+ UPDATE_VIDEO_PLAY_STATE: 'UPDATE_VIDEO_PLAY_STATE',
// 🔽 [추가] 플레이 제어 매니저 액션 타입
/**
@@ -224,58 +225,57 @@ export const types = {
* SET_PLAYER_CONTROL: 특정 컴포넌트에게 비디오 재생 제어권을 부여합니다.
* CLEAR_PLAYER_CONTROL: 컴포넌트로부터 비디오 재생 제어권을 회수합니다.
*/
- SET_PLAYER_CONTROL: "SET_PLAYER_CONTROL",
- CLEAR_PLAYER_CONTROL: "CLEAR_PLAYER_CONTROL",
+ SET_PLAYER_CONTROL: 'SET_PLAYER_CONTROL',
+ CLEAR_PLAYER_CONTROL: 'CLEAR_PLAYER_CONTROL',
// reset action
- RESET_REDUX_STATE: "RESET_REDUX_STATE",
+ RESET_REDUX_STATE: 'RESET_REDUX_STATE',
// cancel actions
- GET_MY_INFO_ORDER_CANCEL_SEARCH: "GET_MY_INFO_ORDER_CANCEL_SEARCH",
- GET_MY_INFO_ORDER_CANCEL_COLUMNS_SEARCH:
- "GET_MY_INFO_ORDER_CANCEL_COLUMNS_SEARCH",
- UPDATE_ORDER_PARTIAL_CANCEL: "UPDATE_ORDER_PARTIAL_CANCEL",
- PAYMENT_TOTAL_CANCEL: "PAYMENT_TOTAL_CANCEL",
+ GET_MY_INFO_ORDER_CANCEL_SEARCH: 'GET_MY_INFO_ORDER_CANCEL_SEARCH',
+ GET_MY_INFO_ORDER_CANCEL_COLUMNS_SEARCH: 'GET_MY_INFO_ORDER_CANCEL_COLUMNS_SEARCH',
+ UPDATE_ORDER_PARTIAL_CANCEL: 'UPDATE_ORDER_PARTIAL_CANCEL',
+ PAYMENT_TOTAL_CANCEL: 'PAYMENT_TOTAL_CANCEL',
// emp actions
- GET_SHOPTIME_TERMS: "GET_SHOPTIME_TERMS",
+ GET_SHOPTIME_TERMS: 'GET_SHOPTIME_TERMS',
// pinCode actions
- GET_MY_INFO_CARD_PINCODE_CHECK: "GET_MY_INFO_CARD_PINCODE_CHECK",
+ GET_MY_INFO_CARD_PINCODE_CHECK: 'GET_MY_INFO_CARD_PINCODE_CHECK',
// new actions
- CANCEL_FOCUS_ELEMENT: "CANCEL_FOCUS_ELEMENT",
+ CANCEL_FOCUS_ELEMENT: 'CANCEL_FOCUS_ELEMENT',
// 약관동의 여부 확인 상태
- GET_TERMS_AGREE_YN_START: "GET_TERMS_AGREE_YN_START",
- GET_TERMS_AGREE_YN_SUCCESS: "GET_TERMS_AGREE_YN_SUCCESS",
- GET_TERMS_AGREE_YN_FAILURE: "GET_TERMS_AGREE_YN_FAILURE",
+ GET_TERMS_AGREE_YN_START: 'GET_TERMS_AGREE_YN_START',
+ GET_TERMS_AGREE_YN_SUCCESS: 'GET_TERMS_AGREE_YN_SUCCESS',
+ GET_TERMS_AGREE_YN_FAILURE: 'GET_TERMS_AGREE_YN_FAILURE',
// device
- REQ_REG_DEVICE_INFO: "REQ_REG_DEVICE_INFO",
+ REQ_REG_DEVICE_INFO: 'REQ_REG_DEVICE_INFO',
// 🔽 [추가] 영구재생 비디오 정보 저장
- SET_PERSISTENT_VIDEO_INFO: "SET_PERSISTENT_VIDEO_INFO",
+ SET_PERSISTENT_VIDEO_INFO: 'SET_PERSISTENT_VIDEO_INFO',
// 🔽 [추가] 배너 비디오 제어 액션 타입
/**
* HomeBanner의 배너 간 비디오 재생 제어를 위한 액션 타입들.
* 첫 번째 배너 상시 재생과 두 번째 배너 포커스 재생을 관리합니다.
*/
- SET_BANNER_STATE: "SET_BANNER_STATE",
- SET_BANNER_FOCUS: "SET_BANNER_FOCUS",
- SET_BANNER_AVAILABILITY: "SET_BANNER_AVAILABILITY",
- SET_BANNER_TRANSITION: "SET_BANNER_TRANSITION",
- PAUSE_PLAYER_CONTROL: "PAUSE_PLAYER_CONTROL",
- RESUME_PLAYER_CONTROL: "RESUME_PLAYER_CONTROL",
+ SET_BANNER_STATE: 'SET_BANNER_STATE',
+ SET_BANNER_FOCUS: 'SET_BANNER_FOCUS',
+ SET_BANNER_AVAILABILITY: 'SET_BANNER_AVAILABILITY',
+ SET_BANNER_TRANSITION: 'SET_BANNER_TRANSITION',
+ PAUSE_PLAYER_CONTROL: 'PAUSE_PLAYER_CONTROL',
+ RESUME_PLAYER_CONTROL: 'RESUME_PLAYER_CONTROL',
// 🔽 [추가] HomeBanner 동영상 포커스 정책 관리
- SET_CURRENT_FOCUS_BANNER: "SET_CURRENT_FOCUS_BANNER",
- UPDATE_VIDEO_POLICY: "UPDATE_VIDEO_POLICY",
- SET_MODAL_BORDER: "SET_MODAL_BORDER",
- SET_BANNER_VISIBILITY: "SET_BANNER_VISIBILITY",
+ SET_CURRENT_FOCUS_BANNER: 'SET_CURRENT_FOCUS_BANNER',
+ UPDATE_VIDEO_POLICY: 'UPDATE_VIDEO_POLICY',
+ SET_MODAL_BORDER: 'SET_MODAL_BORDER',
+ SET_BANNER_VISIBILITY: 'SET_BANNER_VISIBILITY',
// 🔽 [추가] JustForYou 상품 관리 부분
- GET_RECENTLY_SAW_ITEM: "GET_RECENTLY_SAW_ITEM",
- GET_LIKE_BRAND_PRODUCT: "GET_LIKE_BRAND_PRODUCT",
- GET_MORE_TO_CONCIDER_AT_THIS_PRICE: "GET_MORE_TO_CONCIDER_AT_THIS_PRICE",
+ GET_RECENTLY_SAW_ITEM: 'GET_RECENTLY_SAW_ITEM',
+ GET_LIKE_BRAND_PRODUCT: 'GET_LIKE_BRAND_PRODUCT',
+ GET_MORE_TO_CONCIDER_AT_THIS_PRICE: 'GET_MORE_TO_CONCIDER_AT_THIS_PRICE',
};
diff --git a/com.twin.app.shoptime/src/actions/playActions.js b/com.twin.app.shoptime/src/actions/playActions.js
index 0c6524fd..24d20d06 100644
--- a/com.twin.app.shoptime/src/actions/playActions.js
+++ b/com.twin.app.shoptime/src/actions/playActions.js
@@ -135,6 +135,52 @@ export const resumeModalVideo = () => (dispatch, getState) => {
}
};
+// 전체화면 비디오를 일시정지 (패널은 유지)
+export const pauseFullscreenVideo = () => (dispatch, getState) => {
+ const panels = getState().panels.panels;
+
+ // 전체화면 PlayerPanel 찾기 (modal이 false인 패널)
+ const fullscreenPlayerPanel = panels.find(
+ (panel) => panel.name === panel_names.PLAYER_PANEL && !panel.panelInfo?.modal
+ );
+
+ if (fullscreenPlayerPanel) {
+ console.log('[pauseFullscreenVideo] Pausing fullscreen video');
+ dispatch(
+ updatePanel({
+ name: panel_names.PLAYER_PANEL,
+ panelInfo: {
+ ...fullscreenPlayerPanel.panelInfo,
+ isPaused: true, // 일시정지 플래그 추가
+ },
+ })
+ );
+ }
+};
+
+// 전체화면 비디오를 재생 (일시정지 해제)
+export const resumeFullscreenVideo = () => (dispatch, getState) => {
+ const panels = getState().panels.panels;
+
+ // 전체화면 PlayerPanel 찾기 (modal이 false인 패널)
+ const fullscreenPlayerPanel = panels.find(
+ (panel) => panel.name === panel_names.PLAYER_PANEL && !panel.panelInfo?.modal
+ );
+
+ if (fullscreenPlayerPanel && fullscreenPlayerPanel.panelInfo?.isPaused) {
+ console.log('[resumeFullscreenVideo] Resuming fullscreen video');
+ dispatch(
+ updatePanel({
+ name: panel_names.PLAYER_PANEL,
+ panelInfo: {
+ ...fullscreenPlayerPanel.panelInfo,
+ isPaused: false, // 일시정지 해제
+ },
+ })
+ );
+ }
+};
+
// 채팅 로그 가져오기 IF-LGSP-371
export const getChatLog =
({ patnrId, showId }) =>
@@ -187,6 +233,20 @@ export const CLEAR_PLAYER_INFO = () => ({
type: types.CLEAR_PLAYER_INFO,
});
+/**
+ * 비디오 재생 상태를 Redux에 업데이트합니다.
+ * @param {Object} playState - 업데이트할 재생 상태
+ * @param {boolean} playState.isPlaying - 재생 중인지 여부
+ * @param {boolean} playState.isPaused - 일시정지 상태인지 여부
+ * @param {number} playState.currentTime - 현재 재생 시간(초)
+ * @param {number} playState.duration - 전체 비디오 길이(초)
+ * @param {number} playState.playbackRate - 재생 속도
+ */
+export const updateVideoPlayState = (playState) => ({
+ type: types.UPDATE_VIDEO_PLAY_STATE,
+ payload: playState,
+});
+
/* 🔽 [추가] 새로운 '플레이 제어 매니저' 액션들 */
/**
diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js
index b2a7ec56..03709b78 100644
--- a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js
+++ b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js
@@ -64,6 +64,7 @@ import Overlay from './Overlay';
import TReactPlayer from './TReactPlayer';
import Video from './Video';
import css from './VideoPlayer.module.less';
+import { updateVideoPlayState } from '../../actions/playActions';
const isEnter = is('enter');
const isLeft = is('left');
@@ -714,6 +715,7 @@ const VideoPlayerBase = class extends React.Component {
belowContentsVisible: PropTypes.bool,
tabContainerVersion: PropTypes.number,
tabIndexV2: PropTypes.number,
+ dispatch: PropTypes.func,
};
static contextType = FloatingLayerContext;
@@ -1507,6 +1509,19 @@ const VideoPlayerBase = class extends React.Component {
updatedState.thumbnailUrl = null;
}
this.setState(updatedState);
+
+ // Redux에 비디오 재생 상태 업데이트
+ if (this.props.dispatch) {
+ this.props.dispatch(
+ updateVideoPlayState({
+ isPlaying: !updatedState.paused,
+ isPaused: updatedState.paused,
+ currentTime: updatedState.currentTime,
+ duration: updatedState.duration,
+ playbackRate: updatedState.playbackRate,
+ })
+ );
+ }
};
renderBottomControl = new Job(() => {
diff --git a/com.twin.app.shoptime/src/reducers/playReducer.js b/com.twin.app.shoptime/src/reducers/playReducer.js
index 0cd4aca3..579a5ea6 100644
--- a/com.twin.app.shoptime/src/reducers/playReducer.js
+++ b/com.twin.app.shoptime/src/reducers/playReducer.js
@@ -1,8 +1,15 @@
-import { types } from "../actions/actionTypes";
+import { types } from '../actions/actionTypes';
const initialState = {
subTitleBlobs: {},
chatData: null,
+ videoPlayState: {
+ isPlaying: false,
+ isPaused: true,
+ currentTime: 0,
+ duration: 0,
+ playbackRate: 1,
+ },
};
export const playReducer = (state = initialState, action) => {
@@ -19,14 +26,13 @@ export const playReducer = (state = initialState, action) => {
...state,
subTitleBlobs: {
...state.subTitleBlobs,
- [action.payload.url]: "Error",
+ [action.payload.url]: 'Error',
},
};
}
- var srtRegex =
- /(.*\n)?(\d\d:\d\d:\d\d),(\d\d\d --> \d\d:\d\d:\d\d),(\d\d\d)/g;
- var vttText = "WEBVTT\n\n" + srtText.replace(srtRegex, "$1$2.$3.$4");
- var vttBlob = new Blob([vttText], { type: "text/vtt" });
+ var srtRegex = /(.*\n)?(\d\d:\d\d:\d\d),(\d\d\d --> \d\d:\d\d:\d\d),(\d\d\d)/g;
+ var vttText = 'WEBVTT\n\n' + srtText.replace(srtRegex, '$1$2.$3.$4');
+ var vttBlob = new Blob([vttText], { type: 'text/vtt' });
let blobUrl = URL.createObjectURL(vttBlob);
return {
@@ -43,6 +49,15 @@ export const playReducer = (state = initialState, action) => {
chatData: {},
};
}
+ case types.UPDATE_VIDEO_PLAY_STATE: {
+ return {
+ ...state,
+ videoPlayState: {
+ ...state.videoPlayState,
+ ...action.payload,
+ },
+ };
+ }
default:
return state;
diff --git a/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/HomeBanner.jsx b/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/HomeBanner.jsx
index dcf54e9f..f5b78dcd 100644
--- a/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/HomeBanner.jsx
+++ b/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/HomeBanner.jsx
@@ -84,82 +84,6 @@ export default function HomeBanner({ firstSpot, spotlightId, handleItemFocus, ha
}
}, [handleItemFocus]);
- // 🔽 [추가] 0번째 배너에 대한 영구 비디오 재생을 처리하는 useEffect
- // useEffect(() => {
- // if (
- // bannerDataList &&
- // bannerDataList.length > 0 &&
- // selectTemplate === "DSP00201"
- // ) {
- // const banner0Data = bannerDataList[0]?.bannerDetailInfos?.[0];
-
- // if (banner0Data && banner0Data.showUrl) {
- // // DOM 요소가 존재하는지 확인 후 실행
- // console.log("[HomeBanner] banner0Data", banner0Data);
- // const checkAndPlay = () => {
- // const targetElement = document.querySelector(
- // '[data-spotlight-id="banner0"]',
- // );
- // console.log("[HomeBanner] targetElement", targetElement);
- // if (targetElement) {
- // console.log("[HomeBanner] targetElement 존재");
- // dispatch(
- // startVideoPlayer({
- // showUrl: banner0Data.showUrl,
- // patnrId: banner0Data.patnrId,
- // showId: banner0Data.showId,
- // shptmBanrTpNm: "MEDIA",
- // modal: true,
- // modalContainerId: "banner0",
- // spotlightDisable: true,
- // }),
- // );
- // console.log("[HomeBanner] startVideoPlayer 호출");
- // } else {
- // // 요소가 없으면 잠시 후 재시도
- // console.log("[HomeBanner] targetElement 없음");
- // setTimeout(checkAndPlay, 100);
- // }
- // };
-
- // // 다음 tick에서 실행하여 렌더링 완료 보장
- // setTimeout(checkAndPlay, 0);
- // }
- // }
- // }, [dispatch, bannerDataList, selectTemplate]);
-
- // 🔽 [수정] 새로운 1번 배너 포커스/블러 핸들러
- const handleSecondBannerFocus = useCallback(() => {
- const secondBannerData = bannerDataList?.[1];
- if (secondBannerData) {
- const randomData = secondBannerData.bannerDetailInfos[secondBannerData.randomIndex];
- const videoInfo = {
- showUrl: randomData.showUrl,
- patnrId: randomData.patnrId,
- showId: randomData.showId,
- shptmBanrTpNm: randomData.showId ? randomData.shptmBanrTpNm : 'MEDIA',
- lgCatCd: randomData.lgCatCd,
- chanId: randomData.brdcChnlId,
- modal: true,
- modalContainerId: 'banner1',
- modalClassName: css.videoModal,
- isVerticalModal: true, // Assuming second banner is horizontal, so modal is vertical
- };
-
- // 중앙 제어 시스템에 '미리보기' 재생을 요청
- dispatch(requestPlayControl('banner1_preview', videoInfo));
- }
-
- if (handleItemFocus) {
- handleItemFocus();
- }
- }, [dispatch, bannerDataList, handleItemFocus]);
-
- const handleSecondBannerBlur = useCallback(() => {
- // 중앙 제어 시스템에 '미리보기' 제어권 해제를 요청
- dispatch(releasePlayControl('banner1_preview'));
- }, [dispatch]);
-
const termsData = useSelector((state) => state.home.termsData);
const termsIdMap = useSelector((state) => state.home.termsIdMap);
const optionalTermsAvailable = useSelector((state) => state.home.optionalTermsAvailable);
@@ -379,27 +303,6 @@ export default function HomeBanner({ firstSpot, spotlightId, handleItemFocus, ha
return null;
}, [bannerDataList]);
- // useEffect(() => {
- // if (firstSpot && defaultFocus && popupVisible === false) {
- // setTimeout(() => {
- // Spotlight.focus(defaultFocus);
- // }, 0);
- // }
-
- // if (defaultFocus) {
- // dispatch(setDefaultFocus(defaultFocus));
- // }
- // }, [defaultFocus, dispatch, popupVisible]);
-
- // 테스트용 팝업 표시
- // useEffect(() => {
- // setTimeout(() => {
- // console.log("App.js optionalTermsTest 팝업 표시");
- // setIsOptionalConfirmVisible(true);
- // // setIsOptionalTermsVisible(true);
- // }, 1000);
- // }, []);
-
// 약관 동의 및 선택 약관 팝업 처리 (TV 환경 최적화)
useEffect(() => {
if (termsLoading) {
@@ -423,77 +326,6 @@ export default function HomeBanner({ firstSpot, spotlightId, handleItemFocus, ha
}
}, [shouldShowOptionalTermsPopup, termsLoading, isOptionalConfirmVisible, dispatch]);
- // const renderItem = useCallback(
- // (index, isHorizontal) => {
- // const data = bannerDataList?.[index] ?? {};
-
- // if (index === 1) {
- // return (
- //
- //
- //
- // );
- // }
-
- // return (
- //
- // {data.shptmDspyTpNm === "Rolling" ? (
- //
- // ) : data.shptmDspyTpNm === "Random" ? (
- //
- // ) : (
- //
- //
- //
- // )}
- //
- // );
- // },
- // [
- // bannerDataList,
- // _handleItemFocus,
- // _handleShelfFocus,
- // handleSecondBannerFocus,
- // handleSecondBannerBlur,
- // ],
- // );
-
const renderItem = useCallback(
(index, isHorizontal, videoPlayerable = false) => {
const data = bannerDataList?.[index] ?? {};
@@ -678,7 +510,7 @@ export default function HomeBanner({ firstSpot, spotlightId, handleItemFocus, ha
}
}
return null;
- }, [selectTemplate, renderItem, renderSimpleVideoContainer]);
+ }, [selectTemplate, renderItem, renderSimpleVideoContainer, introTermsAgree]);
return (
<>
diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx
index 5b63a5cf..0f7c638e 100644
--- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx
+++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx
@@ -254,6 +254,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
const liveShowInfos = USE_SELECTOR('liveShowInfos', (state) => state.main.liveShowInfos);
const vodSubtitleData = USE_SELECTOR('vodSubtitleData', (state) => state.play.subTitleBlobs);
const broadcast = USE_SELECTOR('broadcast', (state) => state.common.broadcast);
+ const videoPlayState = USE_SELECTOR('videoPlayState', (state) => state.play.videoPlayState);
const lastPanelAction = USE_SELECTOR('lastPanelAction', (state) => state.panels.lastPanelAction);
const nowMenu = USE_SELECTOR('nowMenu', (state) => state.common.menu.nowMenu);
@@ -2215,6 +2216,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
broadcast={broadcast}
tabContainerVersion={tabContainerVersion}
tabIndexV2={tabIndexV2}
+ dispatch={dispatch}
>
{typeof window === 'object' && window.PalmSystem && (