Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/GU-99/grow-up-fe into fe…
Browse files Browse the repository at this point in the history
…ature/#35-search-id-pw-ui
  • Loading branch information
Yoonyesol committed Aug 3, 2024
2 parents fe9f804 + 3745476 commit 1ad11bc
Show file tree
Hide file tree
Showing 13 changed files with 177 additions and 56 deletions.
30 changes: 30 additions & 0 deletions src/components/modal/task/CreateModalTask.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { SubmitHandler } from 'react-hook-form';
import ModalLayout from '@layouts/ModalLayout';
import ModalPortal from '@components/modal/ModalPortal';
import ModalTaskForm from '@components/modal/task/ModalTaskForm';
import ModaFormButton from '@components/modal/ModaFormButton';
import { TaskForm } from '@/types/TaskType';

type CreateModalTaskProps = {
onClose: () => void;
};

export default function CreateModalTask({ onClose: handleClose }: CreateModalTaskProps) {
// ToDo: 상태 생성을 위한 네트워크 로직 추가
const handleSubmit: SubmitHandler<TaskForm> = async (data) => {
console.log('생성 폼 제출');
console.log(data);
handleClose();
};
return (
<ModalPortal>
<ModalLayout onClose={handleClose}>
<div className="flex h-full flex-col items-center justify-center">
{/* ToDo: Task 생성 모달 작성시 수정할 것 */}
<ModalTaskForm formId="updateTaskForm" onSubmit={handleSubmit} />
<ModaFormButton formId="updateTaskForm" isCreate={false} onClose={handleClose} />
</div>
</ModalLayout>
</ModalPortal>
);
}
21 changes: 21 additions & 0 deletions src/components/modal/task/ModalTaskForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { SubmitHandler, useForm } from 'react-hook-form';
import { Task, TaskForm } from '@/types/TaskType';

type ModalTaskFromProps = {
formId: string;
taskId?: Task['taskId'];
onSubmit: SubmitHandler<TaskForm>;
};

// ToDo: Task 모달 작성시 Task Form 만들기
export default function ModalTaskForm({ formId, taskId, onSubmit }: ModalTaskFromProps) {
const { register, handleSubmit } = useForm<TaskForm>({
mode: 'onChange',
defaultValues: {},
});
return (
<form id={formId} className="mb-10 flex grow flex-col justify-center" onSubmit={handleSubmit(onSubmit)}>
<div>{taskId}</div>
</form>
);
}
31 changes: 31 additions & 0 deletions src/components/modal/task/UpdateModalTask.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { SubmitHandler } from 'react-hook-form';
import ModalLayout from '@layouts/ModalLayout';
import ModalPortal from '@components/modal/ModalPortal';
import ModalTaskForm from '@components/modal/task/ModalTaskForm';
import ModaFormButton from '@components/modal/ModaFormButton';
import { Task, TaskForm } from '@/types/TaskType';

type UpdateModalTaskProps = {
taskId: Task['taskId'];
onClose: () => void;
};

export default function UpdateModalTask({ taskId, onClose: handleClose }: UpdateModalTaskProps) {
// ToDo: 상태 생성을 위한 네트워크 로직 추가
const handleSubmit: SubmitHandler<TaskForm> = async (data) => {
console.log('생성 폼 제출');
console.log(data);
handleClose();
};
return (
<ModalPortal>
<ModalLayout onClose={handleClose}>
<div className="flex h-full flex-col items-center justify-center">
{/* ToDo: Task 수정 모달 작성시 수정할 것 */}
<ModalTaskForm formId="updateTaskForm" taskId={taskId} onSubmit={handleSubmit} />
<ModaFormButton formId="updateTaskForm" isCreate={false} onClose={handleClose} />
</div>
</ModalLayout>
</ModalPortal>
);
}
22 changes: 15 additions & 7 deletions src/components/task/calendar/CustomDateHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useMemo } from 'react';
import { DateTime } from 'luxon';
import { DateHeaderProps } from 'react-big-calendar';
import { LuxonWeekday } from '@constants/date';
import useProjectContext from '@hooks/useProjectContext';
import Validator from '@utils/Validator';

