diff --git a/frontend-temp/src/components/index.js b/frontend-temp/src/components/index.js
index fb45a36..553d53f 100644
--- a/frontend-temp/src/components/index.js
+++ b/frontend-temp/src/components/index.js
@@ -1,6 +1,9 @@
// 공통 컴포넌트 (디바이스 무관)
export * from './common';
+// 스케줄 컴포넌트
+export * from './schedule';
+
// PC 컴포넌트
export * as PC from './pc';
diff --git a/frontend-temp/src/components/schedule/MobileScheduleCard.jsx b/frontend-temp/src/components/schedule/MobileScheduleCard.jsx
new file mode 100644
index 0000000..754d725
--- /dev/null
+++ b/frontend-temp/src/components/schedule/MobileScheduleCard.jsx
@@ -0,0 +1,101 @@
+import { Clock, Tag, Link2 } from 'lucide-react';
+
+/**
+ * Mobile 일정 카드 컴포넌트
+ * 홈, 스케줄 페이지 등에서 공통으로 사용
+ */
+function MobileScheduleCard({ schedule, onClick, className = '' }) {
+ const scheduleDate = new Date(schedule.date);
+ const today = new Date();
+ const currentYear = today.getFullYear();
+ const currentMonth = today.getMonth();
+
+ const scheduleYear = scheduleDate.getFullYear();
+ const scheduleMonth = scheduleDate.getMonth();
+ const isCurrentYear = scheduleYear === currentYear;
+ const isCurrentMonth = isCurrentYear && scheduleMonth === currentMonth;
+
+ // 멤버 처리
+ const memberList = schedule.member_names
+ ? schedule.member_names.split(',').map((n) => n.trim()).filter(Boolean)
+ : schedule.members?.map((m) => m.name) || [];
+
+ // 5명 이상이면 '프로미스나인'으로 표시
+ const displayMembers = memberList.length >= 5 ? ['프로미스나인'] : memberList;
+
+ const categoryName = schedule.category_name || schedule.category?.name;
+ const sourceName = schedule.source?.name;
+
+ return (
+
+ {/* 날짜 영역 */}
+
+ {!isCurrentYear && (
+
+ {scheduleYear}.{scheduleMonth + 1}
+
+ )}
+ {isCurrentYear && !isCurrentMonth && (
+
+ {scheduleMonth + 1}월
+
+ )}
+
+ {scheduleDate.getDate()}
+
+
+ {['일', '월', '화', '수', '목', '금', '토'][scheduleDate.getDay()]}
+
+
+
+ {/* 세로 구분선 */}
+
+
+ {/* 내용 영역 */}
+
+
+ {schedule.title}
+
+ {/* 시간 + 카테고리 + 소스 */}
+
+ {schedule.time && (
+
+
+ {schedule.time.slice(0, 5)}
+
+ )}
+ {categoryName && (
+
+
+ {categoryName}
+
+ )}
+ {sourceName && (
+
+
+ {sourceName}
+
+ )}
+
+ {/* 멤버 */}
+ {displayMembers.length > 0 && (
+
+ {displayMembers.map((name, i) => (
+
+ {name}
+
+ ))}
+
+ )}
+
+
+ );
+}
+
+export default MobileScheduleCard;
diff --git a/frontend-temp/src/components/schedule/ScheduleCard.jsx b/frontend-temp/src/components/schedule/ScheduleCard.jsx
new file mode 100644
index 0000000..82e1b70
--- /dev/null
+++ b/frontend-temp/src/components/schedule/ScheduleCard.jsx
@@ -0,0 +1,98 @@
+import { Clock, Tag, Link2 } from 'lucide-react';
+
+/**
+ * PC 일정 카드 컴포넌트
+ * 홈, 스케줄 페이지 등에서 공통으로 사용
+ */
+function ScheduleCard({ schedule, onClick, className = '' }) {
+ const scheduleDate = new Date(schedule.date);
+ const today = new Date();
+ const currentYear = today.getFullYear();
+ const currentMonth = today.getMonth();
+
+ const scheduleYear = scheduleDate.getFullYear();
+ const scheduleMonth = scheduleDate.getMonth();
+ const isCurrentYear = scheduleYear === currentYear;
+ const isCurrentMonth = isCurrentYear && scheduleMonth === currentMonth;
+
+ const day = scheduleDate.getDate();
+ const weekdays = ['일', '월', '화', '수', '목', '금', '토'];
+ const weekday = weekdays[scheduleDate.getDay()];
+
+ // 멤버 처리
+ const memberList = schedule.member_names
+ ? schedule.member_names.split(',').map((n) => n.trim()).filter(Boolean)
+ : schedule.members?.map((m) => m.name) || [];
+
+ // 5명 이상이면 '프로미스나인'으로 표시
+ const displayMembers = memberList.length >= 5 ? ['프로미스나인'] : memberList;
+
+ const categoryColor = schedule.category_color || '#6366f1';
+ const categoryName = schedule.category_name || schedule.category?.name;
+ const sourceName = schedule.source?.name;
+
+ return (
+
+ {/* 날짜 영역 */}
+
+ {!isCurrentYear && (
+
+ {scheduleYear}.{scheduleMonth + 1}
+
+ )}
+ {isCurrentYear && !isCurrentMonth && (
+
+ {scheduleMonth + 1}월
+
+ )}
+ {day}
+ {weekday}
+
+
+ {/* 내용 영역 */}
+
+
{schedule.title}
+
+ {schedule.time && (
+
+
+ {schedule.time.slice(0, 5)}
+
+ )}
+ {categoryName && (
+
+
+ {categoryName}
+
+ )}
+ {sourceName && (
+
+
+ {sourceName}
+
+ )}
+
+ {displayMembers.length > 0 && (
+
+ {displayMembers.map((name, i) => (
+
+ {name}
+
+ ))}
+
+ )}
+
+
+ );
+}
+
+export default ScheduleCard;
diff --git a/frontend-temp/src/components/schedule/index.js b/frontend-temp/src/components/schedule/index.js
new file mode 100644
index 0000000..94dd3e2
--- /dev/null
+++ b/frontend-temp/src/components/schedule/index.js
@@ -0,0 +1,2 @@
+export { default as ScheduleCard } from './ScheduleCard';
+export { default as MobileScheduleCard } from './MobileScheduleCard';
diff --git a/frontend-temp/src/pages/home/mobile/Home.jsx b/frontend-temp/src/pages/home/mobile/Home.jsx
index 9c1dd03..46f87e8 100644
--- a/frontend-temp/src/pages/home/mobile/Home.jsx
+++ b/frontend-temp/src/pages/home/mobile/Home.jsx
@@ -1,7 +1,8 @@
import { motion } from 'framer-motion';
-import { ChevronRight, Clock, Tag } from 'lucide-react';
+import { ChevronRight } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import { useMembers, useAlbums, useUpcomingSchedules } from '@/hooks';
+import { MobileScheduleCard } from '@/components';
/**
* Mobile 홈 페이지
@@ -157,101 +158,20 @@ function MobileHome() {
{schedules.length > 0 ? (
- {schedules.map((schedule, index) => {
- const scheduleDate = new Date(schedule.date);
- const today = new Date();
- const currentYear = today.getFullYear();
- const currentMonth = today.getMonth();
-
- const scheduleYear = scheduleDate.getFullYear();
- const scheduleMonth = scheduleDate.getMonth();
- const isCurrentYear = scheduleYear === currentYear;
- const isCurrentMonth =
- isCurrentYear && scheduleMonth === currentMonth;
-
- // 멤버 처리
- const memberList = schedule.member_names
- ? schedule.member_names
- .split(',')
- .map((n) => n.trim())
- .filter(Boolean)
- : schedule.members?.map((m) => m.name) || [];
-
- return (
-
(
+
+ navigate('/schedule')}
- >
- {/* 날짜 영역 */}
-
- {!isCurrentYear && (
-
- {scheduleYear}.{scheduleMonth + 1}
-
- )}
- {isCurrentYear && !isCurrentMonth && (
-
- {scheduleMonth + 1}월
-
- )}
-
- {scheduleDate.getDate()}
-
-
- {
- ['일', '월', '화', '수', '목', '금', '토'][
- scheduleDate.getDay()
- ]
- }
-
-
-
- {/* 세로 구분선 */}
-
-
- {/* 내용 영역 */}
-
-
- {schedule.title}
-
- {/* 시간 + 카테고리 */}
-
- {schedule.time && (
-
-
- {schedule.time.slice(0, 5)}
-
- )}
- {schedule.category_name && (
-
-
- {schedule.category_name}
- {schedule.source?.name && ` · ${schedule.source.name}`}
-
- )}
-
- {/* 멤버 */}
- {memberList.length > 0 && (
-
- {memberList.map((name, i) => (
-
- {name.trim()}
-
- ))}
-
- )}
-
-
- );
- })}
+ />
+
+ ))}
) : (
diff --git a/frontend-temp/src/pages/home/pc/Home.jsx b/frontend-temp/src/pages/home/pc/Home.jsx
index d3624bc..527e1e7 100644
--- a/frontend-temp/src/pages/home/pc/Home.jsx
+++ b/frontend-temp/src/pages/home/pc/Home.jsx
@@ -1,7 +1,8 @@
import { motion } from 'framer-motion';
import { Link } from 'react-router-dom';
-import { Calendar, ArrowRight, Clock, Tag, Music } from 'lucide-react';
+import { Calendar, ArrowRight, Music } from 'lucide-react';
import { useMembers, useAlbums, useUpcomingSchedules } from '@/hooks';
+import { ScheduleCard } from '@/components';
/**
* PC 홈 페이지
@@ -218,95 +219,21 @@ function Home() {
visible: { opacity: 1, transition: { staggerChildren: 0.1 } },
}}
>
- {upcomingSchedules.map((schedule) => {
- const scheduleDate = new Date(schedule.date);
- const todayDate = new Date();
- const currentYear = todayDate.getFullYear();
- const currentMonth = todayDate.getMonth();
-
- const scheduleYear = scheduleDate.getFullYear();
- const scheduleMonth = scheduleDate.getMonth();
- const isCurrentYear = scheduleYear === currentYear;
- const isCurrentMonth =
- isCurrentYear && scheduleMonth === currentMonth;
-
- const day = scheduleDate.getDate();
- const weekdays = ['일', '월', '화', '수', '목', '금', '토'];
- const weekday = weekdays[scheduleDate.getDay()];
-
- // 멤버 처리
- const memberList = schedule.member_names
- ? schedule.member_names.split(',')
- : schedule.members?.map((m) => m.name) || [];
-
- const categoryColor = schedule.category_color || '#6366f1';
-
- return (
-
- {/* 날짜 영역 */}
-
- {!isCurrentYear && (
-
- {scheduleYear}.{scheduleMonth + 1}
-
- )}
- {isCurrentYear && !isCurrentMonth && (
-
- {scheduleMonth + 1}월
-
- )}
- {day}
-
- {weekday}
-
-
-
- {/* 내용 영역 */}
-
-
{schedule.title}
-
- {schedule.time && (
-
-
- {schedule.time.slice(0, 5)}
-
- )}
-
-
- {schedule.category_name}
- {schedule.source?.name && ` · ${schedule.source.name}`}
-
-
- {memberList.length > 0 && (
-
- {memberList.map((name, i) => (
-
- {name.trim()}
-
- ))}
-
- )}
-
-
- );
- })}
+ {upcomingSchedules.map((schedule) => (
+
+
+
+ ))}
)}