@7365admin1/layer-common 3.0.24 → 3.0.26

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/components/AccessCardAddForm.vue +2 -2
  3. package/components/AccessCardAssignToUnitForm.vue +2 -2
  4. package/components/AccessCardDetailsDialog.vue +31 -1
  5. package/components/AccessManagement.vue +16 -6
  6. package/components/AddPassKeyToVisitor.vue +346 -225
  7. package/components/BuildingUnitFormEdit.vue +1 -1
  8. package/components/DashboardMain.vue +124 -60
  9. package/components/DocumentManagement.vue +294 -1
  10. package/components/HidIntercomManagement.vue +186 -0
  11. package/components/HidReaderManagement.vue +21 -1
  12. package/components/Nfc/NFCPatrolReportMain.vue +1 -0
  13. package/components/Nfc/PatrolReport/PatrolReportTab.vue +2 -1
  14. package/components/Nfc/PatrolReport/ReportFilters.vue +3 -1
  15. package/components/RolePermissionMain.vue +34 -5
  16. package/components/SiteSettings.vue +3 -1
  17. package/components/VisitorForm.vue +174 -398
  18. package/components/VisitorManagement.vue +302 -679
  19. package/components/VisitorSocketPopUp.vue +29 -1
  20. package/composables/useANPRSettings.ts +57 -8
  21. package/composables/useAccessManagement.ts +9 -1
  22. package/composables/useCleaningPermission.ts +2 -2
  23. package/composables/useCommonPermission.ts +2 -39
  24. package/composables/useDocument.ts +21 -0
  25. package/composables/useLocalAuth.ts +3 -1
  26. package/composables/useNFCPatrolLog.ts +35 -0
  27. package/composables/useNFCPatrolReport.ts +37 -4
  28. package/composables/useNFCPatrolReportFilters.ts +28 -5
  29. package/package.json +1 -1
  30. package/pages/[org]/[site]/access-mgmt/administrator/index.vue +2 -0
  31. package/pages/[org]/[site]/access-mgmt/hid-readers/index.vue +2 -0
  32. package/pages/[org]/[site]/access-mgmt/hid-users/index.vue +2 -0
  33. package/pages/[org]/[site]/access-mgmt/identity-mapping/index.vue +2 -0
  34. package/services/nfcPatrolReport.ts +5 -1
  35. package/types/nfc-patrol-report.ts +7 -1
  36. package/types/visitor.d.ts +1 -0
@@ -1,137 +1,51 @@
1
1
  <template>
2
2
  <v-row no-gutters>
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
- @refresh="getVisitorRefresh"
13
- @update:page="handleUpdatePage"
14
- show-header
15
- @row-click="handleRowClick"
16
- >
3
+ <TableMain :headers="headers" :items="items" :loading="getVisitorPending" :page="page" :pages="pages"
4
+ :extension-height="110" :offset="300" :pageRange="pageRange" @refresh="getVisitorRefresh"
5
+ @update:page="handleUpdatePage" show-header @row-click="handleRowClick">
17
6
  <template #actions>
18
7
  <v-row no-gutters>
19
- <v-btn
20
- v-if="canAddVisitor"
21
- class="text-none"
22
- rounded="pill"
23
- variant="tonal"
24
- size="large"
25
- @click="handleAddNew"
26
- text="Add Visitor"
27
- />
28
- <v-btn
29
- v-if="canScanVisitorQRCode"
30
- text="Scan QR Code"
31
- class="text-none ml-2"
32
- rounded="pill"
33
- variant="tonal"
34
- size="large"
35
- @click="dialog.scanVisitorQRCode = true"
36
- />
8
+ <v-btn v-if="canAddVisitor" class="text-none" rounded="pill" variant="tonal" size="large"
9
+ @click="handleAddNew" text="Add Visitor" />
10
+ <v-btn v-if="canScanVisitorQRCode" text="Scan QR Code" class="text-none ml-2" rounded="pill" variant="tonal"
11
+ size="large" @click="dialog.scanVisitorQRCode = true" />
37
12
  <v-menu>
38
13
  <template #activator="{ props }">
39
- <v-btn
40
- v-bind="props"
41
- text="Download Report"
42
- class="text-none ml-2"
43
- prepend-icon="mdi-download"
44
- rounded="pill"
45
- variant="tonal"
46
- size="large"
47
- />
14
+ <v-btn v-bind="props" text="Download Report" class="text-none ml-2" prepend-icon="mdi-download"
15
+ rounded="pill" variant="tonal" size="large" />
48
16
  </template>
49
17
  <v-list>
50
- <v-list-item
51
- prepend-icon="mdi-file-pdf"
52
- title="Download PDF Report"
53
- @click="handleDownloadPDFReport"
54
- />
55
- <v-list-item
56
- prepend-icon="mdi-file-csv"
57
- title="Download CSV Report"
58
- @click="handleDownloadCSVReport"
59
- />
18
+ <v-list-item prepend-icon="mdi-file-pdf" title="Download PDF Report" @click="handleDownloadPDFReport" />
19
+ <v-list-item prepend-icon="mdi-file-csv" title="Download CSV Report" @click="handleDownloadCSVReport" />
60
20
  </v-list>
61
21
  </v-menu>
62
22
  </v-row>
63
23
  </template>
64
24
  <template #extension>
65
25
  <v-row no-gutters class="w-100 d-flex flex-column">
66
- <v-tabs
67
- v-model="activeTab"
68
- color="primary"
69
- :height="40"
70
- @update:model-value="toRoute"
71
- class="w-100"
72
- >
73
- <v-tab
74
- v-for="tab in tabOptions"
75
- :value="tab.value"
76
- :key="tab.value"
77
- class="text-capitalize"
78
- >
26
+ <v-tabs v-model="activeTab" color="primary" :height="40" @update:model-value="toRoute" class="w-100">
27
+ <v-tab v-for="tab in tabOptions" :value="tab.value" :key="tab.value" class="text-capitalize">
79
28
  {{ tab.name }}
80
29
  </v-tab>
81
30
  </v-tabs>
82
31
 
83
- <v-card
84
- class="w-100 px-3 d-flex align-center ga-5 py-2"
85
- flat
86
- :height="60"
87
- >
88
- <v-text-field
89
- v-model="searchInput"
90
- density="compact"
91
- placeholder="Search"
92
- clearable
93
- max-width="300"
94
- append-inner-icon="mdi-magnify"
95
- hide-details
96
- />
97
- <v-checkbox
98
- v-model="displayNotCheckedOut"
99
- class="text-subtitle-2"
100
- hide-details
101
- >
32
+ <v-card class="w-100 px-3 d-flex align-center ga-5 py-2" flat :height="60">
33
+ <v-text-field v-model="searchInput" density="compact" placeholder="Search" clearable max-width="300"
34
+ append-inner-icon="mdi-magnify" hide-details />
35
+ <v-checkbox v-model="displayNotCheckedOut" class="text-subtitle-2" hide-details>
102
36
  <template #label>
103
37
  <span class="text-caption">Not Checked Out</span>
104
38
  </template>
105
39
  </v-checkbox>
106
- <InputDatePicker
107
- v-model="dateFrom"
108
- density="compact"
109
- hide-details
110
- />
40
+ <InputDatePicker v-model="dateFrom" density="compact" hide-details />
111
41
  <InputDatePicker v-model="dateTo" density="compact" hide-details />
