Add subtask CRUD and axios for it

This commit is contained in:
sosokker 2023-11-28 01:28:06 +07:00
parent 97e4cc5a0d
commit 3a7437aa09
2 changed files with 103 additions and 61 deletions

View File

@ -1,6 +1,6 @@
import { axiosInstance } from "./AxiosConfig"; import { axiosInstance } from "./AxiosConfig";
export const getSubtasks = async (parentTaskId) => { export const getSubtask = async (parentTaskId) => {
try { try {
const response = await axiosInstance.get(`subtasks?parent_task=${parentTaskId}`); const response = await axiosInstance.get(`subtasks?parent_task=${parentTaskId}`);
return response.data; return response.data;
@ -10,10 +10,11 @@ export const getSubtasks = async (parentTaskId) => {
} }
}; };
export const addSubtask = async (parentTaskId, text) => { export const addSubtasks = async (parentTaskId, text) => {
try { try {
const response = await axiosInstance.post("subtasks/", { const response = await axiosInstance.post("subtasks/", {
text, description: text,
completed: false,
parent_task: parentTaskId, parent_task: parentTaskId,
}); });
return response.data; return response.data;
@ -23,7 +24,7 @@ export const addSubtask = async (parentTaskId, text) => {
} }
}; };
export const deleteSubtask = async (subtaskId) => { export const deleteSubtasks = async (subtaskId) => {
try { try {
await axiosInstance.delete(`subtasks/${subtaskId}/`); await axiosInstance.delete(`subtasks/${subtaskId}/`);
} catch (error) { } catch (error) {
@ -31,3 +32,13 @@ export const deleteSubtask = async (subtaskId) => {
throw error; throw error;
} }
}; };
export const updateSubtask = async (subtaskId, data) => {
try {
const response = await axiosInstance.patch(`subtasks/${subtaskId}/`, data);
return response.data;
} catch (error) {
console.error("Error updating subtask:", error);
throw error;
}
};

View File

@ -1,23 +1,13 @@
import { useState } from "react"; import { useState, useEffect } from "react";
import { FaTasks, FaRegListAlt } from "react-icons/fa"; import { FaTasks, FaRegListAlt } from "react-icons/fa";
import { FaPlus } from "react-icons/fa6"; import { FaPlus, FaRegTrashCan } from "react-icons/fa6";
import { TbChecklist } from "react-icons/tb"; import { TbChecklist } from "react-icons/tb";
import DatePicker from "react-datepicker"; import DatePicker from "react-datepicker";
import { TimePicker } from "react-ios-time-picker"; import { TimePicker } from "react-ios-time-picker";
import "react-datepicker/dist/react-datepicker.css"; import "react-datepicker/dist/react-datepicker.css";
import { borderColor } from "@mui/system"; import { addSubtasks, deleteSubtasks, getSubtask, updateSubtask } from "src/api/SubTaskApi";
export function TaskDetailModal({ export function TaskDetailModal({ title, description, tags, difficulty, challenge, importance, taskId, updateTask }) {
title,
description,
tags,
difficulty,
challenge,
importance,
taskId,
updateTask,
}) {
let date = new Date();
const [isChallengeChecked, setChallengeChecked] = useState(challenge); const [isChallengeChecked, setChallengeChecked] = useState(challenge);
const [isImportantChecked, setImportantChecked] = useState(importance); const [isImportantChecked, setImportantChecked] = useState(importance);
const [currentDifficulty, setCurrentDifficulty] = useState(difficulty); const [currentDifficulty, setCurrentDifficulty] = useState(difficulty);
@ -27,7 +17,9 @@ export function TaskDetailModal({
const [startDateEnabled, setStartDateEnabled] = useState(false); const [startDateEnabled, setStartDateEnabled] = useState(false);
const [endDateEnabled, setEndDateEnabled] = useState(false); const [endDateEnabled, setEndDateEnabled] = useState(false);
const [isTaskComplete, setTaskComplete] = useState(false); const [isTaskComplete, setTaskComplete] = useState(false);
const [value, setValue] = useState('10:00'); const [value, setValue] = useState("10:00");
const [subtaskText, setSubtaskText] = useState("");
const [subtasks, setSubtasks] = useState([]);
const onChange = (timeValue) => { const onChange = (timeValue) => {
setValue(timeValue); setValue(timeValue);
@ -46,11 +38,7 @@ export function TaskDetailModal({
const handleTagChange = (tag) => { const handleTagChange = (tag) => {
const isSelected = selectedTags.includes(tag); const isSelected = selectedTags.includes(tag);
setSelectedTags( setSelectedTags(isSelected ? selectedTags.filter((selectedTag) => selectedTag !== tag) : [...selectedTags, tag]);
isSelected
? selectedTags.filter((selectedTag) => selectedTag !== tag)
: [...selectedTags, tag]
);
}; };
const handleStartDateChange = () => { const handleStartDateChange = () => {
@ -75,12 +63,73 @@ export function TaskDetailModal({
} }
}; };
const addSubtask = async () => {
try {
if (subtaskText.trim() !== "") {
const newSubtask = await addSubtasks(taskId, subtaskText.trim());
setSubtasks([...subtasks, newSubtask]);
setSubtaskText("");
}
} catch (error) {
console.error("Error adding subtask:", error);
}
};
const toggleSubtaskCompletion = async (index) => {
try {
const updatedSubtasks = [...subtasks];
updatedSubtasks[index].completed = !updatedSubtasks[index].completed;
await updateSubtask(updatedSubtasks[index].id, { completed: updatedSubtasks[index].completed });
setSubtasks(updatedSubtasks);
} catch (error) {
console.error("Error updating subtask:", error);
}
};
const deleteSubtask = async (index) => {
try {
await deleteSubtasks(subtasks[index].id);
const updatedSubtasks = [...subtasks];
updatedSubtasks.splice(index, 1);
setSubtasks(updatedSubtasks);
} catch (error) {
console.error("Error deleting subtask:", error);
}
};
const subtaskElements = subtasks.map((subtask, index) => (
<div key={index} className="flex items-center space-x-2">
<input
type="checkbox"
checked={subtask.completed}
className="checkbox checkbox-xs bg-gray-400"
onChange={() => toggleSubtaskCompletion(index)}
/>
<div className={`flex items-center rounded p-2 shadow border-2 ${subtask.completed && "line-through"}`}>
{subtask.description}
<FaRegTrashCan className="cursor-pointer ml-2 text-red-500" onClick={() => deleteSubtask(index)} />
</div>
</div>
));
useEffect(() => {
const fetchSubtasks = async () => {
try {
const fetchedSubtasks = await getSubtask(taskId);
setSubtasks(fetchedSubtasks);
} catch (error) {
console.error("Error fetching subtasks:", error);
}
};
fetchSubtasks();
}, [taskId]);
// Existing tags // Existing tags
const existingTags = tags.map((tag, index) => ( const existingTags = tags.map((tag, index) => (
<div <div
key={index} key={index}
className={`text-xs inline-flex items-center font-bold leading-sm uppercase px-2 py-1 bg-${tag.color}-200 text-${tag.color}-700 rounded-full`} className={`text-xs inline-flex items-center font-bold leading-sm uppercase px-2 py-1 bg-${tag.color}-200 text-${tag.color}-700 rounded-full`}>
>
{tag.label} {tag.label}
</div> </div>
)); ));
@ -89,8 +138,7 @@ export function TaskDetailModal({
const selectedTagElements = selectedTags.map((tag, index) => ( const selectedTagElements = selectedTags.map((tag, index) => (
<div <div
key={index} key={index}
className={`text-xs inline-flex items-center font-bold leading-sm uppercase px-2 py-1 bg-${tag.color}-200 text-${tag.color}-700 rounded-full`} className={`text-xs inline-flex items-center font-bold leading-sm uppercase px-2 py-1 bg-${tag.color}-200 text-${tag.color}-700 rounded-full`}>
>
{tag.label} {tag.label}
</div> </div>
)); ));
@ -114,16 +162,10 @@ export function TaskDetailModal({
<div className="flex flex-col py-2 pb-4"> <div className="flex flex-col py-2 pb-4">
<div className="flex flex-row space-x-5"> <div className="flex flex-row space-x-5">
<div className="dropdown"> <div className="dropdown">
<label <label tabIndex={0} className="btn-md border-2 rounded-xl m-1 py-1">
tabIndex={0}
className="btn-md border-2 rounded-xl m-1 py-1"
>
+ Add Tags + Add Tags
</label> </label>
<ul <ul tabIndex={0} className="dropdown-content z-[10] menu p-2 shadow bg-base-100 rounded-box w-52">
tabIndex={0}
className="dropdown-content z-[10] menu p-2 shadow bg-base-100 rounded-box w-52"
>
{tags.map((tag, index) => ( {tags.map((tag, index) => (
<li key={index}> <li key={index}>
<label className="cursor-pointer space-x-2"> <label className="cursor-pointer space-x-2">
@ -155,14 +197,10 @@ export function TaskDetailModal({
<input <input
type="checkbox" type="checkbox"
checked={startDateEnabled} checked={startDateEnabled}
className="checkbox checkbox-xs bg-black" className="checkbox checkbox-xs bg-gray-400"
onChange={handleStartDateChange} onChange={handleStartDateChange}
/> />
<div <div className={`rounded p-2 shadow border-2 ${!startDateEnabled && "opacity-50"}`}>
className={`rounded p-2 shadow border-2 ${
!startDateEnabled && "opacity-50"
}`}
>
<DatePicker <DatePicker
selected={dateStart} selected={dateStart}
onChange={(date) => setDateStart(date)} onChange={(date) => setDateStart(date)}
@ -173,7 +211,6 @@ export function TaskDetailModal({
</div> </div>
<div className="rounded p-2 shadow border-2"> <div className="rounded p-2 shadow border-2">
<TimePicker <TimePicker
value={value} value={value}
onChange={onChange} onChange={onChange}
@ -188,7 +225,7 @@ export function TaskDetailModal({
<input <input
type="checkbox" type="checkbox"
checked={isTaskComplete} checked={isTaskComplete}
className="checkbox checkbox-xl bg-black" className="checkbox checkbox-xl bg-gray-400"
onChange={handleTaskCompleteChange} onChange={handleTaskCompleteChange}
/> />
</div> </div>
@ -202,19 +239,11 @@ export function TaskDetailModal({
<input <input
type="checkbox" type="checkbox"
checked={endDateEnabled} checked={endDateEnabled}
className="checkbox checkbox-xs bg-black" className="checkbox checkbox-xs bg-gray-400"
onChange={handleEndDateChange} onChange={handleEndDateChange}
/> />
<div <div className={`rounded p-2 shadow border-2 ${!endDateEnabled && "opacity-50"}`}>
className={`rounded p-2 shadow border-2 ${ <DatePicker selected={dateEnd} onChange={(date) => setDateEnd(date)} disabled={!endDateEnabled} />
!endDateEnabled && "opacity-50"
}`}
>
<DatePicker
selected={dateEnd}
onChange={(date) => setDateEnd(date)}
disabled={!endDateEnabled}
/>
</div> </div>
</div> </div>
</div> </div>
@ -295,17 +324,19 @@ export function TaskDetailModal({
type="text" type="text"
placeholder="subtask topic" placeholder="subtask topic"
className="input input-bordered flex-1 w-full" className="input input-bordered flex-1 w-full"
value={subtaskText}
onChange={(e) => setSubtaskText(e.target.value)}
/> />
<button className="btn"> <button className="btn" onClick={addSubtask}>
<FaPlus /> <FaPlus />
Add Subtask Add Subtask
</button> </button>
</div> </div>
{/* Display Subtasks */}
<div className="flex flex-col space-y-2 pt-2">{subtaskElements}</div>
</div> </div>
<form method="dialog"> <form method="dialog">
<button className="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"> <button className="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">X</button>
X
</button>
</form> </form>
</div> </div>
</dialog> </dialog>