Created
February 6, 2025 14:57
-
-
Save syafiqfaiz/22d7bd7d9c8786e82cfbce3cbc703468 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<title>Todo App with Authentication</title> | |
<style> | |
body { | |
font-family: Arial, sans-serif; | |
background-color: #f4f4f4; | |
text-align: center; | |
margin: 0; | |
padding: 20px; | |
} | |
.container { | |
max-width: 400px; | |
margin: 0 auto; | |
background: white; | |
padding: 20px; | |
border-radius: 10px; | |
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); | |
} | |
h2 { | |
color: #333; | |
} | |
.todo-item { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
padding: 10px; | |
border-bottom: 1px solid #ddd; | |
} | |
.todo-item:last-child { | |
border-bottom: none; | |
} | |
.completed { | |
text-decoration: line-through; | |
color: gray; | |
} | |
.hidden { | |
display: none; | |
} | |
button { | |
padding: 8px 12px; | |
border: none; | |
border-radius: 5px; | |
cursor: pointer; | |
} | |
.btn-primary { | |
background-color: #28a745; | |
color: white; | |
} | |
.btn-danger { | |
background-color: #dc3545; | |
color: white; | |
} | |
.btn-secondary { | |
background-color: #007bff; | |
color: white; | |
} | |
input[type="text"] { | |
width: calc(100% - 20px); | |
padding: 8px; | |
margin-bottom: 10px; | |
border: 1px solid #ccc; | |
border-radius: 5px; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h2>Todo List</h2> | |
<div id="auth-section"> | |
<button class="btn-secondary" onclick="login()">Login</button> | |
<button class="btn-danger" onclick="logout()">Logout</button> | |
<p id="auth-status">Not logged in</p> | |
</div> | |
<div id="todo-form" class="hidden"> | |
<input type="text" id="todo-input" placeholder="New todo" /> | |
<button class="btn-primary" onclick="addTodo()">Add</button> | |
</div> | |
<ul id="todo-list"></ul> | |
</div> | |
<script> | |
const headersOption = { | |
Authorization: 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2FwaS5rZWxhc3Byb2dyYW1taW5nLmNvbS50ZXN0Iiwic3ViIjoiYzAxZTc0YTEtMjQwZC01MWU3LWFhYWUtZTQzMWJiZTBiZmYxIiwiaWF0IjoxNzM4ODUwMzczLCJleHAiOjE3MzkwMjMxNzMsIm5hbWUiOiJrYXNpbXNlbGFtYXQifQ.3TmClRMj4lxBf7H6w-EDGhruWY7qJb2wzchkV45_Ekk' | |
} | |
async function getTodos(){ | |
let todos = [] | |
await fetch('https://api.kelasprogramming.com/todo', { | |
headers: headersOption | |
}) | |
.then((res) => res.json()) | |
.then((body) => { | |
todos = body.entry | |
}) | |
return todos | |
} | |
async function getTodo(id){ | |
let todo | |
await fetch(`https://api.kelasprogramming.com/todo/${id}`, { | |
headers: headersOption | |
}) | |
.then((res) => res.json()) | |
.then((body) => { | |
todo = body[0] | |
}) | |
return todo | |
} | |
// dia buat api call utk create todo | |
async function createTodo(details) { | |
await fetch('https://api.kelasprogramming.com/todo',{ | |
method: 'POST', | |
headers: headersOption, | |
body: JSON.stringify({"details": details }) | |
}) | |
} | |
async function updateTodo(id, body) { | |
await fetch(`https://api.kelasprogramming.com/todo/${id}`, { | |
method: 'PUT', | |
headers: headersOption, | |
body: JSON.stringify(body) | |
}) | |
} | |
let isAuthenticated = true; | |
document.addEventListener("DOMContentLoaded", loadTodos); | |
function login() { | |
isAuthenticated = true; | |
document.getElementById("auth-status").innerText = "Logged in"; | |
document.getElementById("todo-form").classList.remove("hidden"); | |
loadTodos(); | |
} | |
function logout() { | |
isAuthenticated = false; | |
document.getElementById("auth-status").innerText = "Not logged in"; | |
document.getElementById("todo-form").classList.add("hidden"); | |
loadTodos(); | |
} | |
async function loadTodos() { | |
// get all todos from api | |
const todos = await getTodos() | |
const list = document.getElementById("todo-list"); | |
list.innerHTML = ""; | |
todos.forEach((todo, index) => { | |
const li = document.createElement("li"); | |
li.className = `todo-item ${todo.completed === 1 ? "completed" : ""}`; | |
li.innerHTML = ` | |
<span onclick="toggleComplete(${index})">${todo.details}</span> | |
${ | |
isAuthenticated | |
? `<button class="btn-secondary" onclick="editTodo(${todo.id})">Edit</button> | |
<button class="btn-danger" onclick="deleteTodo(${index})">Delete</button>` | |
: "" | |
} | |
`; | |
list.appendChild(li); | |
}); | |
} | |
async function addTodo() { | |
// check, dah login ke belum? | |
// kalau belum dia keluar alert | |
if (!isAuthenticated) { | |
return alert("You must be logged in to add a todo."); | |
} | |
// dapatkan value dari text input#todo-input | |
const input = document.getElementById("todo-input"); | |
// kalau kosong, jangan buat apa2 | |
if (!input.value.trim()) return; | |
// add new todo item to api | |
await createTodo(input.value) | |
// kita reset text input pada kosong | |
input.value = ""; | |
// kita refetch todo list, so that item yg kita baru tambah akan keluar dalam list | |
loadTodos(); | |
} | |
async function editTodo(id) { | |
if (!isAuthenticated) return; | |
const selectedTodo = await getTodo(id) | |
const newValue = prompt("Edit todo:", selectedTodo.details); | |
await updateTodo(id, { | |
"details": newValue, | |
"completed": selectedTodo.completed | |
}) | |
loadTodos(); | |
} | |
function deleteTodo(index) { | |
if (!isAuthenticated) return; | |
const todos = JSON.parse(localStorage.getItem("todos")); | |
todos.splice(index, 1); | |
localStorage.setItem("todos", JSON.stringify(todos)); | |
loadTodos(); | |
} | |
function toggleComplete(index) { | |
const todos = JSON.parse(localStorage.getItem("todos")); | |
todos[index].completed = !todos[index].completed; | |
localStorage.setItem("todos", JSON.stringify(todos)); | |
loadTodos(); | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment