diff --git a/backend/routes/schedules.js b/backend/routes/schedules.js index cb737f2..84c5cee 100644 --- a/backend/routes/schedules.js +++ b/backend/routes/schedules.js @@ -7,7 +7,7 @@ const router = express.Router(); // 공개 일정 목록 조회 (검색 포함) router.get("/", async (req, res) => { try { - const { search } = req.query; + const { search, startDate, endDate, limit } = req.query; // 검색어가 있으면 Meilisearch 사용 if (search && search.trim()) { @@ -15,8 +15,25 @@ router.get("/", async (req, res) => { return res.json(results); } + // 날짜 필터 및 제한 조건 구성 + let whereClause = "WHERE 1=1"; + const params = []; + + if (startDate) { + whereClause += " AND s.date >= ?"; + params.push(startDate); + } + if (endDate) { + whereClause += " AND s.date <= ?"; + params.push(endDate); + } + + // limit 파라미터 처리 + const limitClause = limit ? `LIMIT ${parseInt(limit)}` : ""; + // 검색어 없으면 DB에서 전체 조회 - const [schedules] = await pool.query(` + const [schedules] = await pool.query( + ` SELECT s.id, s.title, @@ -34,9 +51,13 @@ router.get("/", async (req, res) => { LEFT JOIN schedule_categories c ON s.category_id = c.id LEFT JOIN schedule_members sm ON s.id = sm.schedule_id LEFT JOIN members m ON sm.member_id = m.id + ${whereClause} GROUP BY s.id - ORDER BY s.date DESC, s.time DESC - `); + ORDER BY s.date ASC, s.time ASC + ${limitClause} + `, + params + ); res.json(schedules); } catch (error) { diff --git a/frontend/src/pages/pc/Home.jsx b/frontend/src/pages/pc/Home.jsx index 7c3212a..aecc689 100644 --- a/frontend/src/pages/pc/Home.jsx +++ b/frontend/src/pages/pc/Home.jsx @@ -1,17 +1,31 @@ import { useState, useEffect } from 'react'; import { motion } from 'framer-motion'; import { Link } from 'react-router-dom'; -import { Calendar, Users, Disc3, ArrowRight } from 'lucide-react'; -import { schedules, albums } from '../../data/dummy'; +import { Calendar, Users, Disc3, ArrowRight, Clock } from 'lucide-react'; function Home() { const [members, setMembers] = useState([]); + const [upcomingSchedules, setUpcomingSchedules] = useState([]); useEffect(() => { + // 멤버 데이터 로드 fetch('/api/members') .then(res => res.json()) .then(data => setMembers(data)) .catch(error => console.error('멤버 데이터 로드 오류:', error)); + + // 다가오는 일정 로드 (오늘 이후 3개) + // KST 기준으로 오늘 날짜 계산 + const now = new Date(); + const kstOffset = 9 * 60; // KST는 UTC+9 + const kstTime = new Date(now.getTime() + (kstOffset + now.getTimezoneOffset()) * 60000); + const todayStr = kstTime.toISOString().split('T')[0]; + + fetch(`/api/schedules?startDate=${todayStr}&limit=3`) + + .then(res => res.json()) + .then(data => setUpcomingSchedules(data)) + .catch(error => console.error('일정 데이터 로드 오류:', error)); }, []); return ( @@ -126,30 +140,87 @@ function Home() { 전체보기 -
- {schedules.slice(0, 3).map((schedule) => ( -
-
-

- {schedule.date.split('-')[2]} -

-

- {schedule.date.split('-')[1]}월 -

-
-
-

{schedule.title}

-

{schedule.platform} · {schedule.time}

-
-
- {schedule.members.join(', ')} -
-
- ))} -
+ {upcomingSchedules.length === 0 ? ( +
+ +

예정된 일정이 없습니다

+
+ ) : ( +
+ {upcomingSchedules.map((schedule, index) => { + const scheduleDate = new Date(schedule.date); + const day = scheduleDate.getDate(); + const weekdays = ['일', '월', '화', '수', '목', '금', '토']; + const weekday = weekdays[scheduleDate.getDay()]; + + // 멤버 처리 + const memberList = schedule.member_names ? schedule.member_names.split(',') : []; + const displayMembers = memberList.length >= 5 ? ['프로미스나인'] : memberList; + + // 카테고리 색상 (기본값) + const categoryColor = schedule.category_color || '#6B8E6B'; + + return ( + + {/* 날짜 영역 */} +
+ {day} + {weekday} +
+ + + {/* 내용 영역 */} +
+

{schedule.title}

+ +
+ {schedule.time && ( +
+ + {schedule.time.slice(0, 5)} +
+ )} + {schedule.category_name && ( +
+ + + {schedule.category_name} + {schedule.source_name && ` · ${schedule.source_name}`} + +
+ )} +
+ + {/* 멤버 태그 */} + {displayMembers.length > 0 && ( +
+ {displayMembers.map((name, i) => ( + + {name.trim()} + + ))} +
+ )} +
+
+ ); + })} +
+ )} + + @@ -157,3 +228,4 @@ function Home() { } export default Home; +