limalex commited on
Commit
f19692c
·
verified ·
1 Parent(s): 20d3e34

undefined - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +988 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Alexandre
3
- emoji: 🐢
4
- colorFrom: gray
5
  colorTo: gray
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: alexandre
3
+ emoji: 🐳
4
+ colorFrom: blue
5
  colorTo: gray
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,988 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # Time Tracker Pro - Offline Installation
3
+
4
+ ## Prerequisites
5
+ - Node.js (v16 or later)
6
+ - npm (comes with Node.js)
7
+
8
+ ## Installation Steps
9
+
10
+ 1. **Download the application files** including:
11
+ - `index.html` (main application file)
12
+ - `package.json` (configuration file)
13
+ - `main.js` (Electron main process file)
14
+ - `/build` folder with application icon (optional)
15
+
16
+ 2. **Install dependencies**:
17
+ ```bash
18
+ npm install
19
+ ```
20
+
21
+ 3. **Run the application in development mode**:
22
+ ```bash
23
+ npm start
24
+ ```
25
+
26
+ 4. **Create installer packages**:
27
+
28
+ For Windows:
29
+ ```bash
30
+ npm run dist
31
+ ```
32
+
33
+ This will create:
34
+ - Setup executable in `dist` folder
35
+ - Portable version in `dist/win-unpacked`
36
+
37
+ ## Building for Other Platforms
38
+
39
+ To build for other platforms, add the appropriate build configuration to `package.json` and run:
40
+ ```bash
41
+ npm run dist
42
+ ```
43
+
44
+ ## Offline Usage
45
+ Once installed, the application works completely offline:
46
+ - All data is stored in local storage
47
+ - No internet connection required
48
+ - Reports can be printed or saved as PDF
49
+
50
+
51
+ const { app, BrowserWindow } = require('electron')
52
+ const path = require('path')
53
+
54
+ function createWindow () {
55
+ const win = new BrowserWindow({
56
+ width: 1200,
57
+ height: 800,
58
+ webPreferences: {
59
+ nodeIntegration: true,
60
+ contextIsolation: false
61
+ }
62
+ })
63
+
64
+ win.loadFile('index.html')
65
+ }
66
+
67
+ app.whenReady().then(() => {
68
+ createWindow()
69
+
70
+ app.on('activate', () => {
71
+ if (BrowserWindow.getAllWindows().length === 0) {
72
+ createWindow()
73
+ }
74
+ })
75
+ })
76
+
77
+ app.on('window-all-closed', () => {
78
+ if (process.platform !== 'darwin') {
79
+ app.quit()
80
+ }
81
+ })
82
+
83
+
84
+ {
85
+ "name": "time-tracker-pro",
86
+ "version": "1.0.0",
87
+ "description": "Offline Time Tracking Application",
88
+ "main": "main.js",
89
+ "scripts": {
90
+ "start": "electron .",
91
+ "pack": "electron-builder --dir",
92
+ "dist": "electron-builder",
93
+ "postinstall": "electron-builder install-app-deps"
94
+ },
95
+ "build": {
96
+ "appId": "com.example.timetrackerpro",
97
+ "productName": "Time Tracker Pro",
98
+ "win": {
99
+ "target": "nsis",
100
+ "icon": "build/icon.ico"
101
+ },
102
+ "nsis": {
103
+ "oneClick": false,
104
+ "allowToChangeInstallationDirectory": true
105
+ }
106
+ },
107
+ "devDependencies": {
108
+ "electron": "^25.0.0",
109
+ "electron-builder": "^24.0.0"
110
+ }
111
+ }
112
+
113
+ <!DOCTYPE html>
114
+ <html lang="en">
115
+ <head>
116
+ <meta charset="UTF-8">
117
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
118
+ <title>Time Tracker Pro</title>
119
+ <script src="https://cdn.tailwindcss.com"></script>
120
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
121
+ <script>
122
+ tailwind.config = {
123
+ theme: {
124
+ extend: {
125
+ colors: {
126
+ primary: '#3b82f6',
127
+ secondary: '#10b981',
128
+ dark: '#1e293b',
129
+ light: '#f8fafc'
130
+ }
131
+ }
132
+ }
133
+ }
134
+ </script>
135
+ <style>
136
+ /* Custom scrollbar */
137
+ ::-webkit-scrollbar {
138
+ width: 8px;
139
+ height: 8px;
140
+ }
141
+ ::-webkit-scrollbar-track {
142
+ background: #f1f1f1;
143
+ }
144
+ ::-webkit-scrollbar-thumb {
145
+ background: #888;
146
+ border-radius: 4px;
147
+ }
148
+ ::-webkit-scrollbar-thumb:hover {
149
+ background: #555;
150
+ }
151
+
152
+ /* Animation for buttons */
153
+ @keyframes pulse {
154
+ 0% { transform: scale(1); }
155
+ 50% { transform: scale(1.05); }
156
+ 100% { transform: scale(1); }
157
+ }
158
+ .pulse:hover {
159
+ animation: pulse 1.5s infinite;
160
+ }
161
+
162
+ /* Print styles */
163
+ @media print {
164
+ .no-print {
165
+ display: none !important;
166
+ }
167
+ .print-full {
168
+ width: 100% !important;
169
+ }
170
+ }
171
+ </style>
172
+ </head>
173
+ <body class="bg-gray-100 font-sans">
174
+ <div class="min-h-screen flex flex-col">
175
+ <!-- Header -->
176
+ <header class="bg-dark text-white shadow-lg">
177
+ <div class="container mx-auto px-4 py-4 flex justify-between items-center">
178
+ <div class="flex items-center space-x-2">
179
+ <i class="fas fa-clock text-2xl text-primary"></i>
180
+ <h1 class="text-2xl font-bold">Time Tracker Pro</h1>
181
+ </div>
182
+ <div class="flex items-center space-x-4">
183
+ <div id="current-time" class="text-sm bg-primary px-3 py-1 rounded-full"></div>
184
+ <button id="theme-toggle" class="p-2 rounded-full hover:bg-gray-700">
185
+ <i class="fas fa-moon"></i>
186
+ </button>
187
+ </div>
188
+ </div>
189
+ </header>
190
+
191
+ <!-- Main Content -->
192
+ <main class="flex-grow container mx-auto px-4 py-6">
193
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
194
+ <!-- Time Entry Section -->
195
+ <div class="lg:col-span-1">
196
+ <div class="bg-white rounded-lg shadow-md p-6">
197
+ <h2 class="text-xl font-semibold mb-4 text-dark flex items-center">
198
+ <i class="fas fa-stopwatch mr-2 text-primary"></i> Time Entry
199
+ </h2>
200
+
201
+ <div class="space-y-4">
202
+ <div>
203
+ <label class="block text-sm font-medium text-gray-700 mb-1">Employee ID</label>
204
+ <input type="text" id="employee-id" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary">
205
+ </div>
206
+
207
+ <div class="grid grid-cols-2 gap-4">
208
+ <button id="clock-in" class="bg-green-600 hover:bg-green-700 text-white py-3 px-4 rounded-md font-medium flex items-center justify-center pulse">
209
+ <i class="fas fa-sign-in-alt mr-2"></i> Clock In
210
+ </button>
211
+ <button id="lunch-out" class="bg-yellow-600 hover:bg-yellow-700 text-white py-3 px-4 rounded-md font-medium flex items-center justify-center pulse">
212
+ <i class="fas fa-utensils mr-2"></i> Lunch Out
213
+ </button>
214
+ <button id="lunch-in" class="bg-blue-600 hover:bg-blue-700 text-white py-3 px-4 rounded-md font-medium flex items-center justify-center pulse">
215
+ <i class="fas fa-utensils mr-2"></i> Lunch In
216
+ </button>
217
+ <button id="clock-out" class="bg-red-600 hover:bg-red-700 text-white py-3 px-4 rounded-md font-medium flex items-center justify-center pulse">
218
+ <i class="fas fa-sign-out-alt mr-2"></i> Clock Out
219
+ </button>
220
+ </div>
221
+
222
+ <div class="pt-4 border-t border-gray-200">
223
+ <h3 class="text-lg font-medium text-dark mb-2">Today's Summary</h3>
224
+ <div class="grid grid-cols-2 gap-2">
225
+ <div class="bg-gray-50 p-3 rounded">
226
+ <p class="text-xs text-gray-500">Clock In</p>
227
+ <p id="today-clock-in" class="font-semibold">--:--</p>
228
+ </div>
229
+ <div class="bg-gray-50 p-3 rounded">
230
+ <p class="text-xs text-gray-500">Lunch Out</p>
231
+ <p id="today-lunch-out" class="font-semibold">--:--</p>
232
+ </div>
233
+ <div class="bg-gray-50 p-3 rounded">
234
+ <p class="text-xs text-gray-500">Lunch In</p>
235
+ <p id="today-lunch-in" class="font-semibold">--:--</p>
236
+ </div>
237
+ <div class="bg-gray-50 p-3 rounded">
238
+ <p class="text-xs text-gray-500">Clock Out</p>
239
+ <p id="today-clock-out" class="font-semibold">--:--</p>
240
+ </div>
241
+ </div>
242
+ <div class="mt-2 bg-gray-50 p-3 rounded">
243
+ <p class="text-xs text-gray-500">Total Hours</p>
244
+ <p id="today-total-hours" class="font-semibold text-lg">0.00 hrs</p>
245
+ </div>
246
+ <div class="mt-2 bg-gray-50 p-3 rounded">
247
+ <p class="text-xs text-gray-500">Overtime</p>
248
+ <p id="today-overtime" class="font-semibold text-lg">0.00 hrs</p>
249
+ </div>
250
+ </div>
251
+ </div>
252
+ </div>
253
+ </div>
254
+
255
+ <!-- Records and Reports Section -->
256
+ <div class="lg:col-span-2 space-y-6">
257
+ <!-- Records Table -->
258
+ <div class="bg-white rounded-lg shadow-md p-6">
259
+ <div class="flex justify-between items-center mb-4">
260
+ <h2 class="text-xl font-semibold text-dark flex items-center">
261
+ <i class="fas fa-list-alt mr-2 text-primary"></i> Time Records
262
+ </h2>
263
+ <div class="flex space-x-2">
264
+ <select id="records-filter" class="text-sm border border-gray-300 rounded px-3 py-1 focus:outline-none focus:ring-1 focus:ring-primary">
265
+ <option value="today">Today</option>
266
+ <option value="week">This Week</option>
267
+ <option value="month">This Month</option>
268
+ <option value="all">All Records</option>
269
+ </select>
270
+ <button id="refresh-records" class="p-1 text-gray-500 hover:text-primary">
271
+ <i class="fas fa-sync-alt"></i>
272
+ </button>
273
+ </div>
274
+ </div>
275
+
276
+ <div class="overflow-x-auto">
277
+ <table class="min-w-full divide-y divide-gray-200">
278
+ <thead class="bg-gray-50">
279
+ <tr>
280
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
281
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Clock In</th>
282
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Lunch Out</th>
283
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Lunch In</th>
284
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Clock Out</th>
285
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Total</th>
286
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Overtime</th>
287
+ </tr>
288
+ </thead>
289
+ <tbody id="records-body" class="bg-white divide-y divide-gray-200">
290
+ <tr>
291
+ <td colspan="7" class="px-4 py-6 text-center text-gray-500">No records found</td>
292
+ </tr>
293
+ </tbody>
294
+ </table>
295
+ </div>
296
+ </div>
297
+
298
+ <!-- Reports Section -->
299
+ <div class="bg-white rounded-lg shadow-md p-6">
300
+ <div class="flex justify-between items-center mb-4">
301
+ <h2 class="text-xl font-semibold text-dark flex items-center">
302
+ <i class="fas fa-chart-bar mr-2 text-primary"></i> Reports
303
+ </h2>
304
+ <div class="flex space-x-2">
305
+ <select id="report-period" class="text-sm border border-gray-300 rounded px-3 py-1 focus:outline-none focus:ring-1 focus:ring-primary">
306
+ <option value="daily">Daily</option>
307
+ <option value="weekly">Weekly</option>
308
+ <option value="monthly">Monthly</option>
309
+ </select>
310
+ <button id="generate-report" class="bg-primary hover:bg-blue-700 text-white px-4 py-1 rounded flex items-center">
311
+ <i class="fas fa-file-pdf mr-1"></i> Generate
312
+ </button>
313
+ <button id="print-report" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-1 rounded flex items-center no-print">
314
+ <i class="fas fa-print mr-1"></i> Print
315
+ </button>
316
+ </div>
317
+ </div>
318
+
319
+ <div id="report-content" class="mt-4">
320
+ <div class="text-center py-10 text-gray-400">
321
+ <i class="fas fa-file-alt text-4xl mb-2"></i>
322
+ <p>Select report type and click Generate</p>
323
+ </div>
324
+ </div>
325
+ </div>
326
+ </div>
327
+ </div>
328
+ </main>
329
+
330
+ <!-- Footer -->
331
+ <footer class="bg-dark text-white py-4">
332
+ <div class="container mx-auto px-4 text-center text-sm">
333
+ <p>© 2023 Time Tracker Pro. All rights reserved.</p>
334
+ </div>
335
+ </footer>
336
+ </div>
337
+
338
+ <script>
339
+ // Sample data storage
340
+ let timeRecords;
341
+
342
+ // Initialize storage - works differently in Electron
343
+ function initStorage() {
344
+ if (typeof localStorage !== 'undefined') {
345
+ timeRecords = JSON.parse(localStorage.getItem('timeRecords')) || [];
346
+ } else {
347
+ // Fallback for Electron
348
+ const fs = require('fs');
349
+ const path = require('path');
350
+ const dataPath = path.join(app.getPath('userData'), 'timeRecords.json');
351
+
352
+ try {
353
+ timeRecords = JSON.parse(fs.readFileSync(dataPath)) || [];
354
+ } catch (e) {
355
+ timeRecords = [];
356
+ }
357
+
358
+ // Override localStorage methods
359
+ window.localStorage = {
360
+ getItem: () => null,
361
+ setItem: (key, value) => {
362
+ if (key === 'timeRecords') {
363
+ fs.writeFileSync(dataPath, JSON.stringify(timeRecords));
364
+ }
365
+ }
366
+ };
367
+ }
368
+ }
369
+
370
+ initStorage();
371
+ let currentEmployeeId = '';
372
+
373
+ // DOM Elements
374
+ const employeeIdInput = document.getElementById('employee-id');
375
+ const clockInBtn = document.getElementById('clock-in');
376
+ const lunchOutBtn = document.getElementById('lunch-out');
377
+ const lunchInBtn = document.getElementById('lunch-in');
378
+ const clockOutBtn = document.getElementById('clock-out');
379
+ const todayClockIn = document.getElementById('today-clock-in');
380
+ const todayLunchOut = document.getElementById('today-lunch-out');
381
+ const todayLunchIn = document.getElementById('today-lunch-in');
382
+ const todayClockOut = document.getElementById('today-clock-out');
383
+ const todayTotalHours = document.getElementById('today-total-hours');
384
+ const todayOvertime = document.getElementById('today-overtime');
385
+ const recordsFilter = document.getElementById('records-filter');
386
+ const recordsBody = document.getElementById('records-body');
387
+ const refreshRecordsBtn = document.getElementById('refresh-records');
388
+ const reportPeriod = document.getElementById('report-period');
389
+ const generateReportBtn = document.getElementById('generate-report');
390
+ const printReportBtn = document.getElementById('print-report');
391
+ const reportContent = document.getElementById('report-content');
392
+ const currentTimeDisplay = document.getElementById('current-time');
393
+ const themeToggle = document.getElementById('theme-toggle');
394
+
395
+ // Initialize
396
+ document.addEventListener('DOMContentLoaded', () => {
397
+ updateCurrentTime();
398
+ setInterval(updateCurrentTime, 1000);
399
+ loadTodayRecords();
400
+ loadAllRecords();
401
+
402
+ // Check for dark mode preference
403
+ if (localStorage.getItem('darkMode') === 'enabled') {
404
+ document.documentElement.classList.add('dark');
405
+ themeToggle.innerHTML = '<i class="fas fa-sun"></i>';
406
+ }
407
+ });
408
+
409
+ // Update current time
410
+ function updateCurrentTime() {
411
+ const now = new Date();
412
+ currentTimeDisplay.textContent = now.toLocaleTimeString() + ' ' + now.toLocaleDateString();
413
+ }
414
+
415
+ // Theme toggle
416
+ themeToggle.addEventListener('click', () => {
417
+ document.documentElement.classList.toggle('dark');
418
+ if (document.documentElement.classList.contains('dark')) {
419
+ localStorage.setItem('darkMode', 'enabled');
420
+ themeToggle.innerHTML = '<i class="fas fa-sun"></i>';
421
+ } else {
422
+ localStorage.setItem('darkMode', 'disabled');
423
+ themeToggle.innerHTML = '<i class="fas fa-moon"></i>';
424
+ }
425
+ });
426
+
427
+ // Time entry buttons
428
+ clockInBtn.addEventListener('click', () => recordTime('clockIn'));
429
+ lunchOutBtn.addEventListener('click', () => recordTime('lunchOut'));
430
+ lunchInBtn.addEventListener('click', () => recordTime('lunchIn'));
431
+ clockOutBtn.addEventListener('click', () => recordTime('clockOut'));
432
+
433
+ // Record time function
434
+ function recordTime(type) {
435
+ currentEmployeeId = employeeIdInput.value.trim();
436
+
437
+ if (!currentEmployeeId) {
438
+ alert('Please enter your Employee ID');
439
+ return;
440
+ }
441
+
442
+ const now = new Date();
443
+ const today = now.toISOString().split('T')[0];
444
+
445
+ // Find or create today's record
446
+ let record = timeRecords.find(r => r.date === today && r.employeeId === currentEmployeeId);
447
+
448
+ if (!record) {
449
+ record = {
450
+ date: today,
451
+ employeeId: currentEmployeeId,
452
+ clockIn: '',
453
+ lunchOut: '',
454
+ lunchIn: '',
455
+ clockOut: '',
456
+ totalHours: 0,
457
+ overtime: 0
458
+ };
459
+ timeRecords.push(record);
460
+ }
461
+
462
+ // Update the record
463
+ const timeString = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
464
+
465
+ switch (type) {
466
+ case 'clockIn':
467
+ if (record.clockIn) {
468
+ alert('Clock-in already recorded for today');
469
+ return;
470
+ }
471
+ record.clockIn = timeString;
472
+ break;
473
+ case 'lunchOut':
474
+ if (!record.clockIn) {
475
+ alert('Please clock in first');
476
+ return;
477
+ }
478
+ if (record.lunchOut) {
479
+ alert('Lunch-out already recorded for today');
480
+ return;
481
+ }
482
+ record.lunchOut = timeString;
483
+ break;
484
+ case 'lunchIn':
485
+ if (!record.lunchOut) {
486
+ alert('Please take lunch out first');
487
+ return;
488
+ }
489
+ if (record.lunchIn) {
490
+ alert('Lunch-in already recorded for today');
491
+ return;
492
+ }
493
+ record.lunchIn = timeString;
494
+ break;
495
+ case 'clockOut':
496
+ if (!record.clockIn) {
497
+ alert('Please clock in first');
498
+ return;
499
+ }
500
+ if (record.clockOut) {
501
+ alert('Clock-out already recorded for today');
502
+ return;
503
+ }
504
+ record.clockOut = timeString;
505
+
506
+ // Calculate total hours and overtime
507
+ const clockInTime = parseTimeString(record.clockIn);
508
+ const clockOutTime = parseTimeString(record.clockOut);
509
+
510
+ let totalMinutes = (clockOutTime - clockInTime) / (1000 * 60);
511
+
512
+ // Subtract lunch time if applicable
513
+ if (record.lunchOut && record.lunchIn) {
514
+ const lunchOutTime = parseTimeString(record.lunchOut);
515
+ const lunchInTime = parseTimeString(record.lunchIn);
516
+ const lunchMinutes = (lunchInTime - lunchOutTime) / (1000 * 60);
517
+ totalMinutes -= lunchMinutes;
518
+ }
519
+
520
+ const totalHours = totalMinutes / 60;
521
+ record.totalHours = totalHours.toFixed(2);
522
+
523
+ // Calculate overtime (assuming 8 hours standard workday)
524
+ const overtime = Math.max(0, totalHours - 8);
525
+ record.overtime = overtime.toFixed(2);
526
+ break;
527
+ }
528
+
529
+ // Save to localStorage
530
+ localStorage.setItem('timeRecords', JSON.stringify(timeRecords));
531
+
532
+ // Update UI
533
+ loadTodayRecords();
534
+ loadAllRecords();
535
+ }
536
+
537
+ // Helper function to parse time string into Date object
538
+ function parseTimeString(timeStr) {
539
+ const [time, period] = timeStr.split(' ');
540
+ const [hours, minutes] = time.split(':').map(Number);
541
+
542
+ let hours24 = hours;
543
+ if (period === 'PM' && hours < 12) hours24 += 12;
544
+ if (period === 'AM' && hours === 12) hours24 = 0;
545
+
546
+ const date = new Date();
547
+ date.setHours(hours24, minutes, 0, 0);
548
+ return date;
549
+ }
550
+
551
+ // Load today's records
552
+ function loadTodayRecords() {
553
+ const today = new Date().toISOString().split('T')[0];
554
+ const employeeId = employeeIdInput.value.trim();
555
+
556
+ if (!employeeId) {
557
+ resetTodayDisplay();
558
+ return;
559
+ }
560
+
561
+ const record = timeRecords.find(r => r.date === today && r.employeeId === employeeId);
562
+
563
+ if (record) {
564
+ todayClockIn.textContent = record.clockIn || '--:--';
565
+ todayLunchOut.textContent = record.lunchOut || '--:--';
566
+ todayLunchIn.textContent = record.lunchIn || '--:--';
567
+ todayClockOut.textContent = record.clockOut || '--:--';
568
+ todayTotalHours.textContent = record.totalHours ? record.totalHours + ' hrs' : '0.00 hrs';
569
+ todayOvertime.textContent = record.overtime ? record.overtime + ' hrs' : '0.00 hrs';
570
+ } else {
571
+ resetTodayDisplay();
572
+ }
573
+ }
574
+
575
+ // Reset today's display
576
+ function resetTodayDisplay() {
577
+ todayClockIn.textContent = '--:--';
578
+ todayLunchOut.textContent = '--:--';
579
+ todayLunchIn.textContent = '--:--';
580
+ todayClockOut.textContent = '--:--';
581
+ todayTotalHours.textContent = '0.00 hrs';
582
+ todayOvertime.textContent = '0.00 hrs';
583
+ }
584
+
585
+ // Load all records based on filter
586
+ function loadAllRecords() {
587
+ const filter = recordsFilter.value;
588
+ const employeeId = employeeIdInput.value.trim();
589
+
590
+ if (!employeeId) {
591
+ recordsBody.innerHTML = '<tr><td colspan="7" class="px-4 py-6 text-center text-gray-500">Please enter Employee ID</td></tr>';
592
+ return;
593
+ }
594
+
595
+ let filteredRecords = timeRecords.filter(r => r.employeeId === employeeId);
596
+
597
+ // Apply additional filters
598
+ const now = new Date();
599
+ const today = now.toISOString().split('T')[0];
600
+ const weekStart = getWeekStartDate(now);
601
+ const monthStart = new Date(now.getFullYear(), now.getMonth(), 1).toISOString().split('T')[0];
602
+
603
+ if (filter === 'today') {
604
+ filteredRecords = filteredRecords.filter(r => r.date === today);
605
+ } else if (filter === 'week') {
606
+ filteredRecords = filteredRecords.filter(r => r.date >= weekStart);
607
+ } else if (filter === 'month') {
608
+ filteredRecords = filteredRecords.filter(r => r.date >= monthStart);
609
+ }
610
+
611
+ // Sort by date (newest first)
612
+ filteredRecords.sort((a, b) => new Date(b.date) - new Date(a.date));
613
+
614
+ // Update table
615
+ if (filteredRecords.length === 0) {
616
+ recordsBody.innerHTML = '<tr><td colspan="7" class="px-4 py-6 text-center text-gray-500">No records found</td></tr>';
617
+ return;
618
+ }
619
+
620
+ let html = '';
621
+ filteredRecords.forEach(record => {
622
+ html += `
623
+ <tr>
624
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${formatDate(record.date)}</td>
625
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${record.clockIn || '--:--'}</td>
626
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${record.lunchOut || '--:--'}</td>
627
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${record.lunchIn || '--:--'}</td>
628
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${record.clockOut || '--:--'}</td>
629
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900 font-medium">${record.totalHours || '0.00'} hrs</td>
630
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900 font-medium">${record.overtime || '0.00'} hrs</td>
631
+ </tr>
632
+ `;
633
+ });
634
+
635
+ recordsBody.innerHTML = html;
636
+ }
637
+
638
+ // Helper function to get week start date (Monday)
639
+ function getWeekStartDate(date) {
640
+ const day = date.getDay();
641
+ const diff = date.getDate() - day + (day === 0 ? -6 : 1); // adjust when day is Sunday
642
+ return new Date(date.setDate(diff)).toISOString().split('T')[0];
643
+ }
644
+
645
+ // Format date for display
646
+ function formatDate(dateStr) {
647
+ const options = { year: 'numeric', month: 'short', day: 'numeric', weekday: 'short' };
648
+ return new Date(dateStr).toLocaleDateString(undefined, options);
649
+ }
650
+
651
+ // Refresh records when filter changes
652
+ recordsFilter.addEventListener('change', loadAllRecords);
653
+ refreshRecordsBtn.addEventListener('click', loadAllRecords);
654
+
655
+ // Employee ID input change
656
+ employeeIdInput.addEventListener('change', () => {
657
+ loadTodayRecords();
658
+ loadAllRecords();
659
+ });
660
+
661
+ // Generate report
662
+ generateReportBtn.addEventListener('click', generateReport);
663
+ printReportBtn.addEventListener('click', () => window.print());
664
+
665
+ // Generate report function
666
+ function generateReport() {
667
+ const period = reportPeriod.value;
668
+ const employeeId = employeeIdInput.value.trim();
669
+
670
+ if (!employeeId) {
671
+ reportContent.innerHTML = `
672
+ <div class="text-center py-10 text-red-500">
673
+ <i class="fas fa-exclamation-circle text-4xl mb-2"></i>
674
+ <p>Please enter Employee ID</p>
675
+ </div>
676
+ `;
677
+ return;
678
+ }
679
+
680
+ let filteredRecords = timeRecords.filter(r => r.employeeId === employeeId);
681
+
682
+ if (filteredRecords.length === 0) {
683
+ reportContent.innerHTML = `
684
+ <div class="text-center py-10 text-gray-500">
685
+ <i class="fas fa-file-alt text-4xl mb-2"></i>
686
+ <p>No records found for this employee</p>
687
+ </div>
688
+ `;
689
+ return;
690
+ }
691
+
692
+ // Sort by date (oldest first for reports)
693
+ filteredRecords.sort((a, b) => new Date(a.date) - new Date(b.date));
694
+
695
+ let reportTitle = '';
696
+ let reportData = [];
697
+ let summary = { totalHours: 0, overtime: 0, daysWorked: 0 };
698
+
699
+ if (period === 'daily') {
700
+ reportTitle = 'Daily Time Report';
701
+ reportData = filteredRecords.map(record => ({
702
+ date: formatDate(record.date),
703
+ clockIn: record.clockIn || '--:--',
704
+ lunchOut: record.lunchOut || '--:--',
705
+ lunchIn: record.lunchIn || '--:--',
706
+ clockOut: record.clockOut || '--:--',
707
+ totalHours: record.totalHours || '0.00',
708
+ overtime: record.overtime || '0.00'
709
+ }));
710
+
711
+ // Calculate summary
712
+ filteredRecords.forEach(record => {
713
+ if (record.totalHours) {
714
+ summary.totalHours += parseFloat(record.totalHours);
715
+ summary.overtime += parseFloat(record.overtime);
716
+ summary.daysWorked++;
717
+ }
718
+ });
719
+ } else if (period === 'weekly') {
720
+ reportTitle = 'Weekly Time Report';
721
+
722
+ // Group by week
723
+ const weeklyData = {};
724
+ filteredRecords.forEach(record => {
725
+ const date = new Date(record.date);
726
+ const weekStart = getWeekStartDate(date);
727
+ const weekEnd = new Date(new Date(weekStart).getTime() + 6 * 24 * 60 * 60 * 1000);
728
+ const weekLabel = `${formatDate(weekStart)} to ${formatDate(weekEnd.toISOString().split('T')[0])}`;
729
+
730
+ if (!weeklyData[weekLabel]) {
731
+ weeklyData[weekLabel] = {
732
+ week: weekLabel,
733
+ days: [],
734
+ totalHours: 0,
735
+ overtime: 0
736
+ };
737
+ }
738
+
739
+ weeklyData[weekLabel].days.push({
740
+ date: formatDate(record.date),
741
+ clockIn: record.clockIn || '--:--',
742
+ lunchOut: record.lunchOut || '--:--',
743
+ lunchIn: record.lunchIn || '--:--',
744
+ clockOut: record.clockOut || '--:--',
745
+ totalHours: record.totalHours || '0.00',
746
+ overtime: record.overtime || '0.00'
747
+ });
748
+
749
+ if (record.totalHours) {
750
+ weeklyData[weekLabel].totalHours += parseFloat(record.totalHours);
751
+ weeklyData[weekLabel].overtime += parseFloat(record.overtime);
752
+ }
753
+ });
754
+
755
+ // Convert to array and calculate summary
756
+ reportData = Object.values(weeklyData);
757
+ reportData.forEach(week => {
758
+ summary.totalHours += week.totalHours;
759
+ summary.overtime += week.overtime;
760
+ summary.daysWorked += week.days.length;
761
+ });
762
+ } else if (period === 'monthly') {
763
+ reportTitle = 'Monthly Time Report';
764
+
765
+ // Group by month
766
+ const monthlyData = {};
767
+ filteredRecords.forEach(record => {
768
+ const date = new Date(record.date);
769
+ const monthLabel = date.toLocaleDateString(undefined, { month: 'long', year: 'numeric' });
770
+
771
+ if (!monthlyData[monthLabel]) {
772
+ monthlyData[monthLabel] = {
773
+ month: monthLabel,
774
+ days: [],
775
+ totalHours: 0,
776
+ overtime: 0
777
+ };
778
+ }
779
+
780
+ monthlyData[monthLabel].days.push({
781
+ date: formatDate(record.date),
782
+ clockIn: record.clockIn || '--:--',
783
+ lunchOut: record.lunchOut || '--:--',
784
+ lunchIn: record.lunchIn || '--:--',
785
+ clockOut: record.clockOut || '--:--',
786
+ totalHours: record.totalHours || '0.00',
787
+ overtime: record.overtime || '0.00'
788
+ });
789
+
790
+ if (record.totalHours) {
791
+ monthlyData[monthLabel].totalHours += parseFloat(record.totalHours);
792
+ monthlyData[monthLabel].overtime += parseFloat(record.overtime);
793
+ }
794
+ });
795
+
796
+ // Convert to array and calculate summary
797
+ reportData = Object.values(monthlyData);
798
+ reportData.forEach(month => {
799
+ summary.totalHours += month.totalHours;
800
+ summary.overtime += month.overtime;
801
+ summary.daysWorked += month.days.length;
802
+ });
803
+ }
804
+
805
+ // Generate report HTML
806
+ let reportHTML = `
807
+ <div class="print-full">
808
+ <div class="flex justify-between items-center mb-6 border-b pb-4">
809
+ <div>
810
+ <h3 class="text-2xl font-bold text-dark">${reportTitle}</h3>
811
+ <p class="text-gray-600">Employee ID: ${employeeId}</p>
812
+ <p class="text-gray-600">Generated on: ${new Date().toLocaleDateString()}</p>
813
+ </div>
814
+ <div class="bg-primary text-white p-2 rounded">
815
+ <i class="fas fa-clock text-3xl"></i>
816
+ </div>
817
+ </div>
818
+ `;
819
+
820
+ if (period === 'daily') {
821
+ reportHTML += `
822
+ <div class="overflow-x-auto">
823
+ <table class="min-w-full divide-y divide-gray-200">
824
+ <thead class="bg-gray-50">
825
+ <tr>
826
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
827
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Clock In</th>
828
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Lunch Out</th>
829
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Lunch In</th>
830
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Clock Out</th>
831
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Total Hours</th>
832
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Overtime</th>
833
+ </tr>
834
+ </thead>
835
+ <tbody class="bg-white divide-y divide-gray-200">
836
+ `;
837
+
838
+ reportData.forEach(record => {
839
+ reportHTML += `
840
+ <tr>
841
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${record.date}</td>
842
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${record.clockIn}</td>
843
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${record.lunchOut}</td>
844
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${record.lunchIn}</td>
845
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${record.clockOut}</td>
846
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900 font-medium">${record.totalHours} hrs</td>
847
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900 font-medium">${record.overtime} hrs</td>
848
+ </tr>
849
+ `;
850
+ });
851
+
852
+ reportHTML += `
853
+ </tbody>
854
+ </table>
855
+ </div>
856
+ `;
857
+ } else if (period === 'weekly') {
858
+ reportData.forEach(week => {
859
+ reportHTML += `
860
+ <div class="mb-8">
861
+ <h4 class="text-lg font-semibold mb-2 bg-gray-100 p-2 rounded">${week.week}</h4>
862
+ <div class="overflow-x-auto mb-2">
863
+ <table class="min-w-full divide-y divide-gray-200">
864
+ <thead class="bg-gray-50">
865
+ <tr>
866
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
867
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Clock In</th>
868
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Lunch Out</th>
869
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Lunch In</th>
870
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Clock Out</th>
871
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Total Hours</th>
872
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Overtime</th>
873
+ </tr>
874
+ </thead>
875
+ <tbody class="bg-white divide-y divide-gray-200">
876
+ `;
877
+
878
+ week.days.forEach(day => {
879
+ reportHTML += `
880
+ <tr>
881
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${day.date}</td>
882
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${day.clockIn}</td>
883
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${day.lunchOut}</td>
884
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${day.lunchIn}</td>
885
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${day.clockOut}</td>
886
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900 font-medium">${day.totalHours} hrs</td>
887
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900 font-medium">${day.overtime} hrs</td>
888
+ </tr>
889
+ `;
890
+ });
891
+
892
+ reportHTML += `
893
+ </tbody>
894
+ </table>
895
+ </div>
896
+ <div class="flex justify-end">
897
+ <div class="bg-gray-100 p-3 rounded">
898
+ <p class="text-sm font-medium">Week Total: <span class="font-bold">${week.totalHours.toFixed(2)} hrs</span></p>
899
+ <p class="text-sm font-medium">Week Overtime: <span class="font-bold">${week.overtime.toFixed(2)} hrs</span></p>
900
+ </div>
901
+ </div>
902
+ </div>
903
+ `;
904
+ });
905
+ } else if (period === 'monthly') {
906
+ reportData.forEach(month => {
907
+ reportHTML += `
908
+ <div class="mb-8">
909
+ <h4 class="text-lg font-semibold mb-2 bg-gray-100 p-2 rounded">${month.month}</h4>
910
+ <div class="overflow-x-auto mb-2">
911
+ <table class="min-w-full divide-y divide-gray-200">
912
+ <thead class="bg-gray-50">
913
+ <tr>
914
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
915
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Clock In</th>
916
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Lunch Out</th>
917
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Lunch In</th>
918
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Clock Out</th>
919
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Total Hours</th>
920
+ <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Overtime</th>
921
+ </tr>
922
+ </thead>
923
+ <tbody class="bg-white divide-y divide-gray-200">
924
+ `;
925
+
926
+ month.days.forEach(day => {
927
+ reportHTML += `
928
+ <tr>
929
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${day.date}</td>
930
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${day.clockIn}</td>
931
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${day.lunchOut}</td>
932
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${day.lunchIn}</td>
933
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900">${day.clockOut}</td>
934
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900 font-medium">${day.totalHours} hrs</td>
935
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-900 font-medium">${day.overtime} hrs</td>
936
+ </tr>
937
+ `;
938
+ });
939
+
940
+ reportHTML += `
941
+ </tbody>
942
+ </table>
943
+ </div>
944
+ <div class="flex justify-end">
945
+ <div class="bg-gray-100 p-3 rounded">
946
+ <p class="text-sm font-medium">Month Total: <span class="font-bold">${month.totalHours.toFixed(2)} hrs</span></p>
947
+ <p class="text-sm font-medium">Month Overtime: <span class="font-bold">${month.overtime.toFixed(2)} hrs</span></p>
948
+ </div>
949
+ </div>
950
+ </div>
951
+ `;
952
+ });
953
+ }
954
+
955
+ // Add summary section
956
+ reportHTML += `
957
+ <div class="mt-8 pt-4 border-t border-gray-200">
958
+ <h4 class="text-lg font-semibold mb-4">Summary</h4>
959
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
960
+ <div class="bg-blue-50 p-4 rounded-lg">
961
+ <p class="text-sm text-blue-600">Days Worked</p>
962
+ <p class="text-2xl font-bold text-blue-800">${summary.daysWorked}</p>
963
+ </div>
964
+ <div class="bg-green-50 p-4 rounded-lg">
965
+ <p class="text-sm text-green-600">Total Hours</p>
966
+ <p class="text-2xl font-bold text-green-800">${summary.totalHours.toFixed(2)} hrs</p>
967
+ </div>
968
+ <div class="bg-purple-50 p-4 rounded-lg">
969
+ <p class="text-sm text-purple-600">Total Overtime</p>
970
+ <p class="text-2xl font-bold text-purple-800">${summary.overtime.toFixed(2)} hrs</p>
971
+ </div>
972
+ </div>
973
+ </div>
974
+ `;
975
+
976
+ // Add footer
977
+ reportHTML += `
978
+ <div class="mt-8 pt-4 border-t border-gray-200 text-center text-xs text-gray-500">
979
+ <p>This report was generated by Time Tracker Pro on ${new Date().toLocaleString()}</p>
980
+ </div>
981
+ </div>
982
+ `;
983
+
984
+ reportContent.innerHTML = reportHTML;
985
+ }
986
+ </script>
987
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=limalex/alexandre" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
988
+ </html>