@7365admin1/layer-common 1.11.19 → 1.11.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,34 +1,95 @@
1
1
  <template>
2
2
  <v-row no-gutters>
3
- <TableMain :headers="headers" :items="items" :loading="getVisitorPending" :page="page" :pages="pages"
4
- :extension-height="110" :offset="300" :pageRange="pageRange" :canCreate="canAddVisitor"
5
- @refresh="getVisitorRefresh" @update:page="handleUpdatePage" createLabel="Add Visitor" show-header
6
- @row-click="handleRowClick" @create="handleAddNew">
3
+ <TableMain
4
+ :headers="headers"
5
+ :items="items"
6
+ :loading="getVisitorPending"
7
+ :page="page"
8
+ :pages="pages"
9
+ :extension-height="110"
10
+ :offset="300"
11
+ :pageRange="pageRange"
12
+ :canCreate="canAddVisitor"
13
+ :canScanVisitorQRCode="canScanVisitorQRCode"
14
+ @refresh="getVisitorRefresh"
15
+ @update:page="handleUpdatePage"
16
+ createLabel="Add Visitor"
17
+ show-header
18
+ @row-click="handleRowClick"
19
+ @create="handleAddNew"
20
+ @scan="dialog.scanVisitorQRCode = true"
21
+ >
7
22
  <template #extension>
8
23
  <v-row no-gutters class="w-100 d-flex flex-column">
9
- <v-tabs v-model="activeTab" color="primary" :height="40" @update:model-value="toRoute" class="w-100">
10
- <v-tab v-for="tab in tabOptions" :value="tab.value" :key="tab.value" class="text-capitalize">
24
+ <v-tabs
25
+ v-model="activeTab"
26
+ color="primary"
27
+ :height="40"
28
+ @update:model-value="toRoute"
29
+ class="w-100"
30
+ >
31
+ <v-tab
32
+ v-for="tab in tabOptions"
33
+ :value="tab.value"
34
+ :key="tab.value"
35
+ class="text-capitalize"
36
+ >
11
37
  {{ tab.name }}
12
38
  </v-tab>
13
39
  </v-tabs>
14
40
 
15
- <v-card class="w-100 px-3 d-flex align-center ga-5 py-2" flat :height="60">
16
- <v-text-field v-model="searchInput" density="compact" placeholder="Search" clearable max-width="300"
17
- append-inner-icon="mdi-magnify" hide-details />
18
- <v-checkbox v-model="displayNotCheckedOut" class="text-subtitle-2" hide-details>
41
+ <v-card
42
+ class="w-100 px-3 d-flex align-center ga-5 py-2"
43
+ flat
44
+ :height="60"
45
+ >
46
+ <v-text-field
47
+ v-model="searchInput"
48
+ density="compact"
49
+ placeholder="Search"
50
+ clearable
51
+ max-width="300"
52
+ append-inner-icon="mdi-magnify"
53
+ hide-details
54
+ />
55
+ <v-checkbox
56
+ v-model="displayNotCheckedOut"
57
+ class="text-subtitle-2"
58
+ hide-details
59
+ >
19
60
  <template #label>
20
61
  <span class="text-caption">Not Checked Out</span>
21
62
  </template>
22
63
  </v-checkbox>
23
- <InputDateTimePicker v-model:utc="dateFrom" density="compact" hide-details />
24
- <InputDateTimePicker v-model:utc="dateTo" density="compact" hide-details />
25
- <v-select v-if="activeTab == 'registered'" v-model="filterTypes" label="Filter by types" item-title="label"
26
- item-value="value" :items="visitorSelection" density="compact" clearable multiple max-width="200"
27
- hide-details>
64
+ <InputDatePicker
65
+ v-model="dateFrom"
66
+ density="compact"
67
+ hide-details
68
+ />
69
+ <InputDatePicker v-model="dateTo" density="compact" hide-details />
70
+ <v-select
71
+ v-if="activeTab == 'registered'"
72
+ v-model="filterTypes"
73
+ label="Filter by types"
74
+ item-title="label"
75
+ item-value="value"
76
+ :items="visitorSelection"
77
+ density="compact"
78
+ clearable
79
+ multiple
80
+ max-width="200"
81
+ hide-details
82
+ >
28
83
  <template v-slot:selection="{ item, index }">
29
84
  <div class="d-flex align-center text-caption text-nowrap">
30
- <v-chip v-if="index === 0" color="error" :text="filterTypeSelectionLabel()" size="x-small"
31
- variant="tonal" class="ml-2" />
85
+ <v-chip
86
+ v-if="index === 0"
87
+ color="error"
88
+ :text="filterTypeSelectionLabel()"
89
+ size="x-small"
90
+ variant="tonal"
91
+ class="ml-2"
92
+ />
32
93
  </div>
33
94
  </template>
34
95
  </v-select>
@@ -43,8 +104,9 @@
43
104
  </span>
44
105
  <span class="text-capitalize">{{ item?.name }}</span>
45
106
  </span>
46
- <span class="text-grey text-caption" v-if="item?.members?.length > 0">( +{{ item?.members?.length }}
47
- members)</span>
107
+ <span class="text-grey text-caption" v-if="item?.members?.length > 0"
108
+ >( +{{ item?.members?.length }} members)</span
109
+ >
48
110
  </template>
49
111
 
50
112
  <template v-slot:item.type-company="{ item }">
@@ -52,7 +114,7 @@
52
114
  <v-icon icon="mdi-user" size="15" />
53
115
  <span v-if="item.type === 'contractor'" class="text-capitalize">{{
54
116
  formatCamelCaseToWords(item.contractorType)
55
- }}</span>
117
+ }}</span>
56
118
  <span v-else class="text-capitalize">{{ formatType(item) }}</span>
57
119
  </span>
58
120
  <span class="d-flex align-center ga-2">
@@ -88,109 +150,255 @@
88
150
  <template v-slot:item.checkin-out="{ item }">
89
151
  <v-row no-gutters class="d-flex flex-column py-2">
90
152
  <span class="d-flex align-center ga-2">
91
- <v-icon icon="mdi-clock-time-four-outline" color="green" size="20" />
153
+ <v-icon
154
+ icon="mdi-clock-time-four-outline"
155
+ color="green"
156
+ size="20"
157
+ />
92
158
  <span class="text-capitalize">{{
93
159
  UTCToLocalTIme(item.checkIn) || "-"
94
160
  }}</span>
95
161
  <span>
96
- <v-icon v-if="item?.snapshotEntryImage" size="17" icon="mdi-image"
97
- @click.stop="handleViewImage(item.snapshotEntryImage)" />
162
+ <v-icon
163
+ v-if="item?.snapshotEntryImage"
164
+ size="17"
165
+ icon="mdi-image"
166
+ @click.stop="handleViewImage(item.snapshotEntryImage)"
167
+ />
98
168
  </span>
99
169
  </span>
