diff --git a/src/frontend/src/components/NERFormModal.tsx b/src/frontend/src/components/NERFormModal.tsx index 9b07327840..b6deeabdef 100644 --- a/src/frontend/src/components/NERFormModal.tsx +++ b/src/frontend/src/components/NERFormModal.tsx @@ -1,6 +1,7 @@ import { ReactNode } from 'react'; import { FieldValues, UseFormHandleSubmit, UseFormReset } from 'react-hook-form'; import NERModal, { NERModalProps } from './NERModal'; +import { useToast } from '../hooks/toasts.hooks'; interface NERFormModalProps extends NERModalProps { reset: UseFormReset; @@ -27,18 +28,23 @@ const NERFormModal = ({ hideBackDrop = false, paperProps }: NERFormModalProps) => { + const toast = useToast(); /** * Wrapper function for onSubmit so that form data is reset after submit */ const onSubmitWrapper = async (data: any) => { - await onFormSubmit(data); - reset(); + try { + await onFormSubmit(data); + reset(); + } catch (e: unknown) { + if (e instanceof Error) toast.error(e.message, 6000); + } }; - const handleFormSubmit = (e: React.FormEvent) => { + const handleFormSubmit = async (e: React.FormEvent) => { e.preventDefault(); e.stopPropagation(); // Prevent event bubbling - handleUseFormSubmit(onSubmitWrapper)(e); + await handleUseFormSubmit(onSubmitWrapper)(e); }; return ( diff --git a/src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/TaskList/TaskFormModal.tsx b/src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/TaskList/TaskFormModal.tsx index 2cb26fdb43..7a5f80760f 100644 --- a/src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/TaskList/TaskFormModal.tsx +++ b/src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/TaskList/TaskFormModal.tsx @@ -2,7 +2,7 @@ import { yupResolver } from '@hookform/resolvers/yup'; import { Autocomplete, FormControl, FormHelperText, FormLabel, Grid, MenuItem, TextField } from '@mui/material'; import { DatePicker } from '@mui/x-date-pickers'; import { Controller, useForm } from 'react-hook-form'; -import { countWords, isGuest, isUnderWordCount, notGuest, Task, TaskPriority, TeamPreview } from 'shared'; +import { countWords, isGuest, isUnderWordCount, notGuest, Task, TaskStatus, TaskPriority, TeamPreview } from 'shared'; import { useAllUsers, useCurrentUser } from '../../../../hooks/users.hooks'; import * as yup from 'yup'; import { taskUserToAutocompleteOption } from '../../../../utils/task.utils'; @@ -10,16 +10,6 @@ import NERFormModal from '../../../../components/NERFormModal'; import LoadingIndicator from '../../../../components/LoadingIndicator'; import ErrorPage from '../../../ErrorPage'; -const schema = yup.object().shape({ - notes: yup.string().optional(), - startDate: yup.date().optional(), - deadline: yup.date().optional(), - priority: yup.mixed().oneOf(Object.values(TaskPriority)).required(), - assignees: yup.array().required(), - title: yup.string().required(), - taskId: yup.string().required() -}); - export interface EditTaskFormInput { taskId: string; title: string; @@ -32,6 +22,7 @@ export interface EditTaskFormInput { interface TaskFormModalProps { task?: Task; + status?: Task['status']; teams: TeamPreview[]; modalShow: boolean; onHide: () => void; @@ -39,7 +30,45 @@ interface TaskFormModalProps { onReset?: () => void; } -const TaskFormModal: React.FC = ({ task, onSubmit, modalShow, onHide, onReset }) => { +const TaskFormModal: React.FC = ({ task, status, onSubmit, modalShow, onHide, onReset }) => { + let schema; + + if (status === TaskStatus.IN_PROGRESS) { + schema = yup.object().shape({ + notes: yup + .string() + .optional() + .test((value) => { + if (!value) return true; + const wordCount = countWords(value); + return wordCount < 250; + }), + startDate: yup.date().optional(), + deadline: yup.date().required('Deadline is required for In Progress tasks'), + priority: yup.mixed().oneOf(Object.values(TaskPriority)).required(), + assignees: yup.array().required().min(1, 'At least one assignee is required for In Progress tasks'), + title: yup.string().required(), + taskId: yup.string().required() + }); + } else { + schema = yup.object().shape({ + notes: yup + .string() + .optional() + .test((value) => { + if (!value) return true; + const wordCount = countWords(value); + return wordCount < 250; + }), + startDate: yup.date().optional(), + deadline: yup.date().optional(), + priority: yup.mixed().oneOf(Object.values(TaskPriority)).required(), + assignees: yup.array().required(), + title: yup.string().required(), + taskId: yup.string().required() + }); + } + const user = useCurrentUser(); const { data: users, isLoading, isError, error } = useAllUsers(); @@ -161,6 +190,7 @@ const TaskFormModal: React.FC = ({ task, onSubmit, modalShow /> )} /> + {errors.assignees?.message} @@ -199,6 +229,7 @@ const TaskFormModal: React.FC = ({ task, onSubmit, modalShow /> )} /> + {errors.deadline?.message} diff --git a/src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/TaskList/v2/TaskColumn.tsx b/src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/TaskList/v2/TaskColumn.tsx index 5fcf249231..ff1f42ff05 100644 --- a/src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/TaskList/v2/TaskColumn.tsx +++ b/src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/TaskList/v2/TaskColumn.tsx @@ -30,30 +30,25 @@ export const TaskColumn = ({ const theme = useTheme(); const handleCreateTask = async ({ notes, title, deadline, assignees, priority, startDate }: EditTaskFormInput) => { - try { - const task = await createTask({ - wbsNum: project.wbsNum, - title, - deadline: deadline ? transformDate(deadline) : undefined, - startDate: startDate ? transformDate(startDate) : undefined, - priority, - status: status as TaskStatus, - assignees, - notes - }); - onAddTask(task); - toast.success('Task Successfully Created!'); - } catch (e: unknown) { - if (e instanceof Error) { - toast.error(e.message, 6000); - } - } + const task = await createTask({ + wbsNum: project.wbsNum, + title, + deadline: deadline ? transformDate(deadline) : undefined, + startDate: startDate ? transformDate(startDate) : undefined, + priority, + status: status as TaskStatus, + assignees, + notes + }); + onAddTask(task); + toast.success('Task Successfully Created!'); setShowCreateTaskModal(false); }; return ( <> setShowCreateTaskModal(false)} modalShow={showCreateTaskModal}