[251210] feat: FeaturedBrandsPanel , See More Products - 1
🕐 커밋 시간: 2025. 12. 10. 18:29:18 📊 변경 통계: • 총 파일: 5개 • 추가: +133줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/actionTypes.js ~ com.twin.app.shoptime/src/actions/brandActions.js ~ com.twin.app.shoptime/src/reducers/brandReducer.js ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedBrandsPanel.jsx 🔧 주요 변경 내용: • 타입 시스템 안정성 강화 • 핵심 비즈니스 로직 개선 • 중간 규모 기능 개선
This commit is contained in:
@@ -137,6 +137,9 @@ export const types = {
|
|||||||
RESET_BRAND_STATE: 'RESET_BRAND_STATE',
|
RESET_BRAND_STATE: 'RESET_BRAND_STATE',
|
||||||
RESET_BRAND_STATE_EXCEPT_BRAND_INFO: 'RESET_BRAND_STATE_EXCEPT_BRAND_INFO',
|
RESET_BRAND_STATE_EXCEPT_BRAND_INFO: 'RESET_BRAND_STATE_EXCEPT_BRAND_INFO',
|
||||||
RESET_BRAND_LAYOUT_INFO: 'RESET_BRAND_LAYOUT_INFO',
|
RESET_BRAND_LAYOUT_INFO: 'RESET_BRAND_LAYOUT_INFO',
|
||||||
|
// 🆕 [251210] patnrId=21 카테고리 그룹 데이터 관리
|
||||||
|
SET_BRAND_SHOP_BY_SHOW_CATEGORY_GROUPS: 'SET_BRAND_SHOP_BY_SHOW_CATEGORY_GROUPS',
|
||||||
|
RESET_BRAND_SHOP_BY_SHOW_CATEGORY_GROUPS: 'RESET_BRAND_SHOP_BY_SHOW_CATEGORY_GROUPS',
|
||||||
|
|
||||||
// main actions
|
// main actions
|
||||||
GET_SUB_CATEGORY: 'GET_SUB_CATEGORY',
|
GET_SUB_CATEGORY: 'GET_SUB_CATEGORY',
|
||||||
|
|||||||
@@ -410,6 +410,8 @@ export const getBrandShopByShow = (props) => (dispatch, getState) => {
|
|||||||
type: types.GET_BRAND_SHOP_BY_SHOW,
|
type: types.GET_BRAND_SHOP_BY_SHOW,
|
||||||
payload: {
|
payload: {
|
||||||
data: response.data.data,
|
data: response.data.data,
|
||||||
|
patnrId,
|
||||||
|
contsId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ const initialState = {
|
|||||||
brandTopBannerData: {
|
brandTopBannerData: {
|
||||||
data: {},
|
data: {},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 🆕 [251210] patnrId=21 카테고리 그룹 데이터 저장소
|
||||||
|
brandShopByShowCategoryGroups: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const brandReducer = (state = initialState, action) => {
|
export const brandReducer = (state = initialState, action) => {
|
||||||
@@ -174,12 +177,31 @@ export const brandReducer = (state = initialState, action) => {
|
|||||||
? nextData
|
? nextData
|
||||||
: { ...prevData, ...nextData, brandShopByShowContsList: prevData.brandShopByShowContsList };
|
: { ...prevData, ...nextData, brandShopByShowContsList: prevData.brandShopByShowContsList };
|
||||||
|
|
||||||
|
// 🆕 [251210] patnrId=21인 경우 그룹 데이터 별도 저장
|
||||||
|
const updatedCategoryGroups = { ...state.brandShopByShowCategoryGroups };
|
||||||
|
|
||||||
|
if (action.payload?.patnrId === 21 || action.payload?.patnrId === "21") {
|
||||||
|
const patnrId = String(action.payload.patnrId);
|
||||||
|
|
||||||
|
// patnrId별 그룹 데이터가 없으면 초기화
|
||||||
|
if (!updatedCategoryGroups[patnrId]) {
|
||||||
|
updatedCategoryGroups[patnrId] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 현재 contsId에 대한 그룹 정보 저장
|
||||||
|
if (nextData.brandShopByShowContsInfo?.contsId) {
|
||||||
|
const contsId = nextData.brandShopByShowContsInfo.contsId;
|
||||||
|
updatedCategoryGroups[patnrId][contsId] = nextData.brandShopByShowContsInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
brandShopByShowData: {
|
brandShopByShowData: {
|
||||||
...action.payload,
|
...action.payload,
|
||||||
data: mergedData,
|
data: mergedData,
|
||||||
},
|
},
|
||||||
|
brandShopByShowCategoryGroups: updatedCategoryGroups,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,6 +240,25 @@ export const brandReducer = (state = initialState, action) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🆕 [251210] patnrId=21 카테고리 그룹 데이터 설정
|
||||||
|
case types.SET_BRAND_SHOP_BY_SHOW_CATEGORY_GROUPS: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
brandShopByShowCategoryGroups: {
|
||||||
|
...state.brandShopByShowCategoryGroups,
|
||||||
|
...action.payload,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🆕 [251210] patnrId=21 카테고리 그룹 데이터 초기화
|
||||||
|
case types.RESET_BRAND_SHOP_BY_SHOW_CATEGORY_GROUPS: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
brandShopByShowCategoryGroups: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1108,6 +1108,7 @@ export default function ProductAllSection({
|
|||||||
const descriptionRef = useRef(null);
|
const descriptionRef = useRef(null);
|
||||||
const reviewRef = useRef(null);
|
const reviewRef = useRef(null);
|
||||||
const youMayAlsoLikelRef = useRef(null);
|
const youMayAlsoLikelRef = useRef(null);
|
||||||
|
const seeMoreProductsRef = useRef(null);
|
||||||
const prevMediaPanelModalStateRef = useRef(null); // MediaPanel의 이전 modal 상태 추적
|
const prevMediaPanelModalStateRef = useRef(null); // MediaPanel의 이전 modal 상태 추적
|
||||||
|
|
||||||
// 동영상과 이미지를 통합한 렌더링 아이템 리스트 생성 (Indicator.jsx 로직 기반)
|
// 동영상과 이미지를 통합한 렌더링 아이템 리스트 생성 (Indicator.jsx 로직 기반)
|
||||||
@@ -1264,6 +1265,15 @@ export default function ProductAllSection({
|
|||||||
Spotlight.focus("detail_youMayAlsoLike_area")
|
Spotlight.focus("detail_youMayAlsoLike_area")
|
||||||
},100);
|
},100);
|
||||||
}, [scrollToSection, dispatch]);
|
}, [scrollToSection, dispatch]);
|
||||||
|
|
||||||
|
const handleSeeMoreProductsClick = useCallback(() => {
|
||||||
|
console.log('[SEE MORE PRODUCTS] Button clicked - currently no action');
|
||||||
|
// TODO: 나중에 그룹 상품 표시 로직 추가
|
||||||
|
scrollToSection('scroll-marker-see-more-products');
|
||||||
|
setTimeout(() => {
|
||||||
|
Spotlight.focus("see-more-products-area");
|
||||||
|
}, 100);
|
||||||
|
}, [scrollToSection]);
|
||||||
// 헤더 Back 아이콘에서 아래로 내려올 때 첫 번째 버튼을 바라보도록 설정
|
// 헤더 Back 아이콘에서 아래로 내려올 때 첫 번째 버튼을 바라보도록 설정
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const firstId = stackOrder[0];
|
const firstId = stackOrder[0];
|
||||||
@@ -1751,10 +1761,27 @@ export default function ProductAllSection({
|
|||||||
activeButton === 'youmaylike' ? css.active : ''
|
activeButton === 'youmaylike' ? css.active : ''
|
||||||
)}
|
)}
|
||||||
onClick={handleYouMayAlsoLikeClick}
|
onClick={handleYouMayAlsoLikeClick}
|
||||||
|
onFocus={() => handleButtonFocus('youmaylike')}
|
||||||
|
onBlur={handleButtonBlur}
|
||||||
>
|
>
|
||||||
{$L('YOU MAY ALSO LIKE')}
|
{$L('YOU MAY ALSO LIKE')}
|
||||||
</TButton>
|
</TButton>
|
||||||
)}
|
)}
|
||||||
|
{/* 🆕 [251210] patnrId=21인 경우 SEE MORE PRODUCTS 버튼 */}
|
||||||
|
{(panelInfo?.patnrId === 21 || panelInfo?.patnrId === "21") && (
|
||||||
|
<TButton
|
||||||
|
className={classNames(
|
||||||
|
css.youMayLikeButton,
|
||||||
|
activeButton === 'seemoreproducts' ? css.active : ''
|
||||||
|
)}
|
||||||
|
onClick={handleSeeMoreProductsClick}
|
||||||
|
onFocus={() => handleButtonFocus('seemoreproducts')}
|
||||||
|
onBlur={handleButtonBlur}
|
||||||
|
spotlightId="see-more-products-button"
|
||||||
|
>
|
||||||
|
{$L('SEE MORE PRODUCTS')}
|
||||||
|
</TButton>
|
||||||
|
)}
|
||||||
{/* YouMayLike 버튼 렌더링 상태 로그 */}
|
{/* YouMayLike 버튼 렌더링 상태 로그 */}
|
||||||
{/* {(() => {
|
{/* {(() => {
|
||||||
console.log('[YouMayLike] 버튼 렌더링 체크:', {
|
console.log('[YouMayLike] 버튼 렌더링 체크:', {
|
||||||
@@ -1938,6 +1965,20 @@ export default function ProductAllSection({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 🆕 [251210] patnrId=21인 경우 SEE MORE PRODUCTS 섹션 */}
|
||||||
|
{(panelInfo?.patnrId === 21 || panelInfo?.patnrId === "21") && (
|
||||||
|
<div ref={seeMoreProductsRef}>
|
||||||
|
<div id="scroll-marker-see-more-products" className={css.scrollMarker}></div>
|
||||||
|
<div id="see-more-products-section" data-spotlight-id="see-more-products-area">
|
||||||
|
{/* TODO: 나중에 그룹 상품 표시 컴포넌트 추가 */}
|
||||||
|
<div style={{ padding: '20px', textAlign: 'center', color: '#666' }}>
|
||||||
|
<h3>SEE MORE PRODUCTS</h3>
|
||||||
|
<p>그룹 상품이 여기에 표시될 예정입니다</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className={css.topButtonBox}>
|
<div className={css.topButtonBox}>
|
||||||
<TButton
|
<TButton
|
||||||
|
|||||||
@@ -280,6 +280,10 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
|
|||||||
const brandTopBannerInfo = useSelector(
|
const brandTopBannerInfo = useSelector(
|
||||||
(state) => state.brand.brandTopBannerData.data.brandTopBannerInfo
|
(state) => state.brand.brandTopBannerData.data.brandTopBannerInfo
|
||||||
);
|
);
|
||||||
|
// 🆕 [251210] patnrId=21 카테고리 그룹 데이터
|
||||||
|
const brandShopByShowCategoryGroups = useSelector(
|
||||||
|
(state) => state.brand.brandShopByShowCategoryGroups
|
||||||
|
);
|
||||||
|
|
||||||
const [displayTopButton, setDisplayTopButton] = useState(false);
|
const [displayTopButton, setDisplayTopButton] = useState(false);
|
||||||
const [focusedContainerId, setFocusedContainerId] = useState(null);
|
const [focusedContainerId, setFocusedContainerId] = useState(null);
|
||||||
@@ -310,6 +314,9 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
|
|||||||
});
|
});
|
||||||
const renderedShelfCountRef = useRef(0);
|
const renderedShelfCountRef = useRef(0);
|
||||||
|
|
||||||
|
// 🆕 [251210] patnrId=21 카테고리 그룹 조회 상태 추적
|
||||||
|
const fetchedCategoryGroupsRef = useRef(new Set());
|
||||||
|
|
||||||
const fromDetail = panelInfo?.from && panelInfo.from === "detail";
|
const fromDetail = panelInfo?.from && panelInfo.from === "detail";
|
||||||
const fromGNB = panelInfo?.from && panelInfo.from === "gnb";
|
const fromGNB = panelInfo?.from && panelInfo.from === "gnb";
|
||||||
const fromUpcoming = panelInfo?.from && panelInfo.from === "upcoming";
|
const fromUpcoming = panelInfo?.from && panelInfo.from === "upcoming";
|
||||||
@@ -803,6 +810,18 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
|
|||||||
console.log("[FB-PANEL-DATA-FETCH] sortedBrandLayoutInfo:", sortedBrandLayoutInfo);
|
console.log("[FB-PANEL-DATA-FETCH] sortedBrandLayoutInfo:", sortedBrandLayoutInfo);
|
||||||
console.log("[FB-PANEL-DATA-FETCH] selectedPatnrId:", selectedPatnrId);
|
console.log("[FB-PANEL-DATA-FETCH] selectedPatnrId:", selectedPatnrId);
|
||||||
|
|
||||||
|
// 🆕 [251210] patnrId 변경 시 조회 상태 초기화
|
||||||
|
if (selectedPatnrId) {
|
||||||
|
const patnrIdString = String(selectedPatnrId);
|
||||||
|
// 이전 patnrId와 다르면 ref 초기화
|
||||||
|
const currentFetchKeys = Array.from(fetchedCategoryGroupsRef.current).filter(key => key.startsWith(patnrIdString));
|
||||||
|
if (currentFetchKeys.length === 0) {
|
||||||
|
console.log("[FB-PANEL-DATA-FETCH] patnrId changed, clearing category group fetch status");
|
||||||
|
// 다른 patnrId로 전환 시 ref 초기화
|
||||||
|
fetchedCategoryGroupsRef.current.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sortedBrandLayoutInfo && selectedPatnrId) {
|
if (sortedBrandLayoutInfo && selectedPatnrId) {
|
||||||
console.log("[FB-PANEL-DATA-FETCH] Fetching data - patnrId:", selectedPatnrId);
|
console.log("[FB-PANEL-DATA-FETCH] Fetching data - patnrId:", selectedPatnrId);
|
||||||
Object.entries(DISPATCH_MAP) //
|
Object.entries(DISPATCH_MAP) //
|
||||||
@@ -835,6 +854,33 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
|
|||||||
}
|
}
|
||||||
}, [sortedBrandLayoutInfo, selectedPatnrId]);
|
}, [sortedBrandLayoutInfo, selectedPatnrId]);
|
||||||
|
|
||||||
|
// 🆕 [251210] patnrId=21인 경우 모든 카테고리 그룹 데이터 미리 조회
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedPatnrId === 21 || selectedPatnrId === "21") {
|
||||||
|
console.log("[FB-PANEL-CATEGORY-GROUPS] patnrId=21 detected - fetching all category group data");
|
||||||
|
console.log("[FB-PANEL-CATEGORY-GROUPS] brandShopByShowContsList:", brandShopByShowContsList);
|
||||||
|
|
||||||
|
// 각 카테고리(contsId)별 그룹 데이터 조회
|
||||||
|
if (brandShopByShowContsList && brandShopByShowContsList.length > 0) {
|
||||||
|
brandShopByShowContsList.forEach((conts) => {
|
||||||
|
const fetchKey = `${selectedPatnrId}-${conts.contsId}`;
|
||||||
|
|
||||||
|
// useRef로 이미 조회된 contsId 추적 (무한루프 방지)
|
||||||
|
if (!fetchedCategoryGroupsRef.current.has(fetchKey)) {
|
||||||
|
console.log("[FB-PANEL-CATEGORY-GROUPS] Fetching category group for contsId:", conts.contsId);
|
||||||
|
fetchedCategoryGroupsRef.current.add(fetchKey); // 조회 상태 기록
|
||||||
|
dispatch(getBrandShopByShow({
|
||||||
|
patnrId: selectedPatnrId,
|
||||||
|
contsId: conts.contsId
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
console.log("[FB-PANEL-CATEGORY-GROUPS] Category group already fetched for contsId:", conts.contsId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedPatnrId, brandShopByShowContsList, dispatch]); // brandShopByShowCategoryGroups 제거
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedCatCd) {
|
if (selectedCatCd) {
|
||||||
dispatch(
|
dispatch(
|
||||||
|
|||||||
Reference in New Issue
Block a user