Skip to content

Instantly share code, notes, and snippets.

@syafiqfaiz
Created February 6, 2025 14:57
Show Gist options
  • Save syafiqfaiz/22d7bd7d9c8786e82cfbce3cbc703468 to your computer and use it in GitHub Desktop.
Save syafiqfaiz/22d7bd7d9c8786e82cfbce3cbc703468 to your computer and use it in GitHub Desktop.
<!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