function getTextColor(weekday: LuxonWeekday, isOffRange: boolean) {
if (isOffRange) return 'text-[#999999]';
function getTextColor(weekday: LuxonWeekday, isWithinRange: boolean) {
if (!isWithinRange) return 'text-[#999999]';

switch (weekday) {
case LuxonWeekday.SATURDAY:
Expand All @@ -16,9 +17,16 @@ function getTextColor(weekday: LuxonWeekday, isOffRange: boolean) {
}
}

export default function CustomDateHeader({ date, isOffRange }: DateHeaderProps) {
const { weekday } = useMemo(() => DateTime.fromJSDate(date), [date]);
const textColor = useMemo(() => getTextColor(weekday, isOffRange), [weekday, isOffRange]);
export default function CustomDateHeader({ date, label }: DateHeaderProps) {
const { project } = useProjectContext();

return <div className={`pl-3 text-left ${textColor}`}>{date.getDate()}</div>;
// prettier-ignore
const isWithinDateRange = project.startDate && project.endDate
? Validator.isWithinDateRange(project.startDate, project.endDate, date)
: true;

const { weekday } = DateTime.fromJSDate(date);
const textColor = getTextColor(weekday, isWithinDateRange);

return <div className={`pl-3 text-left ${textColor}`}>{label.padStart(2, '0')}</div>;
}
1 change: 0 additions & 1 deletion src/components/task/kanban/ProjectStatusContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ type TaskStatusContainerProps = {
};

export default function TaskStatusContainer({ statusTask }: TaskStatusContainerProps) {
// const [showStatusModal, setShowStatusModal] = useState(false);
const { showModal, openModal, closeModal } = useModal();
const { statusId, name, color, order, tasks } = statusTask;
const draggableId = useMemo(() => generatePrefixId(statusId, DND_DRAGGABLE_PREFIX.STATUS), [statusId]);
Expand Down
7 changes: 7 additions & 0 deletions src/customReactBigCalendar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.rbc-off-range-bg {
background: #f4f4f4;
}

.rbc-selected-cell {
background: var(--color-sub);
}
8 changes: 8 additions & 0 deletions src/hooks/useProjectContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { useOutletContext } from 'react-router-dom';
import { Project } from '@/types/ProjectType';

export type ProjectContext = { project: Project };

export default function useProjectContext() {
return useOutletContext<ProjectContext>();
}
27 changes: 18 additions & 9 deletions src/layouts/page/ProjectLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import { useMemo } from 'react';
import { NavLink, Outlet, useParams } from 'react-router-dom';
import { Navigate, NavLink, Outlet, useParams } from 'react-router-dom';
import useModal from '@hooks/useModal';
import ListSidebar from '@components/sidebar/ListSidebar';
import ListProject from '@components/sidebar/ListProject';
import CreateModalTask from '@components/modal/task/CreateModalTask';
import CreateModalProjectStatus from '@components/modal/project-status/CreateModalProjectStatus';
import { ProjectContext } from '@hooks/useProjectContext';
import { PROJECT_DUMMY } from '@mocks/mockData';
import { RiSettings5Fill } from 'react-icons/ri';

export default function ProjectLayout() {
const { projectId } = useParams();
const { showModal, openModal, closeModal } = useModal();
const target = useMemo(
const { showModal: showTaskModal, openModal: openTaskModal, closeModal: closeTaskModal } = useModal();
const { showModal: showStatusModal, openModal: openStatusModal, closeModal: closeStatusModal } = useModal();
const project = useMemo(
() => PROJECT_DUMMY.find((project) => project.projectId.toString() === projectId),
[projectId],
);

if (!project) return <Navigate to="/error" replace />;

return (
<>
<section className="flex h-full p-15">
Expand All @@ -25,7 +30,7 @@ export default function ProjectLayout() {
<header className="flex h-30 items-center justify-between border-b p-10">
<div>
<small className="mr-5 font-bold text-category">project</small>
<span className="text-emphasis">{target?.name}</span>
<span className="text-emphasis">{project?.name}</span>
</div>
<div className="flex cursor-pointer items-center text-sm text-main">
<RiSettings5Fill /> Project Setting
Expand All @@ -45,17 +50,21 @@ export default function ProjectLayout() {
</NavLink>
</li>
</ul>
<div className="text-main">
<button type="button" onClick={openModal}>
<small>+</small> New State
<div className="text-main *:ml-10">
<button type="button" onClick={openTaskModal}>
+ 할일 추가
</button>
<button type="button" onClick={openStatusModal}>
+ 상태 추가
</button>
</div>
</div>
<Outlet />
<Outlet context={{ project } satisfies ProjectContext} />
</div>
</section>
</section>
{showModal && <CreateModalProjectStatus onClose={closeModal} />}
{showTaskModal && <CreateModalTask onClose={closeTaskModal} />}
{showStatusModal && <CreateModalProjectStatus onClose={closeStatusModal} />}
</>
);
}
28 changes: 14 additions & 14 deletions src/mocks/mockData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export const PROJECT_DUMMY: Project[] = [
teamId: 1,
name: '캘린더 만들기1',
content: '캘린더 만들기 설명1',
startDate: new Date('2022-01-01'),
endDate: new Date('2022-02-14'),
startDate: new Date('2022-01-01 00:00:00'),
endDate: new Date('2022-02-14 00:00:00'),
createAt: new Date('2022-01-01'),
updateAt: new Date('2022-01-01'),
},
Expand All @@ -39,8 +39,8 @@ export const PROJECT_DUMMY: Project[] = [
teamId: 1,
name: '캘린더 만들기2',
content: '캘린더 만들기 설명2',
startDate: new Date('2022-05-12'),
endDate: new Date('2022-07-31'),
startDate: new Date('2022-05-12 00:00:00'),
endDate: new Date('2022-07-31 00:00:00'),
createAt: new Date('2022-05-12'),
updateAt: new Date('2022-06-01'),
},
Expand All @@ -49,8 +49,8 @@ export const PROJECT_DUMMY: Project[] = [
teamId: 1,
name: '캘린더 만들기3',
content: '캘린더 만들기 설명3',
startDate: new Date('2023-02-05'),
endDate: new Date('2023-06-05'),
startDate: new Date('2023-02-05 00:00:00'),
endDate: new Date('2023-06-05 00:00:00'),
createAt: new Date('2023-02-05'),
updateAt: new Date('2023-02-05'),
},
Expand All @@ -59,8 +59,8 @@ export const PROJECT_DUMMY: Project[] = [
teamId: 1,
name: '캘린더 만들기4',
content: '캘린더 만들기 설명4',
startDate: new Date('2023-04-25'),
endDate: new Date('2023-06-05'),
startDate: new Date('2023-04-25 00:00:00'),
endDate: new Date('2023-06-05 00:00:00'),
createAt: new Date('2023-04-25'),
updateAt: new Date('2023-04-25'),
},
Expand All @@ -69,8 +69,8 @@ export const PROJECT_DUMMY: Project[] = [
teamId: 1,
name: '캘린더 만들기5',
content: '캘린더 만들기 설명5',
startDate: new Date('2023-06-05'),
endDate: new Date('2023-09-12'),
startDate: new Date('2023-06-05 00:00:00'),
endDate: new Date('2023-09-12 00:00:00'),
createAt: new Date('2023-06-05'),
updateAt: new Date('2023-06-05'),
},
Expand Down Expand Up @@ -109,8 +109,8 @@ export const PROJECT_DUMMY: Project[] = [
teamId: 1,
name: '캘린더 만들기9',
content: '캘린더 만들기 설명9',
startDate: new Date('2024-01-01'),
endDate: new Date('2024-12-31'),
startDate: new Date('2024-01-01 00:00:00'),
endDate: new Date('2025-01-01 00:00:00'),
createAt: new Date('2024-01-01'),
updateAt: new Date('2024-07-16'),
},
Expand All @@ -119,8 +119,8 @@ export const PROJECT_DUMMY: Project[] = [
teamId: 1,
name: '캘린더 만들기10',
content: '캘린더 만들기 설명10',
startDate: new Date('2024-05-15'),
endDate: new Date('2024-08-31'),
startDate: new Date('2024-05-15 00:00:00'),
endDate: new Date('2024-09-01 00:00:00'),
createAt: new Date('2024-05-15'),
updateAt: new Date('2025-05-15'),
},
Expand Down
42 changes: 19 additions & 23 deletions src/pages/project/CalendarPage.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { useCallback, useMemo, useState } from 'react';
import { DateTime, Settings } from 'luxon';
import { Calendar, luxonLocalizer, Views } from 'react-big-calendar';
import { Calendar, DayPropGetter, EventPropGetter, luxonLocalizer, Views } from 'react-big-calendar';
import CalendarToolbar from '@components/task/calendar/CalendarToolbar';
import CustomDateHeader from '@components/task/calendar/CustomDateHeader';
import CustomEventWrapper from '@components/task/calendar/CustomEventWrapper';
import UpdateModalTask from '@components/modal/task/UpdateModalTask';
import useModal from '@hooks/useModal';
import ModalLayout from '@layouts/ModalLayout';
import ModalPortal from '@components/modal/ModalPortal';
import ModaFormButton from '@components/modal/ModaFormButton';
import useProjectContext from '@hooks/useProjectContext';
import Validator from '@utils/Validator';
import { TASK_DUMMY } from '@mocks/mockData';
import { TaskListWithStatus, TaskWithStatus } from '@/types/TaskType';
import { CustomEvent } from '@/types/CustomEventType';
import 'react-big-calendar/lib/css/react-big-calendar.css';
import '@/customReactBigCalendar.css';

function getCalendarTask(statusTasks: TaskListWithStatus[]) {
const calendarTasks: TaskWithStatus[] = [];
Expand All @@ -31,17 +32,13 @@ Settings.defaultZone = dt.zoneName;
const localizer = luxonLocalizer(DateTime, { firstDayOfWeek: 7 });

export default function CalendarPage() {
const { project } = useProjectContext();
const { showModal, openModal, closeModal } = useModal();
const [selectedTask, setSelectedTask] = useState<TaskWithStatus>();
const [date, setDate] = useState<Date>(() => DateTime.now().toJSDate());

const handleNavigate = useCallback((newDate: Date) => setDate(newDate), [setDate]);

const handleEventClick = (task: TaskWithStatus) => {
setSelectedTask(task);
openModal();
};

const handleSelectEvent = (event: CustomEvent) => {
setSelectedTask(event?.task);
openModal();
Expand All @@ -51,7 +48,16 @@ export default function CalendarPage() {
alert(`시작일: ${start}, 마감일: ${end}`);
}, []);

const handleEventPropGetter = () => ({ style: { padding: '0px', backgroundColor: 'inherit' } });
const handleDayPropGetter: DayPropGetter = (targetDate) => {
if (!project.startDate || !project.endDate) return {};

const isWithinRange = Validator.isWithinDateRange(project.startDate, project.endDate, targetDate);
const bgColor = isWithinRange ? '' : '!bg-[#D9D9D9]';
return { className: bgColor };
};
const handleEventPropGetter: EventPropGetter<CustomEvent> = () => ({
style: { padding: '0px', backgroundColor: 'inherit' },
});

const { views, components: customComponents } = useMemo(
() => ({
Expand All @@ -75,13 +81,11 @@ export default function CalendarPage() {
end: new Date(task.endDate),
allDays: true,
task: { ...task },
handleEventClick,
}))
.sort((a, b) => a.start.getTime() - b.start.getTime()),
};
const startDate = state.events.length ? state.events[0].start : null;

// ToDo: 프로젝트 기간 이외의 영역 처리
// ToDo: DnD, Resize 이벤트 추가 생각해보기
// ToDo: 할일 추가 모달 Form 작업 완료시 모달 컴포넌트 분리
// ToDo: 캘린더 크기 전체적으로 조정
Expand All @@ -104,22 +108,14 @@ export default function CalendarPage() {
endAccessor="end"
allDayAccessor="allDay"
popup
onSelectEvent={handleSelectEvent}
showAllEvents={false}
dayPropGetter={handleDayPropGetter}
eventPropGetter={handleEventPropGetter}
selectable
onSelectSlot={handleSelectSlot}
onSelectEvent={handleSelectEvent}
/>
{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>
)}
{showModal && <UpdateModalTask taskId={selectedTask!.taskId} onClose={closeModal} />}
</div>
);
}
1 change: 0 additions & 1 deletion src/types/CustomEventType.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ import { TaskWithStatus } from '@/types/TaskType';

export type CustomEvent = Event & {
task: TaskWithStatus;
handleEventClick: (task: TaskWithStatus) => void;
};
Loading

0 comments on commit 1ad11bc

Please sign in to comment.