ideleon24/tinytots-tracker-kiosk
0
1<!DOCTYPE html>2<html lang="en">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>Nachito's Admin Dashboard</title>7 <link rel="icon" type="image/x-icon" href="/static/favicon.ico">8 <script src="https://cdn.tailwindcss.com"></script>9 <script src="https://unpkg.com/feather-icons"></script>10</head>11<body class="bg-gray-100">12 <div class="flex h-screen">13 <!-- Sidebar -->14 <div class="bg-gray-800 text-white w-64 p-4">15 <div class="flex items-center space-x-2 mb-8 p-2">16 <img src="https://huggingface.co/spaces/ideleon24/tinytots-tracker-kiosk/resolve/main/images/Screen_Shot_2023-01-17_at_10.05.09_PM-removebg-preview.png" class="h-10 w-10">17<span class="font-bold text-lg">Admin Portal</span>18 </div>19 <nav>20 <a href="#" class="flex items-center space-x-2 p-2 bg-gray-700 rounded-lg">21 <i data-feather="calendar" class="h-5 w-5"></i>22 <span>Attendance</span>23 </a>24 <a href="#" class="flex items-center space-x-2 p-2 hover:bg-gray-700 rounded-lg mt-1">25 <i data-feather="users" class="h-5 w-5"></i>26 <span>Children</span>27 </a>28 <a href="#" class="flex items-center space-x-2 p-2 hover:bg-gray-700 rounded-lg mt-1">29 <i data-feather="file-text" class="h-5 w-5"></i>30 <span>Reports</span>31 </a>32 </nav>33 </div>34 35 <!-- Main Content -->36 <div class="flex-1 overflow-auto">37 <header class="bg-white shadow-sm p-4">38 <h1 class="text-2xl font-bold text-gray-800">39 <i data-feather="calendar" class="inline mr-2"></i> 40 Attendance Records41 </h1>42 </header>43 44 <main class="p-6">45 <div class="bg-white rounded-lg shadow overflow-hidden">46 <div class="p-4 border-b flex justify-between items-center">47 <div class="flex items-center space-x-4">48 <input type="date" class="border rounded px-3 py-1">49 <button class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-1 rounded">50Filter51 </button>52 </div>53 <button class="bg-gray-100 hover:bg-gray-200 px-4 py-1 rounded flex items-center">54 <i data-feather="download" class="mr-2 w-4 h-4"></i>55 Export56 </button>57 </div>58 59 <div class="overflow-x-auto">60 <table class="min-w-full divide-y divide-gray-200">61 <thead class="bg-gray-50">62 <tr>63 <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Child</th>64 <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Time In</th>65 <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Time Out</th>66 <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Parent</th>67 <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Signature</th>68 </tr>69 </thead>70 <tbody class="bg-white divide-y divide-gray-200">71 <tr>72 <td class="px-6 py-4 whitespace-nowrap">Emma Johnson</td>73 <td class="px-6 py-4 whitespace-nowrap">08:15 AM</td>74 <td class="px-6 py-4 whitespace-nowrap">-</td>75 <td class="px-6 py-4 whitespace-nowrap">Sarah Johnson</td>76 <td class="px-6 py-4 whitespace-nowrap text-blue-500">View</td>77 </tr>78 <tr>79 <td class="px-6 py-4 whitespace-nowrap">Michael Chen</td>80 <td class="px-6 py-4 whitespace-nowrap">08:05 AM</td>81 <td class="px-6 py-4 whitespace-nowrap">04:30 PM</td>82 <td class="px-6 py-4 whitespace-nowrap">Lisa Chen</td>83 <td class="px-6 py-4 whitespace-nowrap text-blue-500">View</td>84 </tr>85 </tbody>86 </table>87 </div>88 </div>89 </main>90 </div>91 </div>92 <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>93 <script>94 feather.replace();95 // Get records from API96 async function getAttendanceRecords() {97 try {98 const apiUrl = 'https://6613f7a153b0d5d80f66fc45.mockapi.io/api/v1/attendance';99 const response = await axios.get(apiUrl);100 return response.data;101 } catch (error) {102 console.error('API error:', error);103 return [];104 }105 }106// Display records in table107 function displayRecords(records) {108 const tbody = document.querySelector('tbody');109 tbody.innerHTML = '';110 111 if (records.length === 0) {112 const tr = document.createElement('tr');113 tr.innerHTML = `114 <td colspan="5" class="px-6 py-4 text-center text-gray-500">115 No attendance records found116 </td>117 `;118 tbody.appendChild(tr);119 return;120 }121 122 records.forEach(record => {123 const tr = document.createElement('tr');124 tr.innerHTML = `125 <td class="px-6 py-4 whitespace-nowrap">${record.childName}</td>126 <td class="px-6 py-4 whitespace-nowrap">${record.timeIn}</td>127 <td class="px-6 py-4 whitespace-nowrap">${record.timeOut || '-'}</td>128 <td class="px-6 py-4 whitespace-nowrap">${record.parentName}</td>129 <td class="px-6 py-4 whitespace-nowrap">130 ${record.signature ? 131 `<button onclick="showSignature('${record.childName}', '${record.signature}')" 132 class="text-blue-500 hover:underline">View</button>` : 133 'N/A'}134 </td>135 `;136 tbody.appendChild(tr);137 });138 }139 140 // Show signature modal141 function showSignature(childName, signatureData) {142 const modal = document.createElement('div');143 modal.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50';144 modal.innerHTML = `145 <div class="bg-white rounded-lg p-6 max-w-md w-full">146 <div class="flex justify-between items-center mb-4">147 <h3 class="text-lg font-bold">${childName}'s Signature</h3>148 <button onclick="this.parentNode.parentNode.parentNode.remove()" 149 class="text-gray-500 hover:text-gray-700">150 <i data-feather="x"></i>151 </button>152 </div>153 <img src="${signatureData}" alt="Signature" class="w-full border rounded">154 <div class="mt-4 text-right">155 <button onclick="this.parentNode.parentNode.parentNode.remove()" 156 class="px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded">157 Close158 </button>159 </div>160 </div>161 `;162 document.body.appendChild(modal);163 feather.replace();164 }165 // Filter records by date166 async function filterRecords() {167 const dateInput = document.querySelector('input[type="date"]');168 const selectedDate = dateInput.value;169 let records = await getAttendanceRecords();170 171 if (selectedDate) {172 records = records.filter(record => record.date === selectedDate);173 }174displayRecords(records);175 }176 // Export to CSV177 async function exportToCSV() {178 const records = await getAttendanceRecords();179if (records.length === 0) {180 alert('No records to export');181 return;182 }183 184 const headers = ['Child Name', 'Parent Name', 'Date', 'Time In', 'Time Out'];185 const csvRows = [];186 187 // Add header row188 csvRows.push(headers.join(','));189 190 // Add data rows191 records.forEach(record => {192 const values = [193 `"${record.childName}"`,194 `"${record.parentName}"`,195 `"${record.date}"`,196 `"${record.timeIn}"`,197 `"${record.timeOut || ''}"`198 ];199 csvRows.push(values.join(','));200 });201 202 // Create CSV file203 const csvContent = csvRows.join('\n');204 const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });205 const url = URL.createObjectURL(blob);206 207 // Create download link208 const link = document.createElement('a');209 link.href = url;210 link.download = `attendance_${new Date().toISOString().split('T')[0]}.csv`;211 document.body.appendChild(link);212 link.click();213 document.body.removeChild(link);214 }215 // Initial load216 document.addEventListener('DOMContentLoaded', async () => {217 const today = new Date().toISOString().split('T')[0];218 document.querySelector('input[type="date"]').value = today;219 220 const records = await getAttendanceRecords();221 displayRecords(records);222 223 document.querySelector('button[class*="bg-blue"]').addEventListener('click', filterRecords);224 document.querySelector('button[class*="bg-gray"]').addEventListener('click', exportToCSV);225 });226</script>227</body>228</html>