112
- <v-select
113
- v-if="activeTab == 'registered'"
114
- v-model="filterTypes"
115
- label="Filter by types"
116
- item-title="label"
117
- item-value="value"
118
- :items="visitorSelection"
119
- density="compact"
120
- clearable
121
- multiple
122
- max-width="200"
123
- hide-details
124
- >
42
+ <v-select v-if="activeTab == 'registered'" v-model="filterTypes" label="Filter by types" item-title="label"
43
+ item-value="value" :items="visitorSelection" density="compact" clearable multiple max-width="200"
44
+ hide-details>
125
45
  <template v-slot:selection="{ item, index }">
126
46
  <div class="d-flex align-center text-caption text-nowrap">
127
- <v-chip
128
- v-if="index === 0"
129
- color="error"
130
- :text="filterTypeSelectionLabel()"
131
- size="x-small"
132
- variant="tonal"
133
- class="ml-2"
134
- />
47
+ <v-chip v-if="index === 0" color="error" :text="filterTypeSelectionLabel()" size="x-small"
48
+ variant="tonal" class="ml-2" />
135
49
  </div>
136
50
  </template>
137
51
  </v-select>
@@ -146,9 +60,8 @@
146
60
  </span>
147
61
  <span class="text-capitalize">{{ item?.name }}</span>
148
62
  </span>
149
- <span class="text-grey text-caption" v-if="item?.members?.length > 0"
150
- >( +{{ item?.members?.length }} members)</span
151
- >
63
+ <span class="text-grey text-caption" v-if="item?.members?.length > 0">( +{{ item?.members?.length }}
64
+ members)</span>
152
65
  </template>
153
66
 
154
67
  <template v-slot:item.email="{ value }">
@@ -157,12 +70,7 @@
157
70
 
158
71
  <template v-slot:item.invited-by="{ item }">
159
72
  <span class="d-flex align-center ga-2">
160
- <AvatarMain
161
- v-if="item?.inviterName"
162
- :name="item?.inviterName"
163
- :size="20"
164
- :id="item?._id"
165
- />
73
+ <AvatarMain v-if="item?.inviterName" :name="item?.inviterName" :size="20" :id="item?._id" />
166
74
  <span class="text-capitalize">{{ item?.inviterName ?? "N/A" }}</span>
167
75
  </span>
168
76
  </template>
@@ -172,7 +80,7 @@
172
80
  <v-icon icon="mdi-user" size="15" />
173
81
  <span v-if="item.type === 'contractor'" class="text-capitalize">{{
174
82
  formatCamelCaseToWords(item.contractorType)
175
- }}</span>
83
+ }}</span>
176
84
  <span v-else class="text-capitalize">{{ formatType(item) }}</span>
177
85
  </span>
178
86
  <span class="d-flex align-center ga-2">
@@ -208,52 +116,26 @@
208
116
  <template v-slot:item.checkin-out="{ item }">
209
117
  <v-row no-gutters class="d-flex flex-column py-2">
210
118
  <span class="d-flex align-center ga-2">
211
- <v-icon
212
- icon="mdi-clock-time-four-outline"
213
- color="green"
214
- size="20"
215
- />
119
+ <v-icon icon="mdi-clock-time-four-outline" color="green" size="20" />
216
120
  <span class="text-capitalize">{{
217
121
  UTCToLocalTIme(item.checkIn) || "-"
218
- }}</span>
122
+ }}</span>
219
123
  <span>
220
- <v-icon
221
- v-if="item?.snapshotEntryImage"
222
- size="17"
223
- icon="mdi-image"
224
- @click.stop="handleViewImage(item.snapshotEntryImage)"
225
- />
124
+ <v-icon v-if="item?.snapshotEntryImage" size="17" icon="mdi-image"
125
+ @click.stop="handleViewImage(item.snapshotEntryImage)" />
226
126
  </span>
227
127
  </span>
228
128
 
229
- <span
230
- v-if="
231
- !item.checkOut &&
232
- (item?.status === 'registered' ||
233
- item?.status === 'unregistered') &&
234
- canCheckoutVisitor
235
- "
236
- >
237
- <span
238
- class="d-flex align-center ga-2"
239
- v-bind="menuProps"
240
- style="cursor: pointer"
241
- >
242
- <v-icon
243
- icon="mdi-clock-time-eight-outline"
244
- color="red"
245
- size="20"
246
- />
247
- <v-btn
248
- size="x-small"
249
- class="text-capitalize"
250
- color="red"
251
- text="Checkout"
252
- :loading="
253
- loading.checkingOut && item?._id === selectedVisitorId
254
- "
255
- @click.stop="handleCheckout(item._id)"
256
- />
129
+ <span v-if="
130
+ !item.checkOut &&
131
+ (item?.status === 'registered' ||
132
+ item?.status === 'unregistered') &&
133
+ canCheckoutVisitor
134
+ ">
135
+ <span class="d-flex align-center ga-2" v-bind="menuProps" style="cursor: pointer">
136
+ <v-icon icon="mdi-clock-time-eight-outline" color="red" size="20" />
137
+ <v-btn size="x-small" class="text-capitalize" color="red" text="Checkout" :loading="loading.checkingOut && item?._id === selectedVisitorId
138
+ " @click.stop="handleCheckout(item._id)" />
257
139
  </span>
258
140
  </span>
259
141
  <span v-else class="d-flex align-center ga-2">
@@ -261,96 +143,88 @@
261
143
  <template v-if="item.checkOut">
262
144
  <span class="text-capitalize">{{
263
145
  UTCToLocalTIme(item.checkOut)
264
- }}</span>
146
+ }}</span>
265
147
  <span>
266
- <v-icon
267
- v-if="item?.snapshotExitImage"
268
- size="17"
269
- icon="mdi-image"
270
- @click.stop="handleViewImage(item.snapshotExitImage)"
271
- />
148
+ <v-icon v-if="item?.snapshotExitImage" size="17" icon="mdi-image"
149
+ @click.stop="handleViewImage(item.snapshotExitImage)" />
272
150
  </span>
273
151
  <span v-if="item?.manualCheckout">
274
- <TooltipInfo
275
- text="Manual Checkout"
276
- density="compact"
277
- size="x-small"
278
- />
152
+ <TooltipInfo text="Manual Checkout" density="compact" size="x-small" />
279
153
  </span>
280
154
  </template>
281
155
  <template v-else> <span class="mt-1"> N/A </span> </template>
282
156
  </span>
283
157
 
284
- <div
285
- v-if="showAddPassKeyButton(item)"
286
- class="d-flex flex-wrap ga-1 mt-1"
287
- v-bind="menuProps"
288
- style="cursor: pointer"
289
- >
290
- <v-chip
291
- size="x-small"
292
- variant="tonal"
293
- prepend-icon="mdi-key"
294
- @click.stop="handleOpenAddPassKey(item)"
295
- >Add Pass/Key</v-chip
296
- >
158
+ <div v-if="showAddPassKeyButton(item)" class="d-flex flex-wrap ga-1 mt-1" v-bind="menuProps"
159
+ style="cursor: pointer">
160
+ <v-chip size="x-small" variant="tonal" prepend-icon="mdi-key" @click.stop="handleOpenAddPassKey(item)">Add
161
+ Pass/Key</v-chip>
297
162
  </div>
298
163
 
299
164
  <v-menu :close-on-content-click="true">
300
165
  <template v-slot:activator="{ props: menuProps }">
