From 5724d4506536fc0d8fdb949afe7033abe792f9a3 Mon Sep 17 00:00:00 2001 From: hyejj19 Date: Sat, 4 Apr 2026 14:08:48 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EC=9D=B4=EC=8A=88=203=EA=B1=B4=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - WhiskyList 카테고리 서브라벨이 필터값을 표시하던 버그 수정 (getCategoryGroup 사용) - 배럴 파일 import를 직접 모듈 import로 변경 (CLAUDE.md 준수) - CategoryReference.categoryGroup을 optional로 수정 및 타입 단언 제거 Co-Authored-By: Claude Opus 4.6 --- src/hooks/__tests__/useAdminAlcohols.test.ts | 57 +++++++++++++++++++- src/pages/whisky/WhiskyList.tsx | 20 ++++--- src/test/mocks/data.ts | 21 ++++++++ src/types/api/alcohol.api.ts | 55 ++++++++++++++++++- 4 files changed, 143 insertions(+), 10 deletions(-) diff --git a/src/hooks/__tests__/useAdminAlcohols.test.ts b/src/hooks/__tests__/useAdminAlcohols.test.ts index 7e2da80..3487c60 100644 --- a/src/hooks/__tests__/useAdminAlcohols.test.ts +++ b/src/hooks/__tests__/useAdminAlcohols.test.ts @@ -4,7 +4,8 @@ import { http, HttpResponse } from 'msw'; import { server } from '@/test/mocks/server'; import { renderHook } from '@/test/test-utils'; import { wrapApiError } from '@/test/mocks/data'; -import { useAdminAlcoholList } from '../useAdminAlcohols'; +import { useAdminAlcoholList, useCategoryReferences } from '../useAdminAlcohols'; +import { getCategoryGroup } from '@/types/api/alcohol.api'; const BASE = '/admin/api/v1/alcohols'; @@ -72,4 +73,58 @@ describe('useAdminAlcohols hooks', () => { expect(result.current.data!.meta.totalElements).toBeGreaterThan(0); }); }); + + // ========================================== + // useCategoryReferences + // ========================================== + describe('useCategoryReferences', () => { + it('카테고리 레퍼런스 목록을 반환한다', async () => { + const { result } = renderHook(() => useCategoryReferences()); + + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + + expect(result.current.data!.length).toBeGreaterThan(0); + }); + + it('실제 API 응답에는 categoryGroup이 없다', async () => { + const { result } = renderHook(() => useCategoryReferences()); + + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + + // 백엔드 CategoryReference API는 categoryGroup을 내려주지 않음 + result.current.data!.forEach((ref) => { + expect(ref.categoryGroup).toBeUndefined(); + }); + }); + }); + + // ========================================== + // getCategoryGroup (프론트엔드 매핑) + // ========================================== + describe('getCategoryGroup', () => { + it('메인 카테고리를 올바른 그룹으로 매핑한다', () => { + expect(getCategoryGroup('싱글 몰트')).toBe('SINGLE_MALT'); + expect(getCategoryGroup('블렌디드')).toBe('BLEND'); + expect(getCategoryGroup('블렌디드 몰트')).toBe('BLENDED_MALT'); + expect(getCategoryGroup('버번')).toBe('BOURBON'); + expect(getCategoryGroup('라이')).toBe('RYE'); + }); + + it('싱글몰트 알코올 변형도 SINGLE_MALT로 매핑한다', () => { + expect(getCategoryGroup('싱글몰트 알코올')).toBe('SINGLE_MALT'); + }); + + it('기타 하위 카테고리는 OTHER로 매핑한다', () => { + expect(getCategoryGroup('테네시')).toBe('OTHER'); + expect(getCategoryGroup('싱글 그레인')).toBe('OTHER'); + expect(getCategoryGroup('싱글 팟 스틸')).toBe('OTHER'); + expect(getCategoryGroup('위트')).toBe('OTHER'); + expect(getCategoryGroup('콘')).toBe('OTHER'); + expect(getCategoryGroup('스피릿')).toBe('OTHER'); + }); + + it('알 수 없는 카테고리도 OTHER로 매핑한다', () => { + expect(getCategoryGroup('새로운카테고리')).toBe('OTHER'); + }); + }); }); diff --git a/src/pages/whisky/WhiskyList.tsx b/src/pages/whisky/WhiskyList.tsx index 71cbb1e..15586f6 100644 --- a/src/pages/whisky/WhiskyList.tsx +++ b/src/pages/whisky/WhiskyList.tsx @@ -31,15 +31,14 @@ import { Badge } from '@/components/ui/badge'; import { Pagination } from '@/components/common/Pagination'; import { useAdminAlcoholList } from '@/hooks/useAdminAlcohols'; import type { AlcoholSearchParams, AlcoholCategory } from '@/types/api'; +import { ALCOHOL_CATEGORIES, CATEGORY_GROUP_LABELS, getCategoryGroup } from '@/types/api'; const CATEGORY_OPTIONS: { value: AlcoholCategory | 'ALL'; label: string }[] = [ { value: 'ALL', label: '전체' }, - { value: 'SINGLE_MALT', label: '싱글몰트' }, - { value: 'BLEND', label: '블렌디드' }, - { value: 'BLENDED_MALT', label: '블렌디드 몰트' }, - { value: 'BOURBON', label: '버번' }, - { value: 'RYE', label: '라이' }, - { value: 'OTHER', label: '기타' }, + ...ALCOHOL_CATEGORIES.map((value) => ({ + value, + label: CATEGORY_GROUP_LABELS[value], + })), ]; export function WhiskyListPage() { @@ -246,7 +245,14 @@ export function WhiskyListPage() { {item.engName} - {item.korCategoryName} + +
+ {item.korCategoryName} + + {CATEGORY_GROUP_LABELS[getCategoryGroup(item.korCategoryName)]} + +
+
{new Date(item.modifiedAt).toLocaleDateString('ko-KR')} diff --git a/src/test/mocks/data.ts b/src/test/mocks/data.ts index 4929f2c..50f7bb0 100644 --- a/src/test/mocks/data.ts +++ b/src/test/mocks/data.ts @@ -7,6 +7,7 @@ import type { TastingTagAlcohol, AlcoholListItem, AlcoholDeleteResponse, + CategoryReference, BannerListItem, BannerDetail, BannerCreateResponse, @@ -158,6 +159,26 @@ export const mockAlcoholDeleteResponse: AlcoholDeleteResponse = { responseAt: '2024-06-01T00:00:00', }; +// ============================================ +// Category Reference Mock Data +// ============================================ + +/** 실제 API 응답과 동일한 구조 (categoryGroup 없음) */ +export const mockCategoryReferences: CategoryReference[] = [ + { korCategory: '라이', engCategory: 'Rye' }, + { korCategory: '버번', engCategory: 'Bourbon' }, + { korCategory: '블렌디드', engCategory: 'Blend' }, + { korCategory: '블렌디드 몰트', engCategory: 'Blended Malt' }, + { korCategory: '스피릿', engCategory: 'Spirit' }, + { korCategory: '싱글 그레인', engCategory: 'Single Grain' }, + { korCategory: '싱글 몰트', engCategory: 'Single Malt' }, + { korCategory: '싱글 팟 스틸', engCategory: 'Single Pot Still' }, + { korCategory: '싱글몰트 알코올', engCategory: 'Single Malts' }, + { korCategory: '위트', engCategory: 'Wheat' }, + { korCategory: '콘', engCategory: 'Corn' }, + { korCategory: '테네시', engCategory: 'Tennessee' }, +]; + // ============================================ // Banner Mock Data // ============================================ diff --git a/src/types/api/alcohol.api.ts b/src/types/api/alcohol.api.ts index 693404a..b4ad3c4 100644 --- a/src/types/api/alcohol.api.ts +++ b/src/types/api/alcohol.api.ts @@ -347,6 +347,57 @@ export type AlcoholUpdateRequest = AlcoholApiTypes['update']['request']; /** 술 수정 응답 데이터 */ export type AlcoholUpdateResponse = AlcoholApiTypes['update']['response']; +// ============================================ +// 카테고리 그룹 라벨 +// ============================================ + +/** 카테고리 그룹별 한글 라벨 */ +export const CATEGORY_GROUP_LABELS: Record = { + SINGLE_MALT: '싱글몰트', + BLEND: '블렌디드', + BLENDED_MALT: '블렌디드 몰트', + BOURBON: '버번', + RYE: '라이', + OTHER: '기타', +}; + +/** 카테고리 그룹 키 목록 (타입 안전) */ +export const ALCOHOL_CATEGORIES: AlcoholCategory[] = Object.keys(CATEGORY_GROUP_LABELS) as AlcoholCategory[]; + +/** + * korCategory → categoryGroup 매핑 + * 메인 5개 그룹에 해당하는 카테고리만 명시, 나머지는 모두 OTHER + */ +const CATEGORY_TO_GROUP_MAP: Record = { + '싱글 몰트': 'SINGLE_MALT', + '싱글몰트 알코올': 'SINGLE_MALT', + '블렌디드': 'BLEND', + '블렌디드 몰트': 'BLENDED_MALT', + '버번': 'BOURBON', + '라이': 'RYE', +}; + +/** + * korCategory 문자열로부터 categoryGroup을 결정한다. + * CategoryReference API가 categoryGroup을 내려주지 않으므로 프론트에서 매핑. + * 메인 5개 그룹에 해당하지 않으면 OTHER로 분류. + */ +export function getCategoryGroup(korCategory: string): AlcoholCategory { + return CATEGORY_TO_GROUP_MAP[korCategory] ?? 'OTHER'; +} + +/** + * categoryGroup → 고정 카테고리 이름 매핑 (메인 5개 그룹용) + * OTHER는 자유 입력이므로 포함하지 않음 + */ +export const GROUP_TO_CATEGORY: Record, { korCategory: string; engCategory: string }> = { + SINGLE_MALT: { korCategory: '싱글 몰트', engCategory: 'Single Malt' }, + BLEND: { korCategory: '블렌디드', engCategory: 'Blend' }, + BLENDED_MALT: { korCategory: '블렌디드 몰트', engCategory: 'Blended Malt' }, + BOURBON: { korCategory: '버번', engCategory: 'Bourbon' }, + RYE: { korCategory: '라이', engCategory: 'Rye' }, +}; + // ============================================ // 카테고리 레퍼런스 타입 // ============================================ @@ -357,6 +408,6 @@ export interface CategoryReference { korCategory: string; /** 영문 카테고리 */ engCategory: string; - /** 카테고리 그룹 */ - categoryGroup: AlcoholCategory; + /** 카테고리 그룹 (API 응답에 포함되지 않을 수 있음) */ + categoryGroup?: AlcoholCategory; } From 4aa6ff37d6e5fe1d5fc6815249edd46bf6d2629e Mon Sep 17 00:00:00 2001 From: Hyejung Park Date: Sat, 4 Apr 2026 14:17:45 +0900 Subject: [PATCH 2/2] Bump version from 1.2.6 to 1.2.7 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3c43790..c04c650 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.6 +1.2.7