Skip to content

Instantly share code, notes, and snippets.

@syafiqfaiz
Created February 12, 2025 15:21
Show Gist options
  • Save syafiqfaiz/0afa1bafacdc1217ac468521510837d8 to your computer and use it in GitHub Desktop.
Save syafiqfaiz/0afa1bafacdc1217ac468521510837d8 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;
}
input[type="password"] {
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 class="hidden" id="bekasContainer">
<input type="text" id="username" placeholder="Username" />
<input type="password" id="password" placeholder="Password" />
<br />
<button class="btn-primary" onclick="bilaKlikSubmit()">Submit</button>
<button class="btn-secondary" onclick="bilaKlikCancel()">Cancel</button>
</div>
<div id="auth-section">
<button class="btn-secondary" id="loginButton" onclick="bilaKlikLogin()">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 bilaKlikSubmit = () => {
// on klik, kita login
// dapatkan value username
const username = document.getElementById('username').value
// dapatkan value password
const password = document.getElementById('password').value
console.log('username', username)
console.log('password', password)
console.log('stringified body', JSON.stringify({
"username": username,
"password": password
}))
// buat API call utk login
fetch('https://api.kelasprogramming.com/consumer/login',{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
"username": username,
"password": password
})
})
.then((response) => response.json())
.then((body) => {
// kalau success, kita save token
if (body.success == false){
// kalau fail, kita alert apa error dia
alert('ada error ' + body.message)
} else {
localStorage.setItem('jwToken', body.token);
}
})
.catch((err)=> {
// kalau fail, kita alert apa error dia
alert('ada error ' + err )
})
}
const bilaKlikLogin = () => {
// dapatkan login container
const loginContainer = document.getElementById("bekasContainer")
// remove class hidden supaya dia visible
loginContainer.classList.remove("hidden");
// dapatkan container yg kita nak hide
const authContainer = document.getElementById("auth-section")
// tambah kan class hidden supaya dia invisible
authContainer.classList.add("hidden")
}
const bilaKlikCancel = () => {
// dapatkan login container
const loginContainer = document.getElementById("bekasContainer")
// remove class hidden supaya dia visible
loginContainer.classList.add("hidden");
// dapatkan container yg kita nak hide
const authContainer = document.getElementById("auth-section")
// tambah kan class hidden supaya dia invisible
authContainer.classList.remove("hidden")
}
const onLogin = async () => {
const username = document.getElementById('username').value
const password = document.getElementById('password').value
console.log(username, password)
}
const jwToken = window.localStorage.getItem('jwToken')
const headersOption = {
Authorization: `Bearer ${jwToken}`
}
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 logout() {
// on logout, kita delete token
localStorage.removeItem('jwToken')
}
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>
${
jwToken
? `<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();
}
// on page fully loaded, kita check jwt token
// kalau token wujud, kita hide login button
window.onload = (event)=> {
const jwToken = localStorage.getItem('jwToken')
if (jwToken) {
// if token wujud, saya hide button login,
const loginButton = document.getElementById('loginButton')
loginButton.setAttribute('style', 'display: none;')
// dan display textfield utk create new todo
const todoInput = document.getElementById('todo-form')
todoInput.classList.remove('hidden')
}
}
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>
pseudocode
===========
1) set target
2) pecahkan target kepada step paling kecil
3) then baru convert kepada code,
pseudocode utk togle login form
=================================
saya nak buat function utk toggle visibility login form
apa trigger utk display login form
1.1) saya nak bila on click login button, kita display login form
1.1.1) kita nak hide pulak button login yg kita baru klik
1.2) dan bila cancel kita hide semula login form
1.2.1) dan sorok kembali login container
onClick login button, display login form
onClick cancel button, hide login form
pseudocode utk login
======================
kita nak user boleh isi username and password
dan boleh submit utk login
1) user boleh isi username
2) user boleh isi password
3) user boleh klik button submit utk login
on click submit, kita login
4) lepas success login, kita simpan jwt token
4.1) kalau fail, kita keluarkan error message
pseudocode, user yang dah berjaya login
=====================================
kalau user dah login, dia boleh CRUD todo list dia
pseudocode utk logout
======================
on logout, kita delete token
homework
=========
1) siapkan registration
2) siapakn function remove
3) siapkan function utk toggle completion
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment