From 41f85d92a7f1cb3437bd62bfdfca813b30bcab4f Mon Sep 17 00:00:00 2001 From: fr0gydev Date: Thu, 14 Aug 2025 11:22:36 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EC=83=88=20=EA=B8=80=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20=EB=B0=8F=20=ED=83=9C=EA=B7=B8=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20API=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/feeds/getWriteInfo.ts | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/api/feeds/getWriteInfo.ts diff --git a/src/api/feeds/getWriteInfo.ts b/src/api/feeds/getWriteInfo.ts new file mode 100644 index 00000000..8e4d3ec8 --- /dev/null +++ b/src/api/feeds/getWriteInfo.ts @@ -0,0 +1,38 @@ +import { apiClient } from '../index'; + +// 카테고리 및 태그 데이터 타입 +export interface CategoryData { + category: string; + tagList: string[]; +} + +// API 응답 데이터 타입 +export interface WriteInfoData { + categoryList: CategoryData[]; +} + +// API 응답 타입 +export interface GetWriteInfoResponse { + isSuccess: boolean; + code: number; + message: string; + data: WriteInfoData; +} + +// 새 글 작성을 위한 카테고리 및 태그 조회 API 함수 +export const getWriteInfo = async () => { + const response = await apiClient.get('/feeds/write-info'); + return response.data; +}; + +/* +사용 예시: +const writeInfo = await getWriteInfo(); +console.log(writeInfo.data.categoryList); // CategoryData[] + +// 카테고리별 태그 접근 +writeInfo.data.categoryList.forEach(category => { + console.log(`카테고리: ${category.category}`); + console.log(`태그: ${category.tagList.join(', ')}`); +}); +*/ From 634b041109819e01ad6318ae2f613f59d9ab2be5 Mon Sep 17 00:00:00 2001 From: fr0gydev Date: Thu, 14 Aug 2025 11:23:20 +0900 Subject: [PATCH 2/2] =?UTF-8?q?refactor:=20TagSelectionSection=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EB=A5=BC=20API=20=EC=97=B0=EB=8F=99?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../createpost/TagSelectionSection.tsx | 70 +++++++++++++------ 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/src/components/createpost/TagSelectionSection.tsx b/src/components/createpost/TagSelectionSection.tsx index 78884b97..311dbd6b 100644 --- a/src/components/createpost/TagSelectionSection.tsx +++ b/src/components/createpost/TagSelectionSection.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { Section, SectionTitle } from '../../pages/group/CommonSection.styled'; import { TagContainer, @@ -13,28 +13,42 @@ import { TagCount, } from './TagSelectionSection.styled'; import closeIcon from '../../assets/post/close.svg'; +import { getWriteInfo, type CategoryData } from '@/api/feeds/getWriteInfo'; interface TagSelectionSectionProps { selectedTags: string[]; onTagToggle: (tag: string) => void; } -// 상위 장르와 하위 태그 매핑 -const genreTagsMap: Record = { - 문학: ['소설', '시', '에세이', '인문학', '철학'], - '과학·IT': ['기술', '과학', 'AI', '데이터'], - 사회과학: ['정치', '경제', '사회학', '심리학', '역사'], - 인문학: ['철학', '역사', '문화', '언어학', '종교'], - 예술: ['미술', '음악', '영화', '디자인', '사진'], -}; +const TagSelectionSection = ({ selectedTags, onTagToggle }: TagSelectionSectionProps) => { + const [categories, setCategories] = useState([]); + const [selectedCategory, setSelectedCategory] = useState(''); + const [loading, setLoading] = useState(true); -const availableGenres = Object.keys(genreTagsMap); + // API에서 카테고리 및 태그 데이터 로드 + useEffect(() => { + const loadWriteInfo = async () => { + try { + setLoading(true); + const response = await getWriteInfo(); -const TagSelectionSection = ({ selectedTags, onTagToggle }: TagSelectionSectionProps) => { - const [selectedGenre, setSelectedGenre] = useState('문학'); + if (response.isSuccess && response.data.categoryList.length > 0) { + setCategories(response.data.categoryList); + // 첫 번째 카테고리를 기본 선택 + setSelectedCategory(response.data.categoryList[0].category); + } + } catch (error) { + console.error('카테고리 정보 로드 실패:', error); + } finally { + setLoading(false); + } + }; - const handleGenreSelect = (genre: string) => { - setSelectedGenre(genre); + loadWriteInfo(); + }, []); + + const handleCategorySelect = (category: string) => { + setSelectedCategory(category); }; const handleTagToggle = (tag: string) => { @@ -54,28 +68,38 @@ const TagSelectionSection = ({ selectedTags, onTagToggle }: TagSelectionSectionP onTagToggle(tag); }; - const currentSubTags = genreTagsMap[selectedGenre] || []; + // 현재 선택된 카테고리의 태그 목록 + const currentTags = categories.find(cat => cat.category === selectedCategory)?.tagList || []; + + if (loading) { + return ( +
+ 태그 + +
로딩 중...
+
+
+ ); + } return (
태그 - {/* 상위 장르 선택 */} - {availableGenres.map(genre => ( + {categories.map(categoryData => ( handleGenreSelect(genre)} + key={categoryData.category} + active={selectedCategory === categoryData.category} + onClick={() => handleCategorySelect(categoryData.category)} > - {genre} + {categoryData.category} ))} - {/* 하위 태그 그리드 */} - {currentSubTags.map(tag => ( + {currentTags.map(tag => (