301
- <div
302
- v-if="
303
- (item.visitorPass?.length ?? 0) > 0 ||
304
- (item.passKeys?.length ?? 0) > 0
305
- "
306
- class="d-flex flex-wrap ga-1 mt-1"
307
- v-bind="menuProps"
308
- style="cursor: pointer"
309
- >
310
- <v-chip
311
- v-for="pass in item.visitorPass"
312
- :key="(pass as any)._id ?? (pass as any).keyId"
313
- prepend-icon="mdi-card-bulleted-outline"
314
- size="x-small"
315
- variant="tonal"
316
- color="blue"
317
- >
166
+ <div v-if="
167
+ (item.visitorPass?.length ?? 0) > 0 ||
168
+ (item.passKeys?.length ?? 0) > 0
169
+ " class="d-flex flex-wrap ga-1 mt-1" v-bind="menuProps" style="cursor: pointer">
170
+ <v-chip v-for="pass in item.visitorPass" :key="(pass as any)._id ?? (pass as any).keyId"
171
+ prepend-icon="mdi-card-bulleted-outline" size="x-small" variant="tonal" color="blue">
318
172
  {{ (pass as any)?.prefixAndName }}
319
173
  </v-chip>
320
- <v-chip
321
- v-for="key in item.passKeys"
322
- :key="(key as any)._id ?? (key as any).keyId"
323
- prepend-icon="mdi-key"
324
- size="x-small"
325
- variant="tonal"
326
- color="orange"
327
- >
174
+ <v-chip v-for="key in item.passKeys" :key="(key as any)._id ?? (key as any).keyId"
175
+ prepend-icon="mdi-key" size="x-small" variant="tonal" color="orange">
328
176
  {{ (key as any)?.prefixAndName }}
329
177
  </v-chip>
330
178
  </div>
331
179
  </template>
332
180
  <v-list density="compact">
181
+ <v-list-item v-if="!item?.checkOut" prepend-icon="mdi-logout" title="Checkout"
182
+ @click.stop="handleCheckout(item._id)" />
183
+ <v-list-item v-if="
184
+ (item.visitorPass?.length ?? 0) > 0 ||
185
+ (item.passKeys?.length ?? 0) > 0
186
+ " prepend-icon="mdi-card-bulleted-outline" :title="item.checkOut ? 'View Pass/Key' : 'Edit Pass/Key'"
187
+ @click.stop="handleOpenEditPassKey(item)" />
188
+ <v-list-item v-if="showAddPassKeyButton(item)" prepend-icon="mdi-plus" title="Add Pass/Key"
189
+ @click.stop="handleOpenAddPassKey(item)" />
190
+ </v-list>
191
+ </v-menu>
192
+
193
+ <!-- NFC Access Cards -->
194
+ <v-menu
195
+ v-if="item.accessCards?.type === 'NFC' && item.accessCards?.cardNo"
196
+ :close-on-content-click="false"
197
+ >
198
+ <template #activator="{ props: nfcMenuProps }">
199
+ <div
200
+ class="d-flex align-center ga-1 mt-1"
201
+ style="cursor: pointer"
202
+ v-bind="nfcMenuProps"
203
+ @click.stop
204
+ >
205
+ <v-icon size="15" icon="mdi-credit-card-outline" color="purple" />
206
+ <v-chip size="x-small" variant="tonal" color="purple">
207
+ {{ item.accessCards.cardNo }}
208
+ <template v-if="(item.cards?.flat().length ?? 0) > 1">
209
+ (+{{ item.cards.flat().length - 1 }})
210
+ </template>
211
+ </v-chip>
212
+ </div>
213
+ </template>
214
+ <v-list density="compact" min-width="200">
215
+ <v-list-subheader>NFC Cards</v-list-subheader>
333
216
  <v-list-item
334
- v-if="!item?.checkOut"
335
- prepend-icon="mdi-logout"
336
- title="Checkout"
337
- @click.stop="handleCheckout(item._id)"
338
- />
339
- <v-list-item
340
- v-if="
341
- (item.visitorPass?.length ?? 0) > 0 ||
342
- (item.passKeys?.length ?? 0) > 0
343
- "
344
- prepend-icon="mdi-card-bulleted-outline"
345
- :title="item.checkOut ? 'View Pass/Key' : 'Edit Pass/Key'"
346
- @click.stop="handleOpenEditPassKey(item)"
347
- />
348
- <v-list-item
349
- v-if="showAddPassKeyButton(item)"
350
- prepend-icon="mdi-plus"
351
- title="Add Pass/Key"
352
- @click.stop="handleOpenAddPassKey(item)"
217
+ prepend-icon="mdi-credit-card-outline"
218
+ :title="item.accessCards.cardNo"
353
219
  />
220
+ <template v-for="(cardGroup, gi) in item.cards" :key="gi">
221
+ <v-list-item
222
+ v-for="card in cardGroup.filter((c: any) => c._id !== item.accessCards._id)"
223
+ :key="card._id"
224
+ prepend-icon="mdi-credit-card-outline"
225
+ :title="card._id"
226
+ />
227
+ </template>
354
228
  </v-list>
355
229
  </v-menu>
356
230
  </v-row>
@@ -369,44 +243,27 @@
369
243
 
370
244
  <span v-if="!item.checkIn && canUpdateVisitor">
371
245
  <span class="d-flex align-center ga-2 cursor-pointer">
372
- <v-icon
373
- icon="mdi-clock-time-eight-outline"
374
- color="success"
375
- size="20"
376
- />
377
- <v-btn
378
- size="x-small"
379
- class="text-capitalize"
380
- color="success"
381
- text="Checkin"
382
- @click.stop="handleCheckin(item)"
383
- />
246
+ <v-icon icon="mdi-clock-time-eight-outline" color="success" size="20" />
247
+ <v-btn size="x-small" class="text-capitalize" color="success" text="Checkin"
248
+ @click.stop="handleCheckin(item)" />
384
249
  </span>
385
250
  </span>
386
251
  </v-row>
387
252
  </template>
388
253
 
389
254
  <template v-slot:item.status="{ item }">
390
- <v-card
391
- v-if="item?.overnightParking?.status"
392
- size="small"
255
+ <v-card v-if="item?.overnightParking?.status" size="small"
393
256
  class="rounded-xl text-capitalize text-center elevation-0 py-1 px-2"
394
257
  :color="getOvernightParkingRequestStatusColor(item?.overnightParking?.status as string)"
395
- style="max-width: 150px; margin: auto"
396
- >
258
+ style="max-width: 150px; margin: auto">
397
259
  {{ item?.overnightParking?.status }}
398
260
  </v-card>
399
261
  <span v-else> N/A </span>
400
262
  </template>
401
263
 
402
264
  <template v-slot:item.action="{ item }">
403
- <v-btn
404
- v-if="activeTab === 'unregistered' && canAddVisitor"
405
- size="small"
406
- color="primary"
407
- text="Register"
408
- @click.stop="handleRegistrationUnregisteredVisitor(item)"
409
- />
265
+ <v-btn v-if="activeTab === 'unregistered' && canAddVisitor" size="small" color="primary" text="Register"
266
+ @click.stop="handleRegistrationUnregisteredVisitor(item)" />
410
267
  <v-menu v-else-if="activeTab === 'overnight-parking'">
411
268
  <template #activator="{ props }">
412
269
  <v-avatar v-bind="props" class="rounded-xl border-md">
