diff --git a/backend/typescript/services/implementations/authService.ts b/backend/typescript/services/implementations/authService.ts index b6243979..594ad0c4 100644 --- a/backend/typescript/services/implementations/authService.ts +++ b/backend/typescript/services/implementations/authService.ts @@ -34,7 +34,9 @@ class AuthService implements IAuthService { const user = await this.userService.getUserByEmail(email); return { ...token, ...user }; } catch (error) { - Logger.error(`Failed to generate token for user with email ${email}`); + Logger.error( + `Failed to generate token for user with email ${email}, error ${error}`, + ); throw error; } } diff --git a/frontend/src/features/task-management/components/TaskDetailsModal.tsx b/frontend/src/features/task-management/components/TaskDetailsModal.tsx index 78b59fa5..12b3b80a 100644 --- a/frontend/src/features/task-management/components/TaskDetailsModal.tsx +++ b/frontend/src/features/task-management/components/TaskDetailsModal.tsx @@ -13,9 +13,11 @@ import { useToast, } from "@chakra-ui/react"; import React, { useEffect, useState } from "react"; +import { useHistory } from "react-router-dom"; import TaskTemplateAPIClient from "../../../APIClients/TaskTemplateAPIClient"; import Button from "../../../components/common/Button"; import TaskCategoryBadge from "../../../components/common/TaskCategoryBadge"; +import { EDIT_TASK_TEMPLATE_PAGE } from "../../../constants/Routes"; import { Task } from "../../../types/TaskTypes"; interface TaskDetailsModelsProps { @@ -30,6 +32,7 @@ const TaskDetailsModal = ({ onClose, }: TaskDetailsModelsProps): React.ReactElement => { const toast = useToast(); + const history = useHistory(); const [taskTemplateData, setTaskTemplateData] = useState(null); useEffect(() => { @@ -118,13 +121,7 @@ const TaskDetailsModal = ({ variant="blue-outline" width="100%" onClick={() => { - toast({ - title: "Edit Task", - description: "Edit task functionality not implemented yet", - status: "info", - duration: 3000, - isClosable: true, - }); + history.push(`${EDIT_TASK_TEMPLATE_PAGE}/${taskTemplateId}`); }} > Edit Task diff --git a/frontend/src/features/task-management/components/TaskManagementTable.tsx b/frontend/src/features/task-management/components/TaskManagementTable.tsx index 77b003ef..7027cda5 100644 --- a/frontend/src/features/task-management/components/TaskManagementTable.tsx +++ b/frontend/src/features/task-management/components/TaskManagementTable.tsx @@ -7,11 +7,13 @@ import TaskManagementTableSection from "./TaskManagementTableSection"; interface TaskManagementTableProps { tasks: Task[]; clearFilters: () => void; + onTaskClick: (task: Task) => void; } const TaskManagementTable = ({ tasks, clearFilters, + onTaskClick, }: TaskManagementTableProps): React.ReactElement => { return ( @@ -48,7 +50,7 @@ const TaskManagementTable = ({ ) : ( - + )} diff --git a/frontend/src/features/task-management/components/TaskManagementTableSection.tsx b/frontend/src/features/task-management/components/TaskManagementTableSection.tsx index 344319c9..bbf42d58 100644 --- a/frontend/src/features/task-management/components/TaskManagementTableSection.tsx +++ b/frontend/src/features/task-management/components/TaskManagementTableSection.tsx @@ -5,15 +5,22 @@ import { Task } from "../../../types/TaskTypes"; interface TaskManagementTableSectionProps { tasks: Task[]; + onTaskClick: (task: Task) => void; } const TaskManagementTableSection = ({ tasks, + onTaskClick, }: TaskManagementTableSectionProps): React.ReactElement => { return ( {tasks.map((task) => ( - + onTaskClick(task)} + cursor="pointer" + _hover={{ bg: "gray.100" }} + > {task.name} diff --git a/frontend/src/features/task-management/pages/AddTaskTemplatePage.tsx b/frontend/src/features/task-management/pages/AddTaskTemplatePage.tsx index ce84229b..72e5b23f 100644 --- a/frontend/src/features/task-management/pages/AddTaskTemplatePage.tsx +++ b/frontend/src/features/task-management/pages/AddTaskTemplatePage.tsx @@ -24,12 +24,8 @@ import { ReactComponent as GamesIcon } from "../../../assets/icons/games.svg"; import { ReactComponent as TrainingIcon } from "../../../assets/icons/training.svg"; import { ReactComponent as WalkIcon } from "../../../assets/icons/walk.svg"; import { ReactComponent as MiscIcon } from "../../../assets/icons/misc.svg"; - -interface TaskTemplateForm { - taskName: string; - taskCategory: TaskCategory | null; - taskInstructions: string; -} +import TaskTemplateAPIClient from "../../../APIClients/TaskTemplateAPIClient"; +import { type CreateTaskDTO } from "../../../types/TaskTypes"; interface FormErrors { taskName?: string; @@ -39,10 +35,10 @@ interface FormErrors { const AddTaskTemplatePage = (): React.ReactElement => { const history = useHistory(); - const [formData, setFormData] = useState({ + const [formData, setFormData] = useState({ taskName: "", - taskCategory: null, - taskInstructions: "", + category: TaskCategory.MISC, + instructions: "", }); const [errors, setErrors] = useState({}); const [isSubmitting, setIsSubmitting] = useState(false); @@ -93,7 +89,7 @@ const AddTaskTemplatePage = (): React.ReactElement => { }; const handleCategoryChange = (category: TaskCategory) => { - setFormData({ ...formData, taskCategory: category }); + setFormData({ ...formData, category }); setHasChanges(true); if (errors.taskCategory) { setErrors({ ...errors, taskCategory: undefined }); @@ -103,7 +99,7 @@ const AddTaskTemplatePage = (): React.ReactElement => { const handleInstructionsChange = ( event: React.ChangeEvent, ) => { - setFormData({ ...formData, taskInstructions: event.target.value }); + setFormData({ ...formData, instructions: event.target.value }); setHasChanges(true); if (errors.taskInstructions) { setErrors({ ...errors, taskInstructions: undefined }); @@ -117,11 +113,11 @@ const AddTaskTemplatePage = (): React.ReactElement => { newErrors.taskName = "Field is required."; } - if (!formData.taskCategory) { + if (!formData.category) { newErrors.taskCategory = "Please select an option from the dropdown."; } - if (!formData.taskInstructions.trim()) { + if (!formData.instructions?.trim()) { newErrors.taskInstructions = "Information must not exceed 10,000 words."; } @@ -144,12 +140,18 @@ const AddTaskTemplatePage = (): React.ReactElement => { /* eslint-disable-next-line no-console */ console.log({ taskName: formData.taskName, - taskCategory: formData.taskCategory, - taskInstructions: formData.taskInstructions, + taskCategory: formData.category, + taskInstructions: formData.instructions, }); - // Simulate API call delay - await new Promise((resolve) => setTimeout(resolve, 1000)); + // Call the API endpoint + try { + await TaskTemplateAPIClient.createTaskTemplate(formData); + } catch (error) { + // TODO: deprecate console use in frontend + /* eslint-disable-next-line no-console */ + console.error("Could not post task template: ", error); + } // Navigate back to task management page history.push(TASK_MANAGEMENT_PAGE); @@ -217,7 +219,7 @@ const AddTaskTemplatePage = (): React.ReactElement => { {