[251104] fix: UserReviewsPanel Review Filters

🕐 커밋 시간: 2025. 11. 04. 09:33:23

📊 변경 통계:
  • 총 파일: 4개
  • 추가: +34줄
  • 삭제: -7줄

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/actions/actionTypes.js
  ~ com.twin.app.shoptime/src/actions/productActions.js
  ~ com.twin.app.shoptime/src/reducers/productReducer.js
  ~ com.twin.app.shoptime/src/views/UserReview/UserReviewPanel.jsx

🔧 주요 변경 내용:
  • 타입 시스템 안정성 강화
  • 핵심 비즈니스 로직 개선
  • 소규모 기능 개선
This commit is contained in:
2025-11-04 09:33:24 +09:00
parent 521b9cb905
commit 74f362bbbc
4 changed files with 34 additions and 7 deletions

View File

@@ -171,6 +171,7 @@ export const types = {
GET_USER_REVIEW_LIST: 'GET_USER_REVIEW_LIST',
GET_REVIEW_FILTERS: 'GET_REVIEW_FILTERS',
GET_FILTERED_REVIEW_LIST: 'GET_FILTERED_REVIEW_LIST',
CLEAR_REVIEW_FILTER: 'CLEAR_REVIEW_FILTER',
TOGGLE_SHOW_ALL_REVIEWS: 'TOGGLE_SHOW_ALL_REVIEWS',
RESET_SHOW_ALL_REVIEWS: 'RESET_SHOW_ALL_REVIEWS',

View File

@@ -626,4 +626,11 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
};
TAxios(dispatch, getState, 'get', URLS.GET_REVIEW_FILTERS, params, body, onSuccess, onFail);
};
// All Star 필터 해제 - API 호출 없이 상태만 초기화
export const clearReviewFilter = () => (dispatch) => {
dispatch({
type: types.CLEAR_REVIEW_FILTER
});
};

View File

@@ -122,6 +122,17 @@ const handleFilteredReviewList = curry((state, action) => {
);
});
// All Star 필터 해제 핸들러 - 필터 상태와 필터링된 데이터를 초기화
const handleClearReviewFilter = curry((state) => {
console.log('[productReducer_clearReviewFilter] 🟡 handleClearReviewFilter: 필터 해제됨');
return set(
'currentReviewFilter',
null,
set('filteredReviewListData', null, state)
);
});
const handlers = {
[types.GET_BEST_SELLER]: handleBestSeller,
[types.GET_PRODUCT_OPTION]: handleProductOption,
@@ -134,6 +145,7 @@ const handlers = {
[types.GET_USER_REVIEW_LIST]: handleUserReviewList,
[types.GET_REVIEW_FILTERS]: handleReviewFilters,
[types.GET_FILTERED_REVIEW_LIST]: handleFilteredReviewList,
[types.CLEAR_REVIEW_FILTER]: handleClearReviewFilter,
[types.TOGGLE_SHOW_ALL_REVIEWS]: handleToggleShowAllReviews,
[types.RESET_SHOW_ALL_REVIEWS]: handleResetShowAllReviews,
};

View File

@@ -4,7 +4,7 @@ import classNames from 'classnames';
import { useDispatch } from 'react-redux';
import { popPanel, updatePanel } from '../../actions/panelActions';
import { getUserReviewList } from '../../actions/productActions';
import { getUserReviewList, clearReviewFilter } from '../../actions/productActions';
import TBody from '../../components/TBody/TBody';
import TPanel from '../../components/TPanel/TPanel';
import useReviews, { REVIEW_VERSION } from '../../hooks/useReviews/useReviews';
@@ -243,7 +243,10 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => {
[prdtId, patnrId, dispatch]
);
const handleAllStarsFilter = useCallback(() => handleApiRatingFilter('all'), [handleApiRatingFilter]);
const handleAllStarsFilter = useCallback(() => {
console.log('[UserReviewPanel] 🔄 All Star 필터 해제');
dispatch(clearReviewFilter());
}, [dispatch]);
const handle5StarsFilter = useCallback(() => handleApiRatingFilter(5), [handleApiRatingFilter]);
const handle4StarsFilter = useCallback(() => handleApiRatingFilter(4), [handleApiRatingFilter]);
const handle3StarsFilter = useCallback(() => handleApiRatingFilter(3), [handleApiRatingFilter]);
@@ -484,7 +487,9 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => {
</div>
<div className={css.reviewsSection__filters__group}>
{keywordsFilterData && keywordsFilterData.length > 0 ? (
keywordsFilterData.map((keyword, index) => (
keywordsFilterData
.filter((keyword) => parseInt(keyword.filterNmCnt, 10) > 0)
.map((keyword, index) => (
<FilterItemButton
key={keyword.filterTpVal}
text={`${keyword.filterNm} (${keyword.filterNmCnt})`}
@@ -492,7 +497,7 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => {
spotlightId={`filter-keyword-${index}`}
ariaLabel={`Filter by ${keyword.filterNm} keyword`}
dataSpotlightUp={index === 0 ? 'filter-1-stars' : `filter-keyword-${index - 1}`}
dataSpotlightDown={index === keywordsFilterData.length - 1 ? 'filter-positive' : `filter-keyword-${index + 1}`}
dataSpotlightDown={index === keywordsFilterData.filter((k) => parseInt(k.filterNmCnt, 10) > 0).length - 1 ? 'filter-positive' : `filter-keyword-${index + 1}`}
isActive={currentReviewFilter?.filterTpCd === 'KEYWORDS' && currentReviewFilter?.filterTpVal === keyword.filterTpVal}
/>
))
@@ -542,15 +547,17 @@ const UserReviewPanel = ({ className, panelInfo, spotlightId }) => {
</div>
<div className={css.reviewsSection__filters__group}>
{sentimentFilterData && Object.keys(sentimentFilterData).length > 0 ? (
Object.entries(sentimentFilterData).map(([sentiment, count], index) => (
Object.entries(sentimentFilterData)
.filter(([, count]) => count > 0)
.map(([sentiment, count], index) => (
<FilterItemButton
key={sentiment}
text={`${sentiment.charAt(0).toUpperCase() + sentiment.slice(1)} (${count})`}
onClick={() => handleApiSentimentFilter(sentiment)}
spotlightId={`filter-sentiment-${sentiment}`}
ariaLabel={`Filter by ${sentiment} sentiment`}
dataSpotlightUp={index === 0 ? 'filter-quality' : `filter-sentiment-${Object.keys(sentimentFilterData)[index - 1]}`}
dataSpotlightDown={index === Object.keys(sentimentFilterData).length - 1 ? undefined : `filter-sentiment-${Object.keys(sentimentFilterData)[index + 1]}`}
dataSpotlightUp={index === 0 ? 'filter-quality' : `filter-sentiment-${Object.entries(sentimentFilterData).filter(([, c]) => c > 0)[index - 1][0]}`}
dataSpotlightDown={index === Object.entries(sentimentFilterData).filter(([, c]) => c > 0).length - 1 ? undefined : `filter-sentiment-${Object.entries(sentimentFilterData).filter(([, c]) => c > 0)[index + 1][0]}`}
isActive={currentReviewFilter?.filterTpCd === 'SENTIMENT' && currentReviewFilter?.filterTpVal === sentiment}
/>
))