From e50a6c91e6796d870fb554c6d018abb4d257d2aa Mon Sep 17 00:00:00 2001 From: Tim Basten Date: Tue, 21 Apr 2026 15:45:25 +0800 Subject: [PATCH] a --- frontend/css/styles.css | 12 -- frontend/dashboard.html | 28 +++- frontend/features.html | 6 +- frontend/index.html | 6 +- frontend/js/api.js | 355 ++++++++++++++++++++++++---------------- frontend/login.html | 32 ++-- frontend/pricing.html | 21 +-- frontend/signup.html | 34 ++-- frontend/support.html | 6 +- index.js | 90 ---------- 10 files changed, 299 insertions(+), 291 deletions(-) delete mode 100644 index.js diff --git a/frontend/css/styles.css b/frontend/css/styles.css index 0e63d0b..ae364fe 100644 --- a/frontend/css/styles.css +++ b/frontend/css/styles.css @@ -24,15 +24,10 @@ radial-gradient(ellipse 600px 500px at 55% 5%, rgba(177, 98, 134, 0.18), transparent), radial-gradient(ellipse 500px 400px at 75% 20%, rgba(104, 157, 106, 0.12), transparent), linear-gradient(160deg, #1d2021 0%, #282828 45%, #32302f 100%); - min-height: 90vh; - height: auto; - background-size: cover; - background-position: center center; - background-repeat: no-repeat; } @@ -62,31 +57,24 @@ footer { .navbar-toggler { border: none !important; - box-shadow: none !important; } .btn-primary { background-color: var(--secondary); - color: var(--fg); - border-color: transparent; } .btn-primary:hover { background-color: var(--secondary-hover); - color: var(--primary); - border-color: transparent; } form a { text-decoration: none; - color: var(--fg); - transition: 0.2s ease-in-out; } diff --git a/frontend/dashboard.html b/frontend/dashboard.html index a65e849..ce77ea8 100644 --- a/frontend/dashboard.html +++ b/frontend/dashboard.html @@ -36,6 +36,10 @@ +
+ Login + Signup +
@@ -111,10 +115,32 @@ + + + - \ No newline at end of file + diff --git a/frontend/features.html b/frontend/features.html index a7f19fd..5460aa8 100644 --- a/frontend/features.html +++ b/frontend/features.html @@ -36,6 +36,10 @@ +
+ Login + Signup +
@@ -91,4 +95,4 @@ crossorigin="anonymous"> - \ No newline at end of file + diff --git a/frontend/index.html b/frontend/index.html index b93a5c7..089c240 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -36,6 +36,10 @@ +
+ Login + Signup +
@@ -88,4 +92,4 @@ crossorigin="anonymous"> - \ No newline at end of file + diff --git a/frontend/js/api.js b/frontend/js/api.js index 1172469..af40903 100644 --- a/frontend/js/api.js +++ b/frontend/js/api.js @@ -1,170 +1,235 @@ -// GLOBALS -const $taskForm = document.getElementById('taskForm'); -const $toDoList = document.getElementById('toDoList'); -const $completedList = document.getElementById('completedList'); +const taskForm = document.getElementById('taskForm'); +const toDoList = document.getElementById('toDoList'); +const completedList = document.getElementById('completedList'); +const url = "http://localhost:3001"; -// RESET FORM function resetForm() { - $taskForm.reset(); -}; + taskForm.reset(); +} -// EVENT LISTENERS +const sortButton = document.getElementById("sortSelect"); window.addEventListener("DOMContentLoaded", () => { - displayTasks(); + sortButton.value = "default"; +}); +sortButton.addEventListener('change', () => { + displayTasks(); }); -$taskForm.addEventListener("submit", (event) => { - event.preventDefault(); - createNewTask(); +window.addEventListener("DOMContentLoaded", () => { + displayTasks(); }); -[$toDoList, $completedList].forEach(list => { - list.addEventListener("click", (event) => { - if ( - event.target.classList.contains("done") || - event.target.classList.contains("notDone") - ) { - toggleTaskStatus(event.target.dataset.id); - } - else if (event.target.classList.contains("delete")) { - deleteTask(event.target.dataset.id); - } - }); +taskForm.addEventListener("submit", (event) => { + event.preventDefault(); + createNewTask(); }); -// EXAMPLE API -// async function exampleAPI() { -// const response = await fetch("http://localhost:3001/test"); -// const data = await response.text(); -// console.log(data); -// } -// -// exampleAPI(); - - -// DISPLAY TASKS -async function displayTasks() { - - const response = await fetch("http://localhost:3001/api/tasks") - - if (!response.ok) { - throw new Error(`Failed to get tasks: ${response.status}`); +[toDoList, completedList].forEach(list => { + list.addEventListener('click', (event) => { + if (event.target.classList.contains("done")) { + const taskId = event.target.getAttribute("data-id"); + completeTask(taskId); + } + else if (event.target.classList.contains("notDone")) { + const taskId = event.target.getAttribute("data-id"); + taskNotCompleted(taskId); } + else if (event.target.classList.contains("delete")) { + const taskId = event.target.getAttribute("data-id"); + deleteTask(taskId); + } + else if (event.target.classList.contains('edit')) { + const task = { + id: event.target.getAttribute('data-id'), + title: event.target.getAttribute('data-title'), + description: event.target.getAttribute('data-description'), + dueDate: new Date(event.target.getAttribute('data-due-date')) + }; + const modal = { + titleInput: document.getElementById('editTaskName'), + descriptionInput: document.getElementById('editTaskDescription'), + dueDateInput: document.getElementById('editDueDate'), + saveButton: document.getElementById('saveButton') + }; + modal.titleInput.value = task.title; + modal.descriptionInput.value = task.description; + modal.dueDateInput.value = task.dueDate.toISOString().split('T')[0]; + modal.saveButton.addEventListener('click', async () => { + await editTask(task.id); + bootstrap.Modal.getInstance(document.getElementById('editModal')).hide(); + }, { once: true }); + } + }); +}); + + +async function displayTasks() { + const sortSelect = document.getElementById('sortSelect'); + const sortBy = sortSelect.value; + let query = ''; + if (sortBy !== 'default') { + query = `?sortBy=${sortBy}`; + } + try { + const response = await fetch(`${url}/api/tasks${query}`); + if (!response.ok) { + throw new Error(`Failed to get tasks: ${response.status}`); + } const data = await response.json(); - try { - function formatTask(task) { - const li = document.createElement("li"); - - li.classList.add('card', 'p-3', 'mt-2'); - const done = task.completed - ? "text-decoration-line-through opacity-50" - : ""; - li.innerHTML = ` -
-

${task.title}

- -
-

${task.description}

-

Due: ${task.dueDate}

-
-
- ${task.completed - ? `` - : ` - - - ` - } -
-

Created on: ${task.dateCreated}

-
- `; - - return li; - + function formatTask(task) { + const li = document.createElement("li"); + li.classList.add("card", "p-3", "shadow-sm", "mt-2"); + const done = task.completed ? "text-decoration-line-through opacity-50" : ""; + li.innerHTML = ` +
+

${task.title}

+ +
+

${task.description}

+

Due: ${new Date(task.dueDate).toLocaleDateString()}

+
+
+ ${task.completed ? + `` + : + ` + + + ` } - - $toDoList.innerHTML = ""; - $completedList.innerHTML = ""; - - const tasks = Array.isArray(data) ? data : []; - - if (!Array.isArray(data)) { - console.error("ERROR: Expected an array of tasks from /api/tasks", data); - } - - tasks.forEach(task => { - const formattedTask = formatTask(task); - task.completed - ? $completedList.appendChild(formattedTask) - : $toDoList.appendChild(formattedTask) - }) - resetForm(); - - } catch (error) { - console.error(`ERROR: ${error}`); +
+

Created on: ${new Date(task.dateCreated).toLocaleDateString()}

+
+ `; + return li; } - - + toDoList.innerHTML = ""; + completedList.innerHTML = ""; + const tasks = data; + tasks.forEach(task => { + const formattedTask = formatTask(task); + task.completed ? completedList.appendChild(formattedTask) : toDoList.appendChild(formattedTask); + }); + resetForm(); + } catch (error) { + console.error("Error: ", error); + } } - async function createNewTask() { - const taskDetails = { - title: $taskForm.taskName.value.trim(), - description: $taskForm.taskDescription.value.trim(), - dueDate: $taskForm.dueDate.value, - } - if (!taskDetails.title || !taskDetails.description || !taskDetails.dueDate) { - alert("Please fill in all fields"); - return; - } - - try { - const response = await fetch("http://localhost:3001/api/tasks/todo", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify(taskDetails) - }); - - if (!response.ok) { - throw new Error(`Failed to create task: ${response.status}`); - } - - const data = await response.json(); - console.log("Task created:", data); - displayTasks(); - - - } - catch (error) { - console.error(`ERROR: ${error}`); - } - -}; - -function toggleTaskStatus(taskId) { - const task = tasks.find(task => task.id === Number(taskId)); - - if (task) { - task.completed = !task.completed; - displayTasks(); + + const taskDetails = { + title: taskForm.taskName.value.trim(), + description: taskForm.taskDescription.value.trim(), + dueDate: taskForm.dueDate.value + } + if (!taskDetails.title || !taskDetails.description || !taskDetails.dueDate) { + return alert("All fields required!"); + } + try { + const response = await fetch(`${url}/api/tasks/todo`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(taskDetails) + }); + if (!response.ok) { + throw new Error(`Failed to post task: ${response.status}`); } + const data = await response.json(); + console.log(data); + displayTasks(); + } catch (error) { + console.error("Error:", error); + } } - -function deleteTask(taskId) { - const taskIndex = tasks.findIndex(task => task.id == taskId); - if (taskIndex !== -1) { - tasks.splice(taskIndex, 1); +async function completeTask(taskId) { + try { + const response = await fetch(`${url}/api/tasks/complete/${taskId}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ completed: true }) + }); + if (!response.ok) { + throw new Error(`Failed to complete task: ${response.status}`); } + const data = await response.json(); + console.log("Task completed:", data); + displayTasks(); + } + catch (error) { + console.error("Error:", error); + } +}; +async function taskNotCompleted(taskId) { + try { + const response = await fetch(`${url}/api/tasks/notComplete/${taskId}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ completed: false }) + }); + if (!response.ok) { + throw new Error(`Failed to make task incomplete: ${response.status}`); + } + const data = await response.json(); + console.log("Task not complete:", data); displayTasks(); -} + } catch (error) { + console.error("Error:", error); + } +}; +async function deleteTask(taskId) { + try { + const response = await fetch(`${url}/api/tasks/delete/${taskId}`, { + method: "DELETE", + headers: { + "Content-Type": "application/json" + } + }); + if (!response.ok) { + throw new Error(`Failed to delete task: ${response.status}`); + } + const data = await response.json(); + console.log({ message: "Deleted Task:", Task: data }); + displayTasks(); -function convertDate(dateString) { - return new Date(dateString).toLocaleDateString("en-AU"); -} + } catch (error) { + console.error("Error:", error); + } +}; +async function editTask(taskId) { + const updatedDetails = { + title: document.getElementById('editTaskName').value.trim(), + description: document.getElementById('editTaskDescription').value.trim(), + dueDate: document.getElementById('editDueDate').value + }; + if (!updatedDetails.title || !updatedDetails.description || !updatedDetails.dueDate) { + return alert("All fields required!"); + } + + try { + const response = await fetch(`${url}/api/tasks/update/${taskId}`, { + method: "PUT", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(updatedDetails) + }); + if (!response.ok) { + throw new Error(`Failed to edit task: ${response.status}`); + } + const data = await response.json(); + console.log("Edited Task:", data); + displayTasks(); + } catch (error) { + console.error("Error:", error); + } +}; diff --git a/frontend/login.html b/frontend/login.html index 00bf2bd..d28bcc7 100644 --- a/frontend/login.html +++ b/frontend/login.html @@ -36,24 +36,32 @@ +
+ Login + Signup +
- -
-
- Under Construction - -

Page under construction. Check back later!

- -
- Go Home +
+
+

Login

+
+ + + +
-
-