324 lines
9.8 KiB
JavaScript
324 lines
9.8 KiB
JavaScript
// ===== TOAST NOTIFICATIONS =====
|
|
function showToast(message, type = 'info') {
|
|
document.querySelectorAll('.toast').forEach(t => t.remove());
|
|
|
|
const toast = document.createElement('div');
|
|
toast.className = `toast ${type}`;
|
|
toast.textContent = message;
|
|
document.body.appendChild(toast);
|
|
|
|
toast.offsetHeight;
|
|
toast.classList.add('show');
|
|
|
|
setTimeout(() => {
|
|
toast.classList.remove('show');
|
|
setTimeout(() => toast.remove(), 400);
|
|
}, 3000);
|
|
}
|
|
|
|
// ===== LOCAL STORAGE HELPERS =====
|
|
function getUsers() {
|
|
try {
|
|
return JSON.parse(localStorage.getItem('users')) || [];
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function saveUsers(users) {
|
|
localStorage.setItem('users', JSON.stringify(users));
|
|
}
|
|
|
|
// ===== MONTH NAMES =====
|
|
const monthNames = [
|
|
'', 'Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni',
|
|
'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember'
|
|
];
|
|
|
|
function formatDate(day, month, year) {
|
|
return `${day} ${monthNames[parseInt(month)]} ${year}`;
|
|
}
|
|
|
|
function formatGender(gender) {
|
|
if (gender === 'laki-laki') return 'Laki-laki';
|
|
if (gender === 'perempuan') return 'Perempuan';
|
|
return gender;
|
|
}
|
|
|
|
// ===== POPULATE DATE DROPDOWNS =====
|
|
function populateDays(selectId) {
|
|
const daySelect = document.getElementById(selectId || 'inputDay');
|
|
if (!daySelect) return;
|
|
|
|
// Keep first option if it exists
|
|
const firstOption = daySelect.querySelector('option[disabled]');
|
|
if (daySelect.options.length <= 1) {
|
|
for (let i = 1; i <= 31; i++) {
|
|
const option = document.createElement('option');
|
|
option.value = i;
|
|
option.textContent = i;
|
|
daySelect.appendChild(option);
|
|
}
|
|
}
|
|
}
|
|
|
|
function populateYears(selectId) {
|
|
const yearSelect = document.getElementById(selectId || 'inputYear');
|
|
if (!yearSelect) return;
|
|
|
|
if (yearSelect.options.length <= 1) {
|
|
const currentYear = new Date().getFullYear();
|
|
for (let y = currentYear; y >= 1950; y--) {
|
|
const option = document.createElement('option');
|
|
option.value = y;
|
|
option.textContent = y;
|
|
yearSelect.appendChild(option);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ===== RENDER USER TABLE (Dashboard page) =====
|
|
function renderUserTable() {
|
|
const tbody = document.getElementById('userTableBody');
|
|
const emptyState = document.getElementById('emptyState');
|
|
const table = document.getElementById('userTable');
|
|
if (!tbody) return;
|
|
|
|
const users = getUsers();
|
|
tbody.innerHTML = '';
|
|
|
|
if (users.length === 0) {
|
|
if (table) table.style.display = 'none';
|
|
if (emptyState) emptyState.style.display = 'flex';
|
|
return;
|
|
}
|
|
|
|
if (table) table.style.display = 'table';
|
|
if (emptyState) emptyState.style.display = 'none';
|
|
|
|
users.forEach((user, index) => {
|
|
const tr = document.createElement('tr');
|
|
tr.innerHTML = `
|
|
<td>${index + 1}</td>
|
|
<td>${escapeHtml(user.nama)}</td>
|
|
<td>${escapeHtml(user.email)}</td>
|
|
<td>${formatGender(user.gender)}</td>
|
|
<td>${formatDate(user.day, user.month, user.year)}</td>
|
|
<td>
|
|
<div class="action-buttons">
|
|
<button class="btn-action btn-edit" onclick="openEditModal(${index})" title="Edit">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15">
|
|
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
|
|
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
|
</svg>
|
|
</button>
|
|
<button class="btn-action btn-delete" onclick="openDeleteModal(${index})" title="Hapus">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15">
|
|
<polyline points="3 6 5 6 21 6"/>
|
|
<path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/>
|
|
<line x1="10" y1="11" x2="10" y2="17"/>
|
|
<line x1="14" y1="11" x2="14" y2="17"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
`;
|
|
tbody.appendChild(tr);
|
|
});
|
|
}
|
|
|
|
function escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
// ===== EDIT MODAL =====
|
|
function openEditModal(index) {
|
|
const users = getUsers();
|
|
const user = users[index];
|
|
if (!user) return;
|
|
|
|
document.getElementById('editId').value = index;
|
|
document.getElementById('editNama').value = user.nama;
|
|
document.getElementById('editEmail').value = user.email;
|
|
document.getElementById('editGender').value = user.gender;
|
|
|
|
// Populate edit dropdowns
|
|
populateDays('editDay');
|
|
populateYears('editYear');
|
|
|
|
// Set values after populating
|
|
setTimeout(() => {
|
|
document.getElementById('editDay').value = user.day;
|
|
document.getElementById('editMonth').value = user.month;
|
|
document.getElementById('editYear').value = user.year;
|
|
}, 50);
|
|
|
|
document.getElementById('editModal').style.display = 'flex';
|
|
}
|
|
|
|
function closeEditModal() {
|
|
document.getElementById('editModal').style.display = 'none';
|
|
}
|
|
|
|
function handleEditSave(e) {
|
|
e.preventDefault();
|
|
|
|
const index = parseInt(document.getElementById('editId').value);
|
|
const users = getUsers();
|
|
|
|
users[index] = {
|
|
nama: document.getElementById('editNama').value.trim(),
|
|
email: document.getElementById('editEmail').value.trim(),
|
|
gender: document.getElementById('editGender').value,
|
|
day: document.getElementById('editDay').value,
|
|
month: document.getElementById('editMonth').value,
|
|
year: document.getElementById('editYear').value
|
|
};
|
|
|
|
saveUsers(users);
|
|
closeEditModal();
|
|
renderUserTable();
|
|
showToast('Data berhasil diperbarui!', 'success');
|
|
}
|
|
|
|
// ===== DELETE MODAL =====
|
|
let deleteIndex = null;
|
|
|
|
function openDeleteModal(index) {
|
|
const users = getUsers();
|
|
const user = users[index];
|
|
if (!user) return;
|
|
|
|
deleteIndex = index;
|
|
document.getElementById('deleteUserName').textContent = user.nama;
|
|
document.getElementById('deleteModal').style.display = 'flex';
|
|
}
|
|
|
|
function closeDeleteModal() {
|
|
document.getElementById('deleteModal').style.display = 'none';
|
|
deleteIndex = null;
|
|
}
|
|
|
|
function confirmDelete() {
|
|
if (deleteIndex === null) return;
|
|
|
|
const users = getUsers();
|
|
users.splice(deleteIndex, 1);
|
|
saveUsers(users);
|
|
closeDeleteModal();
|
|
renderUserTable();
|
|
showToast('Data berhasil dihapus!', 'success');
|
|
}
|
|
|
|
// ===== HANDLE INPUT DATA FORM (input-data.html) =====
|
|
function handleInputData(e) {
|
|
e.preventDefault();
|
|
|
|
const nama = document.getElementById('inputNama')?.value.trim();
|
|
const email = document.getElementById('inputEmail')?.value.trim();
|
|
const gender = document.getElementById('inputGender')?.value;
|
|
const day = document.getElementById('inputDay')?.value;
|
|
const month = document.getElementById('inputMonth')?.value;
|
|
const year = document.getElementById('inputYear')?.value;
|
|
|
|
if (!nama || !email || !gender || !day || !month || !year) {
|
|
showToast('Silakan isi semua field', 'error');
|
|
return;
|
|
}
|
|
|
|
const btn = document.getElementById('submitBtn');
|
|
if (btn) {
|
|
btn.disabled = true;
|
|
btn.textContent = 'MENYIMPAN...';
|
|
btn.style.opacity = '0.6';
|
|
btn.style.pointerEvents = 'none';
|
|
}
|
|
|
|
// Save to localStorage
|
|
setTimeout(() => {
|
|
const users = getUsers();
|
|
users.push({ nama, email, gender, day, month, year });
|
|
saveUsers(users);
|
|
|
|
showToast('Data pengguna berhasil disimpan!', 'success');
|
|
|
|
if (btn) {
|
|
btn.disabled = false;
|
|
btn.textContent = 'SIMPAN DATA';
|
|
btn.style.opacity = '1';
|
|
btn.style.pointerEvents = 'auto';
|
|
}
|
|
|
|
document.getElementById('inputDataForm')?.reset();
|
|
}, 1000);
|
|
}
|
|
|
|
// ===== LOGOUT =====
|
|
function handleLogout(e) {
|
|
e.preventDefault();
|
|
showToast('Berhasil logout. Mengalihkan...', 'info');
|
|
setTimeout(() => {
|
|
window.location.href = 'login.html';
|
|
}, 1200);
|
|
}
|
|
|
|
|
|
|
|
// ===== CLOSE MODAL ON OVERLAY CLICK =====
|
|
function setupModalClose() {
|
|
document.querySelectorAll('.modal-overlay').forEach(overlay => {
|
|
overlay.addEventListener('click', (e) => {
|
|
if (e.target === overlay) {
|
|
overlay.style.display = 'none';
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// ===== INIT =====
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
populateDays('inputDay');
|
|
populateYears('inputYear');
|
|
|
|
// Dashboard: render user table
|
|
renderUserTable();
|
|
|
|
// Dashboard: delete confirm button
|
|
const confirmDeleteBtn = document.getElementById('confirmDeleteBtn');
|
|
if (confirmDeleteBtn) {
|
|
confirmDeleteBtn.addEventListener('click', confirmDelete);
|
|
}
|
|
|
|
// Histori: filter & search listeners
|
|
const filterStatus = document.getElementById('filterStatus');
|
|
if (filterStatus) {
|
|
filterStatus.addEventListener('change', () => {
|
|
if (typeof loadLogs === 'function') loadLogs();
|
|
});
|
|
}
|
|
|
|
const searchName = document.getElementById('searchName');
|
|
if (searchName) {
|
|
searchName.addEventListener('input', () => {
|
|
if (typeof loadLogs === 'function') loadLogs();
|
|
});
|
|
}
|
|
|
|
// Logout handler
|
|
const logoutBtn = document.getElementById('logoutBtn');
|
|
if (logoutBtn) {
|
|
logoutBtn.addEventListener('click', handleLogout);
|
|
}
|
|
|
|
// Modal close on overlay click
|
|
setupModalClose();
|
|
});
|
|
|
|
setTimeout(() => {
|
|
const toast = document.querySelector('.toast');
|
|
if (toast) {
|
|
toast.style.display = "none";
|
|
}
|
|
}, 3000); |