diff --git a/admin/card/index.js b/admin/card/index.js
index adcfdb5..2f8d121 100644
--- a/admin/card/index.js
+++ b/admin/card/index.js
@@ -20,9 +20,7 @@ document.addEventListener('DOMContentLoaded', () => {
try {
const url = query
- ? `${CONFIG.basePath}/card/search/${encodeURIComponent(
- query
- )}`
+ ? `${CONFIG.basePath}/card/search/${encodeURIComponent(query)}`
: `${CONFIG.basePath}/card/getAll`;
const response = await fetch(url, options);
@@ -35,83 +33,112 @@ document.addEventListener('DOMContentLoaded', () => {
displayData(data.data);
} catch (error) {
console.error('Error fetching data:', error);
- dataList.innerHTML = '
| No results found |
';
+ dataList.innerHTML =
+ '| No results found |
';
}
};
-const displayData = (data) => {
- console.log(`Displaying ${data.length} records`);
- dataList.innerHTML = '';
-
- if (Array.isArray(data) && data.length > 0) {
- document.getElementById('data-list').style.display = 'table'; // Show the table
- data.forEach((item) => {
- const row = document.createElement('tr');
-
- // Name
- const nameCell = document.createElement('td');
- nameCell.textContent = item.issuedto;
- row.appendChild(nameCell);
-
- // Card Number
- const cardCell = document.createElement('td');
- cardCell.textContent = item.cardno;
- row.appendChild(cardCell);
-
- // Mobile Number
- const mobnoCell = document.createElement('td');
- mobnoCell.textContent = item.mobno || '-';
- row.appendChild(mobnoCell);
-
- // Action Cell
- const actionCell = document.createElement('td');
-
- // Edit Button
- const editButton = document.createElement('button');
- editButton.textContent = 'Edit';
- editButton.classList.add('edit-btn');
- editButton.addEventListener('click', () => {
- sessionStorage.setItem('cardno', item.cardno); // use cardno instead
- window.location.href = 'updateCard.html';
+ const displayData = (data) => {
+ console.log(`Displaying ${data.length} records`);
+ dataList.innerHTML = '';
+
+ if (Array.isArray(data) && data.length > 0) {
+ document.getElementById('data-list').style.display = 'table';
+
+ data.forEach((item) => {
+ const row = document.createElement('tr');
+
+ // Name
+ const nameCell = document.createElement('td');
+ nameCell.textContent = item.issuedto;
+ row.appendChild(nameCell);
+
+ // Card Number
+ const cardCell = document.createElement('td');
+ cardCell.textContent = item.cardno;
+ row.appendChild(cardCell);
+
+ // Mobile Number
+ const mobnoCell = document.createElement('td');
+ mobnoCell.textContent = item.mobno || '-';
+ row.appendChild(mobnoCell);
+
+ // Action Cell
+ const actionCell = document.createElement('td');
+
+ // ================= EDIT BUTTON =================
+ const editButton = document.createElement('button');
+ editButton.textContent = 'Edit';
+ editButton.classList.add('edit-btn');
+ editButton.addEventListener('click', () => {
+ sessionStorage.setItem('cardno', item.cardno);
+ window.location.href = 'updateCard.html';
+ });
+ actionCell.appendChild(editButton);
+
+ // ================= RESET PASSWORD =================
+ const resetPwdButton = document.createElement('button');
+ resetPwdButton.textContent = 'Reset PWD';
+ resetPwdButton.classList.add('reset-btn');
+ resetPwdButton.style.marginLeft = '10px';
+
+ resetPwdButton.addEventListener('click', async () => {
+ if (
+ !confirm(
+ `Are you sure you want to reset password for ${item.issuedto}?`
+ )
+ )
+ return;
+
+ try {
+ const response = await fetch(
+ `${CONFIG.basePath}/card/reset-pwd`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${sessionStorage.getItem('token')}`
+ },
+ body: JSON.stringify({ cardno: item.cardno })
+ }
+ );
+
+ if (!response.ok) throw new Error('Reset failed');
+
+ showSuccessMessage(
+ `Password reset to 'vitraag' for ${item.issuedto}`
+ );
+ } catch (err) {
+ showErrorMessage(
+ `Failed to reset password: ${err.message}`
+ );
+ }
+ });
+
+ actionCell.appendChild(resetPwdButton);
+
+ // ================= ⭐ VIEW HISTORY =================
+ const historyButton = document.createElement('button');
+ historyButton.textContent = 'View History';
+ historyButton.classList.add('history-btn');
+ historyButton.style.marginLeft = '10px';
+
+ historyButton.addEventListener('click', () => {
+ sessionStorage.setItem('history_cardno', item.cardno);
+ window.location.href = 'personHistory.html';
+ });
+
+ actionCell.appendChild(historyButton);
+
+ row.appendChild(actionCell);
+ dataList.appendChild(row);
});
- actionCell.appendChild(editButton);
-
- // Reset Password Button
- const resetPwdButton = document.createElement('button');
- resetPwdButton.textContent = 'Reset PWD';
- resetPwdButton.classList.add('reset-btn');
- resetPwdButton.style.marginLeft = '10px';
- resetPwdButton.addEventListener('click', async () => {
- if (!confirm(`Are you sure you want to reset password for ${item.issuedto}?`)) return;
-
- try {
- const response = await fetch(`${CONFIG.basePath}/card/reset-pwd`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- Authorization: `Bearer ${sessionStorage.getItem('token')}`,
- },
- body: JSON.stringify({ cardno: item.cardno })
- });
-
- if (!response.ok) throw new Error('Reset failed');
-
- showSuccessMessage(`Password reset to 'vitraag' for ${item.issuedto}`);
- } catch (err) {
- showErrorMessage(`Failed to reset password: ${err.message}`);
- }
- });
- actionCell.appendChild(resetPwdButton);
-
- row.appendChild(actionCell);
- dataList.appendChild(row);
- });
- } else {
- document.getElementById('data-list').style.display = 'none'; // Hide if no results
- }
-};
+ } else {
+ document.getElementById('data-list').style.display = 'none';
+ }
+ };
- // Debounce function: waits for user to stop typing before triggering search
+ // ================= DEBOUNCE =================
const debounce = (callback, delay) => {
return (...args) => {
clearTimeout(debounceTimer);
@@ -119,19 +146,19 @@ const displayData = (data) => {
};
};
- // Search functionality with debounce (500ms delay)
+ // ================= SEARCH =================
searchInput.addEventListener(
'input',
debounce(async () => {
const query = searchInput.value.trim().toLowerCase();
if (query.length === 0) {
- document.getElementById('data-list').style.display = 'none'; // Hide the table
+ document.getElementById('data-list').style.display = 'none';
return;
}
await fetchData(query);
- }, 500) // 500ms delay before search starts
+ }, 500)
);
});
@@ -140,9 +167,7 @@ function showSuccessMessage(message) {
}
function showErrorMessage(message) {
- alert("Error: " + message);
+ alert('Error: ' + message);
}
-function resetAlert() {
- // This could clear UI banners if used in future (currently placeholder)
-}
\ No newline at end of file
+function resetAlert() {}
\ No newline at end of file
diff --git a/admin/card/personHistory.html b/admin/card/personHistory.html
new file mode 100644
index 0000000..0fa1298
--- /dev/null
+++ b/admin/card/personHistory.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+ Person History
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Person Booking History
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/admin/card/personHistory.js b/admin/card/personHistory.js
new file mode 100644
index 0000000..e5df708
--- /dev/null
+++ b/admin/card/personHistory.js
@@ -0,0 +1,185 @@
+document.addEventListener('DOMContentLoaded', async () => {
+ const cardno = sessionStorage.getItem('history_cardno');
+
+ if (!cardno) {
+ alert('Card not found');
+ history.back();
+ return;
+ }
+
+ try {
+ const response = await fetch(
+ `${CONFIG.basePath}/card/person-activity?cardno=${cardno}`,
+ {
+ headers: {
+ Authorization: `Bearer ${sessionStorage.getItem('token')}`
+ }
+ }
+ );
+
+ if (!response.ok) throw new Error('API failed');
+
+ const data = await response.json();
+
+ renderSummary(data.summary);
+ renderTimelineTable('upcoming', data.upcoming);
+ renderTimelineTable('past', data.past30Days);
+ renderMaintenance(data.maintenanceOpen);
+ renderWifi(data.wifiCodes);
+
+ } catch (err) {
+ console.error(err);
+ alert('Failed to load history');
+ }
+});
+
+
+// ================= SUMMARY =================
+function renderSummary(summary) {
+ const box = document.getElementById('summaryBox');
+
+ box.innerHTML = `
+
+ Total Upcoming: ${summary.totalUpcoming}
+ Past 30 Days: ${summary.totalPast}
+ Open Maintenance: ${summary.openMaintenance}
+ WiFi Codes: ${summary.wifiCodes}
+
+ `;
+}
+
+
+// ================= TIMELINE TABLE =================
+function renderTimelineTable(elementId, list) {
+ const el = document.getElementById(elementId);
+
+ if (!list || list.length === 0) {
+ el.innerHTML = 'No records found
';
+ return;
+ }
+
+ let html = `
+
+
+
+ | Type |
+ Date |
+ Status |
+
+
+
+ `;
+
+ list.forEach(item => {
+ html += `
+
+ | ${formatType(item.type)} |
+ ${formatDate(item.date)} |
+ ${formatStatus(item.status)} |
+
+ `;
+ });
+
+ html += `
`;
+
+ el.innerHTML = html;
+}
+
+
+// ================= MAINTENANCE =================
+function renderMaintenance(list) {
+ const el = document.getElementById('maintenance');
+
+ if (!list || list.length === 0) {
+ el.innerHTML = 'No open maintenance requests
';
+ return;
+ }
+
+ let html = `
+
+
+
+ | Department |
+ Work Detail |
+ Status |
+
+
+
+ `;
+
+ list.forEach(item => {
+ html += `
+
+ | ${item.department} |
+ ${item.work_detail} |
+ OPEN |
+
+ `;
+ });
+
+ html += `
`;
+
+ el.innerHTML = html;
+}
+
+
+// ================= WIFI =================
+function renderWifi(list) {
+ const el = document.getElementById('wifi');
+
+ if (!list || list.length === 0) {
+ el.innerHTML = 'No WiFi codes
';
+ return;
+ }
+
+ let html = `
+
+
+
+ | Username |
+ SSID |
+ Status |
+
+
+
+ `;
+
+ list.forEach(item => {
+ html += `
+
+ | ${item.username} |
+ ${item.ssid || '-'} |
+ ${item.status} |
+
+ `;
+ });
+
+ html += `
`;
+
+ el.innerHTML = html;
+}
+
+
+// ================= HELPERS =================
+function formatType(type) {
+ if (!type) return '-';
+ return type.replace('_', ' ').toUpperCase();
+}
+
+function formatDate(date) {
+ if (!date) return '-';
+ return new Date(date).toLocaleDateString();
+}
+
+function formatStatus(status) {
+ if (!status) return '-';
+
+ let color = '#444';
+
+ if (status.includes('CONFIRMED')) color = 'green';
+ else if (status.includes('WAITING')) color = 'orange';
+ else if (status.includes('CANCELLED')) color = 'red';
+ else if (status.includes('CHECKEDIN')) color = 'blue';
+
+ return `${status}`;
+}
\ No newline at end of file