100
- <span class="d-flex align-center ga-2">
170
+
171
+ <span
172
+ v-if="
173
+ !item.checkOut &&
174
+ (item?.status === 'registered' ||
175
+ item?.status === 'unregistered') &&
176
+ canCheckoutVisitor
177
+ "
178
+ >
179
+ <span
180
+ class="d-flex align-center ga-2"
181
+ v-bind="menuProps"
182
+ style="cursor: pointer"
183
+ >
184
+ <v-icon
185
+ icon="mdi-clock-time-eight-outline"
186
+ color="red"
187
+ size="20"
188
+ />
189
+ <v-btn
190
+ size="x-small"
191
+ class="text-capitalize"
192
+ color="red"
193
+ text="Checkout"
194
+ :loading="
195
+ loading.checkingOut && item?._id === selectedVisitorId
196
+ "
197
+ />
198
+ </span>
199
+ </span>
200
+ <span v-else class="d-flex align-center ga-2">
101
201
  <v-icon icon="mdi-clock-time-eight-outline" color="red" size="20" />
102
202
  <template v-if="item.checkOut">
103
203
  <span class="text-capitalize">{{
104
204
  UTCToLocalTIme(item.checkOut) || "-"
105
205
  }}</span>
106
206
  <span>
107
- <v-icon v-if="item?.snapshotExitImage" size="17" icon="mdi-image"
108
- @click.stop="handleViewImage(item.snapshotExitImage)" />
207
+ <v-icon
208
+ v-if="item?.snapshotExitImage"
209
+ size="17"
210
+ icon="mdi-image"
211
+ @click.stop="handleViewImage(item.snapshotExitImage)"
212
+ />
109
213
  </span>
110
214
  <span v-if="item?.manualCheckout">
111
- <TooltipInfo text="Manual Checkout" density="compact" size="x-small" />
215
+ <TooltipInfo
216
+ text="Manual Checkout"
217
+ density="compact"
218
+ size="x-small"
219
+ />
112
220
  </span>
113
221
  </template>
114
- <span v-else-if="!item?.checkOut && (item?.status === 'registered' || item?.status === 'unregistered')">
115
- <v-btn size="x-small" class="text-capitalize" color="red" text="Checkout"
116
- :loading="loading.checkingOut && item?._id === selectedVisitorId" @click.stop="handleCheckout(item._id)"
117
- v-if="canCheckoutVisitor" />
118
- </span>
119
222
  </span>
120
- <div v-if="(item.visitorPass?.length ?? 0) > 0 || (item.passKeys?.length ?? 0) > 0"
121
- class="d-flex flex-wrap ga-1 mt-1" @click.stop="handleCheckout(item._id)">
122
- <v-chip v-for="pass in item.visitorPass" :key="(pass as any)._id ?? (pass as any).keyId"
123
- prepend-icon="mdi-card-bulleted-outline" size="x-small" variant="tonal" color="blue">
124
- {{ (pass as any)?.prefixAndName }}
125
- </v-chip>
126
- <v-chip v-for="key in item.passKeys" :key="(key as any)._id ?? (key as any).keyId" prepend-icon="mdi-key"
127
- size="x-small" variant="tonal" color="orange">
128
- {{ (key as any)?.prefixAndName }}
129
- </v-chip>
130
- </div>
131
- <div v-if="showAddPassKeyButton(item)" class="d-flex flex-wrap ga-1 mt-1 mt-2"
132
- @click.stop="handleCheckout(item._id)">
133
- <v-chip size="x-small" variant="tonal" prepend-icon="mdi-key" @click.stop="handleOpenAddPassKey(item)">
134
- Add Pass/Key
135
- </v-chip>
136
223
 
224
+ <div
225
+ v-if="showAddPassKeyButton(item)"
226
+ class="d-flex flex-wrap ga-1 mt-1"
227
+ v-bind="menuProps"
228
+ style="cursor: pointer"
229
+ >
230
+ <v-chip
231
+ size="x-small"
232
+ variant="tonal"
233
+ prepend-icon="mdi-key"
234
+ @click.stop="handleOpenAddPassKey(item)"
235
+ >Add Pass/Key</v-chip
236
+ >
137
237
  </div>
238
+
239
+ <v-menu :close-on-content-click="true">
240
+ <template v-slot:activator="{ props: menuProps }">
241
+ <div
242
+ v-if="
243
+ (item.visitorPass?.length ?? 0) > 0 ||
244
+ (item.passKeys?.length ?? 0) > 0
245
+ "
246
+ class="d-flex flex-wrap ga-1 mt-1"
247
+ v-bind="menuProps"
248
+ style="cursor: pointer"
249
+ >
250
+ <v-chip
251
+ v-for="pass in item.visitorPass"
252
+ :key="(pass as any)._id ?? (pass as any).keyId"
253
+ prepend-icon="mdi-card-bulleted-outline"
254
+ size="x-small"
255
+ variant="tonal"
256
+ color="blue"
257
+ >
258
+ {{ (pass as any)?.prefixAndName }}
259
+ </v-chip>
260
+ <v-chip
261
+ v-for="key in item.passKeys"
262
+ :key="(key as any)._id ?? (key as any).keyId"
263
+ prepend-icon="mdi-key"
264
+ size="x-small"
265
+ variant="tonal"
266
+ color="orange"
267
+ >
268
+ {{ (key as any)?.prefixAndName }}
269
+ </v-chip>
270
+ </div>
271
+ </template>
272
+ <v-list density="compact">
273
+ <v-list-item
274
+ prepend-icon="mdi-logout"
275
+ title="Checkout"
276
+ @click.stop="handleCheckout(item._id)"
277
+ />
278
+ <v-list-item
279
+ v-if="
280
+ (item.visitorPass?.length ?? 0) > 0 ||
281
+ (item.passKeys?.length ?? 0) > 0
282
+ "
283
+ prepend-icon="mdi-card-bulleted-outline"
284
+ :title="item.checkOut ? 'View Pass/Key' : 'Edit Pass/Key'"
285
+ @click.stop="handleOpenEditPassKey(item)"
286
+ />
287
+ <v-list-item
288
+ v-if="showAddPassKeyButton(item)"
289
+ prepend-icon="mdi-plus"
290
+ title="Add Pass/Key"
291
+ @click.stop="handleOpenAddPassKey(item)"
292
+ />
293
+ </v-list>
294
+ </v-menu>
138
295
  </v-row>
139
296
  </template>
140
297
 
141
298
  <template v-slot:item.action="{ item }">
142
- <v-btn v-if="activeTab === 'unregistered' && canAddVisitor" size="small" color="primary" text="Register"
143
- @click.stop="handleRegistrationUnregisteredVisitor(item)" />
299
+ <v-btn
300
+ v-if="activeTab === 'unregistered' && canAddVisitor"
301
+ size="small"
302
+ color="primary"
303
+ text="Register"
304
+ @click.stop="handleRegistrationUnregisteredVisitor(item)"
305
+ />
144
306
  </template>
145
307
 
146
308
  <template v-slot:item.checkInRemarks="{ item }">
147
309
  <span>
148
- <v-btn variant="text" color="blue-darken-2" density="compact" size="small"
149
- @click.stop="handleOpenRemarks(item, 'checkIn')">{{ item.checkInRemarks ? "View Remarks" : "Add Remarks"
150
- }}</v-btn>
310
+ <v-btn
311
+ variant="text"
312
+ color="blue-darken-2"
313
+ density="compact"
314
+ size="small"
315
+ @click.stop="handleOpenRemarks(item, 'checkIn')"
316
+ >{{ item.checkInRemarks ? "View Remarks" : "Add Remarks" }}</v-btn
317
+ >
151
318
  </span>