@@ -415,20 +272,17 @@
415
272
  </template>
416
273
 
417
274
  <v-card>
418
- <v-list-item
419
- v-if="
420
- !overNightParkingListActions[0].disabled ||
421
- !['approved', 'rejected'].includes(
422
- item?.overnightParking?.status
423
- )
424
- "
425
- @click.stop="
275
+ <v-list-item v-if="
276
+ !overNightParkingListActions[0].disabled ||
277
+ !['approved', 'rejected'].includes(
278
+ item?.overnightParking?.status
279
+ )
280
+ " @click.stop="
426
281
  openApproveRejectOverNightParkingRequestDialog(
427
282
  item,
428
283
  overNightParkingListActions[0].status
429
284
  )
430
- "
431
- >
285
+ ">
432
286
  <template #title>
433
287
  <span class="text-caption">
434
288
  {{ overNightParkingListActions[0].text }}
@@ -436,36 +290,30 @@
436
290
  </template>
437
291
  </v-list-item>
438
292
  <v-divider />
439
- <v-list-item
440
- v-if="
441
- !overNightParkingListActions[1].disabled ||
442
- !['approved', 'rejected'].includes(
443
- item?.overnightParking?.status
444
- )
445
- "
446
- @click="
293
+ <v-list-item v-if="
294
+ !overNightParkingListActions[1].disabled ||
295
+ !['approved', 'rejected'].includes(
296
+ item?.overnightParking?.status
297
+ )
298
+ " @click="
447
299
  openApproveRejectOverNightParkingRequestDialog(
448
300
  item,
449
301
  overNightParkingListActions[1].status
450
302
  )
451
- "
452
- >
303
+ ">
453
304
  <template #title>
454
305
  <span class="text-caption">
455
306
  {{ overNightParkingListActions[1].text }}
456
307
  </span>
457
308
  </template>
458
309
  </v-list-item>
459
- <v-list-item
460
- v-if="item?.overnightParking?.remarks"
461
- @click="
462
- openApproveRejectOverNightParkingRequestDialog(
463
- item,
464
- overNightParkingListActions[2].status,
465
- item?.overnightParking?.remarks
466
- )
467
- "
468
- >
310
+ <v-list-item v-if="item?.overnightParking?.remarks" @click="
311
+ openApproveRejectOverNightParkingRequestDialog(
312
+ item,
313
+ overNightParkingListActions[2].status,
314
+ item?.overnightParking?.remarks
315
+ )
316
+ ">
469
317
  <template #title>
470
318
  <span class="text-caption">
471
319
  {{ overNightParkingListActions[2].text }}
@@ -479,147 +327,78 @@
479
327
 
480
328
  <template v-slot:item.checkInRemarks="{ item }">
481
329
  <span>
482
- <v-btn
483
- variant="text"
484
- color="blue-darken-2"
485
- density="compact"
486
- size="small"
487
- @click.stop="handleOpenRemarks(item, 'checkIn')"
488
- >{{ item.checkInRemarks ? "View Remarks" : "Add Remarks" }}</v-btn
489
- >
330
+ <v-btn variant="text" color="blue-darken-2" density="compact" size="small"
331
+ @click.stop="handleOpenRemarks(item, 'checkIn')">{{ item.checkInRemarks ? "View Remarks" : "Add Remarks"
332
+ }}</v-btn>
490
333
  </span>
491
334
  </template>
492
335
  <template v-slot:item.checkOutRemarks="{ item }">
493
336
  <span>
494
- <v-btn
495
- variant="text"
496
- color="blue-darken-2"
497
- density="compact"
498
- size="small"
499
- @click.stop="handleOpenRemarks(item, 'checkOut')"
500
- >{{ item.checkOutRemarks ? "View Remarks" : "Add Remarks" }}</v-btn
501
- >
337
+ <v-btn variant="text" color="blue-darken-2" density="compact" size="small"
338
+ @click.stop="handleOpenRemarks(item, 'checkOut')">{{ item.checkOutRemarks ? "View Remarks" : "Add Remarks"
339
+ }}</v-btn>
502
340
  </span>
503
341
  </template>
504
342
  </TableMain>
505
343
 
506
344
  <v-dialog v-model="dialog.showSelection" width="450" persistent>
507
- <VisitorFormSelection
508
- :mode="mode"
509
- @cancel="dialog.showSelection = false"
510
- @select="handleSelectVisitorType"
511
- />
345
+ <VisitorFormSelection :mode="mode" @cancel="dialog.showSelection = false" @select="handleSelectVisitorType" />
512
346
  </v-dialog>
513
347
 
514
- <v-dialog
515
- v-model="dialog.showForm"
516
- v-if="activeVisitorFormType"
517
- width="450"
518
- persistent
519
- >
520
- <VisitorForm
521
- :mode="mode"
522
- :org="orgId"
523
- :site="siteId"
524
- :visitor-data="selectedVisitorDataObject"
525
- :current-user="currentUser._id"
526
- :type="activeVisitorFormType"
527
- @back="handleClickBack"
528
- @done="handleVisitorFormDone"
529
- @done:more="handleVisitorFormCreateMore"
530
- @close:all="handleCloseAll"
531
- />
348
+ <v-dialog v-model="dialog.showForm" v-if="activeVisitorFormType" width="450" persistent>
349
+ <VisitorForm :mode="mode" :org="orgId" :site="siteId" :visitor-data="selectedVisitorDataObject"
350
+ :current-user="currentUser._id" :type="activeVisitorFormType" @back="handleClickBack"
351
+ @done="handleVisitorFormDone" @done:more="handleVisitorFormCreateMore" @close:all="handleCloseAll" />
532
352
  </v-dialog>
533
353
 
534
354
  <v-dialog v-model="dialog.viewVisitor" width="450" persistent>
535
- <VehicleUpdateMoreAction
536
- title="Preview"
537
- :can-update="false"
538
- :can-delete="false"
539
- @close="dialog.viewVisitor = false"
540
- edit-button-label="Edit Visitor"
541
- >
355
+ <VehicleUpdateMoreAction title="Preview" :can-update="false" :can-delete="false"
356
+ @close="dialog.viewVisitor = false" edit-button-label="Edit Visitor">
542
357
  <template v-slot:content>
543
358
  <v-row no-gutters class="mb-4">
544
359
  <v-col v-for="(label, key) in formattedFields" :key="key" cols="12">
545
- <span
546
- v-if="
547
- key === 'checkIn' &&
548
- !selectedVisitorObject[key] &&
549
- canUpdateVisitor
550
- "
551
- class="d-flex align-center"
552
- >
360
+ <span v-if="
361
+ key === 'checkIn' &&
362
+ !selectedVisitorObject[key] &&
363
+ canUpdateVisitor
364
+ " class="d-flex align-center">
553
365
  <strong>{{ label }}:</strong>
554
- <v-btn
555
- size="x-small"
556
- class="ml-3 text-capitalize"
557
- color="success"
558
- text="Checkin"
366
+ <v-btn size="x-small" class="ml-3 text-capitalize" color="success" text="Checkin"
559
367
  :disabled="isVisitorDataFromScannedQRCodeCheckingInOut"
560
368
  @click="handleCheckin(selectedVisitorDataObject)"
561
- :loading="isVisitorDataFromScannedQRCodeCheckingInOut"
562
- />
369
+ :loading="isVisitorDataFromScannedQRCodeCheckingInOut" />
563
370
  </span>
