mirror of
https://github.com/TurTaskProject/TurTaskWeb.git
synced 2025-12-19 05:54:07 +01:00
commit
fe75c777ef
@ -64,6 +64,8 @@
|
|||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.4",
|
"eslint-plugin-react-refresh": "^0.4.4",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.31",
|
||||||
|
"prettier": "^3.1.0",
|
||||||
|
"prettier-plugin-tailwindcss": "^0.5.7",
|
||||||
"tailwindcss": "^3.3.5",
|
"tailwindcss": "^3.3.5",
|
||||||
"vite": "^4.5.0"
|
"vite": "^4.5.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -163,6 +163,12 @@ devDependencies:
|
|||||||
postcss:
|
postcss:
|
||||||
specifier: ^8.4.31
|
specifier: ^8.4.31
|
||||||
version: 8.4.31
|
version: 8.4.31
|
||||||
|
prettier:
|
||||||
|
specifier: ^3.1.0
|
||||||
|
version: 3.1.0
|
||||||
|
prettier-plugin-tailwindcss:
|
||||||
|
specifier: ^0.5.7
|
||||||
|
version: 0.5.7(prettier@3.1.0)
|
||||||
tailwindcss:
|
tailwindcss:
|
||||||
specifier: ^3.3.5
|
specifier: ^3.3.5
|
||||||
version: 3.3.5
|
version: 3.3.5
|
||||||
@ -3339,6 +3345,67 @@ packages:
|
|||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/prettier-plugin-tailwindcss@0.5.7(prettier@3.1.0):
|
||||||
|
resolution: {integrity: sha512-4v6uESAgwCni6YF6DwJlRaDjg9Z+al5zM4JfngcazMy4WEf/XkPS5TEQjbD+DZ5iNuG6RrKQLa/HuX2SYzC3kQ==}
|
||||||
|
engines: {node: '>=14.21.3'}
|
||||||
|
peerDependencies:
|
||||||
|
'@ianvs/prettier-plugin-sort-imports': '*'
|
||||||
|
'@prettier/plugin-pug': '*'
|
||||||
|
'@shopify/prettier-plugin-liquid': '*'
|
||||||
|
'@shufo/prettier-plugin-blade': '*'
|
||||||
|
'@trivago/prettier-plugin-sort-imports': '*'
|
||||||
|
prettier: ^3.0
|
||||||
|
prettier-plugin-astro: '*'
|
||||||
|
prettier-plugin-css-order: '*'
|
||||||
|
prettier-plugin-import-sort: '*'
|
||||||
|
prettier-plugin-jsdoc: '*'
|
||||||
|
prettier-plugin-marko: '*'
|
||||||
|
prettier-plugin-organize-attributes: '*'
|
||||||
|
prettier-plugin-organize-imports: '*'
|
||||||
|
prettier-plugin-style-order: '*'
|
||||||
|
prettier-plugin-svelte: '*'
|
||||||
|
prettier-plugin-twig-melody: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@ianvs/prettier-plugin-sort-imports':
|
||||||
|
optional: true
|
||||||
|
'@prettier/plugin-pug':
|
||||||
|
optional: true
|
||||||
|
'@shopify/prettier-plugin-liquid':
|
||||||
|
optional: true
|
||||||
|
'@shufo/prettier-plugin-blade':
|
||||||
|
optional: true
|
||||||
|
'@trivago/prettier-plugin-sort-imports':
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-astro:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-css-order:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-import-sort:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-jsdoc:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-marko:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-organize-attributes:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-organize-imports:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-style-order:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-svelte:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-twig-melody:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
prettier: 3.1.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/prettier@3.1.0:
|
||||||
|
resolution: {integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
hasBin: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
/prop-types-extra@1.1.1(react@18.2.0):
|
/prop-types-extra@1.1.1(react@18.2.0):
|
||||||
resolution: {integrity: sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==}
|
resolution: {integrity: sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { readTodoTasks } from "src/api/TaskApi";
|
import { readTodoTasks } from "src/api/TaskApi";
|
||||||
|
import { axiosInstance } from "src/api/AxiosConfig";
|
||||||
|
|
||||||
let eventGuid = 0;
|
let eventGuid = 0;
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,14 @@ export class Calendar extends React.Component {
|
|||||||
currentEvents: [],
|
currentEvents: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async handleGoogleClick() {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.get("calendar-events/");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching data from Google:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="flex font-sans w-full h-screen">
|
<div className="flex font-sans w-full h-screen">
|
||||||
@ -47,10 +55,7 @@ export class Calendar extends React.Component {
|
|||||||
<div className="w-72 bg-blue-100 border-r border-blue-200 p-8 flex flex-col">
|
<div className="w-72 bg-blue-100 border-r border-blue-200 p-8 flex flex-col">
|
||||||
{/* Description Zone */}
|
{/* Description Zone */}
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<h2 className="text-xl font-bold">Instructions</h2>
|
|
||||||
<ul className="list-disc pl-4">
|
<ul className="list-disc pl-4">
|
||||||
<li>Select dates and you will be prompted to create a new event</li>
|
|
||||||
<li>Drag, drop, and resize events</li>
|
|
||||||
<li>Click an event to delete it</li>
|
<li>Click an event to delete it</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -66,7 +71,7 @@ export class Calendar extends React.Component {
|
|||||||
/>
|
/>
|
||||||
Toggle weekends
|
Toggle weekends
|
||||||
</label>
|
</label>
|
||||||
<button className="btn btn-info" onClick={() => alert("Commit soon🥺")}>
|
<button className="btn btn-info" onClick={() => this.handleGoogleClick()}>
|
||||||
Load Data from Google
|
Load Data from Google
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { KanbanBoard } from "./kanbanBoard";
|
import { KanbanBoard } from "./kanbanBoard";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { TableBoard } from "./tableBoard";
|
||||||
|
|
||||||
export const KanbanPage = () => {
|
export const KanbanPage = () => {
|
||||||
const [activeTab, setActiveTab] = useState("kanban");
|
const [activeTab, setActiveTab] = useState("kanban");
|
||||||
@ -16,19 +17,21 @@ export const KanbanPage = () => {
|
|||||||
<a
|
<a
|
||||||
id="kanban"
|
id="kanban"
|
||||||
className={`tab ${activeTab === "kanban" ? "tab-active" : ""}`}
|
className={`tab ${activeTab === "kanban" ? "tab-active" : ""}`}
|
||||||
onClick={() => handleTabClick("kanban")}>
|
onClick={() => handleTabClick("kanban")}
|
||||||
|
>
|
||||||
Kanban
|
Kanban
|
||||||
</a>
|
</a>
|
||||||
{/* <a
|
<a
|
||||||
id="table"
|
id="table"
|
||||||
className={`tab ${activeTab === "table" ? "tab-active" : ""}`}
|
className={`tab ${activeTab === "table" ? "tab-active" : ""}`}
|
||||||
onClick={() => handleTabClick("table")}>
|
onClick={() => handleTabClick("table")}
|
||||||
|
>
|
||||||
Table
|
Table
|
||||||
</a> */}
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<KanbanBoard />
|
{activeTab === "kanban" ? <KanbanBoard /> : <TableBoard />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
102
frontend/src/components/kanbanBoard/tableBoard.jsx
Normal file
102
frontend/src/components/kanbanBoard/tableBoard.jsx
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { axiosInstance } from "src/api/AxiosConfig";
|
||||||
|
|
||||||
|
export function TableBoard() {
|
||||||
|
const [tasks, setTasks] = useState([]);
|
||||||
|
|
||||||
|
// ---------------- Fetch Data ----------------
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
const tasksResponse = await axiosInstance.get("/todo");
|
||||||
|
|
||||||
|
// Transform
|
||||||
|
const transformedTasks = tasksResponse.data.map((task) => ({
|
||||||
|
id: task.id,
|
||||||
|
columnId: task.list_board,
|
||||||
|
content: task.title,
|
||||||
|
difficulty: task.difficulty,
|
||||||
|
notes: task.notes,
|
||||||
|
importance: task.importance,
|
||||||
|
challenge: task.challenge,
|
||||||
|
fromSystem: task.fromSystem,
|
||||||
|
creation_date: task.creation_date,
|
||||||
|
last_update: task.last_update,
|
||||||
|
is_active: task.is_active,
|
||||||
|
is_full_day_event: task.is_full_day_event,
|
||||||
|
start_event: task.start_event,
|
||||||
|
end_event: task.end_event,
|
||||||
|
google_calendar_id: task.google_calendar_id,
|
||||||
|
completed: task.completed,
|
||||||
|
completion_date: task.completion_date,
|
||||||
|
priority: task.priority,
|
||||||
|
user: task.user,
|
||||||
|
list_board: task.list_board,
|
||||||
|
tags: task.tags,
|
||||||
|
subtaskCount: task.sub_task_count,
|
||||||
|
}));
|
||||||
|
setTasks(transformedTasks);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching data from API:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// ---------------- END Fetch Data ----------------
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<table className="table">
|
||||||
|
{/* head */}
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Priority</th>
|
||||||
|
<th>Due Date</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{/* BODY */}
|
||||||
|
{tasks.map((task, index) => (
|
||||||
|
<tr key={index}>
|
||||||
|
<th>
|
||||||
|
<label></label>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div>
|
||||||
|
<div className="font-bold">{task.content}</div>
|
||||||
|
<div className="text-sm opacity-50">{task.content}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{task.notes}
|
||||||
|
<br />
|
||||||
|
<span className="badge badge-ghost badge-sm">Description</span>
|
||||||
|
</td>
|
||||||
|
<td>{task.priority}</td>
|
||||||
|
<th>
|
||||||
|
<button className="btn btn-ghost btn-xs">{task.end_event}</button>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
{/* END BODY */}
|
||||||
|
</tbody>
|
||||||
|
{/* foot */}
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Priority</th>
|
||||||
|
<th>Due Date</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -50,12 +50,12 @@ export function TaskCard({ task, deleteTask, updateTask }) {
|
|||||||
task.difficulty === 1
|
task.difficulty === 1
|
||||||
? "bg-blue-200 text-blue-700"
|
? "bg-blue-200 text-blue-700"
|
||||||
: task.difficulty === 2
|
: task.difficulty === 2
|
||||||
? "bg-green-200 text-green-700"
|
? "bg-green-200 text-green-700"
|
||||||
: task.difficulty === 3
|
: task.difficulty === 3
|
||||||
? "bg-yellow-200 text-yellow-700"
|
? "bg-yellow-200 text-yellow-700"
|
||||||
: task.difficulty === 4
|
: task.difficulty === 4
|
||||||
? "bg-red-200 text-red-700"
|
? "bg-red-200 text-red-700"
|
||||||
: "bg-purple-200 text-purple-700"
|
: "bg-purple-200 text-purple-700"
|
||||||
}`}>
|
}`}>
|
||||||
difficulty
|
difficulty
|
||||||
</span>
|
</span>
|
||||||
@ -71,12 +71,12 @@ export function TaskCard({ task, deleteTask, updateTask }) {
|
|||||||
daysUntilDue >= 365
|
daysUntilDue >= 365
|
||||||
? "gray-200"
|
? "gray-200"
|
||||||
: daysUntilDue >= 30
|
: daysUntilDue >= 30
|
||||||
? "blue-200"
|
? "blue-200"
|
||||||
: daysUntilDue >= 7
|
: daysUntilDue >= 7
|
||||||
? "green-200"
|
? "green-200"
|
||||||
: daysUntilDue > 0
|
: daysUntilDue > 0
|
||||||
? "yellow-200"
|
? "yellow-200"
|
||||||
: "red-200";
|
: "red-200";
|
||||||
|
|
||||||
const formattedDueDate =
|
const formattedDueDate =
|
||||||
daysUntilDue >= 365
|
daysUntilDue >= 365
|
||||||
@ -85,7 +85,10 @@ export function TaskCard({ task, deleteTask, updateTask }) {
|
|||||||
month: "short",
|
month: "short",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
})
|
})
|
||||||
: new Date(task.end_event).toLocaleDateString("en-US", { day: "numeric", month: "short" });
|
: new Date(task.end_event).toLocaleDateString("en-US", {
|
||||||
|
day: "numeric",
|
||||||
|
month: "short",
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={`bg-${colorClass} text-[10px] font-xl font-bold px-2 py-1 rounded-full`}>
|
<span className={`bg-${colorClass} text-[10px] font-xl font-bold px-2 py-1 rounded-full`}>
|
||||||
@ -122,13 +125,15 @@ export function TaskCard({ task, deleteTask, updateTask }) {
|
|||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
taskId={task.id}
|
taskId={task.id}
|
||||||
title={task.content}
|
title={task.content}
|
||||||
description={task.description}
|
description={task.notes}
|
||||||
tags={task.tags}
|
tags={task.tags}
|
||||||
difficulty={task.difficulty}
|
difficulty={task.difficulty}
|
||||||
challenge={task.challenge}
|
challenge={task.challenge}
|
||||||
importance={task.importance}
|
importance={task.importance}
|
||||||
updateTask={updateTask}
|
updateTask={updateTask}
|
||||||
completed={task.completed}
|
completed={task.completed}
|
||||||
|
start_event={task.start_event}
|
||||||
|
end_event={task.end_event}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* -------- Task Card -------- */}
|
{/* -------- Task Card -------- */}
|
||||||
|
|||||||
@ -16,24 +16,48 @@ export function TaskDetailModal({
|
|||||||
challenge,
|
challenge,
|
||||||
importance,
|
importance,
|
||||||
taskId,
|
taskId,
|
||||||
|
start_event,
|
||||||
|
end_event,
|
||||||
updateTask,
|
updateTask,
|
||||||
completed,
|
completed,
|
||||||
}) {
|
}) {
|
||||||
|
if (importance >= 3) {
|
||||||
|
importance = true;
|
||||||
|
} else {
|
||||||
|
importance = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const s = formatAMPM(new Date(start_event));
|
||||||
|
const e = formatAMPM(new Date(end_event));
|
||||||
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 - 1) * 25);
|
const [currentDifficulty, setCurrentDifficulty] = useState((difficulty - 1) * 25);
|
||||||
const [selectedTags, setSelectedTags] = useState([]);
|
const [selectedTags, setSelectedTags] = useState([]);
|
||||||
const [dateStart, setDateStart] = useState(new Date());
|
const [dateStart, setDateStart] = useState(new Date(start_event));
|
||||||
const [dateEnd, setDateEnd] = useState(new Date());
|
const [dateEnd, setDateEnd] = useState(new Date(end_event));
|
||||||
const [startDateEnabled, setStartDateEnabled] = useState(false);
|
const [startDateEnabled, setStartDateEnabled] = useState(false);
|
||||||
const [endDateEnabled, setEndDateEnabled] = useState(false);
|
const [endDateEnabled, setEndDateEnabled] = useState(false);
|
||||||
const [isTaskComplete, setTaskComplete] = useState(completed);
|
const [isTaskComplete, setTaskComplete] = useState(completed);
|
||||||
const [starteventValue, setStartEventValue] = useState("10:00 PM");
|
const [starteventValue, setStartEventValue] = useState(e);
|
||||||
const [endeventValue, setEndEventValue] = useState("11:00 AM");
|
const [endeventValue, setEndEventValue] = useState(s);
|
||||||
const [subtaskText, setSubtaskText] = useState("");
|
const [subtaskText, setSubtaskText] = useState("");
|
||||||
const [subtasks, setSubtasks] = useState([]);
|
const [subtasks, setSubtasks] = useState([]);
|
||||||
const [currentTitle, setTitle] = useState(title);
|
const [currentTitle, setTitle] = useState(title);
|
||||||
const [isTitleEditing, setTitleEditing] = useState(false);
|
const [isTitleEditing, setTitleEditing] = useState(false);
|
||||||
|
const [isDescriptionEditing, setDescriptionEditing] = useState(false);
|
||||||
|
const [updatedDescription, setUpdatedDescription] = useState(description);
|
||||||
|
|
||||||
|
const handleDescriptionEditToggle = () => {
|
||||||
|
setDescriptionEditing(!isDescriptionEditing);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDescriptionChange = async () => {
|
||||||
|
const data = {
|
||||||
|
notes: updatedDescription,
|
||||||
|
};
|
||||||
|
await updateTodoTaskPartial(taskId, data);
|
||||||
|
setDescriptionEditing(false);
|
||||||
|
};
|
||||||
|
|
||||||
const handleTitleChange = async () => {
|
const handleTitleChange = async () => {
|
||||||
const data = {
|
const data = {
|
||||||
@ -43,43 +67,113 @@ export function TaskDetailModal({
|
|||||||
setTitleEditing(false);
|
setTitleEditing(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStartEventTimeChange = async (timeValue) => {
|
{
|
||||||
const formattedTime = convertToFormattedTime(timeValue);
|
/* -------- Time -------- */
|
||||||
setStartEventValue(formattedTime);
|
}
|
||||||
console.log(formattedTime);
|
|
||||||
const data = {
|
|
||||||
startTime: formattedTime,
|
|
||||||
};
|
|
||||||
await updateTodoTaskPartial(taskId, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEndEventTimeChange = async (timeValue) => {
|
function formatAMPM(date) {
|
||||||
const inputTime = event.target.value;
|
var hours = date.getHours();
|
||||||
// Validate the input time format
|
var minutes = date.getMinutes();
|
||||||
if (!validateTimeFormat(inputTime)) {
|
var ampm = hours >= 12 ? "PM" : "AM";
|
||||||
// Display an error message or handle invalid format
|
hours = hours % 12;
|
||||||
console.error("Invalid time format. Please use HH:mm AM/PM");
|
hours = hours ? hours : 12; // the hour '0' should be '12'
|
||||||
|
minutes = minutes < 10 ? "0" + minutes : minutes;
|
||||||
|
var strTime = hours + ":" + minutes + " " + ampm;
|
||||||
|
return strTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleStartEventTimeChange = async (startdate, starttime) => {
|
||||||
|
if (!validateTimeFormat(starttime)) {
|
||||||
|
console.error("Wrong time format");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formattedTime = convertToFormattedTime(timeValue);
|
// Format incoming date
|
||||||
setEndEventValue(formattedTime);
|
setDateStart(startdate);
|
||||||
|
setStartEventValue(starttime);
|
||||||
|
const formatDate = convertToFormattedDate(startdate);
|
||||||
|
// Format incoming time
|
||||||
|
const formatTime = convertToFormattedTime(starttime).slice(0, -1) + ":00.000000Z";
|
||||||
|
console.log(formatTime);
|
||||||
|
// Combine both of them
|
||||||
|
const formatDateTime = formatDate + formatTime;
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
endTime: formattedTime,
|
startTime: formatDateTime,
|
||||||
|
};
|
||||||
|
console.log(formatDateTime);
|
||||||
|
await updateTodoTaskPartial(taskId, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEndEventTimeChange = async (enddate, endtime) => {
|
||||||
|
if (!validateTimeFormat(endtime)) {
|
||||||
|
console.error("Wrong time format");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format incoming date
|
||||||
|
setDateEnd(enddate);
|
||||||
|
setEndEventValue(endtime);
|
||||||
|
const formatDate = convertToFormattedDate(enddate);
|
||||||
|
// Format incoming time
|
||||||
|
const formatTime = convertToFormattedTime(endtime);
|
||||||
|
|
||||||
|
// Combine both of them
|
||||||
|
const formatDateTime = formatDate + formatTime;
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
startTime: formatDateTime,
|
||||||
};
|
};
|
||||||
await updateTodoTaskPartial(taskId, data);
|
await updateTodoTaskPartial(taskId, data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const convertToFormattedDate = (dateValue) => {
|
||||||
|
const formattedDate = format(dateValue, "yyyy-MM-dd'T'", {
|
||||||
|
timeZone: "UTC",
|
||||||
|
});
|
||||||
|
return formattedDate;
|
||||||
|
};
|
||||||
|
|
||||||
const convertToFormattedTime = (timeValue) => {
|
const convertToFormattedTime = (timeValue) => {
|
||||||
const formattedTime = format(timeValue, "HH:mm:ss.SSSX", { timeZone: "UTC" });
|
// 2023-11-28 T [04:37:48.000000Z]
|
||||||
return formattedTime;
|
// 12:00 AM -> 12:00:00.000000Z
|
||||||
|
// 10:00 PM -> 22:00:00.000000Z
|
||||||
|
|
||||||
|
var hours = parseInt(timeValue.substr(0, 2));
|
||||||
|
if (timeValue.indexOf("AM") != -1 && hours == 12) {
|
||||||
|
timeValue = timeValue.replace("12", "0");
|
||||||
|
}
|
||||||
|
if (timeValue.indexOf("PM") != -1 && hours < 12) {
|
||||||
|
timeValue = timeValue.replace(hours, hours + 12);
|
||||||
|
}
|
||||||
|
const formattedTime = timeValue.replace(/(AM|PM)/, "");
|
||||||
|
const [formattedHours, restOfTime] = formattedTime.split(":");
|
||||||
|
const paddedHours = formattedHours.length === 1 ? `0${formattedHours}` : formattedHours;
|
||||||
|
console.log(`${paddedHours}:${restOfTime}`);
|
||||||
|
return `${paddedHours}:${restOfTime}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleStartDateChange = () => {
|
||||||
|
if (!isTaskComplete) {
|
||||||
|
setStartDateEnabled(!startDateEnabled);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEndDateChange = () => {
|
||||||
|
if (!isTaskComplete) {
|
||||||
|
setEndDateEnabled(!endDateEnabled);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateTimeFormat = (time) => {
|
const validateTimeFormat = (time) => {
|
||||||
const timeFormatRegex = /^(0[1-9]|1[0-2]):[0-5][0-9] (AM|PM)$/i;
|
const timeFormatRegex = /^([1-9]|1[0-2]):[0-5][0-9]( |)(AM|PM)$/i;
|
||||||
return timeFormatRegex.test(time);
|
return timeFormatRegex.test(time);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
/* -------- END Time -------- */
|
||||||
|
}
|
||||||
|
|
||||||
const handleChallengeChange = async () => {
|
const handleChallengeChange = async () => {
|
||||||
setChallengeChecked(!isChallengeChecked);
|
setChallengeChecked(!isChallengeChecked);
|
||||||
const data = {
|
const data = {
|
||||||
@ -89,9 +183,14 @@ export function TaskDetailModal({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleImportantChange = async () => {
|
const handleImportantChange = async () => {
|
||||||
|
let important_num = 0;
|
||||||
|
if (isImportantChecked) {
|
||||||
|
important_num = 5;
|
||||||
|
}
|
||||||
|
|
||||||
setImportantChecked(!isImportantChecked);
|
setImportantChecked(!isImportantChecked);
|
||||||
const data = {
|
const data = {
|
||||||
important: !isImportantChecked,
|
important: important_num,
|
||||||
};
|
};
|
||||||
await updateTodoTaskPartial(taskId, data);
|
await updateTodoTaskPartial(taskId, data);
|
||||||
};
|
};
|
||||||
@ -111,45 +210,6 @@ export function TaskDetailModal({
|
|||||||
``;
|
``;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStartDateValueChange = (date) => {
|
|
||||||
if (!isTaskComplete) {
|
|
||||||
setDateStart(date);
|
|
||||||
const formattedStartDate = convertToFormattedDate(date);
|
|
||||||
const data = {
|
|
||||||
startTime: formattedStartDate,
|
|
||||||
};
|
|
||||||
updateTodoTaskPartial(taskId, data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEndDateValueChange = (date) => {
|
|
||||||
if (!isTaskComplete) {
|
|
||||||
setDateEnd(date);
|
|
||||||
const formattedEndDate = convertToFormattedDate(date);
|
|
||||||
const data = {
|
|
||||||
endTime: formattedEndDate,
|
|
||||||
};
|
|
||||||
updateTodoTaskPartial(taskId, data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const convertToFormattedDate = (dateValue) => {
|
|
||||||
const formattedDate = format(dateValue, "yyyy-MM-dd'T'", { timeZone: "UTC" });
|
|
||||||
return formattedDate;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleStartDateChange = () => {
|
|
||||||
if (!isTaskComplete) {
|
|
||||||
setStartDateEnabled(!startDateEnabled);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEndDateChange = () => {
|
|
||||||
if (!isTaskComplete) {
|
|
||||||
setEndDateEnabled(!endDateEnabled);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTaskCompleteChange = async () => {
|
const handleTaskCompleteChange = async () => {
|
||||||
let completed = false;
|
let completed = false;
|
||||||
if (isTaskComplete) {
|
if (isTaskComplete) {
|
||||||
@ -183,7 +243,9 @@ export function TaskDetailModal({
|
|||||||
try {
|
try {
|
||||||
const updatedSubtasks = [...subtasks];
|
const updatedSubtasks = [...subtasks];
|
||||||
updatedSubtasks[index].completed = !updatedSubtasks[index].completed;
|
updatedSubtasks[index].completed = !updatedSubtasks[index].completed;
|
||||||
await updateSubtask(updatedSubtasks[index].id, { completed: updatedSubtasks[index].completed });
|
await updateSubtask(updatedSubtasks[index].id, {
|
||||||
|
completed: updatedSubtasks[index].completed,
|
||||||
|
});
|
||||||
setSubtasks(updatedSubtasks);
|
setSubtasks(updatedSubtasks);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error updating subtask:", error);
|
console.error("Error updating subtask:", error);
|
||||||
@ -321,35 +383,37 @@ export function TaskDetailModal({
|
|||||||
onChange={handleStartDateChange}
|
onChange={handleStartDateChange}
|
||||||
/>
|
/>
|
||||||
<div className={`rounded p-2 shadow border-2 ${!startDateEnabled && "opacity-50"}`}>
|
<div className={`rounded p-2 shadow border-2 ${!startDateEnabled && "opacity-50"}`}>
|
||||||
<DatePicker selected={dateStart} onChange={handleStartDateValueChange} disabled={!startDateEnabled} />
|
<DatePicker
|
||||||
|
selected={dateStart}
|
||||||
|
onChange={(dateStart) => setDateStart(dateStart)}
|
||||||
|
disabled={!startDateEnabled}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Start event time picker */}
|
{/* Start event time picker */}
|
||||||
<div className="rounded p-2 shadow border-2 ml-2 mt-4">
|
<div className="rounded mx-2 mt-4 flex flex-row items-center">
|
||||||
{/* handleStartEventTimeChange */}
|
{/* handleStartEventTimeChange */}
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="10:00 AM"
|
placeholder={starteventValue}
|
||||||
|
value={starteventValue}
|
||||||
|
onChange={(starteventValue) => setStartEventValue(starteventValue)}
|
||||||
className="input input-bordered w-full max-w-xs"
|
className="input input-bordered w-full max-w-xs"
|
||||||
onClick={handleStartEventTimeChange}
|
disabled={!startDateEnabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
<div className="rounded mx-2">
|
||||||
|
<button
|
||||||
{/* Complete? */}
|
className="btn btn-sm"
|
||||||
<div className="mx-4">
|
disabled={isTaskComplete}
|
||||||
<div className="flex items-center space-x-2 mt-4">
|
onClick={() => handleStartEventTimeChange(dateStart, starteventValue)}>
|
||||||
<div className="flex-1 flex-row card shadow border-2 p-2 pr-2">
|
Update Time
|
||||||
<p className="text-md mx-2">Complete</p>
|
</button>
|
||||||
<input type="checkbox" checked={isTaskComplete} className="checkbox checkbox-xl bg-gray-400" />
|
|
||||||
<button className="btn btn-sm mt-2" onClick={handleStartEventTimeChange}>
|
|
||||||
Update Start Time
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* End */}
|
{/* End */}
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-bold">End At</p>
|
<p className="text-xs font-bold">End At</p>
|
||||||
@ -361,25 +425,62 @@ export function TaskDetailModal({
|
|||||||
onChange={handleEndDateChange}
|
onChange={handleEndDateChange}
|
||||||
/>
|
/>
|
||||||
<div className={`rounded p-2 shadow border-2 ${!endDateEnabled && "opacity-50"}`}>
|
<div className={`rounded p-2 shadow border-2 ${!endDateEnabled && "opacity-50"}`}>
|
||||||
<DatePicker selected={dateEnd} onChange={handleEndDateValueChange} disabled={!endDateEnabled} />
|
<DatePicker selected={dateEnd} onChange={(dateEnd) => setDateEnd(dateEnd)} disabled={!endDateEnabled} />
|
||||||
</div>
|
</div>
|
||||||
{/* End event time picker */}
|
{/* End event time picker */}
|
||||||
<div className="rounded p-2 shadow border-2">this is time picker</div>
|
<div className="rounded mx-2 flex flex-row items-center">
|
||||||
|
{/* handleEndEventTimeChange */}
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder={endeventValue}
|
||||||
|
className="input input-bordered w-full max-w-xs"
|
||||||
|
disabled={!endDateEnabled}
|
||||||
|
/>
|
||||||
|
<div className="rounded mx-2">
|
||||||
|
<button
|
||||||
|
className="btn btn-sm"
|
||||||
|
disabled={isTaskComplete}
|
||||||
|
onClick={() => handleEndEventTimeChange(dateEnd, endeventValue)}>
|
||||||
|
Update Time
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Description */}
|
{/* Description */}
|
||||||
<div className="flex flex-col gap-2">
|
{isDescriptionEditing ? (
|
||||||
<h2 className="font-bold">
|
<div className="flex flex-col gap-2">
|
||||||
<span className="flex gap-2">
|
<h2 className="font-bold">
|
||||||
<FaRegListAlt className="my-1" />
|
<span className="flex gap-2">
|
||||||
Description
|
<FaRegListAlt className="my-1" />
|
||||||
</span>
|
Description
|
||||||
</h2>
|
</span>
|
||||||
<textarea className="textarea w-full" disabled>
|
</h2>
|
||||||
{description}
|
<textarea
|
||||||
</textarea>
|
className="textarea w-full"
|
||||||
</div>
|
value={updatedDescription}
|
||||||
|
onChange={(e) => setUpdatedDescription(e.target.value)}
|
||||||
|
/>
|
||||||
|
<button className="btn btn-sm" onClick={handleDescriptionChange}>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<h2 className="font-bold">
|
||||||
|
<span className="flex gap-2">
|
||||||
|
<FaRegListAlt className="my-1" />
|
||||||
|
Description
|
||||||
|
</span>
|
||||||
|
</h2>
|
||||||
|
<textarea className="textarea w-full" disabled>
|
||||||
|
{description}
|
||||||
|
</textarea>
|
||||||
|
<FaPencil className="cursor-pointer" onClick={handleDescriptionEditToggle} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Difficulty, Challenge, and Importance */}
|
{/* Difficulty, Challenge, and Importance */}
|
||||||
<div className="flex flex-row space-x-3 my-4">
|
<div className="flex flex-row space-x-3 my-4">
|
||||||
<div className="flex-1 card shadow border-2 p-2">
|
<div className="flex-1 card shadow border-2 p-2">
|
||||||
@ -430,6 +531,20 @@ export function TaskDetailModal({
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/* Complete? */}
|
||||||
|
<div className="card shadow border-2 p-2">
|
||||||
|
<div className="form-control">
|
||||||
|
<label className="label cursor-pointer space-x-2">
|
||||||
|
<span className="label-text">Complete</span>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={isTaskComplete}
|
||||||
|
className="checkbox bg-black"
|
||||||
|
onChange={handleTaskCompleteChange}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Subtask */}
|
{/* Subtask */}
|
||||||
<div className="flex flex-col pt-2">
|
<div className="flex flex-col pt-2">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user