152
319
  </template>
153
320
  <template v-slot:item.checkOutRemarks="{ item }">
154
321
  <span>
155
- <v-btn variant="text" color="blue-darken-2" density="compact" size="small"
156
- @click.stop="handleOpenRemarks(item, 'checkOut')">{{ item.checkOutRemarks ? "View Remarks" : "Add Remarks"
157
- }}</v-btn>
322
+ <v-btn
323
+ variant="text"
324
+ color="blue-darken-2"
325
+ density="compact"
326
+ size="small"
327
+ @click.stop="handleOpenRemarks(item, 'checkOut')"
328
+ >{{ item.checkOutRemarks ? "View Remarks" : "Add Remarks" }}</v-btn
329
+ >
158
330
  </span>
159
331
  </template>
160
-
161
332
  </TableMain>
162
333
 
163
334
  <v-dialog v-model="dialog.showSelection" width="450" persistent>
164
- <VisitorFormSelection :mode="mode" @cancel="dialog.showSelection = false" @select="handleSelectVisitorType" />
335
+ <VisitorFormSelection
336
+ :mode="mode"
337
+ @cancel="dialog.showSelection = false"
338
+ @select="handleSelectVisitorType"
339
+ />
165
340
  </v-dialog>
166
341
 
167
- <v-dialog v-model="dialog.showForm" v-if="activeVisitorFormType" width="450" persistent>
168
- <VisitorForm :mode="mode" :org="orgId" :site="siteId" :visitor-data="selectedVisitorDataObject"
169
- :type="activeVisitorFormType" @back="handleClickBack" @done="handleVisitorFormDone"
170
- @done:more="handleVisitorFormCreateMore" @close:all="handleCloseAll" />
342
+ <v-dialog
343
+ v-model="dialog.showForm"
344
+ v-if="activeVisitorFormType"
345
+ width="450"
346
+ persistent
347
+ >
348
+ <VisitorForm
349
+ :mode="mode"
350
+ :org="orgId"
351
+ :site="siteId"
352
+ :visitor-data="selectedVisitorDataObject"
353
+ :type="activeVisitorFormType"
354
+ @back="handleClickBack"
355
+ @done="handleVisitorFormDone"
356
+ @done:more="handleVisitorFormCreateMore"
357
+ @close:all="handleCloseAll"
358
+ />
171
359
  </v-dialog>
172
360
 
173
361
  <v-dialog v-model="dialog.viewVisitor" width="450" persistent>
174
- <VehicleUpdateMoreAction title="Preview" :can-update="false" :can-delete="canDeleteVisitor"
175
- @close="dialog.viewVisitor = false" edit-button-label="Edit Visitor" delete-button-label="Delete Visitor"
176
- @delete="handleDeleteVisitor">
362
+ <VehicleUpdateMoreAction
363
+ title="Preview"
364
+ :can-update="false"
365
+ :can-delete="false"
366
+ @close="dialog.viewVisitor = false"
367
+ edit-button-label="Edit Visitor"
368
+ >
177
369
  <template v-slot:content>
178
370
  <v-row no-gutters class="mb-4">
179
371
  <v-col v-for="(label, key) in formattedFields" :key="key" cols="12">
180
- <span v-if="
181
- key === 'checkOut' &&
182
- !selectedVisitorObject[key] &&
183
- canCheckoutVisitor
184
- " class="d-flex align-center">
372
+ <span
373
+ v-if="
374
+ key === 'checkOut' &&
375
+ !selectedVisitorObject[key] &&
376
+ canCheckoutVisitor
377
+ "
378
+ class="d-flex align-center"
379
+ >
185
380
  <strong>{{ label }}:</strong>
186
- <v-btn size="x-small" class="ml-3 text-capitalize" color="red" text="Checkout"
187
- :disabled="loading.checkingOut" @click="handleCheckout(selectedVisitorId as string)" />
381
+ <v-btn
382
+ size="x-small"
383
+ class="ml-3 text-capitalize"
384
+ color="red"
385
+ text="Checkout"
386
+ :disabled="loading.checkingOut"
387
+ @click="handleCheckout(selectedVisitorId as string)"
388
+ />
188
389
  </span>
189
390
 
190
- <span v-else-if="selectedVisitorObject[key]" class="d-flex ga-3 align-center"><strong>{{ label
191
- }}:</strong>
391
+ <span
392
+ v-else-if="selectedVisitorObject[key]"
393
+ class="d-flex ga-3 align-center"
394
+ ><strong>{{ label }}:</strong>
192
395
  {{ formatValues(key, selectedVisitorObject[key]) }}
193
- <TooltipInfo v-if="key === 'checkOut'" text="Manual Checkout" density="compact" size="x-small" />
396
+ <TooltipInfo
397
+ v-if="key === 'checkOut'"
398
+ text="Manual Checkout"
399
+ density="compact"
400
+ size="x-small"
401
+ />
194
402
  </span>
195
403
  </v-col>
196
404
  </v-row>
@@ -198,17 +406,15 @@
198
406
  </VehicleUpdateMoreAction>
199
407
  </v-dialog>
200
408
 
201
- <v-dialog v-model="dialog.deleteConfirmation" width="450" persistent>
202
- <CardDeleteConfirmation prompt-title="Are you sure want to delete this visitor?"
203
- :loading="loading.deletingVisitor" @close="dialog.deleteConfirmation = false"
204
- @delete="handleProceedDeleteVisitor" />
205
- </v-dialog>
206
-
207
409
  <v-dialog v-model="dialog.snapshotImage" max-width="700">
208
410
  <v-card>
209
411
  <v-card-title class="d-flex justify-space-between align-center">
210
412
  <span>Snapshot</span>
211
- <v-btn icon="mdi-close" variant="text" @click="dialog.snapshotImage = false" />
413
+ <v-btn
414
+ icon="mdi-close"
415
+ variant="text"
416
+ @click="dialog.snapshotImage = false"
417
+ />
212
418
  </v-card-title>
213
419
  <v-card-text class="pa-2 d-flex justify-center">
214
420
  <v-img :src="snapshotImageUrl" max-height="600" contain />
@@ -218,23 +424,51 @@
218
424
 
219
425
  <v-dialog v-model="dialog.remarks" max-width="450" persistent>
220
426
  <v-card>
221
- <v-card-title class="d-flex justify-space-between align-center pt-4 px-4">
222
- <span>{{ remarksType === 'checkIn' ? 'Check-In Remarks' : 'Check-Out Remarks' }}</span>
223
- <v-btn icon="mdi-close" variant="text" @click="dialog.remarks = false" />
427
+ <v-card-title
428
+ class="d-flex justify-space-between align-center pt-4 px-4"
429
+ >
430
+ <span>{{
431
+ remarksType === "checkIn" ? "Check-In Remarks" : "Check-Out Remarks"
432
+ }}</span>
433
+ <v-btn
434
+ icon="mdi-close"
435
+ variant="text"
436
+ @click="dialog.remarks = false"
437
+ />
224
438
  </v-card-title>
