diff --git a/frontend/package.json b/frontend/package.json index 618e30c..5c9d96e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -64,6 +64,8 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.4", "postcss": "^8.4.31", + "prettier": "^3.1.0", + "prettier-plugin-tailwindcss": "^0.5.7", "tailwindcss": "^3.3.5", "vite": "^4.5.0" } diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index b514b56..dc65ed8 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -163,6 +163,12 @@ devDependencies: postcss: specifier: ^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: specifier: ^3.3.5 version: 3.3.5 @@ -3339,6 +3345,67 @@ packages: engines: {node: '>= 0.8.0'} 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): resolution: {integrity: sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==} peerDependencies: diff --git a/frontend/src/components/kanbanBoard/taskCard.jsx b/frontend/src/components/kanbanBoard/taskCard.jsx index 4c40a9e..ae4407f 100644 --- a/frontend/src/components/kanbanBoard/taskCard.jsx +++ b/frontend/src/components/kanbanBoard/taskCard.jsx @@ -50,12 +50,12 @@ export function TaskCard({ task, deleteTask, updateTask }) { task.difficulty === 1 ? "bg-blue-200 text-blue-700" : task.difficulty === 2 - ? "bg-green-200 text-green-700" - : task.difficulty === 3 - ? "bg-yellow-200 text-yellow-700" - : task.difficulty === 4 - ? "bg-red-200 text-red-700" - : "bg-purple-200 text-purple-700" + ? "bg-green-200 text-green-700" + : task.difficulty === 3 + ? "bg-yellow-200 text-yellow-700" + : task.difficulty === 4 + ? "bg-red-200 text-red-700" + : "bg-purple-200 text-purple-700" }`}> difficulty @@ -71,12 +71,12 @@ export function TaskCard({ task, deleteTask, updateTask }) { daysUntilDue >= 365 ? "gray-200" : daysUntilDue >= 30 - ? "blue-200" - : daysUntilDue >= 7 - ? "green-200" - : daysUntilDue > 0 - ? "yellow-200" - : "red-200"; + ? "blue-200" + : daysUntilDue >= 7 + ? "green-200" + : daysUntilDue > 0 + ? "yellow-200" + : "red-200"; const formattedDueDate = daysUntilDue >= 365 @@ -85,7 +85,10 @@ export function TaskCard({ task, deleteTask, updateTask }) { month: "short", 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 ( @@ -122,13 +125,15 @@ export function TaskCard({ task, deleteTask, updateTask }) { {/* -------- Task Card -------- */} diff --git a/frontend/src/components/kanbanBoard/taskDetailModal.jsx b/frontend/src/components/kanbanBoard/taskDetailModal.jsx index 614b932..5beb5ed 100644 --- a/frontend/src/components/kanbanBoard/taskDetailModal.jsx +++ b/frontend/src/components/kanbanBoard/taskDetailModal.jsx @@ -16,26 +16,48 @@ export function TaskDetailModal({ challenge, importance, taskId, + start_event, + end_event, updateTask, 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 [isImportantChecked, setImportantChecked] = useState(importance); const [currentDifficulty, setCurrentDifficulty] = useState((difficulty - 1) * 25); const [selectedTags, setSelectedTags] = useState([]); - const [dateStart, setDateStart] = useState(new Date()); - const [dateEnd, setDateEnd] = useState(new Date()); + const [dateStart, setDateStart] = useState(new Date(start_event)); + const [dateEnd, setDateEnd] = useState(new Date(end_event)); const [startDateEnabled, setStartDateEnabled] = useState(false); const [endDateEnabled, setEndDateEnabled] = useState(false); const [isTaskComplete, setTaskComplete] = useState(completed); - const [starteventValue, setStartEventValue] = useState("10:00 PM"); - const [endeventValue, setEndEventValue] = useState("10:00 AM"); + const [starteventValue, setStartEventValue] = useState(e); + const [endeventValue, setEndEventValue] = useState(s); const [subtaskText, setSubtaskText] = useState(""); const [subtasks, setSubtasks] = useState([]); const [currentTitle, setTitle] = useState(title); const [isTitleEditing, setTitleEditing] = useState(false); - const [isCheckboxStartTimeChecked, setCheckboxStartTimeChecked] = useState(false); - const [isCheckboxEndTimeChecked, setCheckboxEndTimeChecked] = 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 data = { @@ -45,51 +67,113 @@ export function TaskDetailModal({ setTitleEditing(false); }; - const handleCheckboxStartTimeChange = () => { - setCheckboxStartTimeChecked(!isCheckboxStartTimeChecked); - }; + { + /* -------- Time -------- */ + } - const handleCheckboxEndTimeChange = () => { - setCheckboxEndTimeChecked(!isCheckboxEndTimeChecked); - }; + function formatAMPM(date) { + var hours = date.getHours(); + var minutes = date.getMinutes(); + var ampm = hours >= 12 ? "PM" : "AM"; + hours = hours % 12; + 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 (timeValue) => { - const formattedTime = convertToFormattedTime(timeValue); - setStartEventValue(formattedTime); - console.log(formattedTime); - const data = { - startTime: formattedTime, - }; - await updateTodoTaskPartial(taskId, data); - }; - - const handleEndEventTimeChange = async (timeValue) => { - const inputTime = event.target.value; - // Validate the input time format - if (!validateTimeFormat(inputTime)) { - // Display an error message or handle invalid format - console.error("Invalid time format. Please use HH:mm AM/PM"); + const handleStartEventTimeChange = async (startdate, starttime) => { + if (!validateTimeFormat(starttime)) { + console.error("Wrong time format"); return; } - const formattedTime = convertToFormattedTime(timeValue); - setEndEventValue(formattedTime); + // Format incoming date + 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 = { - 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); }; + const convertToFormattedDate = (dateValue) => { + const formattedDate = format(dateValue, "yyyy-MM-dd'T'", { + timeZone: "UTC", + }); + return formattedDate; + }; + const convertToFormattedTime = (timeValue) => { - const formattedTime = format(timeValue, "HH:mm:ss.SSSX", { timeZone: "UTC" }); - return formattedTime; + // 2023-11-28 T [04:37:48.000000Z] + // 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 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); }; + { + /* -------- END Time -------- */ + } + const handleChallengeChange = async () => { setChallengeChecked(!isChallengeChecked); const data = { @@ -99,9 +183,14 @@ export function TaskDetailModal({ }; const handleImportantChange = async () => { + let important_num = 0; + if (isImportantChecked) { + important_num = 5; + } + setImportantChecked(!isImportantChecked); const data = { - important: !isImportantChecked, + important: important_num, }; await updateTodoTaskPartial(taskId, data); }; @@ -121,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 () => { let completed = false; if (isTaskComplete) { @@ -193,7 +243,9 @@ export function TaskDetailModal({ try { const updatedSubtasks = [...subtasks]; 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); } catch (error) { console.error("Error updating subtask:", error); @@ -331,7 +383,11 @@ export function TaskDetailModal({ onChange={handleStartDateChange} />
- + setDateStart(dateStart)} + disabled={!startDateEnabled} + />
@@ -339,20 +395,19 @@ export function TaskDetailModal({ {/* Start event time picker */}
{/* handleStartEventTimeChange */} - setStartEventValue(starteventValue)} className="input input-bordered w-full max-w-xs" - disabled={!isCheckboxStartTimeChecked} + disabled={!startDateEnabled} />
-
@@ -370,25 +425,22 @@ export function TaskDetailModal({ onChange={handleEndDateChange} />
- + setDateEnd(dateEnd)} disabled={!endDateEnabled} />
{/* End event time picker */}
{/* handleEndEventTimeChange */} -
-
@@ -397,17 +449,38 @@ export function TaskDetailModal({
{/* Description */} -
-

- - - Description - -

- -
+ {isDescriptionEditing ? ( +
+

+ + + Description + +

+ + +
+ )} + {/* Difficulty, Challenge, and Importance */}