[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_EXCEPT_BRAND_INFO: 'RESET_BRAND_STATE_EXCEPT_BRAND_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
|
||||
GET_SUB_CATEGORY: 'GET_SUB_CATEGORY',
|
||||
|
||||
@@ -410,6 +410,8 @@ export const getBrandShopByShow = (props) => (dispatch, getState) => {
|
||||
type: types.GET_BRAND_SHOP_BY_SHOW,
|
||||
payload: {
|
||||
data: response.data.data,
|
||||
patnrId,
|
||||
contsId,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -52,6 +52,9 @@ const initialState = {
|
||||
brandTopBannerData: {
|
||||
data: {},
|
||||
},
|
||||
|
||||
// 🆕 [251210] patnrId=21 카테고리 그룹 데이터 저장소
|
||||
brandShopByShowCategoryGroups: {},
|
||||
};
|
||||
|
||||
export const brandReducer = (state = initialState, action) => {
|
||||
@@ -174,12 +177,31 @@ export const brandReducer = (state = initialState, action) => {
|
||||
? nextData
|
||||
: { ...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 {
|
||||
...state,
|
||||
brandShopByShowData: {
|
||||
...action.payload,
|
||||
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:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -1108,6 +1108,7 @@ export default function ProductAllSection({
|
||||
const descriptionRef = useRef(null);
|
||||
const reviewRef = useRef(null);
|
||||
const youMayAlsoLikelRef = useRef(null);
|
||||
const seeMoreProductsRef = useRef(null);
|
||||
const prevMediaPanelModalStateRef = useRef(null); // MediaPanel의 이전 modal 상태 추적
|
||||
|
||||
// 동영상과 이미지를 통합한 렌더링 아이템 리스트 생성 (Indicator.jsx 로직 기반)
|
||||
@@ -1264,6 +1265,15 @@ export default function ProductAllSection({
|
||||
Spotlight.focus("detail_youMayAlsoLike_area")
|
||||
},100);
|
||||
}, [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 아이콘에서 아래로 내려올 때 첫 번째 버튼을 바라보도록 설정
|
||||
useEffect(() => {
|
||||
const firstId = stackOrder[0];
|
||||
@@ -1751,10 +1761,27 @@ export default function ProductAllSection({
|
||||
activeButton === 'youmaylike' ? css.active : ''
|
||||
)}
|
||||
onClick={handleYouMayAlsoLikeClick}
|
||||
onFocus={() => handleButtonFocus('youmaylike')}
|
||||
onBlur={handleButtonBlur}
|
||||
>
|
||||
{$L('YOU MAY ALSO LIKE')}
|
||||
</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 버튼 렌더링 상태 로그 */}
|
||||
{/* {(() => {
|
||||
console.log('[YouMayLike] 버튼 렌더링 체크:', {
|
||||
@@ -1938,6 +1965,20 @@ export default function ProductAllSection({
|
||||
</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}>
|
||||
<TButton
|
||||
|
||||
@@ -280,6 +280,10 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
|
||||
const brandTopBannerInfo = useSelector(
|
||||
(state) => state.brand.brandTopBannerData.data.brandTopBannerInfo
|
||||
);
|
||||
// 🆕 [251210] patnrId=21 카테고리 그룹 데이터
|
||||
const brandShopByShowCategoryGroups = useSelector(
|
||||
(state) => state.brand.brandShopByShowCategoryGroups
|
||||
);
|
||||
|
||||
const [displayTopButton, setDisplayTopButton] = useState(false);
|
||||
const [focusedContainerId, setFocusedContainerId] = useState(null);
|
||||
@@ -310,6 +314,9 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
|
||||
});
|
||||
const renderedShelfCountRef = useRef(0);
|
||||
|
||||
// 🆕 [251210] patnrId=21 카테고리 그룹 조회 상태 추적
|
||||
const fetchedCategoryGroupsRef = useRef(new Set());
|
||||
|
||||
const fromDetail = panelInfo?.from && panelInfo.from === "detail";
|
||||
const fromGNB = panelInfo?.from && panelInfo.from === "gnb";
|
||||
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] 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) {
|
||||
console.log("[FB-PANEL-DATA-FETCH] Fetching data - patnrId:", selectedPatnrId);
|
||||
Object.entries(DISPATCH_MAP) //
|
||||
@@ -835,6 +854,33 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
|
||||
}
|
||||
}, [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(() => {
|
||||
if (selectedCatCd) {
|
||||
dispatch(
|
||||
|
||||
Reference in New Issue
Block a user