225
439
  <v-card-text class="px-4 pb-2">
226
- <v-textarea v-model="remarksInput" label="Remarks" rows="4" auto-grow variant="outlined"
227
- :readonly="remarksViewOnly" />
440
+ <v-textarea
441
+ v-model="remarksInput"
442
+ label="Remarks"
443
+ rows="4"
444
+ auto-grow
445
+ variant="outlined"
446
+ :readonly="remarksViewOnly"
447
+ />
228
448
  </v-card-text>
229
449
  <v-toolbar class="pa-0" density="compact">
230
450
  <v-row no-gutters>
231
451
  <v-col cols="6">
232
- <v-btn variant="text" block :disabled="loading.savingRemarks"
233
- @click="dialog.remarks = false">Cancel</v-btn>
452
+ <v-btn
453
+ variant="text"
454
+ block
455
+ :disabled="loading.savingRemarks"
456
+ @click="dialog.remarks = false"
457
+ >Cancel</v-btn
458
+ >
234
459
  </v-col>
235
460
  <v-col cols="6">
236
- <v-btn color="primary" variant="flat" height="48" rounded="0" block :loading="loading.savingRemarks"
237
- :disabled="!remarksInput.trim()" @click="handleSaveRemarks">Save</v-btn>
461
+ <v-btn
462
+ color="primary"
463
+ variant="flat"
464
+ height="48"
465
+ rounded="0"
466
+ block
467
+ :loading="loading.savingRemarks"
468
+ :disabled="!remarksInput.trim()"
469
+ @click="handleSaveRemarks"
470
+ >Save</v-btn
471
+ >
238
472
  </v-col>
239
473
  </v-row>
240
474
  </v-toolbar>
@@ -244,54 +478,134 @@
244
478
  <v-dialog v-model="dialog.returnPassesKeys" max-width="450" persistent>
245
479
  <v-card>
246
480
  <v-toolbar density="compact" color="">
247
- <v-row no-gutters class="d-flex fill-height justify-space-between align-center px-4">
481
+ <v-row
482
+ no-gutters
483
+ class="d-flex fill-height justify-space-between align-center px-4"
484
+ >
248
485
  <span class="font-weight-bold">Return Passes &amp; Keys</span>
249
- <v-btn icon="mdi-close" variant="text" @click="dialog.returnPassesKeys = false" />
486
+ <v-btn
487
+ icon="mdi-close"
488
+ variant="text"
489
+ @click="dialog.returnPassesKeys = false"
490
+ />
250
491
  </v-row>
251
492
  </v-toolbar>
252
493
  <v-card-text class="px-4 pb-2">
253
- <p class="text-body-2 mb-3">Please ensure all passes and keys are returned before checking out.</p>
494
+ <p class="text-body-2 mb-3">
495
+ Please ensure all passes and keys are returned before checking out.
496
+ </p>
254
497
  <div v-if="passReturnStatuses.length > 0" class="mb-2">
255
498
  <p class="text-caption text-medium-emphasis mb-1">Passes</p>
256
- <v-row no-gutters v-for="pass in passReturnStatuses" :key="(pass as any)._id ?? (pass as any).keyId"
257
- class="d-flex flex-wrap justify-space-between align-center ga-5 mb-2">
258
- <v-chip prepend-icon="mdi-card-bulleted-outline" size="small" variant="tonal" color="blue">
499
+ <v-row
500
+ no-gutters
501
+ v-for="pass in passReturnStatuses"
502
+ :key="(pass as any)._id ?? (pass as any).keyId"
503
+ class="d-flex flex-wrap justify-space-between align-center ga-5 mb-2"
504
+ >
505
+ <v-chip
506
+ prepend-icon="mdi-card-bulleted-outline"
507
+ size="small"
508
+ variant="tonal"
509
+ color="blue"
510
+ >
259
511
  {{ (pass as any)?.prefixAndName }}
260
512
  </v-chip>
261
- <v-select hide-details max-width="200px" density="compact" :items="passStatusOptions" item-title="label"
262
- item-value="value" v-model="pass.status" :disabled="selectedVisitorObject.checkOut"></v-select>
263
- <v-textarea v-if="pass.status === 'Lost' || pass.status === 'Damaged'" no-resize rows="3" class="w-100"
264
- density="compact" v-model="pass.remarks" :disabled="selectedVisitorObject.checkOut"></v-textarea>
513
+ <v-select
514
+ hide-details
515
+ max-width="200px"
516
+ density="compact"
517
+ :items="passStatusOptions"
518
+ item-title="label"
519
+ item-value="value"
520
+ v-model="pass.status"
521
+ :disabled="selectedVisitorObject.checkOut"
522
+ ></v-select>
523
+ <v-textarea
524
+ v-if="pass.status === 'Lost' || pass.status === 'Damaged'"
525
+ no-resize
526
+ rows="3"
527
+ class="w-100"
528
+ density="compact"
529
+ v-model="pass.remarks"
530
+ :disabled="selectedVisitorObject.checkOut"
531
+ ></v-textarea>
265
532
  </v-row>
266
533
  </div>
267
- <div v-if="(keyReturnStatuses.length > 0)" class="mb-2">
534
+ <div v-if="keyReturnStatuses.length > 0" class="mb-2">
268
535
  <p class="text-caption text-medium-emphasis mb-1">Keys</p>
269
- <v-row no-gutters v-for="key in keyReturnStatuses" :key="(key as any)._id ?? (key as any).keyId"
270
- class="d-flex flex-wrap justify-space-between align-center ga-5 mb-2">
271
- <v-chip prepend-icon="mdi-key" size="small" variant="tonal" color="orange">
536
+ <v-row
537
+ no-gutters
538
+ v-for="key in keyReturnStatuses"
539
+ :key="(key as any)._id ?? (key as any).keyId"
540
+ class="d-flex flex-wrap justify-space-between align-center ga-5 mb-2"
541
+ >
542
+ <v-chip
543
+ prepend-icon="mdi-key"
544
+ size="small"
545
+ variant="tonal"
546
+ color="orange"
547
+ >
272
548
  {{ (key as any)?.prefixAndName }}
273
549
  </v-chip>
274
- <v-select hide-details max-width="200px" density="compact" :items="passStatusOptions" item-title="label"
275
- item-value="value" v-model="key.status" :disabled="selectedVisitorObject.checkOut"></v-select>
276
- <v-textarea v-if="key.status === 'Lost' || key.status === 'Damaged'" no-resize rows="3" class="w-100"
277
- density="compact" v-model="key.remarks" :disabled="selectedVisitorObject.checkOut"></v-textarea>
550
+ <v-select
551
+ hide-details
552
+ max-width="200px"
553
+ density="compact"
554
+ :items="passStatusOptions"
555
+ item-title="label"
556
+ item-value="value"
557
+ v-model="key.status"
558
+ :disabled="selectedVisitorObject.checkOut"
559
+ ></v-select>
560
+ <v-textarea
561
+ v-if="key.status === 'Lost' || key.status === 'Damaged'"
562
+ no-resize
563
+ rows="3"
564
+ class="w-100"
565
+ density="compact"
566
+ v-model="key.remarks"
567
+ :disabled="selectedVisitorObject.checkOut"
568
+ ></v-textarea>
278
569
  </v-row>
279
570
  </div>
280
571
 
281
572
  <v-row no-gutters class="my-5">
282
- <v-btn variant="flat" color="blue" density="comfortable" class="text-capitalize" :disabled="selectedVisitorObject.checkOut"
283
- :loading="loading.updatingPassKeys" @click.stop="handleUpdatePassKeys" >Update Pass/Keys</v-btn>
573
+ <v-btn
574
+ variant="flat"
575
+ color="blue"
576
+ density="comfortable"
577
+ class="text-capitalize"
578
+ :disabled="selectedVisitorObject.checkOut"
579
+ :loading="loading.updatingPassKeys"
580
+ @click.stop="handleUpdatePassKeys"
581
+ >Update Pass/Keys</v-btn
582
+ >
284
583
  </v-row>
285
584
  </v-card-text>
286
585
  <v-toolbar class="pa-0" density="compact">
287
586
  <v-row no-gutters>
288
587
  <v-col cols="6">
289
- <v-btn variant="text" block
290
- @click="dialog.returnPassesKeys = false">Close</v-btn>
588
+ <v-btn
589
+ variant="text"
590
+ block
591
+ @click="dialog.returnPassesKeys = false"
592
+ >Close</v-btn
593
+ >
291
594
  </v-col>
292
595
  <v-col cols="6">
293
- <v-btn color="red" variant="flat" height="48" rounded="0" block :loading="loading.checkingOut"
294
- :disabled="!canConfirmCheckout || selectedVisitorObject.checkOut" @click="proceedCheckout">Confirm Checkout</v-btn>
596
+ <v-btn
597
+ color="red"
598
+ variant="flat"
599
+ height="48"
600
+ rounded="0"
601
+ block
602
+ :loading="loading.checkingOut"
603
+ :disabled="
604
+ !canConfirmCheckout || selectedVisitorObject.checkOut
605
+ "
606
+ @click="proceedCheckout"
607
+ >Confirm Checkout</v-btn
608
+ >
295
609
  </v-col>
296
610
  </v-row>
297
611
  </v-toolbar>
@@ -299,10 +613,40 @@
299
613
  </v-dialog>
300
614
 
301
615
  <v-dialog v-model="dialog.addPassKey" width="450" persistent>
302
- <AddPassKeyToVisitor :visitor="selectedVisitorDataObject" :site="siteId" @close="dialog.addPassKey = false"
303
- @update="getVisitorRefresh" />
616
+ <AddPassKeyToVisitor
617
+ mode="add"
618
+ :visitor="selectedVisitorDataObject"
619
+ :site="siteId"
620
+ @close="dialog.addPassKey = false"
621
+ @done="
622
+ () => {
623
+ dialog.addPassKey = false;
624
+ getVisitorRefresh();
625
+ }
626
+ "
627
+ />
628
+ </v-dialog>
629
+
630
+ <v-dialog v-model="dialog.editPassKey" width="450" persistent>
631
+ <AddPassKeyToVisitor
632
+ mode="edit"
633
+ :visitor="selectedVisitorDataObject"
634
+ :site="siteId"
635
+ @close="dialog.editPassKey = false"
636
+ @done="
637
+ () => {
638
+ dialog.editPassKey = false;
639
+ getVisitorRefresh();
640
+ }
641
+ "
642
+ />
304
643
  </v-dialog>
305
644
 
645
+ <ScanVisitorQRCode
646
+ :dialog="dialog.scanVisitorQRCode"
647
+ @close-dialog="dialog.scanVisitorQRCode = false"
648
+ />
649
+
306
650
  <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
307
651
  </v-row>
308
652
  </template>