564
- <span
565
- v-if="
566
- key === 'checkOut' &&
567
- selectedVisitorObject['checkIn'] &&
568
- !selectedVisitorObject[key] &&
569
- canCheckoutVisitor
570
- "
571
- class="d-flex align-center"
572
- >
371
+ <span v-if="
372
+ key === 'checkOut' &&
373
+ selectedVisitorObject['checkIn'] &&
374
+ !selectedVisitorObject[key] &&
375
+ canCheckoutVisitor
376
+ " class="d-flex align-center">
573
377
  <strong>{{ label }}:</strong>
574
- <v-btn
575
- size="x-small"
576
- class="ml-3 text-capitalize"
577
- color="red"
578
- text="Checkout"
579
- :disabled="loading.checkingOut"
580
- @click="handleCheckout(selectedVisitorId as string)"
581
- />
378
+ <v-btn size="x-small" class="ml-3 text-capitalize" color="red" text="Checkout"
379
+ :disabled="loading.checkingOut" @click="handleCheckout(selectedVisitorId as string)" />
582
380
  </span>
583
381
 
584
- <span
585
- v-else-if="key === 'nric' && selectedVisitorObject['nric']"
586
- class="d-flex align-center"
587
- >
382
+ <span v-else-if="key === 'nric' && selectedVisitorObject['nric']" class="d-flex align-center">
588
383
  <strong>{{ label }}:</strong>
589
384
  <span v-tooltip:top="selectedVisitorObject[key]" class="ml-2">{{
590
385
  maskNRIC(selectedVisitorObject[key])
591
- }}</span>
386
+ }}</span>
592
387
  </span>
593
- <span
594
- v-else-if="
595
- key === 'attachments' &&
596
- selectedVisitorObject?.[key]?.length > 0
597
- "
598
- class="d-flex flex-column"
599
- >
388
+ <span v-else-if="
389
+ key === 'attachments' &&
390
+ selectedVisitorObject?.[key]?.length > 0
391
+ " class="d-flex flex-column">
600
392
  <strong class="w-full">{{ label }}:</strong>
601
393
  <div class="d-flex flex-wrap ga-2">
602
- <AttachmentsViewer
603
- :files="
604
- mappedAttachments(selectedVisitorObject.attachments)
605
- "
606
- title=""
607
- show-file-type-title
608
- />
394
+ <AttachmentsViewer :files="mappedAttachments(selectedVisitorObject.attachments)
395
+ " title="" show-file-type-title />
609
396
  </div>
610
397
  </span>
611
398
 
612
- <span
613
- v-else-if="selectedVisitorObject[key]"
614
- class="d-flex ga-3 align-start"
615
- ><strong>{{ label }}:</strong>
399
+ <span v-else-if="selectedVisitorObject[key]" class="d-flex ga-3 align-start"><strong>{{ label }}:</strong>
616
400
  {{ formatValues(key, selectedVisitorObject[key]) }}
617
- <TooltipInfo
618
- v-if="key === 'checkOut'"
619
- text="Manual Checkout"
620
- density="compact"
621
- size="x-small"
622
- />
401
+ <TooltipInfo v-if="key === 'checkOut'" text="Manual Checkout" density="compact" size="x-small" />
623
402
  </span>
624
403
  </v-col>
625
404
  </v-row>
@@ -631,11 +410,7 @@
631
410
  <v-card>
632
411
  <v-card-title class="d-flex justify-space-between align-center">
633
412
  <span>Snapshot</span>
634
- <v-btn
635
- icon="mdi-close"
636
- variant="text"
637
- @click="dialog.snapshotImage = false"
638
- />
413
+ <v-btn icon="mdi-close" variant="text" @click="dialog.snapshotImage = false" />
639
414
  </v-card-title>
640
415
  <v-card-text class="pa-2 d-flex justify-center">
641
416
  <v-img :src="snapshotImageUrl" max-height="600" contain />
@@ -645,51 +420,25 @@
645
420
 
646
421
  <v-dialog v-model="dialog.remarks" max-width="450" persistent>
647
422
  <v-card>
648
- <v-card-title
649
- class="d-flex justify-space-between align-center pt-4 px-4"
650
- >
423
+ <v-card-title class="d-flex justify-space-between align-center pt-4 px-4">
651
424
  <span>{{
652
425
  remarksType === "checkIn" ? "Check-In Remarks" : "Check-Out Remarks"
653
- }}</span>
654
- <v-btn
655
- icon="mdi-close"
656
- variant="text"
657
- @click="dialog.remarks = false"
658
- />
426
+ }}</span>
427
+ <v-btn icon="mdi-close" variant="text" @click="dialog.remarks = false" />
659
428
  </v-card-title>
660
429
  <v-card-text class="px-4 pb-2">
661
- <v-textarea
662
- v-model="remarksInput"
663
- label="Remarks"
664
- rows="4"
665
- auto-grow
666
- variant="outlined"
667
- :readonly="remarksViewOnly"
668
- />
430
+ <v-textarea v-model="remarksInput" label="Remarks" rows="4" auto-grow variant="outlined"
431
+ :readonly="remarksViewOnly" />
669
432
  </v-card-text>
670
433
  <v-toolbar class="pa-0" density="compact">
671
434
  <v-row no-gutters>
672
435
  <v-col cols="6">
673
- <v-btn
674
- variant="text"
675
- block
676
- :disabled="loading.savingRemarks"
677
- @click="dialog.remarks = false"
678
- >Cancel</v-btn
679
- >
436
+ <v-btn variant="text" block :disabled="loading.savingRemarks"
437
+ @click="dialog.remarks = false">Cancel</v-btn>
680
438
  </v-col>
681
439
  <v-col cols="6">
682
- <v-btn
683
- color="primary"
684
- variant="flat"
685
- height="48"
686
- rounded="0"
687
- block
688
- :loading="loading.savingRemarks"
689
- :disabled="!remarksInput.trim()"
690
- @click="handleSaveRemarks"
691
- >Save</v-btn
692
- >
440
+ <v-btn color="primary" variant="flat" height="48" rounded="0" block :loading="loading.savingRemarks"
441
+ :disabled="!remarksInput.trim()" @click="handleSaveRemarks">Save</v-btn>
693
442
  </v-col>
694
443
  </v-row>
695
444
  </v-toolbar>
@@ -699,16 +448,9 @@
699
448
  <v-dialog v-model="dialog.returnPassesKeys" max-width="450" persistent>
700
449
  <v-card>
701
450
  <v-toolbar density="compact" color="">
702
- <v-row
703
- no-gutters
704
- class="d-flex fill-height justify-space-between align-center px-4"
705
- >
451
+ <v-row no-gutters class="d-flex fill-height justify-space-between align-center px-4">
706
452
  <span class="font-weight-bold">Return Passes &amp; Keys</span>
707
- <v-btn
708
- icon="mdi-close"
709
- variant="text"
710
- @click="dialog.returnPassesKeys = false"
711
- />
453
+ <v-btn icon="mdi-close" variant="text" @click="dialog.returnPassesKeys = false" />
712
454
  </v-row>
713
455
  </v-toolbar>
714
456
  <v-card-text class="px-4 pb-2">
@@ -718,134 +460,55 @@
718
460
 
719
461
  <div>
720
462
  <InputLabel class="text-capitalize" title="Full Name" />
