-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
일정 코드 개선 완료
- Loading branch information
Showing
23 changed files
with
421 additions
and
221 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
60 changes: 44 additions & 16 deletions
60
apps/member/src/components/calendar/CalendarSchedule/CalendarSchedule.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
99 changes: 99 additions & 0 deletions
99
apps/member/src/components/calendar/CalendarSection/CalendarSection.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { startTransition, useCallback, useState } from 'react'; | ||
import ArrowButton from '@components/common/ArrowButton/ArrowButton'; | ||
import Section from '@components/common/Section/Section'; | ||
import { useSchedule } from '@hooks/queries'; | ||
import { now, transformEvents } from '@utils/date'; | ||
import { cn } from '@utils/string'; | ||
import CalendarSchedule from '../CalendarSchedule/CalendarSchedule'; | ||
|
||
const today = now(); | ||
|
||
const CalendarSection = () => { | ||
const [date, setDate] = useState(today); | ||
const { data } = useSchedule({ | ||
startDate: date.startOf('month').format('YYYY-MM-DD'), | ||
endDate: date.endOf('month').format('YYYY-MM-DD'), | ||
}); | ||
|
||
const handleDateClick = useCallback((action: 'prev' | 'next' | 'today') => { | ||
startTransition(() => { | ||
setDate((current) => { | ||
switch (action) { | ||
case 'prev': | ||
return current.subtract(1, 'month'); | ||
case 'next': | ||
return current.add(1, 'month'); | ||
case 'today': | ||
return today; | ||
} | ||
}); | ||
}); | ||
}, []); | ||
|
||
const events = transformEvents(data.items); | ||
const startDay = date.startOf('month').startOf('week'); // 현재 월의 첫 날짜의 주의 시작일 | ||
const endDay = date.endOf('month').endOf('week'); // 현재 월의 마지막 날짜의 주의 마지막일 | ||
|
||
const days = []; | ||
let day = startDay; | ||
|
||
while (day.isBefore(endDay)) { | ||
const isToday = day.isSame(today, 'day'); | ||
|
||
days.push( | ||
<td key={day.format('DD-MM-YYYY')} className="border h-28"> | ||
<div className="flex flex-col items-end h-full space-y-1"> | ||
<p | ||
className={cn('text-sm text-center rounded-full size-5 m-1', { | ||
'text-white bg-red-500': isToday, | ||
})} | ||
> | ||
{day.format('D')} | ||
</p> | ||
{events[day.format('YYYY-MM-DD')]?.map((event) => ( | ||
<CalendarSchedule key={event.id} day={day} {...event} /> | ||
))} | ||
</div> | ||
</td>, | ||
); | ||
day = day.add(1, 'day'); | ||
} | ||
|
||
const weeks = []; | ||
for (let i = 0; i < days.length; i += 7) { | ||
weeks.push(<tr key={i}>{days.slice(i, i + 7)}</tr>); | ||
} | ||
|
||
return ( | ||
<Section> | ||
<Section.Header title={date.format('YYYY년 MM월')}> | ||
<ArrowButton onClick={() => handleDateClick('prev')} /> | ||
<button | ||
className="px-3 hover:underline" | ||
onClick={() => handleDateClick('today')} | ||
> | ||
오늘 | ||
</button> | ||
<ArrowButton direction="next" onClick={() => handleDateClick('next')} /> | ||
</Section.Header> | ||
<Section.Body> | ||
<table className="w-full table-fixed"> | ||
<thead> | ||
<tr> | ||
<th>일</th> | ||
<th>월</th> | ||
<th>화</th> | ||
<th>수</th> | ||
<th>목</th> | ||
<th>금</th> | ||
<th>토</th> | ||
</tr> | ||
</thead> | ||
<tbody className="border">{weeks}</tbody> | ||
</table> | ||
</Section.Body> | ||
</Section> | ||
); | ||
}; | ||
|
||
export default CalendarSection; |
49 changes: 49 additions & 0 deletions
49
apps/member/src/components/calendar/CalendarStatusSection/CalendarStatusSection.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import Section from '@components/common/Section/Section'; | ||
import StatusCard from '@components/common/StatusCard/StatusCard'; | ||
import { useSchedule } from '@hooks/queries'; | ||
import { calculateDDay, findClosestEvent, transformEvents } from '@utils/date'; | ||
import { FcCalendar, FcLeave, FcOvertime, FcAlarmClock } from 'react-icons/fc'; | ||
import { useScheduleCollect } from '@hooks/queries/useScheduleCollect'; | ||
|
||
const CalendarStatusSection = () => { | ||
const { data: yearData } = useScheduleCollect(); | ||
const { data: monthData } = useSchedule(); | ||
|
||
const closestEvent = findClosestEvent(transformEvents(monthData.items)); | ||
const closestDDay = closestEvent?.startDate | ||
? `D-${calculateDDay(closestEvent.startDate)}` | ||
: '이번 달에 남은 일정이 없어요'; | ||
|
||
return ( | ||
<Section> | ||
<Section.Header | ||
title="모아보기" | ||
description="일정을 한 눈에 확인하세요" | ||
/> | ||
<Section.Body className="grid grid-cols-2 gap-4 md:grid-cols-4 break-keep"> | ||
<StatusCard | ||
icon={<FcCalendar size={32} />} | ||
label={`${yearData.totalScheduleCount}회`} | ||
description="이번 연도 동아리의 모든 일정 횟수에요." | ||
/> | ||
<StatusCard | ||
icon={<FcLeave size={32} />} | ||
label={`${yearData.totalEventCount}회`} | ||
description="이번 연도 총회, MT 등 중요도가 높은 행사 횟수에요." | ||
/> | ||
<StatusCard | ||
icon={<FcOvertime size={32} />} | ||
label={`${monthData.totalItems}회`} | ||
description="이번 달 동아리 일정 횟수에요." | ||
/> | ||
<StatusCard | ||
icon={<FcAlarmClock size={32} />} | ||
label={closestDDay} | ||
description="가장 가까운 일정까지 남은 일수에요." | ||
/> | ||
</Section.Body> | ||
</Section> | ||
); | ||
}; | ||
|
||
export default CalendarStatusSection; |
26 changes: 26 additions & 0 deletions
26
apps/member/src/components/common/ArrowButton/ArrowButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { cn } from '@utils/string'; | ||
import { ComponentPropsWithRef, forwardRef } from 'react'; | ||
import { MdOutlineNavigateNext } from 'react-icons/md'; | ||
|
||
interface ArrowButtonProps extends ComponentPropsWithRef<'button'> { | ||
direction?: 'prev' | 'next'; | ||
} | ||
|
||
const ArrowButton = forwardRef<HTMLButtonElement, ArrowButtonProps>( | ||
({ direction = 'prev', className, ...rest }, ref) => { | ||
return ( | ||
<button | ||
ref={ref} | ||
className={cn('px-0.5 text-gray-500 border rounded', className)} | ||
{...rest} | ||
> | ||
<MdOutlineNavigateNext | ||
size={20} | ||
className={direction === 'prev' ? 'rotate-180' : 'rotate-0'} | ||
/> | ||
</button> | ||
); | ||
}, | ||
); | ||
|
||
export default ArrowButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.