Skip to content

Commit

Permalink
Feat: #208 PeriodDateInput 컴포넌트 종료일 토글 자동 활성화 기능 추가 (#209)
Browse files Browse the repository at this point in the history
* Fix: #208 날짜 관련 Validation 로직 수정

* Feat: #208 프로젝트 목록 데이터 타입 변환 추가

* Feat: #208 PeriodDateInput 컴포넌트 종료일 토글 자동 활성화 기능 추가

* Chore: #208 PeriodDateInput Import 정리

* Chore: #208 오타 수정 (projctStartDate → projectStartDate)

* Refactor: #208 시작일과 종료일 날짜 처리 과정 수정
  • Loading branch information
Seok93 authored Oct 14, 2024
1 parent e1b57a2 commit 6f4250d
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 31 deletions.
48 changes: 33 additions & 15 deletions src/components/common/PeriodDateInput.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { DateTime } from 'luxon';
import { useFormContext } from 'react-hook-form';
import { TASK_VALIDATION_RULES } from '@constants/formValidationRules';
import ToggleButton from '@components/common/ToggleButton';
import useToast from '@hooks/useToast';

import type { FieldError } from 'react-hook-form';
import type { Project } from '@/types/ProjectType';

type PeriodDateInputProps = {
startDateLabel: string;
endDateLabel: string;
startDateId: string;
endDateId: string;
startDate: Project['startDate'];
endDate: Project['endDate'];
startDateLabel: string;
endDateLabel: string;
startDateFieldName: string;
endDateFieldName: string;
limitStartDate: Project['startDate'];
limitEndDate: Project['endDate'];
};