721
- <v-text-field
722
- v-model="selectedVisitorObject.name"
723
- density="comfortable"
724
- readonly
725
- />
463
+ <v-text-field v-model="selectedVisitorObject.name" density="comfortable" readonly />
726
464
  </div>
727
465
 
728
466
  <div>
729
467
  <InputLabel class="text-capitalize" title="Location" />
730
- <v-text-field
731
- v-model="selectedVisitorObject.location"
732
- density="comfortable"
733
- readonly
734
- />
468
+ <v-text-field v-model="selectedVisitorObject.location" density="comfortable" readonly />
735
469
  </div>
736
470
 
737
471
  <div v-if="passReturnStatuses.length > 0" class="mb-2">
738
472
  <p class="text-caption text-medium-emphasis mb-1">Passes</p>
739
- <v-row
740
- no-gutters
741
- v-for="pass in passReturnStatuses"
742
- :key="(pass as any)._id ?? (pass as any).keyId"
743
- class="d-flex flex-wrap justify-space-between align-center ga-5 mb-2"
744
- >
745
- <v-chip
746
- prepend-icon="mdi-card-bulleted-outline"
747
- size="small"
748
- variant="tonal"
749
- color="blue"
750
- >
473
+ <v-row no-gutters v-for="pass in passReturnStatuses" :key="(pass as any)._id ?? (pass as any).keyId"
474
+ class="d-flex flex-wrap justify-space-between align-center ga-5 mb-2">
475
+ <v-chip prepend-icon="mdi-card-bulleted-outline" size="small" variant="tonal" color="blue">
751
476
  {{ (pass as any)?.prefixAndName }}
752
477
  </v-chip>
753
- <v-select
754
- hide-details
755
- max-width="200px"
756
- density="compact"
757
- :items="passStatusOptions"
758
- item-title="label"
759
- item-value="value"
760
- v-model="pass.status"
761
- :disabled="selectedVisitorObject.checkOut"
762
- ></v-select>
763
- <v-textarea
764
- v-if="pass.status === 'Lost' || pass.status === 'Damaged'"
765
- no-resize
766
- rows="3"
767
- class="w-100"
768
- density="compact"
769
- v-model="pass.remarks"
770
- :disabled="selectedVisitorObject.checkOut"
771
- ></v-textarea>
478
+ <v-select hide-details max-width="200px" density="compact" :items="passStatusOptions" item-title="label"
479
+ item-value="value" v-model="pass.status" :disabled="selectedVisitorObject.checkOut"></v-select>
480
+ <v-textarea v-if="pass.status === 'Lost' || pass.status === 'Damaged'" no-resize rows="3" class="w-100"
481
+ density="compact" v-model="pass.remarks" :disabled="selectedVisitorObject.checkOut"></v-textarea>
772
482
  </v-row>
773
483
  </div>
774
484
  <div v-if="keyReturnStatuses.length > 0" class="mb-2">
775
485
  <p class="text-caption text-medium-emphasis mb-1">Keys</p>
776
- <v-row
777
- no-gutters
778
- v-for="key in keyReturnStatuses"
779
- :key="(key as any)._id ?? (key as any).keyId"
780
- class="d-flex flex-wrap justify-space-between align-center ga-5 mb-2"
781
- >
782
- <v-chip
783
- prepend-icon="mdi-key"
784
- size="small"
785
- variant="tonal"
786
- color="orange"
787
- >
486
+ <v-row no-gutters v-for="key in keyReturnStatuses" :key="(key as any)._id ?? (key as any).keyId"
487
+ class="d-flex flex-wrap justify-space-between align-center ga-5 mb-2">
488
+ <v-chip prepend-icon="mdi-key" size="small" variant="tonal" color="orange">
788
489
  {{ (key as any)?.prefixAndName }}
789
490
  </v-chip>
790
- <v-select
791
- hide-details
792
- max-width="200px"
793
- density="compact"
794
- :items="passStatusOptions"
795
- item-title="label"
796
- item-value="value"
797
- v-model="key.status"
798
- :disabled="selectedVisitorObject.checkOut"
799
- ></v-select>
800
- <v-textarea
801
- v-if="key.status === 'Lost' || key.status === 'Damaged'"
802
- no-resize
803
- rows="3"
804
- class="w-100"
805
- density="compact"
806
- v-model="key.remarks"
807
- :disabled="selectedVisitorObject.checkOut"
808
- ></v-textarea>
491
+ <v-select hide-details max-width="200px" density="compact" :items="passStatusOptions" item-title="label"
492
+ item-value="value" v-model="key.status" :disabled="selectedVisitorObject.checkOut"></v-select>
493
+ <v-textarea v-if="key.status === 'Lost' || key.status === 'Damaged'" no-resize rows="3" class="w-100"
494
+ density="compact" v-model="key.remarks" :disabled="selectedVisitorObject.checkOut"></v-textarea>
809
495
  </v-row>
810
496
  </div>
811
497
 
812
498
  <v-row no-gutters class="my-5">
813
- <v-btn
814
- variant="flat"
815
- color="blue"
816
- density="comfortable"
817
- class="text-capitalize"
818
- :disabled="selectedVisitorObject.checkOut"
819
- :loading="loading.updatingPassKeys"
820
- @click.stop="handleUpdatePassKeys"
821
- >Update Pass/Keys</v-btn
822
- >
499
+ <v-btn variant="flat" color="blue" density="comfortable" class="text-capitalize"
500
+ :disabled="selectedVisitorObject.checkOut" :loading="loading.updatingPassKeys"
501
+ @click.stop="handleUpdatePassKeys">Update Pass/Keys</v-btn>
823
502
  </v-row>
824
503
  </v-card-text>
825
504
  <v-toolbar class="pa-0" density="compact">
826
505
  <v-row no-gutters>
827
506
  <v-col cols="6">
828
- <v-btn
829
- variant="text"
830
- block
831
- @click="dialog.returnPassesKeys = false"
832
- >Close</v-btn
833
- >
507
+ <v-btn variant="text" block @click="dialog.returnPassesKeys = false">Close</v-btn>
834
508
  </v-col>
835
509
  <v-col cols="6">
836
- <v-btn
837
- color="red"
838
- variant="flat"
839
- height="48"
840
- rounded="0"
841
- block
842
- :loading="loading.checkingOut"
843
- :disabled="
844
- !canConfirmCheckout || selectedVisitorObject.checkOut
845
- "
846
- @click="proceedCheckout"
847
- >Confirm Checkout</v-btn
848
- >
510
+ <v-btn color="red" variant="flat" height="48" rounded="0" block :loading="loading.checkingOut" :disabled="!canConfirmCheckout || selectedVisitorObject.checkOut
511
+ " @click="proceedCheckout">Confirm Checkout</v-btn>
849
512
  </v-col>
850
513
  </v-row>
851
514
  </v-toolbar>
@@ -853,87 +516,50 @@
853
516
  </v-dialog>
854
517
 
855
518
  <v-dialog v-model="dialog.addPassKey" width="450" persistent>
856
- <AddPassKeyToVisitor
857
- mode="add"
858
- :visitor="selectedVisitorDataObject"
859
- :site="siteId"
860
- @close="dialog.addPassKey = false"
861
- @done="
519
+ <AddPassKeyToVisitor mode="add" :visitor="selectedVisitorDataObject" :site="siteId"
520
+ @close="dialog.addPassKey = false" @done="
862
521
  () => {
863
522
  dialog.addPassKey = false;
864
523
  getVisitorRefresh();
865
524
  }
