From 9d365dcadbd0d291bd3ed8a2a4630f1742d2c61d Mon Sep 17 00:00:00 2001 From: caadiq Date: Wed, 21 Jan 2026 16:26:17 +0900 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20=EB=A9=A4=EB=B2=84=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95=20=EB=B0=8F?= =?UTF-8?q?=20=EC=83=9D=EC=9D=BC=20=EC=9A=B0=EC=84=A0=20=EC=A0=95=EB=A0=AC?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 수정: - AdminSchedule.jsx 1306번 라인 멤버 처리 오류 수정 - getMemberList 헬퍼 함수 사용으로 통일 생일 우선 정렬: - PC 공개 일정 페이지: filteredSchedules에 생일 우선 정렬 추가 - PC 관리 페이지: filteredSchedules에 생일 우선 정렬 추가 - 모바일 공개 페이지: groupedSchedules, selectedDateSchedules에 생일 우선 정렬 추가 Co-Authored-By: Claude Opus 4.5 --- frontend/src/pages/mobile/public/Schedule.jsx | 24 +++++++-- frontend/src/pages/pc/admin/AdminSchedule.jsx | 50 ++++++++++++------- frontend/src/pages/pc/public/Schedule.jsx | 28 +++++++++-- 3 files changed, 76 insertions(+), 26 deletions(-) diff --git a/frontend/src/pages/mobile/public/Schedule.jsx b/frontend/src/pages/mobile/public/Schedule.jsx index 41f7d86..548507b 100644 --- a/frontend/src/pages/mobile/public/Schedule.jsx +++ b/frontend/src/pages/mobile/public/Schedule.jsx @@ -440,7 +440,7 @@ function MobileSchedule() { return category?.color || '#6b7280'; }; - // 날짜별 일정 그룹화 + // 날짜별 일정 그룹화 (생일 우선) const groupedSchedules = useMemo(() => { const groups = {}; schedules.forEach(schedule => { @@ -448,6 +448,16 @@ function MobileSchedule() { if (!groups[date]) groups[date] = []; groups[date].push(schedule); }); + // 각 날짜 그룹 내에서 생일 우선 정렬 + Object.values(groups).forEach(group => { + group.sort((a, b) => { + const aIsBirthday = a.is_birthday || String(a.id).startsWith('birthday-'); + const bIsBirthday = b.is_birthday || String(b.id).startsWith('birthday-'); + if (aIsBirthday && !bIsBirthday) return -1; + if (!aIsBirthday && bIsBirthday) return 1; + return 0; + }); + }); return Object.entries(groups).sort((a, b) => a[0].localeCompare(b[0])); }, [schedules]); @@ -463,7 +473,7 @@ function MobileSchedule() { return days; }, [selectedDate]); - // 선택된 날짜의 일정 + // 선택된 날짜의 일정 (생일 우선) const selectedDateSchedules = useMemo(() => { // KST 기준 날짜 문자열 생성 const year = selectedDate.getFullYear(); @@ -471,7 +481,15 @@ function MobileSchedule() { const day = String(selectedDate.getDate()).padStart(2, '0'); const dateStr = `${year}-${month}-${day}`; // API 응답의 date는 ISO 형식이므로 T 이전 부분만 비교 - return schedules.filter(s => s.date.split('T')[0] === dateStr); + return schedules + .filter(s => s.date.split('T')[0] === dateStr) + .sort((a, b) => { + const aIsBirthday = a.is_birthday || String(a.id).startsWith('birthday-'); + const bIsBirthday = b.is_birthday || String(b.id).startsWith('birthday-'); + if (aIsBirthday && !bIsBirthday) return -1; + if (!aIsBirthday && bIsBirthday) return 1; + return 0; + }); }, [schedules, selectedDate]); // 요일 이름 diff --git a/frontend/src/pages/pc/admin/AdminSchedule.jsx b/frontend/src/pages/pc/admin/AdminSchedule.jsx index e0a25a0..8882ab0 100644 --- a/frontend/src/pages/pc/admin/AdminSchedule.jsx +++ b/frontend/src/pages/pc/admin/AdminSchedule.jsx @@ -575,18 +575,31 @@ function AdminSchedule() { // 일정 목록 (검색 모드일 때 searchResults, 일반 모드일 때 로컬 필터링) - useMemo로 최적화 const filteredSchedules = useMemo(() => { + let result; if (isSearchMode) { if (!searchTerm) return []; // 카테고리 필터링 적용 - if (selectedCategories.length === 0) return searchResults; - return searchResults.filter(s => selectedCategories.includes(s.category_id)); + if (selectedCategories.length === 0) { + result = [...searchResults]; + } else { + result = searchResults.filter(s => selectedCategories.includes(s.category_id)); + } + } else { + // 일반 모드: 로컬 필터링 + result = schedules.filter(schedule => { + const matchesCategory = selectedCategories.length === 0 || selectedCategories.includes(schedule.category_id); + const scheduleDate = formatDate(schedule.date); + const matchesDate = !selectedDate || scheduleDate === selectedDate; + return matchesCategory && matchesDate; + }); } - // 일반 모드: 로컬 필터링 - return schedules.filter(schedule => { - const matchesCategory = selectedCategories.length === 0 || selectedCategories.includes(schedule.category_id); - const scheduleDate = formatDate(schedule.date); - const matchesDate = !selectedDate || scheduleDate === selectedDate; - return matchesCategory && matchesDate; + // 생일 일정을 맨 위로 정렬 + return result.sort((a, b) => { + const aIsBirthday = a.is_birthday || String(a.id).startsWith('birthday-'); + const bIsBirthday = b.is_birthday || String(b.id).startsWith('birthday-'); + if (aIsBirthday && !bIsBirthday) return -1; + if (!aIsBirthday && bIsBirthday) return 1; + return 0; }); }, [isSearchMode, searchTerm, searchResults, schedules, selectedCategories, selectedDate]); @@ -1300,18 +1313,19 @@ function AdminSchedule() { )} - {(schedule.members?.length > 0 || schedule.member_names) && ( -
- {(() => { - const memberList = schedule.members?.map(m => m.name) || schedule.member_names?.split(',') || []; - return memberList.map((name, i) => ( + {(() => { + const memberList = getMemberList(schedule); + if (memberList.length === 0) return null; + return ( +
+ {memberList.map((name, i) => ( - {name.trim()} + {name} - )); - })()} -
- )} + ))} +
+ ); + })()}
diff --git a/frontend/src/pages/pc/public/Schedule.jsx b/frontend/src/pages/pc/public/Schedule.jsx index 0dbe493..ef81dc8 100644 --- a/frontend/src/pages/pc/public/Schedule.jsx +++ b/frontend/src/pages/pc/public/Schedule.jsx @@ -483,27 +483,44 @@ function Schedule() { const currentYearMonth = `${year}-${String(month + 1).padStart(2, '0')}`; const filteredSchedules = useMemo(() => { + // 생일 우선 정렬 함수 + const sortWithBirthdayFirst = (list) => { + return [...list].sort((a, b) => { + const aIsBirthday = a.is_birthday || String(a.id).startsWith('birthday-'); + const bIsBirthday = b.is_birthday || String(b.id).startsWith('birthday-'); + if (aIsBirthday && !bIsBirthday) return -1; + if (!aIsBirthday && bIsBirthday) return 1; + return 0; + }); + }; + // 검색 모드일 때 if (isSearchMode) { // 검색 전엔 빈 목록, 검색 후엔 API 결과 (Meilisearch 유사도순 유지) if (!searchTerm) return []; // 카테고리 필터링 적용 - if (selectedCategories.length === 0) return searchResults; - return searchResults.filter(s => selectedCategories.includes(s.category_id)); + if (selectedCategories.length === 0) return sortWithBirthdayFirst(searchResults); + return sortWithBirthdayFirst(searchResults.filter(s => selectedCategories.includes(s.category_id))); } - + // 일반 모드: 기존 필터링 - return schedules + const filtered = schedules .filter(s => { const scheduleDate = s.date ? s.date.split('T')[0] : ''; - const matchesDate = selectedDate + const matchesDate = selectedDate ? scheduleDate === selectedDate : scheduleDate.startsWith(currentYearMonth); const matchesCategory = selectedCategories.length === 0 || selectedCategories.includes(s.category_id); return matchesDate && matchesCategory; }) .sort((a, b) => { + // 생일 우선 + const aIsBirthday = a.is_birthday || String(a.id).startsWith('birthday-'); + const bIsBirthday = b.is_birthday || String(b.id).startsWith('birthday-'); + if (aIsBirthday && !bIsBirthday) return -1; + if (!aIsBirthday && bIsBirthday) return 1; + // 날짜/시간순 const dateA = a.date ? a.date.split('T')[0] : ''; const dateB = b.date ? b.date.split('T')[0] : ''; if (dateA !== dateB) return dateA.localeCompare(dateB); @@ -511,6 +528,7 @@ function Schedule() { const timeB = b.time || '00:00:00'; return timeA.localeCompare(timeB); }); + return filtered; }, [schedules, selectedDate, currentYearMonth, selectedCategories, isSearchMode, searchTerm, searchResults]); // 가상 스크롤 설정 (검색 모드에서만 활성화, 동적 높이 지원)