refactor: UI 개선 및 날짜 제한 수정
- 멤버 페이지에서 포지션 영역 제거 (PC/모바일) - 모바일 일정 페이지 멤버 표시 로직 API 응답에 맞게 수정 - 데이트픽커 연도 제한 2025 → 2017로 변경 - 2017년 1월에서 이전 달 버튼 비활성화 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
4a4a163abe
commit
8e15cd6d2c
5 changed files with 59 additions and 57 deletions
|
|
@ -178,16 +178,9 @@ function MobileMembers() {
|
||||||
{member.name}
|
{member.name}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* 포지션 */}
|
|
||||||
{member.position && (
|
|
||||||
<p className="mt-2 text-base text-white/90 font-medium">
|
|
||||||
{member.position}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 생일 정보 */}
|
{/* 생일 정보 */}
|
||||||
{member.birth_date && (
|
{member.birth_date && (
|
||||||
<div className="flex items-center gap-1.5 mt-3 text-white/80">
|
<div className="flex items-center gap-1.5 mt-1.5 text-white/80">
|
||||||
<Calendar size={16} className="text-white/70" />
|
<Calendar size={16} className="text-white/70" />
|
||||||
<span className="text-sm">
|
<span className="text-sm">
|
||||||
{member.birth_date?.slice(0, 10).replaceAll('-', '.')}
|
{member.birth_date?.slice(0, 10).replaceAll('-', '.')}
|
||||||
|
|
|
||||||
|
|
@ -324,8 +324,13 @@ function MobileSchedule() {
|
||||||
}
|
}
|
||||||
}, [schedules, loading]);
|
}, [schedules, loading]);
|
||||||
|
|
||||||
|
// 2017년 1월 이전으로 이동 불가
|
||||||
|
const canGoPrevMonth = !(selectedDate.getFullYear() === 2017 && selectedDate.getMonth() === 0);
|
||||||
|
|
||||||
// 월 변경
|
// 월 변경
|
||||||
const changeMonth = (delta) => {
|
const changeMonth = (delta) => {
|
||||||
|
if (delta < 0 && !canGoPrevMonth) return;
|
||||||
|
|
||||||
const newDate = new Date(selectedDate);
|
const newDate = new Date(selectedDate);
|
||||||
newDate.setMonth(newDate.getMonth() + delta);
|
newDate.setMonth(newDate.getMonth() + delta);
|
||||||
|
|
||||||
|
|
@ -643,7 +648,11 @@ function MobileSchedule() {
|
||||||
>
|
>
|
||||||
<Calendar size={20} className="text-gray-600" />
|
<Calendar size={20} className="text-gray-600" />
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => changeMonth(-1)} className="p-2">
|
<button
|
||||||
|
onClick={() => changeMonth(-1)}
|
||||||
|
disabled={!canGoPrevMonth}
|
||||||
|
className={`p-2 ${!canGoPrevMonth ? 'opacity-30' : ''}`}
|
||||||
|
>
|
||||||
<ChevronLeft size={20} />
|
<ChevronLeft size={20} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1012,20 +1021,14 @@ function ScheduleCard({ schedule, categoryColor, categories, delay = 0, onClick
|
||||||
{/* 멤버 */}
|
{/* 멤버 */}
|
||||||
{memberList.length > 0 && (
|
{memberList.length > 0 && (
|
||||||
<div className="flex flex-wrap gap-1.5 mt-3 pt-3 border-t border-gray-100">
|
<div className="flex flex-wrap gap-1.5 mt-3 pt-3 border-t border-gray-100">
|
||||||
{memberList.length >= 5 ? (
|
{memberList.map((name, i) => (
|
||||||
<span className="px-2.5 py-1 bg-gradient-to-r from-primary to-primary-dark text-white text-xs rounded-lg font-semibold shadow-sm">
|
|
||||||
프로미스나인
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
memberList.map((name, i) => (
|
|
||||||
<span
|
<span
|
||||||
key={i}
|
key={i}
|
||||||
className="px-2.5 py-1 bg-gradient-to-r from-primary to-primary-dark text-white text-xs rounded-lg font-semibold shadow-sm"
|
className="px-2.5 py-1 bg-gradient-to-r from-primary to-primary-dark text-white text-xs rounded-lg font-semibold shadow-sm"
|
||||||
>
|
>
|
||||||
{name.trim()}
|
{name.trim()}
|
||||||
</span>
|
</span>
|
||||||
))
|
))}
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1091,20 +1094,14 @@ function TimelineScheduleCard({ schedule, categoryColor, categories, delay = 0,
|
||||||
{/* 멤버 */}
|
{/* 멤버 */}
|
||||||
{memberList.length > 0 && (
|
{memberList.length > 0 && (
|
||||||
<div className="flex flex-wrap gap-1.5 mt-3 pt-3 border-t border-gray-100">
|
<div className="flex flex-wrap gap-1.5 mt-3 pt-3 border-t border-gray-100">
|
||||||
{memberList.length >= 5 ? (
|
{memberList.map((name, i) => (
|
||||||
<span className="px-2.5 py-1 bg-gradient-to-r from-primary to-primary-dark text-white text-xs rounded-lg font-semibold shadow-sm">
|
|
||||||
프로미스나인
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
memberList.map((name, i) => (
|
|
||||||
<span
|
<span
|
||||||
key={i}
|
key={i}
|
||||||
className="px-2.5 py-1 bg-gradient-to-r from-primary to-primary-dark text-white text-xs rounded-lg font-semibold shadow-sm"
|
className="px-2.5 py-1 bg-gradient-to-r from-primary to-primary-dark text-white text-xs rounded-lg font-semibold shadow-sm"
|
||||||
>
|
>
|
||||||
{name.trim()}
|
{name.trim()}
|
||||||
</span>
|
</span>
|
||||||
))
|
))}
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1167,6 +1164,9 @@ function CalendarPicker({
|
||||||
const year = viewDate.getFullYear();
|
const year = viewDate.getFullYear();
|
||||||
const month = viewDate.getMonth();
|
const month = viewDate.getMonth();
|
||||||
|
|
||||||
|
// 2017년 1월 이전으로 이동 불가
|
||||||
|
const canGoPrevMonth = !(year === 2017 && month === 0);
|
||||||
|
|
||||||
// 달력 데이터 생성 함수
|
// 달력 데이터 생성 함수
|
||||||
const getCalendarDays = useCallback((y, m) => {
|
const getCalendarDays = useCallback((y, m) => {
|
||||||
const firstDay = new Date(y, m, 1);
|
const firstDay = new Date(y, m, 1);
|
||||||
|
|
@ -1209,10 +1209,11 @@ function CalendarPicker({
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const changeMonth = useCallback((delta) => {
|
const changeMonth = useCallback((delta) => {
|
||||||
|
if (delta < 0 && !canGoPrevMonth) return;
|
||||||
const newDate = new Date(viewDate);
|
const newDate = new Date(viewDate);
|
||||||
newDate.setMonth(newDate.getMonth() + delta);
|
newDate.setMonth(newDate.getMonth() + delta);
|
||||||
setViewDate(newDate);
|
setViewDate(newDate);
|
||||||
}, [viewDate]);
|
}, [viewDate, canGoPrevMonth]);
|
||||||
|
|
||||||
const isToday = (date) => {
|
const isToday = (date) => {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
|
|
@ -1239,7 +1240,7 @@ function CalendarPicker({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const MIN_YEAR = 2025;
|
const MIN_YEAR = 2017;
|
||||||
const [yearRangeStart, setYearRangeStart] = useState(MIN_YEAR);
|
const [yearRangeStart, setYearRangeStart] = useState(MIN_YEAR);
|
||||||
const yearRange = Array.from({ length: 12 }, (_, i) => yearRangeStart + i);
|
const yearRange = Array.from({ length: 12 }, (_, i) => yearRangeStart + i);
|
||||||
const canGoPrevYearRange = yearRangeStart > MIN_YEAR;
|
const canGoPrevYearRange = yearRangeStart > MIN_YEAR;
|
||||||
|
|
@ -1452,7 +1453,8 @@ function CalendarPicker({
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<button
|
<button
|
||||||
onClick={() => changeMonth(-1)}
|
onClick={() => changeMonth(-1)}
|
||||||
className="p-1"
|
disabled={!canGoPrevMonth}
|
||||||
|
className={`p-1 ${!canGoPrevMonth ? 'opacity-30' : ''}`}
|
||||||
>
|
>
|
||||||
<ChevronLeft size={18} />
|
<ChevronLeft size={18} />
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -291,8 +291,8 @@ function AdminSchedule() {
|
||||||
const days = ['일', '월', '화', '수', '목', '금', '토'];
|
const days = ['일', '월', '화', '수', '목', '금', '토'];
|
||||||
const monthNames = ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'];
|
const monthNames = ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'];
|
||||||
|
|
||||||
// 년도 범위 (2025년부터 시작, 12년 단위)
|
// 년도 범위 (2017년부터 시작, 12년 단위)
|
||||||
const MIN_YEAR = 2025;
|
const MIN_YEAR = 2017;
|
||||||
const startYear = Math.max(MIN_YEAR, Math.floor(year / 12) * 12 - 1);
|
const startYear = Math.max(MIN_YEAR, Math.floor(year / 12) * 12 - 1);
|
||||||
const yearRange = Array.from({ length: 12 }, (_, i) => startYear + i);
|
const yearRange = Array.from({ length: 12 }, (_, i) => startYear + i);
|
||||||
const canGoPrevYearRange = startYear > MIN_YEAR;
|
const canGoPrevYearRange = startYear > MIN_YEAR;
|
||||||
|
|
@ -456,8 +456,12 @@ function AdminSchedule() {
|
||||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||||
}, [showYearMonthPicker, showCategoryTooltip]);
|
}, [showYearMonthPicker, showCategoryTooltip]);
|
||||||
|
|
||||||
|
// 2017년 1월 이전으로 이동 불가
|
||||||
|
const canGoPrevMonth = !(year === 2017 && month === 0);
|
||||||
|
|
||||||
// 월 이동
|
// 월 이동
|
||||||
const prevMonth = () => {
|
const prevMonth = () => {
|
||||||
|
if (!canGoPrevMonth) return;
|
||||||
setSlideDirection(-1);
|
setSlideDirection(-1);
|
||||||
const newDate = new Date(year, month - 1, 1);
|
const newDate = new Date(year, month - 1, 1);
|
||||||
setCurrentDate(newDate);
|
setCurrentDate(newDate);
|
||||||
|
|
@ -485,7 +489,7 @@ function AdminSchedule() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 년도 범위 이동 (12년 단위, 2025년 이전 불가)
|
// 년도 범위 이동 (12년 단위, 2017년 이전 불가)
|
||||||
const prevYearRange = () => canGoPrevYearRange && setCurrentDate(new Date(Math.max(MIN_YEAR, year - 12), month, 1));
|
const prevYearRange = () => canGoPrevYearRange && setCurrentDate(new Date(Math.max(MIN_YEAR, year - 12), month, 1));
|
||||||
const nextYearRange = () => setCurrentDate(new Date(year + 12, month, 1));
|
const nextYearRange = () => setCurrentDate(new Date(year + 12, month, 1));
|
||||||
|
|
||||||
|
|
@ -698,8 +702,8 @@ function AdminSchedule() {
|
||||||
<div className={`flex items-center justify-between mb-8 ${isSearchMode ? 'opacity-50' : ''}`}>
|
<div className={`flex items-center justify-between mb-8 ${isSearchMode ? 'opacity-50' : ''}`}>
|
||||||
<button
|
<button
|
||||||
onClick={prevMonth}
|
onClick={prevMonth}
|
||||||
disabled={isSearchMode}
|
disabled={isSearchMode || !canGoPrevMonth}
|
||||||
className={`p-2 rounded-full transition-colors ${isSearchMode ? 'cursor-not-allowed' : 'hover:bg-gray-100'}`}
|
className={`p-2 rounded-full transition-colors ${isSearchMode || !canGoPrevMonth ? 'opacity-30' : 'hover:bg-gray-100'}`}
|
||||||
>
|
>
|
||||||
<ChevronLeft size={24} />
|
<ChevronLeft size={24} />
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,9 @@ function Members() {
|
||||||
|
|
||||||
{/* 정보 */}
|
{/* 정보 */}
|
||||||
<div className="p-6 flex-1 flex flex-col">
|
<div className="p-6 flex-1 flex flex-col">
|
||||||
<h3 className="text-xl font-bold mb-1">{member.name}</h3>
|
<h3 className="text-xl font-bold mb-3">{member.name}</h3>
|
||||||
<p className="text-primary text-sm font-medium mb-3 min-h-[20px]">{member.position || '\u00A0'}</p>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-2 text-sm text-gray-500 mb-4">
|
<div className="flex items-center gap-2 text-sm text-gray-500 mb-2">
|
||||||
<Calendar size={14} />
|
<Calendar size={14} />
|
||||||
<span>{formatDate(member.birth_date, 'YYYY.MM.DD')}</span>
|
<span>{formatDate(member.birth_date, 'YYYY.MM.DD')}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -123,8 +122,7 @@ function Members() {
|
||||||
|
|
||||||
{/* 정보 */}
|
{/* 정보 */}
|
||||||
<div className="p-6 flex-1 flex flex-col">
|
<div className="p-6 flex-1 flex flex-col">
|
||||||
<h3 className="text-xl font-bold mb-1 text-gray-500">{member.name}</h3>
|
<h3 className="text-xl font-bold mb-3 text-gray-500">{member.name}</h3>
|
||||||
<p className="text-gray-400 text-sm font-medium mb-3 min-h-[20px]">{member.position || '\u00A0'}</p>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-2 text-sm text-gray-400">
|
<div className="flex items-center gap-2 text-sm text-gray-400">
|
||||||
<Calendar size={14} />
|
<Calendar size={14} />
|
||||||
|
|
|
||||||
|
|
@ -395,7 +395,11 @@ function Schedule() {
|
||||||
return scheduleDateMap.has(dateStr);
|
return scheduleDateMap.has(dateStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 2017년 1월 이전으로 이동 불가
|
||||||
|
const canGoPrevMonth = !(year === 2017 && month === 0);
|
||||||
|
|
||||||
const prevMonth = () => {
|
const prevMonth = () => {
|
||||||
|
if (!canGoPrevMonth) return;
|
||||||
setSlideDirection(-1);
|
setSlideDirection(-1);
|
||||||
const newDate = new Date(year, month - 1, 1);
|
const newDate = new Date(year, month - 1, 1);
|
||||||
setCurrentDate(newDate);
|
setCurrentDate(newDate);
|
||||||
|
|
@ -567,8 +571,8 @@ function Schedule() {
|
||||||
return year === now.getFullYear() && m === now.getMonth();
|
return year === now.getFullYear() && m === now.getMonth();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 연도 선택 범위 (2025년부터 시작)
|
// 연도 선택 범위
|
||||||
const MIN_YEAR = 2025;
|
const MIN_YEAR = 2017;
|
||||||
const [yearRangeStart, setYearRangeStart] = useState(MIN_YEAR);
|
const [yearRangeStart, setYearRangeStart] = useState(MIN_YEAR);
|
||||||
const yearRange = Array.from({ length: 12 }, (_, i) => yearRangeStart + i);
|
const yearRange = Array.from({ length: 12 }, (_, i) => yearRangeStart + i);
|
||||||
const monthNames = ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'];
|
const monthNames = ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'];
|
||||||
|
|
@ -652,7 +656,8 @@ function Schedule() {
|
||||||
<div className="flex items-center justify-between mb-8">
|
<div className="flex items-center justify-between mb-8">
|
||||||
<button
|
<button
|
||||||
onClick={prevMonth}
|
onClick={prevMonth}
|
||||||
className="p-2 hover:bg-gray-100 rounded-full transition-colors"
|
disabled={!canGoPrevMonth}
|
||||||
|
className={`p-2 rounded-full transition-colors ${canGoPrevMonth ? 'hover:bg-gray-100' : 'opacity-30'}`}
|
||||||
>
|
>
|
||||||
<ChevronLeft size={24} />
|
<ChevronLeft size={24} />
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue