From 1f289e854584cea60da485090a2670b46792eb3c Mon Sep 17 00:00:00 2001 From: Sergey Elpashev Date: Wed, 7 May 2025 11:24:08 +0300 Subject: [PATCH] feat: CRUD tasks --- src/pages/profile_tasks.dto.ts | 37 +++++++++++++++ src/pages/profile_tasks.tsx | 83 +++++++++++++++++++--------------- 2 files changed, 84 insertions(+), 36 deletions(-) diff --git a/src/pages/profile_tasks.dto.ts b/src/pages/profile_tasks.dto.ts index 8c5d088..c16401c 100644 --- a/src/pages/profile_tasks.dto.ts +++ b/src/pages/profile_tasks.dto.ts @@ -54,3 +54,40 @@ export interface ICreateTaskResponse { }; }; } + +export interface ITaskDetails { + profile: string; + title: string; + description: string; + subject: string; + taskType: string; + dateTime_due: string; + remind_before_days: number; + repeat_reminder: number; + reminder_time: string; +} + +export interface IDeleteTaskResponse { + success: boolean; + message: string; +} + +export interface IEditTaskResponse { + success: boolean; + message: string; + profile: string; + task: { + id: number; + title: string; + description: string; + subject: string; + taskType: string; + dateTime_due: string; + isCompleted: boolean; + reminder?: { + remind_before_days: number; + repeat_interval: number; + reminder_time: string; + }; + }; +} diff --git a/src/pages/profile_tasks.tsx b/src/pages/profile_tasks.tsx index 69a24bb..18da63d 100644 --- a/src/pages/profile_tasks.tsx +++ b/src/pages/profile_tasks.tsx @@ -28,7 +28,15 @@ import { Checkbox, CheckboxPassThroughMethodOptions } from "primereact/checkbox" import { Nullable } from "primereact/ts-helpers"; import { SubmitHandler, useForm } from "react-hook-form"; import { v4 as uuid } from "uuid"; -import { ITask, ITaskForm, IApiResponse, ICreateTaskResponse } from "./profile_tasks.dto"; +import { + ITask, + ITaskForm, + IApiResponse, + ICreateTaskResponse, + ITaskDetails, + IDeleteTaskResponse, + IEditTaskResponse, +} from "./profile_tasks.dto"; import classes from "./profile_tasks.module.scss"; import apiClient from "@/services/api"; @@ -68,11 +76,9 @@ const ProfileTasks: FunctionComponent = () => { setIsLoading(true); const response = await apiClient("/api/tasks/view_tasks/"); - // Update choices setSubjectChoices(response.subject_choices); setTaskTypeChoices(response.task_type_choices); - // Convert API tasks to our format const convertedTasks: ITask[] = response.days.flatMap((day) => day.tasks.map((apiTask) => ({ id: apiTask.id.toString(), @@ -105,7 +111,6 @@ const ProfileTasks: FunctionComponent = () => { }, }); - // Update example_tags to use the choices from the API const example_tags = useMemo( () => ({ first: Object.keys(subjectChoices), @@ -161,13 +166,16 @@ const ProfileTasks: FunctionComponent = () => { throw new Error(response.message); } } else { - await apiClient(`/api/tasks/update_task/${editContent?.id}/`, { + const response = await apiClient(`/api/tasks/edit_task/${editContent?.id}/`, { method: "PUT", body: JSON.stringify(taskData), }); + + if (!response.success) { + throw new Error(response.message); + } } - // Refresh tasks after saving await fetchTasks(); if (isCreating) setIsOpen(false); @@ -253,11 +261,14 @@ const ProfileTasks: FunctionComponent = () => { if (!editContent) return; try { - await apiClient(`/api/delete_task/${editContent.id}/`, { + const response = await apiClient(`/api/tasks/delete_task/${editContent.id}/`, { method: "DELETE", }); - // Refresh tasks after deletion + if (!response.success) { + throw new Error(response.message); + } + await fetchTasks(); setIsOpen(false); @@ -267,7 +278,6 @@ const ProfileTasks: FunctionComponent = () => { } }; - // Update the task marking functionality const handleMarkTask = async (taskId: string, isCompleted: boolean) => { try { await apiClient(`/api/update_task/${taskId}/`, { @@ -275,7 +285,6 @@ const ProfileTasks: FunctionComponent = () => { body: JSON.stringify({ isCompleted }), }); - // Refresh tasks after marking await fetchTasks(); } catch (error) { console.error("Failed to mark task:", error); @@ -285,7 +294,6 @@ const ProfileTasks: FunctionComponent = () => { const filteredTasks = useMemo(() => { let filtered = tasks; - // Фильтрация по поиску if (searchQuery) { filtered = filtered.filter( (task) => @@ -294,7 +302,6 @@ const ProfileTasks: FunctionComponent = () => { ); } - // Фильтрация по тегам if (filterTags.first || filterTags.second) { filtered = filtered.filter( (task) => @@ -313,6 +320,30 @@ const ProfileTasks: FunctionComponent = () => { if (searchInputRef.current && openSearchModal) searchInputRef.current.focus(); }, [searchInputRef, openSearchModal]); + const handleViewTask = async (taskId: string) => { + try { + const taskDetails = await apiClient(`/api/tasks/view_task/${taskId}/`); + + const task: ITask = { + id: taskId, + name: taskDetails.title, + checked: false, + date: new Date(taskDetails.dateTime_due), + description: taskDetails.description, + tags: [taskDetails.subject, taskDetails.taskType], + new: false, + }; + + setIsOpen(true); + setIsEdit(true); + setEditContent(task); + setCalendarDate(task.date); + setIsEditModal(false); + } catch (error) { + console.error("Failed to fetch task details:", error); + } + }; + return (
{isLoading ? ( @@ -582,12 +613,7 @@ const ProfileTasks: FunctionComponent = () => { key={task.id} checked={task.checked} overdue={task.date < new Date()} - onClick={() => { - setIsOpen(true); - setIsEdit(true); - setEditContent(task); - setCalendarDate(task.date); - }} + onClick={() => handleViewTask(task.id)} onMarkClick={() => handleMarkTask(task.id, !task.checked)} /> ))} @@ -603,12 +629,7 @@ const ProfileTasks: FunctionComponent = () => { name={task.name} key={task.id} checked={task.checked} - onClick={() => { - setIsOpen(true); - setIsEdit(true); - setEditContent(task); - setCalendarDate(task.date); - }} + onClick={() => handleViewTask(task.id)} onMarkClick={() => handleMarkTask(task.id, !task.checked)} /> ))} @@ -622,12 +643,7 @@ const ProfileTasks: FunctionComponent = () => { name={task.name} key={task.id} checked={task.checked} - onClick={() => { - setIsOpen(true); - setIsEdit(true); - setEditContent(task); - setCalendarDate(task.date); - }} + onClick={() => handleViewTask(task.id)} onMarkClick={() => handleMarkTask(task.id, !task.checked)} /> ))} @@ -674,12 +690,7 @@ const ProfileTasks: FunctionComponent = () => { key={task.id} checked={task.checked} overdue={task.date < new Date()} - onClick={() => { - setIsOpen(true); - setIsEdit(true); - setEditContent(task); - setCalendarDate(task.date); - }} + onClick={() => handleViewTask(task.id)} onMarkClick={() => handleMarkTask(task.id, !task.checked)} /> ))