Skip to content
4 changes: 2 additions & 2 deletions src/components/modals/create-evaluation-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const CreateEvaluationFormSchema = z.object({
'C_MINUS',
'F',
]),
comment: z.string().min(1, '정성 코멘트를 입력해주세요.'),
comment: z.string().min(1, '정성 코멘트를 입력해주세요.').max(1000),
});

type CreateEvaluationFormValues = z.infer<typeof CreateEvaluationFormSchema>;
Expand Down Expand Up @@ -147,7 +147,7 @@ function CreateEvaluationForm({
id="comment"
placeholder="정성 코멘트를 입력해 주세요."
className="min-h-[230px]"
maxLength={5000}
maxLength={1000}
/>
</FormField>
</form>
Expand Down
29 changes: 24 additions & 5 deletions src/components/modals/create-mission-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { zodResolver } from '@hookform/resolvers/zod';
import dayjs from 'dayjs';
import { Plus, XIcon } from 'lucide-react';
import { useState } from 'react';
import { Controller, FormProvider, useForm } from 'react-hook-form';
Expand All @@ -9,8 +10,11 @@ import FormField from '@/components/ui/form/form-field';
import { BaseInput, TextAreaInput } from '@/components/ui/input';
import { Modal } from '@/components/ui/modal';
import { useGroupStudyDetailQuery } from '@/features/study/group/model/use-study-query';
import { useCreateMission } from '@/hooks/queries/mission-api';
import { createDateDisabledMatcher } from '@/utils/time';
import { useCreateMission, useGetMissions } from '@/hooks/queries/mission-api';
import {
createDisabledDateMatcherForMission,
MissionPeriod,
} from '@/utils/time';

// Form Schema
const CreateMissionFormSchema = z.object({
Expand Down Expand Up @@ -45,7 +49,12 @@ export default function CreateMissionModal({
}: CreateMissionModalProps) {
const [open, setOpen] = useState<boolean>(false);
const { data: studyData } = useGroupStudyDetailQuery(groupStudyId);
const { data: existingMissions } = useGetMissions({
groupStudyId,
pageSize: 100,
});

const studyStartDate = studyData?.basicInfo?.startDate;
const studyEndDate = studyData?.basicInfo?.endDate;

return (
Expand Down Expand Up @@ -76,7 +85,9 @@ export default function CreateMissionModal({

<CreateMissionForm
groupStudyId={groupStudyId}
studyStartDate={studyStartDate}
studyEndDate={studyEndDate}
existingMissions={existingMissions?.content}
onClose={() => setOpen(false)}
/>
</Modal.Content>
Expand All @@ -87,13 +98,17 @@ export default function CreateMissionModal({

interface CreateMissionFormProps {
groupStudyId: number;
studyStartDate?: string;
studyEndDate?: string;
existingMissions?: MissionPeriod[];
onClose: () => void;
}

function CreateMissionForm({
groupStudyId,
studyStartDate,
studyEndDate,
existingMissions,
onClose,
}: CreateMissionFormProps) {
const methods = useForm<CreateMissionFormValues>({
Expand All @@ -113,8 +128,8 @@ function CreateMissionForm({
const { mutate: createMission } = useCreateMission();

const onValidSubmit = (values: CreateMissionFormValues) => {
const startDate = values.dateRange.from.toISOString();
const endDate = values.dateRange.to.toISOString();
const startDate = dayjs(values.dateRange.from).format('YYYY-MM-DD');
const endDate = dayjs(values.dateRange.to).format('YYYY-MM-DD');

createMission(
{
Expand Down Expand Up @@ -217,7 +232,11 @@ function CreateMissionForm({
mode="range"
selected={field.value}
onSelect={(date) => field.onChange(date)}
disabled={createDateDisabledMatcher(studyEndDate)}
disabled={createDisabledDateMatcherForMission({
studyStartDate,
studyEndDate,
existingMissions,
})}
/>
)}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/components/modals/edit-evaluation-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ function EditEvaluationForm({
id="comment"
placeholder="정성 코멘트를 입력해 주세요."
className="min-h-[230px]"
maxLength={5000}
maxLength={1000}
/>
</FormField>
</form>
Expand Down
4 changes: 2 additions & 2 deletions src/components/modals/edit-homework-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { useEditHomework } from '@/hooks/queries/group-study-homework-api';
import { BaseInput, TextAreaInput } from '../ui/input';

const EditHomeworkFormSchema = z.object({
textContent: z.string().min(1, '과제 상세 내용을 입력해주세요.'),
textContent: z.string().min(1, '과제 상세 내용을 입력해주세요.').max(1000),
attachmentLink: z.string().optional(),
});

Expand Down Expand Up @@ -135,7 +135,7 @@ function EditHomeworkForm({
id="textContent"
className="min-h-[230px]"
placeholder="학습한 내용을 자세히 작성해 주세요."
maxLength={5000}
maxLength={1000}
/>
</FormField>

Expand Down
42 changes: 33 additions & 9 deletions src/components/modals/edit-mission-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { zodResolver } from '@hookform/resolvers/zod';
import dayjs from 'dayjs';
import { XIcon } from 'lucide-react';
import { useEffect, useState } from 'react';
import { Controller, FormProvider, useForm } from 'react-hook-form';
Expand All @@ -9,8 +10,15 @@ import FormField from '@/components/ui/form/form-field';
import { BaseInput, TextAreaInput } from '@/components/ui/input';
import { Modal } from '@/components/ui/modal';
import { useGroupStudyDetailQuery } from '@/features/study/group/model/use-study-query';
import { useGetMission, useUpdateMission } from '@/hooks/queries/mission-api';
import { createDateDisabledMatcher } from '@/utils/time';
import {
useGetMission,
useGetMissions,
useUpdateMission,
} from '@/hooks/queries/mission-api';
import {
createDisabledDateMatcherForMission,
MissionPeriod,
} from '@/utils/time';

// Form Schema
const EditMissionFormSchema = z.object({
Expand Down Expand Up @@ -42,7 +50,12 @@ export default function EditMissionModal({
const [open, setOpen] = useState<boolean>(false);
const { data: missionData, isLoading } = useGetMission(missionId);
const { data: studyData } = useGroupStudyDetailQuery(groupStudyId);
const { data: existingMissions } = useGetMissions({
groupStudyId,
pageSize: 100,
});

const studyStartDate = studyData?.basicInfo?.startDate;
const studyEndDate = studyData?.basicInfo?.endDate;

return (
Expand Down Expand Up @@ -77,7 +90,9 @@ export default function EditMissionModal({
<EditMissionForm
missionData={missionData}
missionId={missionId}
studyStartDate={studyStartDate}
studyEndDate={studyEndDate}
existingMissions={existingMissions?.content}
onClose={() => setOpen(false)}
/>
) : null}
Expand All @@ -97,14 +112,18 @@ interface EditMissionFormProps {
missionEndDate?: string;
};
missionId: number;
studyStartDate?: string;
studyEndDate?: string;
existingMissions?: MissionPeriod[];
onClose: () => void;
}

function EditMissionForm({
missionData,
missionId,
studyStartDate,
studyEndDate,
existingMissions,
onClose,
}: EditMissionFormProps) {
const methods = useForm<EditMissionFormValues>({
Expand All @@ -126,8 +145,10 @@ function EditMissionForm({
},
});

const { handleSubmit, formState, control, reset } = methods;

useEffect(() => {
methods.reset({
reset({
title: missionData.missionTitle || '',
description: missionData.missionDescription || '',
weekNum: missionData.weekNum?.toString() || '',
Expand All @@ -141,15 +162,13 @@ function EditMissionForm({
: new Date(),
},
});
}, [missionData, methods]);

const { handleSubmit, formState, control } = methods;
}, [missionData, reset]);

const { mutate: updateMission } = useUpdateMission();

const onValidSubmit = (values: EditMissionFormValues) => {
const startDate = values.dateRange.from.toISOString();
const endDate = values.dateRange.to.toISOString();
const startDate = dayjs(values.dateRange.from).format('YYYY-MM-DD');
const endDate = dayjs(values.dateRange.to).format('YYYY-MM-DD');

updateMission(
{
Expand Down Expand Up @@ -252,7 +271,12 @@ function EditMissionForm({
mode="range"
selected={field.value}
onSelect={(date) => field.onChange(date)}
disabled={createDateDisabledMatcher(studyEndDate)}
disabled={createDisabledDateMatcherForMission({
studyStartDate,
studyEndDate,
existingMissions,
editingMissionId: missionId,
})}
/>
)}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/features/study/group/const/use-group-study-mutation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useMutation } from '@tanstack/react-query';
import { createGroupStudy } from '../api/creat-group-study';
import { createGroupStudy } from '../api/create-group-study';
import { GroupStudyFormRequest } from '../api/group-study-types';
import { updateGroupStudy } from '../api/update-group-study';

Expand Down
63 changes: 57 additions & 6 deletions src/utils/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,23 +91,74 @@ export const getKoreaDisplayMonday = (base?: Date) => {
return dow === 0 || dow === 6 ? addDays(monday, 7) : monday;
};

export const createDateDisabledMatcher = (endDateString?: string) => {
export interface MissionPeriod {
missionId?: number;
startDate?: string;
endDate?: string;
}

export interface CreateDisabledDateMatcherForMissionOptions {
studyStartDate?: string;
studyEndDate?: string;
existingMissions?: MissionPeriod[];
editingMissionId?: number;
}

export const createDisabledDateMatcherForMission = (
options: CreateDisabledDateMatcherForMissionOptions,
) => {
const { studyStartDate, studyEndDate, existingMissions, editingMissionId } =
options;

return (date: Date) => {
const normalizedDate = new Date(date);
normalizedDate.setHours(0, 0, 0, 0);

const today = new Date();
today.setHours(0, 0, 0, 0);

if (date < today) {
if (normalizedDate < today) {
return true;
}

if (endDateString) {
const endDate = new Date(endDateString);
endDate.setHours(23, 59, 59, 999);
if (date > endDate) {
if (studyStartDate) {
const startDate = new Date(studyStartDate);
startDate.setHours(0, 0, 0, 0);
if (normalizedDate < startDate) {
return true;
}
}

if (studyEndDate) {
const endDate = new Date(studyEndDate);
endDate.setHours(0, 0, 0, 0);
if (normalizedDate > endDate) {
return true;
}
}

if (existingMissions) {
const targetTime = normalizedDate.getTime();
for (const mission of existingMissions) {
if (editingMissionId && mission.missionId === editingMissionId)
continue;

if (mission.startDate && mission.endDate) {
const missionStart = new Date(mission.startDate);
missionStart.setHours(0, 0, 0, 0);
const missionEnd = new Date(mission.endDate);
missionEnd.setHours(0, 0, 0, 0);

if (
targetTime >= missionStart.getTime() &&
targetTime <= missionEnd.getTime()
) {
return true;
}
}
}
}

return false;
};
};
Loading