866
- "
867
- />
525
+ " />
868
526
  </v-dialog>
869
527
 
870
528
  <v-dialog v-model="dialog.editPassKey" width="450" persistent>
871
- <AddPassKeyToVisitor
872
- mode="edit"
873
- :visitor="selectedVisitorDataObject"
874
- :site="siteId"
875
- @close="dialog.editPassKey = false"
876
- @done="
529
+ <AddPassKeyToVisitor mode="edit" :visitor="selectedVisitorDataObject" :site="siteId"
530
+ @close="dialog.editPassKey = false" @done="
877
531
  () => {
878
532
  dialog.editPassKey = false;
879
533
  getVisitorRefresh();
880
534
  }
881
- "
882
- />
535
+ " />
883
536
  </v-dialog>
884
537
 
885
- <ScanVisitorQRCode
886
- :dialog="dialog.scanVisitorQRCode"
887
- :site="siteId"
888
- @open-visitor-data-from-scanned-qr-code-dialog="
889
- handleShowVisitorDataFromScannedQRCodeDialog
890
- "
891
- @close-dialog="dialog.scanVisitorQRCode = false"
892
- />
893
-
894
- <v-dialog
895
- v-model="dialog.showVisitorDataFromScannedQRCode"
896
- width="450"
897
- persistent
898
- >
899
- <VisitorDataFromScannedQRCodeForm
900
- :site="siteId"
901
- :visitor-data="visitorDataFromScannedQRCode"
538
+ <ScanVisitorQRCode :dialog="dialog.scanVisitorQRCode" :site="siteId" @open-visitor-data-from-scanned-qr-code-dialog="
539
+ handleShowVisitorDataFromScannedQRCodeDialog
540
+ " @close-dialog="dialog.scanVisitorQRCode = false" />
541
+
542
+ <v-dialog v-model="dialog.showVisitorDataFromScannedQRCode" width="450" persistent>
543
+ <VisitorDataFromScannedQRCodeForm :site="siteId" :visitor-data="visitorDataFromScannedQRCode"
902
544
  @check-in-out="handleVisitorDataFromScannedQRCodeCheckInOut"
903
545
  :processing="isVisitorDataFromScannedQRCodeCheckingInOut"
904
- @close="handleCloseVisitorDataFromScannedQRCodeDialog"
905
- />
546
+ @close="handleCloseVisitorDataFromScannedQRCodeDialog" />
906
547
  </v-dialog>
907
548
 
908
- <v-dialog
909
- v-model="dialog.approveRejectOvernightParkingRequestDialog"
910
- transition="dialog-bottom-transition"
911
- persistent
912
- width="60vh"
913
- >
549
+ <v-dialog v-model="dialog.approveRejectOvernightParkingRequestDialog" transition="dialog-bottom-transition"
550
+ persistent width="60vh">
914
551
  <v-card>
915
552
  <v-toolbar density="compact">
916
- <v-row
917
- no-gutters
918
- class="d-flex fill-height justify-space-between align-center px-4"
919
- >
553
+ <v-row no-gutters class="d-flex fill-height justify-space-between align-center px-4">
920
554
  <span class="font-weight-bold"> Overnight Parking Request </span>
921
- <v-btn
922
- icon="mdi-close"
923
- variant="text"
924
- @click="dialog.approveRejectOvernightParkingRequestDialog = false"
925
- />
555
+ <v-btn icon="mdi-close" variant="text" @click="dialog.approveRejectOvernightParkingRequestDialog = false" />
926
556
  </v-row>
927
557
  </v-toolbar>
928
558
  <v-card-text class="px-4 pb-6">
929
559
  <v-row no-gutters justify="center" align-content="center">
