-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
238 additions
and
2 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { useMemo } from 'react'; | ||
import { DateTime } from 'luxon'; | ||
import { | ||
MdKeyboardArrowLeft, | ||
MdKeyboardArrowRight, | ||
MdKeyboardDoubleArrowLeft, | ||
MdKeyboardDoubleArrowRight, | ||
} from 'react-icons/md'; | ||
import { Project } from '@/types/ProjectType'; | ||
|
||
type CalendarToolbarProp = { | ||
date: Date; | ||
startDate: Project['startDate']; | ||
onClick: (date: Date) => void; | ||
}; | ||
|
||
export default function CalendarToolbar({ date, startDate, onClick }: CalendarToolbarProp) { | ||
const { year, month } = useMemo(() => DateTime.fromJSDate(date), [date]); | ||
|
||
const handlePrevMonthClick = () => { | ||
const prevMonthDate = DateTime.fromJSDate(date).minus({ month: 1 }).toJSDate(); | ||
onClick(prevMonthDate); | ||
}; | ||
const handlePrevYearClick = () => { | ||
const prevYearDate = DateTime.fromJSDate(date).minus({ year: 1 }).toJSDate(); | ||
onClick(prevYearDate); | ||
}; | ||
const handleNextMonthClick = () => { | ||
const nextMonthDate = DateTime.fromJSDate(date).plus({ month: 1 }).toJSDate(); | ||
onClick(nextMonthDate); | ||
}; | ||
const handleNextYearClick = () => { | ||
const nextYearDate = DateTime.fromJSDate(date).plus({ year: 1 }).toJSDate(); | ||
onClick(nextYearDate); | ||
}; | ||
const handleTodayClick = () => { | ||
const todayDate = DateTime.now().toJSDate(); | ||
onClick(todayDate); | ||
}; | ||
|
||
// ToDo: startDate가 없을 수도 있구나... 그럼 첫태스크가 있는 곳으로 보내야하나 | ||
const handleStartDayClick = () => { | ||
if (startDate === null) return; | ||
const projectStartDate = DateTime.fromJSDate(startDate).toJSDate(); | ||
onClick(projectStartDate); | ||
}; | ||
|
||
return ( | ||
<section className="flex h-30 flex-wrap items-center justify-center bg-main px-10 *:w-1/3"> | ||
<div /> | ||
<div className="flex items-center justify-center text-center font-bold text-white"> | ||
<button type="button" aria-label="이전 연도" onClick={handlePrevYearClick}> | ||
<MdKeyboardDoubleArrowLeft /> | ||
</button> | ||
<button type="button" aria-label="이전 달" onClick={handlePrevMonthClick}> | ||
<MdKeyboardArrowLeft /> | ||
</button> | ||
<span className="mx-10"> | ||
{year}년 {month}월 | ||
</span> | ||
<button type="button" aria-label="다음 달" onClick={handleNextMonthClick}> | ||
<MdKeyboardArrowRight /> | ||
</button> | ||
<button type="button" aria-label="다음 연도" onClick={handleNextYearClick}> | ||
<MdKeyboardDoubleArrowRight /> | ||
</button> | ||
</div> | ||
<div className="text-right text-emphasis *:ml-5"> | ||
<button | ||
type="button" | ||
className="px-8hover:brightness-90 box-border h-20 w-50 rounded-lg bg-button" | ||
onClick={handleStartDayClick} | ||
> | ||
시작일 | ||
</button> | ||
<button | ||
type="button" | ||
className="box-border h-20 w-50 rounded-lg bg-button px-8 hover:brightness-90" | ||
onClick={handleTodayClick} | ||
> | ||
당일 | ||
</button> | ||
</div> | ||
</section> | ||
); | ||
} |
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,8 @@ | ||
import { DateHeaderProps } from 'react-big-calendar'; | ||
|
||
// ToDo: Header 컴포넌트 수정할 것 | ||
export default function CustomDateHeader({ date, drilldownView, isOffRange, label, onDrillDown }: DateHeaderProps) { | ||
console.log(date, drilldownView, isOffRange, label, onDrillDown); | ||
console.log(date.getDate()); | ||
return <div>{date.getDate()}</div>; | ||
} |
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,15 @@ | ||
import { Event, EventProps } from 'react-big-calendar'; | ||
import { TaskWithStatus } from '@/types/TaskType'; | ||
|
||
export type CustomEvents = Event & { | ||
task: TaskWithStatus; | ||
handleEventClick: (task: TaskWithStatus) => void; | ||
}; | ||
|
||
export default function CustomEvent({ event }: EventProps<CustomEvents>) { | ||
return ( | ||
<div style={{ backgroundColor: event.task.color }} className="overflow-hidden text-ellipsis rounded-md px-3 py-1"> | ||
<span>{event.task.name}</span> | ||
</div> | ||
); | ||
} |
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 |
---|---|---|
@@ -1,3 +1,121 @@ | ||
import { useCallback, useMemo, useState } from 'react'; | ||
import { DateTime, Settings } from 'luxon'; | ||
import { Calendar, luxonLocalizer, Views } from 'react-big-calendar'; | ||
import CalendarToolbar from '@components/task/calendar/CalendarToolbar'; | ||
import CustomEvent, { CustomEvents } from '@components/task/calendar/CustomEvent'; | ||
import CustomDateHeader from '@components/task/calendar/CustomDateHeader'; | ||
import useModal from '@hooks/useModal'; | ||
import ModalLayout from '@layouts/ModalLayout'; | ||
import ModalPortal from '@components/modal/ModalPortal'; | ||
import ModaFormButton from '@components/modal/ModaFormButton'; | ||
import { TASK_DUMMY } from '@mocks/mockData'; | ||
import { TaskListWithStatus, TaskWithStatus } from '@/types/TaskType'; | ||
import 'react-big-calendar/lib/css/react-big-calendar.css'; | ||
|
||
function getCalendarTask(statusTasks: TaskListWithStatus[]) { | ||
const calendarTasks: TaskWithStatus[] = []; | ||
|
||
statusTasks.forEach((statusTask) => { | ||
const { statusId, name: statusName, color, order: statusOrder, tasks } = statusTask; | ||
tasks.forEach((task) => { | ||
calendarTasks.push({ statusId, statusName, color, statusOrder, ...task }); | ||
}); | ||
}); | ||
console.log(calendarTasks); | ||
|
||
return calendarTasks; | ||
} | ||
|
||
const dt = DateTime.local(); | ||
Settings.defaultZone = dt.zoneName; | ||
const localizer = luxonLocalizer(DateTime, { firstDayOfWeek: 7 }); | ||
|
||
export default function CalendarPage() { | ||
return <div>CalendarPage</div>; | ||
const { showModal, openModal, closeModal } = useModal(); | ||
const [selectedTask, setSelectedTask] = useState<TaskWithStatus>(); | ||
const [date, setDate] = useState<Date>(() => DateTime.now().toJSDate()); | ||
|
||
const handleToolbarClick = (date: Date) => setDate(date); | ||
|
||
const handleEventClick = (task: TaskWithStatus) => { | ||
setSelectedTask(task); | ||
openModal(); | ||
}; | ||
|
||
const handleSelectEvent = (event: CustomEvents) => { | ||
setSelectedTask(event?.task); | ||
openModal(); | ||
}; | ||
|
||
const handleSelectSlot = useCallback(({ start, end }: { start: Date; end: Date }) => { | ||
console.log(`시작일: ${start}, 마감일: ${end}`); | ||
alert('날짜가 선택되었어요!'); | ||
}, []); | ||
|
||
const { views, components: customComponents } = useMemo( | ||
() => ({ | ||
views: [Views.MONTH, Views.WEEK], | ||
components: { | ||
event: CustomEvent, | ||
month: { | ||
header: () => undefined, | ||
dateHeader: CustomDateHeader, | ||
}, | ||
}, | ||
}), | ||
[], | ||
); | ||
|
||
const state = { | ||
events: getCalendarTask(TASK_DUMMY) | ||
.map((statusTask) => ({ | ||
title: statusTask.name, | ||
start: new Date(statusTask.startDate), | ||
end: new Date(statusTask.endDate), | ||
allDays: true, | ||
task: { ...statusTask }, | ||
handleEventClick, | ||
})) | ||
.sort((a, b) => a.start.getTime() - b.end.getTime()), | ||
}; | ||
|
||
// ToDo: 캘린더 스타일 변경을 위해 커스텀 컴포넌트 추가 | ||
// ToDo: DnD, Resize 이벤트 추가 생각해보기 | ||
// ToDo: 할일 추가 모달 Form 작업 완료시 모달 컴포넌트 분리 | ||
// ToDo: react-big-calendar CSS overwrite | ||
// ToDo: onNavigate로 발생하는 warning 해결 | ||
// ToDo: 캘린더 크기 전체적으로 조정 | ||
// ToDo: 코드 리팩토링 | ||
return ( | ||
<div className="min-h-375 min-w-375 grow"> | ||
<CalendarToolbar date={date} startDate={state.events[0].start} onClick={handleToolbarClick} /> | ||
<Calendar | ||
toolbar={false} | ||
localizer={localizer} | ||
defaultView="month" | ||
date={date} | ||
views={views} | ||
events={state.events} | ||
components={customComponents} | ||
titleAccessor="title" | ||
startAccessor="start" | ||
endAccessor="end" | ||
allDayAccessor="allDay" | ||
popup | ||
onSelectEvent={handleSelectEvent} | ||
// selectable | ||
// onSelectSlot={handleSelectSlot} | ||
/> | ||
{showModal && ( | ||
<ModalPortal> | ||
<ModalLayout onClose={closeModal}> | ||
<div className="flex h-full flex-col items-center justify-center"> | ||
<div>{selectedTask?.name}</div> | ||
<ModaFormButton formId="updateStatusForm" isCreate={false} onClose={closeModal} /> | ||
</div> | ||
</ModalLayout> | ||
</ModalPortal> | ||
)} | ||
</div> | ||
); | ||
} |
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