diff --git a/index.html b/index.html index ffda4cf..e1ca8df 100644 --- a/index.html +++ b/index.html @@ -23,6 +23,7 @@ +
+ +
- +
- +
diff --git a/login/index.html b/login/index.html index 305d461..a8df80b 100644 --- a/login/index.html +++ b/login/index.html @@ -50,7 +50,7 @@ - + diff --git a/package-lock.json b/package-lock.json index 58aab2e..541f1da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,10 +1,11 @@ { "name": "csoc-task-2-web", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, "packages": { "": { + "name": "csoc-task-2-web", "version": "1.0.0", "license": "ISC", "dependencies": { @@ -13,11 +14,11 @@ } }, "node_modules/axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "dependencies": { - "follow-redirects": "^1.10.0" + "follow-redirects": "^1.14.0" } }, "node_modules/colorette": { @@ -35,9 +36,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", "funding": [ { "type": "individual", @@ -94,9 +95,9 @@ } }, "node_modules/nanoid": { - "version": "3.1.23", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", - "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -183,11 +184,11 @@ }, "dependencies": { "axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "requires": { - "follow-redirects": "^1.10.0" + "follow-redirects": "^1.14.0" } }, "colorette": { @@ -201,9 +202,9 @@ "integrity": "sha512-sx/LwlP/SWTGsd9G4RlOPrXnIihAJ2xwBUmzoqe2nWwbXORMQWtAGNJNYLBJJqa3e9PWvVzxdrtyFZJcr7D87g==" }, "follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" }, "fsevents": { "version": "2.3.2", @@ -233,9 +234,9 @@ } }, "nanoid": { - "version": "3.1.23", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", - "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==" + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" }, "path-parse": { "version": "1.0.7", diff --git a/register/index.html b/register/index.html index 3a1f03d..4639f48 100644 --- a/register/index.html +++ b/register/index.html @@ -64,7 +64,7 @@ - + diff --git a/src/auth_required.js b/src/auth_required.js index 7f5e7bc..ef26816 100644 --- a/src/auth_required.js +++ b/src/auth_required.js @@ -1,3 +1,3 @@ -/*** - * @todo Redirect the user to login page if token is not present. - */ +if (localStorage.token === undefined) { + window.location.href = 'login/'; +}; \ No newline at end of file diff --git a/src/init.js b/src/init.js index 3a88d74..5e3fe92 100644 --- a/src/init.js +++ b/src/init.js @@ -1,11 +1,68 @@ import axios from 'axios'; const API_BASE_URL = 'https://todo-app-csoc.herokuapp.com/'; -function getTasks() { - /*** - * @todo Fetch the tasks created by the user and display them in the dom. - */ -} +const tasks = document.getElementById("tasks"); + +export function getTasks() { + const headersForApiRequest = { + Authorization: 'Token ' + localStorage.getItem('token') + } + + axios({ + url:API_BASE_URL + "todo/", + method:"get", + headers:{ + Authorization:"Token "+localStorage.getItem("token") + } + + }) + .then(function({data}) + { + tasks.innerHTML = ""; + data.forEach((task) => newTask(task)); + }) + +}; + +const newTask = (task) => { + const newElement = document.createElement('li'); + newElement.innerHTML = `
  • + +
    + +
    +
    + ${task.title} +
    + + + + + +
  • `; + newElement.id = `todo-${task.id}`; + newElement.classList.add('list-group-item', 'd-flex', 'justify-content-between', 'align-items-center'); + tasks.appendChild(newElement); + + document.querySelector(`#edit-task-${task.id}`) + .addEventListener("click", () => editTask(task.id)); + document.querySelector(`#update-task-${task.id}`) + .addEventListener("click", () => updateTask(task.id)); + document.querySelector(`#delete-task-${task.id}`) + .addEventListener("click", () => deleteTask(task.id)); + document.getElementById("input-button-" +task.id).value = task.title; + +}; + +export {newTask}; + axios({ headers: { diff --git a/src/main.js b/src/main.js index 05849df..b6e42c5 100644 --- a/src/main.js +++ b/src/main.js @@ -1,4 +1,35 @@ import axios from 'axios'; +import { newTask, getTasks } from './init'; + +window.editTask = editTask; +window.deleteTask = deleteTask; +window.updateTask = updateTask; + +const addNewTask = document.getElementById('add-task'); +if (addNewTask) addNewTask.onclick = addTask; + + +const registerButton = document.getElementById("register"); +if (registerButton) registerButton.onclick = register; + +const loginButton = document.getElementById("login"); +if (loginButton) loginButton.onclick = login; + +const logoutButton = document.getElementById("logout-button"); +if (logoutButton) logoutButton.onclick = logout; + +const deleteButton = document.getElementById(`delete-task-${tasks.id}`); +if (deleteButton) deleteButton.onclick = deleteTask; + +const editButton = document.getElementById(`edit-task-${tasks.id}`); +if (editButton) editButton.onclick = editTask; + +const updateButton = document.getElementById(`update-task-${tasks.id}`); +if (updateButton) updateButton.onclick = updateTask; + + + + function displaySuccessToast(message) { iziToast.success({ title: 'Success', @@ -24,7 +55,9 @@ const API_BASE_URL = 'https://todo-app-csoc.herokuapp.com/'; function logout() { localStorage.removeItem('token'); + displaySuccessToast('Logged Out'); window.location.href = '/login/'; + } function registerFieldsAreValid(firstName, lastName, email, username, password) { @@ -46,6 +79,9 @@ function register() { const username = document.getElementById('inputUsername').value.trim(); const password = document.getElementById('inputPassword').value; + + + if (registerFieldsAreValid(firstName, lastName, email, username, password)) { displayInfoToast("Please wait..."); @@ -60,30 +96,76 @@ function register() { url: API_BASE_URL + 'auth/register/', method: 'post', data: dataForApiRequest, - }).then(function({data, status}) { + }) + .then(function({data, status}) { localStorage.setItem('token', data.token); + displaySuccessToast('Registered Successfulyy'); window.location.href = '/'; - }).catch(function(err) { + }) + .catch(function(err) { displayErrorToast('An account using same email or username is already created'); }) } } function login() { - /*** - * @todo Complete this function. - * @todo 1. Write code for form validation. - * @todo 2. Fetch the auth token from backend, login and direct user to home page. - */ + const username = document.getElementById('inputUsername').value.trim(); + const password = document.getElementById('inputPassword').value; + + if (username == '' || password == '') { + displayErrorToast("Please enter the required fields."); + return; + }; + const dataReq = { + username: username, + password: password + } + + axios({ + url: API_BASE_URL + 'auth/login/', + method: 'POST', + data: dataReq, + }).then(function ({ data, status }) { + displaySuccessToast("You are logged in successfully"); + localStorage.setItem('token', data.token); + window.location.href = '/'; + }).catch(function (err) { + displayErrorToast("The credentials used are invalid."); + document.getElementById('inputUsername').value = ''; + document.getElementById('inputPassword').value = ''; + }) } function addTask() { - /** - * @todo Complete this function. - * @todo 1. Send the request to add the task to the backend server. - * @todo 2. Add the task in the dom. - */ -} + const task = document.getElementById('task-input').value.trim(); + + if (task == '') { + displayErrorToast("Todo cannot be blank"); + return; + } + + displayInfoToast("Loading..."); + + const dataForApiRequest = { + title: task + } + const headersForApiRequest = { + Authorization: 'Token ' + localStorage.getItem('token') + } + + axios({ + headers: headersForApiRequest, + url: API_BASE_URL + 'todo/create/', + method: 'POST', + data: dataForApiRequest, + }).then(function ({ data, status }) { + displaySuccessToast("Todo added successfully"); + document.getElementById('task-input').value = ''; + getTasks(); + }).catch(function (err) { + displayErrorToast("Unable to add the todo. Please try again"); + }) +}; function editTask(id) { document.getElementById('task-' + id).classList.add('hideme'); @@ -93,17 +175,49 @@ function editTask(id) { } function deleteTask(id) { - /** - * @todo Complete this function. - * @todo 1. Send the request to delete the task to the backend server. - * @todo 2. Remove the task from the dom. - */ + const headersForApiRequest = { + Authorization: 'Token ' + localStorage.getItem('token') + } + + axios({ + headers: headersForApiRequest, + url: API_BASE_URL + 'todo/' + id + '/', + method: 'DELETE', + }).then(function ({ data, status }) { + displaySuccessToast("Deleted Successfully"); + getTasks(); + }).catch(function (err) { + displayErrorToast("Try Again"); + }) } function updateTask(id) { - /** - * @todo Complete this function. - * @todo 1. Send the request to update the task to the backend server. - * @todo 2. Update the task in the dom. - */ + const newTask = document.getElementById("input-button-" + id).value.trim(); + const taskItem = document.getElementById("task-" + id); + + if (newTask==""){ + displayErrorToast("The todo title can't be blank"); + return; + } + + const dataForApiRequest = { + title: newTask + } + const headersForApiRequest = { + Authorization: 'Token ' + localStorage.getItem('token') + } + + axios({ + headers: headersForApiRequest, + url: API_BASE_URL + 'todo/' + id + '/', + method: 'PUT', + data: dataForApiRequest, + }).then(function ({ data, status }) { + taskItem.textContent=data.title; + editTask(data.id); + displaySuccessToast("Todo updated successfully..."); + getTasks(); + }).catch(function (err) { + displayErrorToast("Unable to update the todo. Please try again..."); + }) } diff --git a/src/no_auth_required.js b/src/no_auth_required.js index 82558d4..3128c4a 100644 --- a/src/no_auth_required.js +++ b/src/no_auth_required.js @@ -1,3 +1,3 @@ -/*** - * @todo Redirect the user to main page if token is present. - */ \ No newline at end of file +if (localStorage.token) { + window.location.href = '/'; +}; \ No newline at end of file