930
- <v-col
931
- v-if="
932
- approveRejectOvernightParkingRequestDialog.status !== 'remarks'
933
- "
934
- cols="12"
935
- class="text-h6 text-center"
936
- >
560
+ <v-col v-if="
561
+ approveRejectOvernightParkingRequestDialog.status !== 'remarks'
562
+ " cols="12" class="text-h6 text-center">
937
563
  {{
938
564
  `Are you sure you want to ${approveRejectOvernightParkingRequestDialog.text} the visitor's overnight
939
565
  parking
@@ -942,58 +568,28 @@
942
568
  </v-col>
943
569
 
944
570
  <v-col cols="12" md="8" class="mt-4">
945
- <v-textarea
946
- v-model="overNightParkingRequestApproveRejectRemarks"
947
- label="Remarks"
948
- placeholder="Enter remarks"
949
- outlined
950
- rows="3"
951
- clearable
952
- :hide-details="
953
- approveRejectOvernightParkingRequestDialog.status ===
571
+ <v-textarea v-model="overNightParkingRequestApproveRejectRemarks" label="Remarks"
572
+ placeholder="Enter remarks" outlined rows="3" clearable :hide-details="approveRejectOvernightParkingRequestDialog.status ===
954
573
  'remarks'
955
- "
956
- :readonly="
957
- approveRejectOvernightParkingRequestDialog.status ===
574
+ " :readonly="approveRejectOvernightParkingRequestDialog.status ===
958
575
  'remarks'
959
- "
960
- />
576
+ " />
961
577
  </v-col>
962
578
  </v-row>
963
579
  </v-card-text>
964
- <v-toolbar
965
- v-if="approveRejectOvernightParkingRequestDialog.status !== 'remarks'"
966
- class="pa-0"
967
- density="compact"
968
- >
580
+ <v-toolbar v-if="approveRejectOvernightParkingRequestDialog.status !== 'remarks'" class="pa-0"
581
+ density="compact">
969
582
  <v-row no-gutters>
970
583
  <v-col cols="6">
971
- <v-btn
972
- text="No"
973
- color="grey-lighten-3"
974
- variant="flat"
975
- height="48"
976
- tile
977
- block
584
+ <v-btn text="No" color="grey-lighten-3" variant="flat" height="48" tile block
978
585
  :disabled="isApprovingRejectingOvernightParkingRequest"
979
- @click="closeApproveRejectOvernightParkingDialog"
980
- />
586
+ @click="closeApproveRejectOvernightParkingDialog" />
981
587
  </v-col>
982
588
  <v-col cols="6">
983
- <v-btn
984
- text="Yes"
985
- color="success"
986
- variant="flat"
987
- height="48"
988
- tile
989
- block
990
- :disabled="
991
- !overNightParkingRequestApproveRejectRemarks ||
992
- isApprovingRejectingOvernightParkingRequest
993
- "
994
- @click="updateOvernightParkingRequestStatus"
995
- :loading="isApprovingRejectingOvernightParkingRequest"
996
- />
589
+ <v-btn text="Yes" color="success" variant="flat" height="48" tile block :disabled="!overNightParkingRequestApproveRejectRemarks ||
590
+ isApprovingRejectingOvernightParkingRequest
591
+ " @click="updateOvernightParkingRequestStatus"
592
+ :loading="isApprovingRejectingOvernightParkingRequest" />
997
593
  </v-col>
998
594
  </v-row>
999
595
  </v-toolbar>
@@ -1039,6 +635,18 @@ const props = defineProps({
1039
635
  const { authenticate, currentUser } = useLocalAuth();
1040
636
  authenticate();
1041
637
 
638
+ const route = useRoute();
639
+ const router = useRouter();
640
+ const { org: orgId, site: siteId } = route.params as {
641
+ org: string;
642
+ site: string;
643
+ };
644
+
645
+ const { enableUnregistered } = useANPRSettings(siteId);
646
+ const enableUnregisteredTab = computed(() => enableUnregistered.value);
647
+
648
+
649
+
1042
650
  const {
1043
651
  getVisitors,
1044
652
  visitorSelection,
@@ -1058,12 +666,6 @@ const { formatLocation } = useSecurityUtils();
1058
666
  const { getFileUrlAnpr } = useFile();
1059
667
  // const { status: visitorStatus, search } = useRoute().query as { status: string, search: string};
1060
668
 
1061
- const route = useRoute();
1062
- const router = useRouter();
1063
- const { org: orgId, site: siteId } = route.params as {
1064
- org: string;
1065
- site: string;
1066
- };
1067
669
  const routeName = route.name;
1068
670
 
1069
671
  const items = ref<Array<Record<string, any>>>([]);
@@ -1167,13 +769,21 @@ const headers = computed(() => {
1167
769
  return list;
1168
770
  });
1169
771
 
1170
- const tabOptions = [
1171
- { name: "Registered", value: "registered" },
1172
- { name: "Unregistered", value: "unregistered" },
1173
- { name: "Guests", value: "guests" },
1174
- { name: "Resident Transactions", value: "resident-transactions" },
1175
- { name: "Overnight Parking", value: "overnight-parking" },
1176
- ];
772
+ const tabOptions = computed(() => {
773
+ const baseTabs = [
774
+ { name: "Registered", value: "registered" },
775
+ ...(enableUnregisteredTab.value
776
+ ? [{ name: "Unregistered", value: "unregistered" }]
777
+ : []
778
+ ),
779
+ { name: "Guests", value: "guests" },
780
+ { name: "Resident Transactions", value: "resident-transactions" },
781
+ { name: "Overnight Parking", value: "overnight-parking" },
782
+ ];
783
+
784
+
785
+ return baseTabs;
786
+ });
1177
787
 
1178
788
  function getOvernightParkingRequestStatusColor(status: string) {
1179
789
  switch (status) {
@@ -1322,7 +932,7 @@ const passStatusOptions = [
1322
932
  function toRoute(tab: any) {
1323
933
  items.value = [];
1324
934
 
1325
- const obj = tabOptions.find((x) => x.value === tab);
935
+ const obj = tabOptions.value.find((x) => x.value === tab);
1326
936
  if (!obj) return;
1327
937
  page.value = 1;
1328
938
  getVisitorRefresh();
@@ -1605,7 +1215,7 @@ function handleRegistrationUnregisteredVisitor(item: Partial<TVisitor>) {
1605
1215
  dialog.showSelection = true;
1606
1216
  mode.value = "register";
1607
1217
 
1608
- if(!selectedVisitorDataObject.value){
1218
+ if (!selectedVisitorDataObject.value) {
1609
1219
  getVisitorRefresh();
1610
1220
  }
1611
1221
  }
@@ -1856,12 +1466,10 @@ async function handleDownloadPDFReport() {
1856
1466
  if (displayNotCheckedOut.value) queryParams.append("checkedOut", "true");
1857
1467
 
1858
1468
  const queryString = queryParams.toString();
1859
- const url = `/${route.params.org}/${siteId}/visitor-management/preview${
1860
- queryString ? "?" + queryString : ""
1861
- }`;
1862
- const title = `Visitor-Report-${siteId}-${
1863
- new Date().toISOString().split("T")[0]
1864
- }`;
1469
+ const url = `/${route.params.org}/${siteId}/visitor-management/preview${queryString ? "?" + queryString : ""
1470
+ }`;
1471
+ const title = `Visitor-Report-${siteId}-${new Date().toISOString().split("T")[0]
1472
+ }`;
1865
1473
 
1866
1474
  await downloadPDF({ url, title, orientation: "P", appKey: "SECURITY" });
1867
1475
  showMessage("PDF report downloaded successfully!", "success");
@@ -2021,7 +1629,12 @@ watch([searchInput, dateFrom, dateTo, filterTypes, activeTab], () => {
2021
1629
  });
2022
1630
 
2023
1631
  onMounted(() => {
2024
- activeTab.value = (route.query.tab as string) || "unregistered";
1632
+ const requestedTab = (route.query.tab as string) || "registered";
1633
+ activeTab.value = enableUnregisteredTab.value
1634
+ ? requestedTab
1635
+ : requestedTab === "unregistered"
1636
+ ? "registered"
1637
+ : requestedTab;
2025
1638
  searchInput.value = (route.query.search as string) || "";
2026
1639
  if (route.query.dateFrom) {
2027
1640
  dateFrom.value = normalizeDateOnly(route.query.dateFrom as string);
@@ -2042,28 +1655,38 @@ onMounted(() => {
2042
1655
  const { socketUnregisteredVisitorTrigger, visitorSocketData } =
2043
1656
  useVisitorSocket();
2044
1657
 
2045
- watchEffect(async () => {
2046
- if (visitorSocketData.value && visitorSocketData.value.reload && activeTab.value === "unregistered") {
2047
- await getVisitorRefresh();
2048
- visitorSocketData.value = null;
2049
- socketUnregisteredVisitorTrigger.value = false;
1658
+ watch(
1659
+ enableUnregisteredTab,
1660
+ (enabled) => {
1661
+ if (!enabled && activeTab.value === "unregistered") {
1662
+ activeTab.value = "registered";
2050
1663
  }
1664
+ },
1665
+ { immediate: true }
1666
+ );
2051
1667
 
2052
- if(visitorSocketData.value && visitorSocketData.value.plateNumber && socketUnregisteredVisitorTrigger.value && activeTab.value === "unregistered" && dialog.showSelection === false) {
2053
- // await getVisitorRefresh();
2054
- // visitorSocketData.value = null;
2055
- // socketUnregisteredVisitorTrigger.value = false;
2056
- setTimeout(async() => {
2057
- const { _id } = visitorSocketData.value;
2058
- await handleRegistrationUnregisteredVisitor({ _id });
2059
- socketUnregisteredVisitorTrigger.value = false;
2060
-
2061
- setTimeout(() => {
2062
- visitorSocketData.value = null;
2063
- }, 1000)
1668
+ watchEffect(async () => {
1669
+ if (visitorSocketData.value && visitorSocketData.value.reload && activeTab.value === "unregistered") {
1670
+ await getVisitorRefresh();
1671
+ visitorSocketData.value = null;
1672
+ socketUnregisteredVisitorTrigger.value = false;
1673
+ }
1674
+
1675
+ if (visitorSocketData.value && visitorSocketData.value.plateNumber && socketUnregisteredVisitorTrigger.value && activeTab.value === "unregistered" && dialog.showSelection === false) {
1676
+ // await getVisitorRefresh();
1677
+ // visitorSocketData.value = null;
1678
+ // socketUnregisteredVisitorTrigger.value = false;
1679
+ setTimeout(async () => {
1680
+ const { _id } = visitorSocketData.value;
1681
+ await handleRegistrationUnregisteredVisitor({ _id });
1682
+ socketUnregisteredVisitorTrigger.value = false;
1683
+
1684
+ setTimeout(() => {
1685
+ visitorSocketData.value = null;
2064
1686
  }, 1000)
2065
- }
2066
- })
1687
+ }, 1000)
1688
+ }
1689
+ })
2067
1690
 
2068
1691
  </script>
2069
1692