export default function PeriodDateInput({
startDateLabel,
endDateLabel,
startDateId,
endDateId,
startDate,
endDate,
startDateLabel,
endDateLabel,
startDateFieldName,
endDateFieldName,
limitStartDate,
limitEndDate,
}: PeriodDateInputProps) {
const [hasDeadline, setHasDeadline] = useState(false);
const { toastWarn } = useToast();
const {
setValue,
getValues,
Expand All @@ -36,6 +39,14 @@ export default function PeriodDateInput({
register,
formState: { errors },
} = useFormContext();
const startDateStr = watch(startDateFieldName);
const endDateStr = watch(endDateFieldName);

useEffect(() => {
const startDate = startDateStr ? DateTime.fromISO(startDateStr).startOf('day') : null;
const endDate = endDateStr ? DateTime.fromISO(endDateStr).startOf('day') : null;
if (startDate && endDate) setHasDeadline(startDate < endDate);
}, [startDateStr, endDateStr]);

const handleDeadlineToggle = () => {
setValue(endDateFieldName, getValues(startDateFieldName));
Expand All @@ -51,7 +62,7 @@ export default function PeriodDateInput({
id={startDateId}
type="date"
{...register(startDateFieldName, {
...TASK_VALIDATION_RULES.START_DATE(startDate, endDate),
...TASK_VALIDATION_RULES.START_DATE(limitStartDate, limitEndDate),
onChange: (e) => {
if (!hasDeadline) setValue(endDateFieldName, e.target.value);
},
Expand All @@ -70,11 +81,18 @@ export default function PeriodDateInput({
id={endDateId}
type="date"
className={`${hasDeadline ? '' : '!bg-disable'}`}
disabled={!hasDeadline}
{...register(
endDateFieldName,
TASK_VALIDATION_RULES.END_DATE(hasDeadline, startDate, endDate, watch(startDateFieldName)),
)}
{...register(endDateFieldName, {
...TASK_VALIDATION_RULES.END_DATE(hasDeadline, limitStartDate, limitEndDate, watch(startDateFieldName)),
onChange: (e) => {
const startDate = DateTime.fromISO(startDateStr).startOf('day');
const endDate = DateTime.fromISO(e.target.value).startOf('day');
if (startDate > endDate) {
toastWarn('종료일은 시작일과 같거나 이후로 설정해주세요.');
setValue(endDateFieldName, startDateStr);
setHasDeadline(false);
}
},
})}
/>
<div className={`my-5 h-10 grow text-xs text-error ${errors[endDateFieldName] ? 'visible' : 'invisible'}`}>
{(errors[endDateFieldName] as FieldError | undefined)?.message}
Expand Down
10 changes: 5 additions & 5 deletions src/components/modal/task/ModalTaskForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type ModalTaskFormProps = {

// ToDo: React Query Error시 처리 추가할 것
export default function ModalTaskForm({ formId, project, taskId, onSubmit }: ModalTaskFormProps) {
const { projectId, startDate, endDate } = project;
const { projectId, startDate: projectStartDate, endDate: projectEndDate } = project;

const [keyword, setKeyword] = useState('');
const [assignees, setAssignees] = useState<UserWithRole[]>([]);
Expand Down Expand Up @@ -153,14 +153,14 @@ export default function ModalTaskForm({ formId, project, taskId, onSubmit }: Mod
/>

<PeriodDateInput
startDateLabel="시작일"
endDateLabel="종료일"
startDateId="startDate"
endDateId="endDate"
startDate={startDate}
endDate={endDate}
startDateLabel="시작일"
endDateLabel="종료일"
startDateFieldName="startDate"
endDateFieldName="endDate"
limitStartDate={projectStartDate}
limitEndDate={projectEndDate}
/>

<div className="mb-20">
Expand Down
10 changes: 5 additions & 5 deletions src/components/modal/task/UpdateModalTask.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default function UpdateModalTask({
onClose: handleClose,
}: UpdateModalTaskProps) {
const updateTaskFormId = 'updateTaskForm';
const { projectId, startDate, endDate } = project;
const { projectId, startDate: projectStartDate, endDate: projectEndDate } = project;

const [keyword, setKeyword] = useState('');
const { toastInfo, toastWarn } = useToast();
Expand Down Expand Up @@ -164,14 +164,14 @@ export default function UpdateModalTask({
/>

<PeriodDateInput
startDateLabel="시작일"
endDateLabel="종료일"
startDateId="startDate"
endDateId="endDate"
startDate={startDate}
endDate={endDate}
startDateLabel="시작일"
endDateLabel="종료일"
startDateFieldName="startDate"
endDateFieldName="endDate"
limitStartDate={projectStartDate}
limitEndDate={projectEndDate}
/>

<MarkdownEditor id="content" label="내용" contentFieldName="content" />
Expand Down
12 changes: 11 additions & 1 deletion src/services/projectService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,17 @@ export async function findUserByProject(
* @returns {Promise<AxiosResponse<Project[]>>}
*/
export async function getProjectList(teamId: Team['teamId'], axiosConfig: AxiosRequestConfig = {}) {
return authAxios.get<Project[]>(`/team/${teamId}/project`, axiosConfig);
return authAxios.get<Project[]>(`/team/${teamId}/project`, {
transformResponse: (data) => {
const parsedData: Project[] = JSON.parse(data);
return parsedData.map((data) => {
data.startDate = data.startDate && new Date(data.startDate);
data.endDate = data.endDate && new Date(data.endDate);
return data;
});
},
...axiosConfig,
});
}

/**
Expand Down
11 changes: 6 additions & 5 deletions src/utils/Validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ export default class Validator {
}

public static isWithinDateRange(start: Date | string, end: Date | string, target: Date | string) {
const startDate = DateTime.fromJSDate(new Date(start));
const endDate = DateTime.fromJSDate(new Date(end));
const targetDate = DateTime.fromJSDate(new Date(target));
const startDate = DateTime.fromJSDate(new Date(start)).startOf('day');
const endDate = DateTime.fromJSDate(new Date(end)).startOf('day');
const targetDate = DateTime.fromJSDate(new Date(target)).startOf('day');
return targetDate >= startDate && targetDate < endDate;
}

public static isEarlierStartDate(start: Date | string, end: Date | string) {
const startDate = DateTime.fromJSDate(new Date(start));
const endDate = DateTime.fromJSDate(new Date(end));
const startDate = DateTime.fromJSDate(new Date(start)).startOf('day');
const endDate = DateTime.fromJSDate(new Date(end)).startOf('day');
console.log(startDate.toISODate(), endDate.toISODate());
return startDate <= endDate;
}

Expand Down

0 comments on commit 6f4250d

Please sign in to comment.