ivanhoang commited on
Commit
cbc49ed
·
verified ·
1 Parent(s): 00ee005

help me build a simple check in, check out app with QR code - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +423 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Check In
3
- emoji: 🏆
4
- colorFrom: indigo
5
- colorTo: green
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: check-in
3
+ emoji: 🐳
4
+ colorFrom: pink
5
+ colorTo: purple
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,423 @@
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
+ <!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>QR Check-In/Check-Out System</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/qrcode@1.5.1/build/qrcode.min.js"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js"></script>
10
+ <style>
11
+ .video-container {
12
+ position: relative;
13
+ width: 100%;
14
+ max-width: 500px;
15
+ margin: 0 auto;
16
+ }
17
+ .scan-region-highlight {
18
+ position: absolute;
19
+ top: 50%;
20
+ left: 50%;
21
+ transform: translate(-50%, -50%);
22
+ width: 70%;
23
+ height: 70%;
24
+ max-width: 300px;
25
+ max-height: 300px;
26
+ border: 3px dashed rgba(255, 255, 255, 0.5);
27
+ border-radius: 10px;
28
+ box-sizing: border-box;
29
+ }
30
+ .hidden {
31
+ display: none;
32
+ }
33
+ </style>
34
+ </head>
35
+ <body class="bg-gray-100 min-h-screen">
36
+ <div class="container mx-auto px-4 py-8">
37
+ <div class="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden">
38
+ <!-- Header -->
39
+ <div class="bg-blue-600 py-4 px-6">
40
+ <h1 class="text-2xl font-bold text-white text-center">QR Check-In/Out System</h1>
41
+ </div>
42
+
43
+ <!-- Main Content -->
44
+ <div class="p-6">
45
+ <!-- Tabs -->
46
+ <div class="flex border-b border-gray-200 mb-6">
47
+ <button id="checkInTab" class="flex-1 py-2 px-4 font-medium text-blue-600 border-b-2 border-blue-600">Check In</button>
48
+ <button id="checkOutTab" class="flex-1 py-2 px-4 font-medium text-gray-500">Check Out</button>
49
+ <button id="scanTab" class="flex-1 py-2 px-4 font-medium text-gray-500">Scan QR</button>
50
+ </div>
51
+
52
+ <!-- Check In Section -->
53
+ <div id="checkInSection" class="space-y-4">
54
+ <div class="form-group">
55
+ <label class="block text-gray-700 text-sm font-bold mb-2" for="name">
56
+ Full Name
57
+ </label>
58
+ <input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" id="name" type="text" placeholder="Enter your name">
59
+ </div>
60
+ <div class="form-group">
61
+ <label class="block text-gray-700 text-sm font-bold mb-2" for="purpose">
62
+ Purpose
63
+ </label>
64
+ <select class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" id="purpose">
65
+ <option value="">Select purpose</option>
66
+ <option value="Meeting">Meeting</option>
67
+ <option value="Delivery">Delivery</option>
68
+ <option value="Visit">Visit</option>
69
+ <option value="Other">Other</option>
70
+ </select>
71
+ </div>
72
+ <div class="form-group">
73
+ <label class="block text-gray-700 text-sm font-bold mb-2" for="host">
74
+ Host/Department
75
+ </label>
76
+ <input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" id="host" type="text" placeholder="Who are you visiting?">
77
+ </div>
78
+ <button id="generateCheckInQR" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-md transition duration-200">
79
+ Generate Check-In QR
80
+ </button>
81
+ <div id="checkInQRCode" class="hidden p-4 border border-gray-200 rounded-md flex flex-col items-center">
82
+ <div id="qrCodeCheckIn" class="mb-4"></div>
83
+ <button id="downloadCheckInQR" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded-md transition duration-200">
84
+ Download QR Code
85
+ </button>
86
+ </div>
87
+ </div>
88
+
89
+ <!-- Check Out Section -->
90
+ <div id="checkOutSection" class="space-y-4 hidden">
91
+ <div class="form-group">
92
+ <label class="block text-gray-700 text-sm font-bold mb-2" for="checkOutId">
93
+ Check-In ID
94
+ </label>
95
+ <input class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" id="checkOutId" type="text" placeholder="Enter your check-in ID">
96
+ </div>
97
+ <button id="generateCheckOutQR" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-md transition duration-200">
98
+ Generate Check-Out QR
99
+ </button>
100
+ <div id="checkOutQRCode" class="hidden p-4 border border-gray-200 rounded-md flex flex-col items-center">
101
+ <div id="qrCodeCheckOut" class="mb-4"></div>
102
+ <button id="downloadCheckOutQR" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded-md transition duration-200">
103
+ Download QR Code
104
+ </button>
105
+ </div>
106
+ </div>
107
+
108
+ <!-- Scan Section -->
109
+ <div id="scanSection" class="space-y-4 hidden">
110
+ <div class="video-container">
111
+ <video id="scanner" width="100%" muted playsinline></video>
112
+ <div class="scan-region-highlight"></div>
113
+ </div>
114
+ <div id="scanResult" class="text-center p-4 bg-gray-100 rounded-md hidden">
115
+ <h3 class="font-bold mb-2">Scan Result:</h3>
116
+ <p id="resultText" class="text-gray-800"></p>
117
+ <div id="actionButtons" class="mt-4 hidden">
118
+ <button id="checkInAction" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-md mr-2 transition duration-200">
119
+ Check In
120
+ </button>
121
+ <button id="checkOutAction" class="bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-4 rounded-md transition duration-200">
122
+ Check Out
123
+ </button>
124
+ </div>
125
+ </div>
126
+ <button id="startScan" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-md transition duration-200">
127
+ Start Scanner
128
+ </button>
129
+ <button id="stopScan" class="w-full bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-4 rounded-md transition duration-200 hidden">
130
+ Stop Scanner
131
+ </button>
132
+ </div>
133
+
134
+ <!-- Log Section -->
135
+ <div class="mt-8 border-t border-gray-200 pt-6">
136
+ <h2 class="text-xl font-bold text-gray-800 mb-4">Recent Activity</h2>
137
+ <div id="activityLog" class="space-y-2 max-h-60 overflow-y-auto">
138
+ <!-- Activity items will be added here -->
139
+ </div>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </div>
144
+
145
+ <script>
146
+ // Tab switching
147
+ document.getElementById('checkInTab').addEventListener('click', () => {
148
+ showSection('checkInSection');
149
+ setActiveTab('checkInTab');
150
+ });
151
+
152
+ document.getElementById('checkOutTab').addEventListener('click', () => {
153
+ showSection('checkOutSection');
154
+ setActiveTab('checkOutTab');
155
+ });
156
+
157
+ document.getElementById('scanTab').addEventListener('click', () => {
158
+ showSection('scanSection');
159
+ setActiveTab('scanTab');
160
+ });
161
+
162
+ function showSection(sectionId) {
163
+ document.getElementById('checkInSection').classList.add('hidden');
164
+ document.getElementById('checkOutSection').classList.add('hidden');
165
+ document.getElementById('scanSection').classList.add('hidden');
166
+ document.getElementById(sectionId).classList.remove('hidden');
167
+ }
168
+
169
+ function setActiveTab(tabId) {
170
+ document.getElementById('checkInTab').classList.remove('text-blue-600', 'border-blue-600');
171
+ document.getElementById('checkInTab').classList.add('text-gray-500');
172
+ document.getElementById('checkOutTab').classList.remove('text-blue-600', 'border-blue-600');
173
+ document.getElementById('checkOutTab').classList.add('text-gray-500');
174
+ document.getElementById('scanTab').classList.remove('text-blue-600', 'border-blue-600');
175
+ document.getElementById('scanTab').classList.add('text-gray-500');
176
+
177
+ document.getElementById(tabId).classList.remove('text-gray-500');
178
+ document.getElementById(tabId).classList.add('text-blue-600', 'border-blue-600');
179
+ }
180
+
181
+ // QR Code Generation for Check-In
182
+ document.getElementById('generateCheckInQR').addEventListener('click', () => {
183
+ const name = document.getElementById('name').value;
184
+ const purpose = document.getElementById('purpose').value;
185
+ const host = document.getElementById('host').value;
186
+
187
+ if (!name || !purpose || !host) {
188
+ alert('Please fill in all fields');
189
+ return;
190
+ }
191
+
192
+ const checkInData = {
193
+ type: 'checkIn',
194
+ name: name,
195
+ purpose: purpose,
196
+ host: host,
197
+ timestamp: new Date().toISOString(),
198
+ id: generateId()
199
+ };
200
+
201
+ const qrData = JSON.stringify(checkInData);
202
+
203
+ QRCode.toCanvas(document.getElementById('qrCodeCheckIn'), qrData, {
204
+ width: 200,
205
+ margin: 2,
206
+ color: {
207
+ dark: '#000000',
208
+ light: '#ffffff'
209
+ }
210
+ }, (error) => {
211
+ if (error) console.error(error);
212
+ document.getElementById('checkInQRCode').classList.remove('hidden');
213
+
214
+ // Store the check-in data in localStorage
215
+ localStorage.setItem(checkInData.id, qrData);
216
+
217
+ // Add to activity log
218
+ addActivityLog(`Checked in: ${name} visiting ${host} for ${purpose}`);
219
+ });
220
+ });
221
+
222
+ // QR Code Generation for Check-Out
223
+ document.getElementById('generateCheckOutQR').addEventListener('click', () => {
224
+ const checkOutId = document.getElementById('checkOutId').value;
225
+
226
+ if (!checkOutId) {
227
+ alert('Please enter your check-in ID');
228
+ return;
229
+ }
230
+
231
+ // Get the original check-in data
232
+ const checkInData = localStorage.getItem(checkOutId);
233
+
234
+ if (!checkInData) {
235
+ alert('No check-in record found with this ID');
236
+ return;
237
+ }
238
+
239
+ const checkOutData = {
240
+ ...JSON.parse(checkInData),
241
+ type: 'checkOut',
242
+ checkOutTimestamp: new Date().toISOString()
243
+ };
244
+
245
+ const qrData = JSON.stringify(checkOutData);
246
+
247
+ QRCode.toCanvas(document.getElementById('qrCodeCheckOut'), qrData, {
248
+ width: 200,
249
+ margin: 2,
250
+ color: {
251
+ dark: '#000000',
252
+ light: '#ffffff'
253
+ }
254
+ }, (error) => {
255
+ if (error) console.error(error);
256
+ document.getElementById('checkOutQRCode').classList.remove('hidden');
257
+
258
+ // Update the localStorage record
259
+ localStorage.setItem(checkOutId, qrData);
260
+
261
+ // Add to activity log
262
+ const data = JSON.parse(checkInData);
263
+ addActivityLog(`Checked out: ${data.name} from visiting ${data.host}`);
264
+ });
265
+ });
266
+
267
+ // Download QR Code functions
268
+ document.getElementById('downloadCheckInQR').addEventListener('click', () => {
269
+ const canvas = document.querySelector('#qrCodeCheckIn canvas');
270
+ const link = document.createElement('a');
271
+ link.download = 'check-in-qr.png';
272
+ link.href = canvas.toDataURL('image/png');
273
+ link.click();
274
+ });
275
+
276
+ document.getElementById('downloadCheckOutQR').addEventListener('click', () => {
277
+ const canvas = document.querySelector('#qrCodeCheckOut canvas');
278
+ const link = document.createElement('a');
279
+ link.download = 'check-out-qr.png';
280
+ link.href = canvas.toDataURL('image/png');
281
+ link.click();
282
+ });
283
+
284
+ // QR Code Scanner
285
+ let scannerInterval;
286
+ const video = document.getElementById('scanner');
287
+ const startScanBtn = document.getElementById('startScan');
288
+ const stopScanBtn = document.getElementById('stopScan');
289
+ const scanResult = document.getElementById('scanResult');
290
+ const resultText = document.getElementById('resultText');
291
+ const actionButtons = document.getElementById('actionButtons');
292
+ const checkInAction = document.getElementById('checkInAction');
293
+ const checkOutAction = document.getElementById('checkOutAction');
294
+
295
+ let currentScanData = null;
296
+
297
+ startScanBtn.addEventListener('click', async () => {
298
+ try {
299
+ const stream = await navigator.mediaDevices.getUserMedia({
300
+ video: {
301
+ facingMode: 'environment',
302
+ width: { ideal: 1280 },
303
+ height: { ideal: 720 }
304
+ }
305
+ });
306
+ video.srcObject = stream;
307
+ video.play();
308
+
309
+ startScanBtn.classList.add('hidden');
310
+ stopScanBtn.classList.remove('hidden');
311
+ scanResult.classList.add('hidden');
312
+
313
+ scannerInterval = setInterval(scanQR, 100);
314
+ } catch (err) {
315
+ console.error('Error accessing camera:', err);
316
+ alert('Could not access the camera. Please ensure you have granted camera permissions.');
317
+ }
318
+ });
319
+
320
+ stopScanBtn.addEventListener('click', () => {
321
+ clearInterval(scannerInterval);
322
+ const stream = video.srcObject;
323
+ if (stream) {
324
+ stream.getTracks().forEach(track => track.stop());
325
+ }
326
+ video.srcObject = null;
327
+
328
+ startScanBtn.classList.remove('hidden');
329
+ stopScanBtn.classList.add('hidden');
330
+ scanResult.classList.add('hidden');
331
+ });
332
+
333
+ function scanQR() {
334
+ const canvas = document.createElement('canvas');
335
+ canvas.width = video.videoWidth;
336
+ canvas.height = video.videoHeight;
337
+ const ctx = canvas.getContext('2d');
338
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
339
+
340
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
341
+ const code = jsQR(imageData.data, imageData.width, imageData.height, {
342
+ inversionAttempts: 'dontInvert',
343
+ });
344
+
345
+ if (code) {
346
+ try {
347
+ const data = JSON.parse(code.data);
348
+ currentScanData = data;
349
+
350
+ if (data.type === 'checkIn') {
351
+ resultText.textContent = `${data.name} is checking in to visit ${data.host} for ${data.purpose}`;
352
+ checkInAction.classList.add('hidden');
353
+ checkOutAction.classList.remove('hidden');
354
+ } else if (data.type === 'checkOut') {
355
+ resultText.textContent = `${data.name} is checking out from visiting ${data.host}`;
356
+ checkInAction.classList.add('hidden');
357
+ checkOutAction.classList.remove('hidden');
358
+ }
359
+
360
+ scanResult.classList.remove('hidden');
361
+ actionButtons.classList.remove('hidden');
362
+
363
+ // Stop scanning after successful scan
364
+ clearInterval(scannerInterval);
365
+ } catch (e) {
366
+ resultText.textContent = 'Invalid QR Code';
367
+ scanResult.classList.remove('hidden');
368
+ actionButtons.classList.add('hidden');
369
+ }
370
+ }
371
+ }
372
+
373
+ checkInAction.addEventListener('click', () => {
374
+ if (currentScanData) {
375
+ addActivityLog(`Checked in via scanner: ${currentScanData.name} visiting ${currentScanData.host}`);
376
+ alert(`Successfully checked in ${currentScanData.name}`);
377
+ scanResult.classList.add('hidden');
378
+ currentScanData = null;
379
+
380
+ // Restart scanner
381
+ scannerInterval = setInterval(scanQR, 100);
382
+ }
383
+ });
384
+
385
+ checkOutAction.addEventListener('click', () => {
386
+ if (currentScanData) {
387
+ addActivityLog(`Checked out via scanner: ${currentScanData.name} from visiting ${currentScanData.host}`);
388
+ alert(`Successfully checked out ${currentScanData.name}`);
389
+ scanResult.classList.add('hidden');
390
+ currentScanData = null;
391
+
392
+ // Restart scanner
393
+ scannerInterval = setInterval(scanQR, 100);
394
+ }
395
+ });
396
+
397
+ // Helper functions
398
+ function generateId() {
399
+ return 'id-' + Math.random().toString(36).substr(2, 9);
400
+ }
401
+
402
+ function addActivityLog(message) {
403
+ const logContainer = document.getElementById('activityLog');
404
+ const logItem = document.createElement('div');
405
+ logItem.className = 'p-3 bg-gray-50 rounded-md border border-gray-200';
406
+ logItem.innerHTML = `
407
+ <p class="text-sm text-gray-800">${message}</p>
408
+ <p class="text-xs text-gray-500 mt-1">${new Date().toLocaleString()}</p>
409
+ `;
410
+ logContainer.insertBefore(logItem, logContainer.firstChild);
411
+
412
+ // Limit log to 10 items
413
+ if (logContainer.children.length > 10) {
414
+ logContainer.removeChild(logContainer.lastChild);
415
+ }
416
+ }
417
+
418
+ // Initialize with check-in tab active
419
+ showSection('checkInSection');
420
+ setActiveTab('checkInTab');
421
+ </script>
422
+ <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=ivanhoang/check-in" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
423
+ </html>