@@ -317,15 +661,15 @@ const props = defineProps({
317
661
  type: Boolean,
318
662
  default: true,
319
663
  },
320
- canViewVisitor: {
664
+ canScanVisitorQRCode: {
321
665
  type: Boolean,
322
666
  default: true,
323
667
  },
324
- canUpdateVisitor: {
668
+ canViewVisitor: {
325
669
  type: Boolean,
326
670
  default: true,
327
671
  },
328
- canDeleteVisitor: {
672
+ canUpdateVisitor: {
329
673
  type: Boolean,
330
674
  default: true,
331
675
  },
@@ -335,21 +679,16 @@ const props = defineProps({
335
679
  },
336
680
  });
337
681
 
338
- const {
339
- getVisitors,
340
- visitorSelection,
341
- typeFieldMap,
342
- deleteVisitor,
343
- updateVisitor,
344
- } = useVisitor();
682
+ const { getVisitors, visitorSelection, typeFieldMap, updateVisitor } =
683
+ useVisitor();
345
684
  const { debounce, formatCamelCaseToWords, formatDate, UTCToLocalTIme } =
346
685
  useUtils();
347
686
  const { formatLocation } = useSecurityUtils();
348
687
  const { getFileUrlAnpr } = useFile();
349
688
  // const { status: visitorStatus, search } = useRoute().query as { status: string, search: string};
350
689
 
351
- const route = useRoute()
352
- const router = useRouter()
690
+ const route = useRoute();
691
+ const router = useRouter();
353
692
  const { org: orgId, site: siteId } = route.params as {
354
693
  org: string;
355
694
  site: string;
@@ -377,7 +716,6 @@ const messageColor = ref("");
377
716
  const messageSnackbar = ref(false);
378
717
 
379
718
  const loading = reactive({
380
- deletingVisitor: false,
381
719
  fetchingVisitors: false,
382
720
  checkingOut: false,
383
721
  savingRemarks: false,
@@ -388,15 +726,16 @@ const dialog = reactive({
388
726
  showSelection: false,
389
727
  showForm: false,
390
728
  viewVisitor: false,
391
- deleteConfirmation: false,
392
729
  snapshotImage: false,
393
730
  remarks: false,
394
731
  returnPassesKeys: false,
395
- addPassKey: false
732
+ addPassKey: false,
733
+ editPassKey: false,
734
+ scanVisitorQRCode: false,
396
735
  });
397
736
 
398
737
  const snapshotImageUrl = ref("");
399
- const remarksType = ref<'checkIn' | 'checkOut'>('checkIn');
738
+ const remarksType = ref<"checkIn" | "checkOut">("checkIn");
400
739
  const remarksInput = ref("");
401
740
  const remarksViewOnly = ref(false);
402
741
 
@@ -406,10 +745,16 @@ const headers = computed(() => [
406
745
  { title: "Location", value: "location" },
407
746
  { title: "Contact/Vehicle No.", value: "contact-vehicleNumber" },
408
747
  { title: "Check In/Out", value: "checkin-out" },
409
- ...(activeTab.value === "resident-transactions" ? [{ title: "Check-in Remarks", value: "checkInRemarks" }, { title: "Check-out Remarks", value: "checkOutRemarks" }] : []),
410
- ...(activeTab.value === 'unregistered' ? [{ title: "Action", value: "action" }] : [])
411
- ])
412
-
748
+ ...(activeTab.value === "resident-transactions"
749
+ ? [
750
+ { title: "Check-in Remarks", value: "checkInRemarks" },
751
+ { title: "Check-out Remarks", value: "checkOutRemarks" },
752
+ ]
753
+ : []),
754
+ ...(activeTab.value === "unregistered"
755
+ ? [{ title: "Action", value: "action" }]
756
+ : []),
757
+ ]);
413
758
 
414
759
  const tabOptions = [
415
760
  { name: "Registered", value: "registered" },
@@ -418,6 +763,19 @@ const tabOptions = [
418
763
  { name: "Resident Transactions", value: "resident-transactions" },
419
764
  ];
420
765
 
766
+ function normalizeDateOnly(value: string) {
767
+ if (!value) return "";
768
+ if (/^\d{4}-\d{2}-\d{2}$/.test(value)) return value;
769
+
770
+ const parsedDate = new Date(value);
771
+ if (Number.isNaN(parsedDate.getTime())) return "";
772
+
773
+ const year = parsedDate.getFullYear();
774
+ const month = String(parsedDate.getMonth() + 1).padStart(2, "0");
775
+ const day = String(parsedDate.getDate()).padStart(2, "0");
776
+ return `${year}-${month}-${day}`;
777
+ }
778
+
421
779
  const selectedVisitorDataObject = computed(() => {
422
780
  return items.value.find((x: any) => x?._id === selectedVisitorId.value) || {};
423
781
  });
@@ -439,7 +797,6 @@ const formattedFields = {
439
797
  checkOut: "Check Out",
440
798
  snapshotExitImage: "Exit Image",
441
799
  remarks: "Remarks",
442
-
443
800
  } as const;
444
801
 
445
802
  function filterTypeSelectionLabel() {
@@ -452,14 +809,14 @@ const passStatusOptions = [
452
809
  { label: "Not Returned", value: "In Use" },
453
810
  { label: "Damaged", value: "Damaged" },
454
811
  { label: "Lost", value: "Lost" },
455
- ]
812
+ ];
456
813
 
457
814
  function toRoute(tab: any) {
458
- items.value = []
815
+ items.value = [];
459
816
 
460
817
  const obj = tabOptions.find((x) => x.value === tab);
461
818
  if (!obj) return;
462
- page.value = 1
819
+ page.value = 1;
463
820
  navigateTo({
464
821
  name: routeName,
465
822
  params: {
@@ -470,54 +827,51 @@ function toRoute(tab: any) {
470
827
  // },
471
828
  });
472
829
  }
473
-
474
830
  const {
475
831
  data: getVisitorReq,
476
832
  refresh: getVisitorRefresh,
477
833
  pending: getVisitorPending,
478
834
  } = await useLazyAsyncData(
479
- `get-all-visitors-${activeTab.value}-${page.value}-${siteId}`,
835
+ "get-all-visitors",
480
836
  async () => {
481
-
482
- // Optional delay (if needed)
483
- await new Promise(resolve => setTimeout(resolve, 100))
484
-
485
837
  const params: any = {
486
838
  page: page.value,
487
839
  site: siteId,
488
840
  search: searchInput.value,
489
- dateTo: dateTo.value,
490
- dateFrom: dateFrom.value,
491
- type: (filterTypes.value.length === 0 && activeTab.value === 'registered' ? "contractor,delivery,walk-in,pick-up,drop-off,guest" : filterTypes.value.filter(Boolean).join(",")),
492
- checkedOut: displayNotCheckedOut.value ? false : undefined
493
- }
494
-
495
- // if (activeTab.value !== "guests") {
496
- // params.status = activeTab.value
497
- // } else if (activeTab.value === "guests") {
498
- // params.type = "guest"
499
- // params.status = "pending"
500
- // }
841
+ dateTo: normalizeDateOnly(dateTo.value),
842
+ dateFrom: normalizeDateOnly(dateFrom.value),
843
+ type:
844
+ filterTypes.value.length === 0 && activeTab.value === "registered"
845
+ ? "contractor,delivery,walk-in,pick-up,drop-off,guest"
846
+ : filterTypes.value.filter(Boolean).join(","),
847
+ checkedOut: displayNotCheckedOut.value ? false : undefined,
848
+ };
501
849
 
502
850
  if (activeTab.value === "guests") {
503
- params.type = "guest"
504
- params.status = "pending"
851
+ params.type = "guest";
852
+ params.status = "pending";
505
853
  } else if (activeTab.value === "resident-transactions") {
506
- params.status = "registered"
507
- params.type = "resident,tenant"
854
+ params.status = "registered";
855
+ params.type = "resident,tenant";
508
856
  } else {
509
- params.status = activeTab.value
857
+ params.status = activeTab.value;
510
858
  }
511
859
 
512
- return await getVisitors(params)
860
+ return await getVisitors(params);
513
861
  },
514
862
  {
515
863
  watch: [
516
864
  page,
865
+ searchInput,
866
+ dateFrom,
867
+ dateTo,
868
+ filterTypes,
869
+ activeTab,
870
+ displayNotCheckedOut,
517
871
  ],
518
- immediate: false
872
+ immediate: true,
519
873
  }
520
- )
874
+ );
521
875
 
522
876
  watch(getVisitorReq, (newData: any) => {
523
877
  if (newData) {
@@ -529,11 +883,16 @@ watch(getVisitorReq, (newData: any) => {
529
883
  });
530
884
 
531
885
  const selectedVisitorObject = computed(() => {
532
-
533
886
  const obj = items.value.find((x: any) => x?._id === selectedVisitorId.value);
534
887
  if (!obj) return {};
535
888
  const type = obj?.type as TVisitorType | undefined;
536
- let includedKeys: string[] = ["checkIn", "checkOut", "plateNumber", "snapshotEntryImage", "snapshotExitImage"];
889
+ let includedKeys: string[] = [
890
+ "checkIn",
891
+ "checkOut",
892
+ "plateNumber",
893
+ "snapshotEntryImage",
894
+ "snapshotExitImage",
895
+ ];
537
896
  includedKeys.unshift(...(typeFieldMap[type] ?? []));
538
897
  return Object.fromEntries(
539
898
  Object.entries(obj).filter(([key]) => includedKeys.includes(key))
@@ -554,8 +913,6 @@ function formatValues(key: string, value: any) {
554
913
  return value;
555
914
  }
556
915
 
557
-
558
-
559
916
  function handleAddNew() {
560
917
  dialog.showSelection = true;
561
918
  activeVisitorFormType.value = null;
@@ -575,9 +932,17 @@ function showAddPassKeyButton(item: any) {
575
932
  const hasPasses = (item?.visitorPass?.length ?? 0) > 0;
576
933
  const hasKeys = (item?.passKeys?.length ?? 0) > 0;
577
934
 
578
- const isTypeWithPassKey = ["contractor", "guest", "walk-in"].includes(item?.type);
935
+ const isTypeWithPassKey = ["contractor", "guest", "walk-in"].includes(
936
+ item?.type
937
+ );
579
938
 
580
- return !hasPasses && !hasKeys && isTypeWithPassKey && item?.status === "registered" && !item?.checkOut;
939
+ return (
940
+ !hasPasses &&
941
+ !hasKeys &&
942
+ isTypeWithPassKey &&
943
+ item?.status === "registered" &&
944
+ !item?.checkOut
945
+ );
581
946
  }
582
947
 
583
948
  function handleSelectVisitorType(type: TVisitorType) {
@@ -603,11 +968,6 @@ function handleVisitorFormCreateMore() {
603
968
  dialog.showForm = false;
604
969
  }
605
970
 
606
- function handleDeleteVisitor() {
607
- dialog.deleteConfirmation = true;
608
- dialog.viewVisitor = false;
609
- }
610
-
611
971
  function showMessage(msg: string, color: string) {
612
972
  message.value = msg;
613
973
  messageColor.value = color;
@@ -637,10 +997,19 @@ function handleOpenAddPassKey(item: any) {
637
997
  dialog.addPassKey = true;
638
998
  }
639
999
 
640
- function handleOpenRemarks(item: any, type: 'checkIn' | 'checkOut') {
1000
+ function handleOpenEditPassKey(item: any) {
1001
+ selectedVisitorId.value = item?._id;
1002
+ if (selectedVisitorDataObject.value.checkOut) {
1003
+ dialog.returnPassesKeys = true;
1004
+ handleCheckout(selectedVisitorId.value as string);
1005
+ } else dialog.editPassKey = true;
1006
+ }
1007
+
1008
+ function handleOpenRemarks(item: any, type: "checkIn" | "checkOut") {
641
1009
  selectedVisitorId.value = item?._id;
642
1010
  remarksType.value = type;
643
- const existingRemarks = type === 'checkIn' ? item?.checkInRemarks : item?.checkOutRemarks;
1011
+ const existingRemarks =
1012
+ type === "checkIn" ? item?.checkInRemarks : item?.checkOutRemarks;
644
1013
  remarksInput.value = existingRemarks || "";
645
1014
  remarksViewOnly.value = !!existingRemarks;
646
1015
  dialog.remarks = true;
@@ -650,16 +1019,20 @@ async function handleSaveRemarks() {
650
1019
  if (!remarksInput.value.trim() || !selectedVisitorId.value) return;
651
1020
  try {
652
1021
  loading.savingRemarks = true;
653
- const payload = remarksType.value === 'checkIn'
654
- ? { checkInRemarks: remarksInput.value.trim() }
655
- : { checkOutRemarks: remarksInput.value.trim() };
1022
+ const payload =
1023
+ remarksType.value === "checkIn"
1024
+ ? { checkInRemarks: remarksInput.value.trim() }
1025
+ : { checkOutRemarks: remarksInput.value.trim() };
656
1026
  await updateVisitor(selectedVisitorId.value, payload);
657
1027
  showMessage("Remarks saved successfully!", "info");
658
1028
  await getVisitorRefresh();
659
1029
  dialog.remarks = false;
660
1030
  } catch (error: any) {
661
1031
  const errorMessage = error?.response?._data?.message;
662
- showMessage(errorMessage || "Something went wrong. Please try again later.", "error");
1032
+ showMessage(
1033
+ errorMessage || "Something went wrong. Please try again later.",
1034
+ "error"
1035
+ );
663
1036
  } finally {
664
1037
  loading.savingRemarks = false;
665
1038
  }
@@ -671,11 +1044,19 @@ async function handleUpdatePassKeys() {
671
1044
  loading.updatingPassKeys = true;
672
1045
  const payload: any = {};
673
1046
  if (passReturnStatuses.value.length > 0) {
674
- const passReturnStatusesPayload = passReturnStatuses.value.map(p => ({ keyId: p.keyId, status: p.status, remarks: p.remarks }));
1047
+ const passReturnStatusesPayload = passReturnStatuses.value.map((p) => ({
1048
+ keyId: p.keyId,
1049
+ status: p.status,
1050
+ remarks: p.remarks,
1051
+ }));
675
1052
  payload.visitorPass = passReturnStatusesPayload;
676
1053
  }
677
1054
  if (keyReturnStatuses.value.length > 0) {
678
- const keyReturnStatusesPayload = keyReturnStatuses.value.map(k => ({ keyId: k.keyId, status: k.status, remarks: k.remarks }));
1055
+ const keyReturnStatusesPayload = keyReturnStatuses.value.map((k) => ({
1056
+ keyId: k.keyId,
1057
+ status: k.status,
1058
+ remarks: k.remarks,
1059
+ }));
679
1060
  payload.passKeys = keyReturnStatusesPayload;
680
1061
  }
681
1062
  await updateVisitor(selectedVisitorId.value, payload);
@@ -683,50 +1064,35 @@ async function handleUpdatePassKeys() {
683
1064
  await getVisitorRefresh();
684
1065
  } catch (error: any) {
685
1066
  const errorMessage = error?.response?._data?.message;
686
- showMessage(errorMessage || "Something went wrong. Please try again later.", "error");
687
- } finally {
688
- loading.updatingPassKeys = false;
689
- }
690
- }
691
-
692
-
693
- async function handleProceedDeleteVisitor() {
694
- try {
695
- loading.deletingVisitor = true;
696
- const userId = selectedVisitorId.value;
697
- const res = await deleteVisitor(userId as string);
698
- if (res) {
699
- showMessage("Visitor successfully deleted!", "info");
700
- await getVisitorRefresh();
701
- dialog.deleteConfirmation = false;
702
- }
703
- } catch (error: any) {
704
- const errorMessage = error?.response?._data?.message;
705
- console.log("[ERROR]", error);
706
1067
  showMessage(
707
1068
  errorMessage || "Something went wrong. Please try again later.",
708
1069
  "error"
709
1070
  );
710
1071
  } finally {
711
- loading.deletingVisitor = false;
1072
+ loading.updatingPassKeys = false;
712
1073
  }
713
1074
  }
714
1075
 
715
-
716
- const passReturnStatuses = ref<{ keyId: string, status: string, prefixAndName: string, remarks: string }[]>([]);
717
- const keyReturnStatuses = ref<{ keyId: string, status: string, prefixAndName: string, remarks: string }[]>([]);
1076
+ const passReturnStatuses = ref<
1077
+ { keyId: string; status: string; prefixAndName: string; remarks: string }[]
1078
+ >([]);
1079
+ const keyReturnStatuses = ref<
1080
+ { keyId: string; status: string; prefixAndName: string; remarks: string }[]
1081
+ >([]);
718
1082
 
719
1083
  const canConfirmCheckout = computed(() => {
720
1084
  const allEntries = [...passReturnStatuses.value, ...keyReturnStatuses.value];
721
1085
  return allEntries.every((entry) => {
722
- if (!entry.status || entry.status === 'In Use') return false;
723
- if ((entry.status === 'Lost' || entry.status === 'Damaged') && !entry.remarks.trim()) return false;
1086
+ if (!entry.status || entry.status === "In Use") return false;
1087
+ if (
1088
+ (entry.status === "Lost" || entry.status === "Damaged") &&
1089
+ !entry.remarks.trim()
1090
+ )
1091
+ return false;
724
1092
  return true;
725
1093
  });
726
1094
  });
727
1095
 
728
-
729
-
730
1096
  function handleCheckout(userId: string) {
731
1097
  if (!userId) {
732
1098
  showMessage("Invalid userId", "error");
@@ -740,8 +1106,22 @@ function handleCheckout(userId: string) {
740
1106
 
741
1107
  if (hasPasses || hasKeys) {
742
1108
  const visitor = items.value.find((x: any) => x?._id === userId);
743
- passReturnStatuses.value = ((visitor?.visitorPass as any[]) || []).map((p: any) => ({ keyId: p.keyId, status: p.status ?? "In Use", remarks: '', prefixAndName: p.prefixAndName }));
744
- keyReturnStatuses.value = ((visitor?.passKeys as any[]) || []).map((k: any) => ({ keyId: k.keyId, status: k.status ?? "In Use", remarks: '', prefixAndName: k.prefixAndName }));
1109
+ passReturnStatuses.value = ((visitor?.visitorPass as any[]) || []).map(
1110
+ (p: any) => ({
1111
+ keyId: p.keyId,
1112
+ status: p.status ?? "In Use",
1113
+ remarks: "",
1114
+ prefixAndName: p.prefixAndName,
1115
+ })
1116
+ );
1117
+ keyReturnStatuses.value = ((visitor?.passKeys as any[]) || []).map(
1118
+ (k: any) => ({
1119
+ keyId: k.keyId,
1120
+ status: k.status ?? "In Use",
1121
+ remarks: "",
1122
+ prefixAndName: k.prefixAndName,
1123
+ })
1124
+ );
745
1125
  dialog.returnPassesKeys = true;
746
1126
  return;
747
1127
  }
@@ -756,13 +1136,25 @@ async function proceedCheckout() {
756
1136
  try {
757
1137
  loading.checkingOut = true;
758
1138
 
759
- const passReturnStatusesPayload = passReturnStatuses.value.map(p => ({ keyId: p.keyId, status: p.status, remarks: p.remarks }));
760
- const keyReturnStatusesPayload = keyReturnStatuses.value.map(k => ({ keyId: k.keyId, status: k.status, remarks: k.remarks }));
1139
+ const passReturnStatusesPayload = passReturnStatuses.value.map((p) => ({
1140
+ keyId: p.keyId,
1141
+ status: p.status,
1142
+ remarks: p.remarks,
1143
+ }));
1144
+ const keyReturnStatusesPayload = keyReturnStatuses.value.map((k) => ({
1145
+ keyId: k.keyId,
1146
+ status: k.status,
1147
+ remarks: k.remarks,
1148
+ }));
761
1149
 
762
1150
  const res = await updateVisitor(userId as string, {
763
1151
  checkOut: new Date().toISOString(),
764
- ...(passReturnStatuses.value.length > 0 ? { visitorPass: passReturnStatusesPayload } : {}),
765
- ...(keyReturnStatuses.value.length > 0 ? { passKeys: keyReturnStatusesPayload } : {}),
1152
+ ...(passReturnStatuses.value.length > 0
1153
+ ? { visitorPass: passReturnStatusesPayload }
1154
+ : {}),
1155
+ ...(keyReturnStatuses.value.length > 0
1156
+ ? { passKeys: keyReturnStatusesPayload }
1157
+ : {}),
766
1158
  });
767
1159
  if (res) {
768
1160
  showMessage("Visitor successfully checked-out!", "info");
@@ -782,11 +1174,23 @@ async function proceedCheckout() {
782
1174
  }
783
1175
  }
784
1176
 
785
-
786
-
787
1177
  const updateRouteQuery = debounce(
788
1178
  // (search: string, from: string, to: string, types: string[], status, checkedOut) => {
789
- ({ search, from, to, types, tab, checkedOut }: { search: string, from: string, to: string, types: string[], tab: string, checkedOut: boolean }) => {
1179
+ ({
1180
+ search,
1181
+ from,
1182
+ to,
1183
+ types,
1184
+ tab,
1185
+ checkedOut,
1186
+ }: {
1187
+ search: string;
1188
+ from: string;
1189
+ to: string;
1190
+ types: string[];
1191
+ tab: string;
1192
+ checkedOut: boolean;
1193
+ }) => {
790
1194
  router.replace({
791
1195
  query: {
792
1196
  ...route.query,
@@ -795,7 +1199,9 @@ const updateRouteQuery = debounce(
795
1199
  dateTo: to || undefined,
796
1200
  type: types.filter(Boolean).join(",") || undefined,
797
1201
  tab: tab || undefined,
798
- ...(checkedOut === true ? { checkedOut: "true" } : { checkedOut: undefined })
1202
+ ...(checkedOut === true
1203
+ ? { checkedOut: "true" }
1204
+ : { checkedOut: undefined }),
799
1205
  },
800
1206
  });
801
1207
  },
@@ -805,23 +1211,39 @@ const updateRouteQuery = debounce(
805
1211
  watch(
806
1212
  [searchInput, dateFrom, dateTo, filterTypes, activeTab, displayNotCheckedOut],
807
1213
  ([search, from, to, types, tab, checkedOut]) => {
1214
+ const normalizedFrom = normalizeDateOnly(from);
1215
+ const normalizedTo = normalizeDateOnly(to);
1216
+ dateFrom.value = normalizedFrom;
1217
+ dateTo.value = normalizedTo;
1218
+
808
1219
  // updateRouteQuery(search, from, to, types, status, checkedOut)
809
- updateRouteQuery({ search, from, to, types, tab, checkedOut })
810
- getVisitorRefresh();
1220
+ updateRouteQuery({
1221
+ search,
1222
+ from: normalizedFrom,
1223
+ to: normalizedTo,
1224
+ types,
1225
+ tab,
1226
+ checkedOut,
1227
+ });
1228
+ // getVisitorRefresh();
811
1229
  },
812
1230
  { deep: true }
813
1231
  );
814
-
815
-
1232
+ watch([searchInput, dateFrom, dateTo, filterTypes, activeTab], () => {
1233
+ page.value = 1;
1234
+ });
816
1235
 
817
1236
  onMounted(() => {
818
- activeTab.value = (route.query.tab as string) || "unregistered"
1237
+ activeTab.value = (route.query.tab as string) || "unregistered";
819
1238
  searchInput.value = (route.query.search as string) || "";
820
- dateFrom.value = (route.query.dateFrom as string) || "";
821
- dateTo.value = (route.query.dateTo as string) || "";
822
- filterTypes.value = ((route.query.type as string)?.split(",") || []).filter(Boolean) as TVisitorType[];
823
- displayNotCheckedOut.value = (route.query.checkedOut as string) == 'true' || false
824
- })
1239
+ dateFrom.value = normalizeDateOnly((route.query.dateFrom as string) || "");
1240
+ dateTo.value = normalizeDateOnly((route.query.dateTo as string) || "");
1241
+ filterTypes.value = ((route.query.type as string)?.split(",") || []).filter(
1242
+ Boolean
1243
+ ) as TVisitorType[];
1244
+ displayNotCheckedOut.value =
1245
+ (route.query.checkedOut as string) == "true" || false;
1246
+ });
825
1247
  </script>
826
1248
 
827
1249
  <style scoped></style>