@7365admin1/layer-common 3.0.7 → 3.0.8

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,7 +1,11 @@
1
1
  <template>
2
2
  <v-card width="100%" :loading="processing">
3
3
  <v-toolbar>
4
- <v-row no-gutters class="fill-height px-6 d-flex justify-space-between align-center" align="center">
4
+ <v-row
5
+ no-gutters
6
+ class="fill-height px-6 d-flex justify-space-between align-center"
7
+ align="center"
8
+ >
5
9
  <span class="font-weight-bold text-h5 text-capitalize">
6
10
  {{ prop.mode }} {{ formatVisitorType(type) }}
7
11
  </span>
@@ -12,25 +16,54 @@
12
16
  <div class="w-100 d-flex justify-space-between ga-2">
13
17
  <span class="text-subtitle-1 w-100 font-weight-bold mb-3">{{
14
18
  formTitle
15
- }}</span>
16
- <span v-if="withStep2 || withStep3" class="text-subtitle-2 font-weight-bold" style="text-wrap: nowrap">Step
17
- <span class="text-primary-button">{{ contractorStep }}</span>/{{ withStep3 ? 3 : withStep2 ? 2 : 1 }}</span>
19
+ }}</span>
20
+ <span
21
+ v-if="withStep2 || withStep3"
22
+ class="text-subtitle-2 font-weight-bold"
23
+ style="text-wrap: nowrap"
24
+ >Step <span class="text-primary-button">{{ contractorStep }}</span
25
+ >/{{ withStep3 ? 3 : withStep2 ? 2 : 1 }}</span
26
+ >
18
27
  </div>
19
- <v-form ref="formRef" v-model="validForm" :disabled="processing" @click="errorMessage = ''">
28
+ <v-form
29
+ ref="formRef"
30
+ v-model="validForm"
31
+ :disabled="processing"
32
+ @click="errorMessage = ''"
33
+ >
20
34
  <v-row no-gutters class="pt-4">
21
35
  <v-col v-if="shouldShowField('contractorType')" cols="12">
22
- <InputLabel class="text-capitalize" title="Contractor Type" required />
23
- <v-combobox v-model="contractorTypeObj" v-model:search="contractorTypeInput" ref="contractorTypeCombo"
24
- autocomplete="off" :hide-no-data="false" @update:focused="handleFocusedContractorType"
25
- :items="contractorTypes" :rules="[requiredRule]" item-value="value"
26
- @update:model-value="handleSelectContractorType" variant="outlined" density="comfortable" persistent-hint
27
- small-chips>
36
+ <InputLabel
37
+ class="text-capitalize"
38
+ title="Contractor Type"
39
+ required
40
+ />
41
+ <v-combobox
42
+ v-model="contractorTypeObj"
43
+ v-model:search="contractorTypeInput"
44
+ ref="contractorTypeCombo"
45
+ autocomplete="off"
46
+ :hide-no-data="false"
47
+ @update:focused="handleFocusedContractorType"
48
+ :items="contractorTypes"
49
+ :rules="[requiredRule]"
50
+ item-value="value"
51
+ @update:model-value="handleSelectContractorType"
52
+ variant="outlined"
53
+ density="comfortable"
54
+ persistent-hint
55
+ small-chips
56
+ >
28
57
  <template v-slot:no-data>
29
58
  <v-list-item>
30
- <v-list-item-title @click.stop="handleAddNewContractorType" class="d-flex align-center ga-1">
59
+ <v-list-item-title
60
+ @click.stop="handleAddNewContractorType"
61
+ class="d-flex align-center ga-1"
62
+ >
31
63
  <span><v-icon icon="mdi-plus" /></span> Add "<strong>{{
32
64
  contractorTypeInput
33
- }}</strong>" as custom contractor type.
65
+ }}</strong
66
+ >" as custom contractor type.
34
67
  </v-list-item-title>
35
68
  </v-list-item>
36
69
  </template>
@@ -39,14 +72,26 @@
39
72
 
40
73
  <v-col v-if="shouldShowField('attachments')" class="w-100">
41
74
  <InputLabel class="text-capitalize" title="Attach Image" />
42
- <InputFileV2 v-model="visitor.attachments" multiple :max-length="3" />
75
+ <InputFileV2
76
+ v-model="visitor.attachments"
77
+ multiple
78
+ :max-length="3"
79
+ />
43
80
  </v-col>
44
81
 
45
82
  <v-col v-if="shouldShowField('name')" cols="12">
46
83
  <v-row>
47
84
  <v-col cols="12">
48
- <InputLabel class="text-capitalize" title="Full Name" required />
49
- <v-text-field v-model.trim="visitor.name" density="comfortable" :rules="[requiredRule]" />
85
+ <InputLabel
86
+ class="text-capitalize"
87
+ title="Full Name"
88
+ required
89
+ />
90
+ <v-text-field
91
+ v-model.trim="visitor.name"
92
+ density="comfortable"
93
+ :rules="[requiredRule]"
94
+ />
50
95
  </v-col>
51
96
  </v-row>
52
97
  </v-col>
@@ -54,25 +99,44 @@
54
99
  <v-col v-if="shouldShowField('nric')" cols="12">
55
100
  <v-row>
56
101
  <v-col cols="12">
57
- <InputLabel class="text-capitalize" title="NRIC" :required="requireNRIC" />
58
- <InputNRICNumber v-model="visitor.nric" density="comfortable"
59
- :rules="[requireNRIC ? requiredRule : () => true]" :key="currentAutofillSource + 'nric-key'"
60
- @update:model-value="handleUpdateNRIC" :loading="fetchPersonByNRICPending" />
102
+ <InputLabel
103
+ class="text-capitalize"
104
+ title="NRIC"
105
+ :required="requireNRIC"
106
+ />
107
+ <InputNRICNumber
108
+ v-model="visitor.nric"
109
+ density="comfortable"
110
+ :rules="[requireNRIC ? requiredRule : () => true]"
111
+ :key="currentAutofillSource + 'nric-key'"
112
+ @update:model-value="handleUpdateNRIC"
113
+ :loading="fetchPersonByNRICPending"
114
+ />
61
115
  </v-col>
62
116
  </v-row>
63
117
  </v-col>
64
118
 
65
119
  <v-col v-if="shouldShowField('contact')" cols="12">
66
120
  <InputLabel class="text-capitalize" title="Phone Number" required />
67
- <InputPhoneNumberV2 v-model="visitor.contact" :rules="[requiredRule]" density="comfortable"
68
- :key="currentAutofillSource + 'phone-key'" :loading="fetchPersonByContactPending"
69
- @update:model-value="handleUpdateContact" />
121
+ <InputPhoneNumberV2
122
+ v-model="visitor.contact"
123
+ :rules="[requiredRule]"
124
+ density="comfortable"
125
+ :key="currentAutofillSource + 'phone-key'"
126
+ :loading="fetchPersonByContactPending"
127
+ @update:model-value="handleUpdateContact"
128
+ />
70
129
  </v-col>
71
130
 
72
131
  <v-col v-if="shouldShowField('deliveryType')" cols="12">
73
132
  <v-row>
74
133
  <v-col cols="12">
75
- <v-radio-group v-model="visitor.deliveryType" inline color="primary" :rules="[requiredRule]">
134
+ <v-radio-group
135
+ v-model="visitor.deliveryType"
136
+ inline
137
+ color="primary"
138
+ :rules="[requiredRule]"
139
+ >
76
140
  <v-radio label="Food" value="Food"></v-radio>
77
141
  <v-radio label="Parcel" value="Parcel"></v-radio>
78
142
  </v-radio-group>
@@ -83,22 +147,44 @@
83
147
  <template v-if="shouldShowField('company')">
84
148
  <v-col cols="12">
85
149
  <InputLabel class="text-capitalize" title="Company Name" />
86
- <v-combobox v-model="visitor.company" v-model:search="companyNameInput" ref="companyCombo"
87
- autocomplete="off" :hide-no-data="false" :items="companyNames" item-value="value"
88
- :loading="fetchCompanyListPending" @update:model-value="handleSelectCompanyName" variant="outlined"
89
- density="comfortable" persistent-hint small-chips>
150
+ <v-combobox
151
+ v-model="visitor.company"
152
+ v-model:search="companyNameInput"
153
+ ref="companyCombo"
154
+ autocomplete="off"
155
+ :hide-no-data="false"
156
+ :items="companyNames"
157
+ item-value="value"
158
+ :loading="fetchCompanyListPending"
159
+ @update:model-value="handleSelectCompanyName"
160
+ variant="outlined"
161
+ density="comfortable"
162
+ persistent-hint
163
+ small-chips
164
+ >
90
165
  <template v-slot:no-data>
91
166
  <v-list-item>
92
167
  <v-list-item-title v-if="fetchCompanyListPending">
93
- <v-progress-circular indeterminate size="20" class="mr-3" />
168
+ <v-progress-circular
169
+ indeterminate
170
+ size="20"
171
+ class="mr-3"
172
+ />
94
173
  Searching companies…
95
174
  </v-list-item-title>
96
- <v-list-item-title v-else-if="companyNameInput" @click.stop="handleAddNewCompany"
97
- class="d-flex align-center ga-1">
98
- <span><v-icon icon="mdi-plus" /></span>Add "<strong>{{ companyNameInput }}</strong>" as new
99
- company.
175
+ <v-list-item-title
176
+ v-else-if="companyNameInput"
177
+ @click.stop="handleAddNewCompany"
178
+ class="d-flex align-center ga-1"
179
+ >
180
+ <span><v-icon icon="mdi-plus" /></span>Add "<strong>{{
181
+ companyNameInput
182
+ }}</strong
183
+ >" as new company.
100
184
  </v-list-item-title>
101
- <v-list-item-title v-else-if="!companyNameInput && companyNames.length === 0">
185
+ <v-list-item-title
186
+ v-else-if="!companyNameInput && companyNames.length === 0"
187
+ >
102
188
  Start typing to search for companies.
103
189
  </v-list-item-title>
104
190
  <v-list-item-title v-else>
@@ -113,21 +199,43 @@
113
199
  <template v-if="shouldShowField('delivery-company')">
114
200
  <v-col cols="12">
115
201
  <InputLabel class="text-capitalize" title="Delivery Company" />
116
- <v-combobox v-model="deliveryCompany" v-model:search="deliveryCompanyInput" ref="companyCombo"
117
- autocomplete="off" :hide-no-data="false" :items="deliveryCompanyList" item-value="value"
118
- :loading="siteDataPending" variant="outlined" density="comfortable" persistent-hint small-chips>
202
+ <v-combobox
203
+ v-model="deliveryCompany"
204
+ v-model:search="deliveryCompanyInput"
205
+ ref="companyCombo"
206
+ autocomplete="off"
207
+ :hide-no-data="false"
208
+ :items="deliveryCompanyList"
209
+ item-value="value"
210
+ :loading="siteDataPending"
211
+ variant="outlined"
212
+ density="comfortable"
213
+ persistent-hint
214
+ small-chips
215
+ >
119
216
  <template v-slot:no-data>
120
217
  <v-list-item>
121
218
  <v-list-item-title v-if="fetchCompanyListPending">
122
- <v-progress-circular indeterminate size="20" class="mr-3" />
219
+ <v-progress-circular
220
+ indeterminate
221
+ size="20"
222
+ class="mr-3"
223
+ />
123
224
  Searching companies…
124
225
  </v-list-item-title>
125
- <v-list-item-title v-else-if="companyNameInput" @click.stop="handleAddNewCompany"
126
- class="d-flex align-center ga-1">
127
- <span><v-icon icon="mdi-plus" /></span>Add "<strong>{{ companyNameInput }}</strong>" as new
128
- company.
226
+ <v-list-item-title
227
+ v-else-if="companyNameInput"
228
+ @click.stop="handleAddNewCompany"
229
+ class="d-flex align-center ga-1"
230
+ >
231
+ <span><v-icon icon="mdi-plus" /></span>Add "<strong>{{
232
+ companyNameInput
233
+ }}</strong
234
+ >" as new company.
129
235
  </v-list-item-title>
130
- <v-list-item-title v-else-if="!companyNameInput && companyNames.length === 0">
236
+ <v-list-item-title
237
+ v-else-if="!companyNameInput && companyNames.length === 0"
238
+ >
131
239
  Start typing to search for companies.
132
240
  </v-list-item-title>
133
241
  <v-list-item-title v-else>
@@ -139,60 +247,135 @@
139
247
  </v-col>
140
248
  </template>
141
249
 
142
-
143
250
  <v-col v-if="shouldShowField('plateNumber')" cols="12">
144
251
  <v-row>
145
252
  <v-col cols="12">
146
- <InputLabel class="text-capitalize" title="Vehicle Number" required />
253
+ <InputLabel
254
+ class="text-capitalize"
255
+ title="Vehicle Number"
256
+ required
257
+ />
147
258
  <!-- <v-text-field v-model.trim.uppercase="visitor.plateNumber" density="comfortable" /> -->
148
- <InputVehicleNumber v-model="visitor.plateNumber" density="comfortable" />
259
+ <InputVehicleNumber
260
+ v-model="visitor.plateNumber"
261
+ density="comfortable"
262
+ />
149
263
  </v-col>
150
264
  </v-row>
151
265
  </v-col>
152
266
 
153
267
  <v-col v-if="shouldShowField('block')" cols="12">
154
268
  <InputLabel class="text-capitalize" title="Block" required />
155
- <v-autocomplete v-model="visitor.block" :items="blocksArray" item-value="value" autocomplete="off" item-title="title" :key="blockListDataPending ? 'block-list-pending' : 'block-list-ready'"
156
- :loading="blockListDataPending" @update:model-value="handleChangeBlock" density="comfortable"
157
- :rules="[requiredRule]" />
269
+ <v-autocomplete
270
+ v-model="visitor.block"
271
+ :items="blocksArray"
272
+ item-value="value"
273
+ autocomplete="off"
274
+ item-title="title"
275
+ :key="
276
+ blockListDataPending ? 'block-list-pending' : 'block-list-ready'
277
+ "
278
+ :loading="blockListDataPending"
279
+ @update:model-value="handleChangeBlock"
280
+ density="comfortable"
281
+ :rules="[requiredRule]"
282
+ />
158
283
  </v-col>
159
284
 
160
285
  <v-col v-if="shouldShowField('level')" cols="12">
161
286
  <InputLabel class="text-capitalize" title="Level" required />
162
- <v-autocomplete v-model="visitor.level" :items="levelsArray" density="comfortable" autocomplete="off"
163
- :disabled="!visitor.block" :key="levelListDataPending ? 'level-list-pending' : 'level-list-ready'" :loading="levelsDataPending" @update:model-value="handleChangeLevel"
164
- :rules="[requiredRule]" />
287
+ <v-autocomplete
288
+ v-model="visitor.level"
289
+ :items="levelsArray"
290
+ density="comfortable"
291
+ autocomplete="off"
292
+ :disabled="!visitor.block"
293
+ :key="
294
+ levelListDataPending ? 'level-list-pending' : 'level-list-ready'
295
+ "
296
+ :loading="levelsDataPending"
297
+ @update:model-value="handleChangeLevel"
298
+ :rules="[requiredRule]"
299
+ />
165
300
  </v-col>
166
301
  <v-col v-if="shouldShowField('unit')" cols="12">
167
302
  <InputLabel class="text-capitalize" title="Unit" required />
168
- <v-autocomplete v-model="visitor.unit" :items="unitsArray" density="comfortable" autocomplete="off" item-title="title"
169
- item-value="value" :disabled="!visitor.level" :key="unitListDataPending ? 'unit-list-pending' : 'unit-list-ready'" :loading="unitsDataPending" :rules="[requiredRule]"
170
- @update:model-value="handleUpdateUnit" />
303
+ <v-autocomplete
304
+ v-model="visitor.unit"
305
+ :items="unitsArray"
306
+ density="comfortable"
307
+ autocomplete="off"
308
+ item-title="title"
309
+ item-value="value"
310
+ :disabled="!visitor.level"
311
+ :key="
312
+ unitListDataPending ? 'unit-list-pending' : 'unit-list-ready'
313
+ "
314
+ :loading="unitsDataPending"
315
+ :rules="[requiredRule]"
316
+ @update:model-value="handleUpdateUnit"
317
+ />
171
318
  </v-col>
172
319
 
173
320
  <v-col v-if="shouldShowField('unit')" cols="12">
174
- <InputLabel class="text-capitalize" title="Registered Unit Company Name" required
175
- :key="'unit-key' + visitor.level" />
176
- <v-text-field v-model.trim="registeredUnitCompanyName" density="comfortable"
177
- :loading="buildingUnitDataPending" readonly class="no-pointer" />
321
+ <InputLabel
322
+ class="text-capitalize"
323
+ title="Registered Unit Company Name"
324
+ required
325
+ :key="'unit-key' + visitor.level"
326
+ />
327
+ <v-text-field
328
+ v-model.trim="registeredUnitCompanyName"
329
+ density="comfortable"
330
+ :loading="buildingUnitDataPending"
331
+ readonly
332
+ class="no-pointer"
333
+ />
178
334
  </v-col>
179
335
 
180
336
  <v-col v-if="shouldShowField('remarks')" cols="12">
181
337
  <InputLabel class="text-capitalize" title="Remarks" />
182
- <v-textarea v-model="visitor.remarks" density="comfortable" :rows="3" no-resize />
338
+ <v-textarea
339
+ v-model="visitor.remarks"
340
+ density="comfortable"
341
+ :rows="3"
342
+ no-resize
343
+ />
183
344
  </v-col>
184
345
 
185
- <v-col v-if="(withStep2 || withStep3) && contractorStep === 2" cols="12">
186
- <PassInformation v-model:pass="visitor.visitorPass" v-model:keys="visitor.passKeys" :site="prop.site"
187
- :type="prop.type" :contractor-type="visitor.contractorType" :hide-keys="!showShowKeysField" />
188
- <EntryPassInformation v-if="entryPassSettings?.data?.settings?.nfcPass" v-model="passType"
189
- v-model:quantity="passQuantity" v-model:cards="passCards" :settings="entryPassSettings"
190
- :loading="entryPassSettingsPending" :site-id="prop.site" :unit-id="visitor.unit || null" />
346
+ <v-col
347
+ v-if="(withStep2 || withStep3) && contractorStep === 2"
348
+ cols="12"
349
+ >
350
+ <PassInformation
351
+ v-model:pass="visitor.visitorPass"
352
+ v-model:keys="visitor.passKeys"
353
+ :site="prop.site"
354
+ :type="prop.type"
355
+ :contractor-type="visitor.contractorType"
356
+ :hide-keys="!showShowKeysField"
357
+ :passKeys="visitor.passKeys"
358
+ />
359
+ <EntryPassInformation
360
+ v-if="entryPassSettings?.data?.settings?.nfcPass"
361
+ v-model="passType"
362
+ v-model:quantity="passQuantity"
363
+ v-model:cards="passCards"
364
+ :settings="entryPassSettings"
365
+ :loading="entryPassSettingsPending"
366
+ :site-id="prop.site"
367
+ :unit-id="visitor.unit || null"
368
+ />
191
369
  </v-col>
192
370
 
193
371
  <v-col v-if="withStep3 && contractorStep === 3" cols="12">
194
- <MemberInformation v-model="visitor.members" :type="prop.type" :contractor-type="visitor.contractorType"
195
- :site="prop.site" :selected-visitor-pass="visitor.visitorPass" />
372
+ <MemberInformation
373
+ v-model="visitor.members"
374
+ :type="prop.type"
375
+ :contractor-type="visitor.contractorType"
376
+ :site="prop.site"
377
+ :selected-visitor-pass="visitor.visitorPass"
378
+ />
196
379
  </v-col>
197
380
 
198
381
  <v-col v-if="prop.mode === 'add'" cols="12" class="mt-2">
@@ -216,33 +399,89 @@
216
399
  <v-toolbar density="compact">
217
400
  <v-row no-gutters>
218
401
  <v-col cols="6">
219
- <v-btn v-if="
220
- prop.mode === 'add' &&
221
- (withStep2 || withStep3) &&
222
- contractorStep > 1
223
- " tile block variant="text" class="text-none" size="48" @click="handleGoToPreviousPage" text="Back" />
224
- <v-btn v-else-if="prop.mode === 'add' || prop.mode === 'register'" tile block variant="text" class="text-none"
225
- size="48" @click="backToSelection" text="Back to Selection" />
226
- <v-btn v-else tile block variant="text" class="text-none" size="48" @click="emit('close:all')" text="Close" />
402
+ <v-btn
403
+ v-if="
404
+ prop.mode === 'add' &&
405
+ (withStep2 || withStep3) &&
406
+ contractorStep > 1
407
+ "
408
+ tile
409
+ block
410
+ variant="text"
411
+ class="text-none"
412
+ size="48"
413
+ @click="handleGoToPreviousPage"
414
+ text="Back"
415
+ />
416
+ <v-btn
417
+ v-else-if="prop.mode === 'add' || prop.mode === 'register'"
418
+ tile
419
+ block
420
+ variant="text"
421
+ class="text-none"
422
+ size="48"
423
+ @click="backToSelection"
424
+ text="Back to Selection"
425
+ />
426
+ <v-btn
427
+ v-else
428
+ tile
429
+ block
430
+ variant="text"
431
+ class="text-none"
432
+ size="48"
433
+ @click="emit('close:all')"
434
+ text="Close"
435
+ />
227
436
  </v-col>
228
437
  <v-col cols="6">
229
- <v-btn v-if="showNextButton" tile block variant="flat" color="primary-button" class="text-none" size="48"
230
- :disabled="processing" @click="handleNextPage" :text="'Next'" />
231
- <v-btn v-else tile block variant="flat" color="black" class="text-none" size="48"
232
- :disabled="!validForm || processing || membersFieldIncomplete" @click="submit"
233
- :text="prop.mode == 'add' ? 'Submit' : 'Update'" />
438
+ <v-btn
439
+ v-if="showNextButton"
440
+ tile
441
+ block
442
+ variant="flat"
443
+ color="primary-button"
444
+ class="text-none"
445
+ size="48"
446
+ :disabled="processing"
447
+ @click="handleNextPage"
448
+ :text="'Next'"
449
+ />
450
+ <v-btn
451
+ v-else
452
+ tile
453
+ block
454
+ variant="flat"
455
+ color="black"
456
+ class="text-none"
457
+ size="48"
458
+ :disabled="!validForm || processing || membersFieldIncomplete"
459
+ @click="submit"
460
+ :text="prop.mode == 'add' ? 'Submit' : 'Update'"
461
+ />
234
462
  </v-col>
235
463
  </v-row>
236
464
  </v-toolbar>
237
465
 
238
- <v-dialog v-model="dialog.vehicleNumberUsersList" v-if="vehicleNumberUserItems.length > 0" persistent
239
- max-width="600">
240
- <SearchVehicleNumberUser :vehicle-number="visitor.plateNumber ?? ''"
241
- :vehicle-number-users-list="vehicleNumberUserItems" @close="dialog.vehicleNumberUsersList = false"
242
- @update:people="handleAutofillDataViaVehicleNumber" />
466
+ <v-dialog
467
+ v-model="dialog.vehicleNumberUsersList"
468
+ v-if="vehicleNumberUserItems.length > 0"
469
+ persistent
470
+ max-width="600"
471
+ >
472
+ <SearchVehicleNumberUser
473
+ :vehicle-number="visitor.plateNumber ?? ''"
474
+ :vehicle-number-users-list="vehicleNumberUserItems"
475
+ @close="dialog.vehicleNumberUsersList = false"
476
+ @update:people="handleAutofillDataViaVehicleNumber"
477
+ />
243
478
  </v-dialog>
244
479
 
245
- <v-dialog v-model="dialog.showNonCheckedOutDialog" max-width="700" persistent>
480
+ <v-dialog
481
+ v-model="dialog.showNonCheckedOutDialog"
482
+ max-width="700"
483
+ persistent
484
+ >
246
485
  <v-card :loading="loading.checkingOut">
247
486
  <v-toolbar>
248
487
  <v-toolbar-title>
@@ -255,10 +494,13 @@
255
494
  </v-toolbar>
256
495
 
257
496
  <v-card-text>
258
-
259
497
  <v-list lines="three">
260
- <v-list-item v-if="matchingPlateNumberNonCheckedOutArr.length > 0"
261
- v-for="v in matchingPlateNumberNonCheckedOutArr" :key="v._id" class="cursor-pointer">
498
+ <v-list-item
499
+ v-if="matchingPlateNumberNonCheckedOutArr.length > 0"
500
+ v-for="v in matchingPlateNumberNonCheckedOutArr"
501
+ :key="v._id"
502
+ class="cursor-pointer"
503
+ >
262
504
  <v-list-item-title>
263
505
  {{ v.plateNumber }} - {{ v.name }}
264
506
  </v-list-item-title>
@@ -268,14 +510,19 @@
268
510
  </v-list-item-subtitle>
269
511
 
270
512
  <template #append>
271
- <v-btn size="x-small" class="text-capitalize" color="red" text="Checkout"
272
- :loading="loading.checkingOut && v?._id === prop.visitorData?._id"
273
- @click.stop="handleCheckout(v._id)" />
513
+ <v-btn
514
+ size="x-small"
515
+ class="text-capitalize"
516
+ color="red"
517
+ text="Checkout"
518
+ :loading="
519
+ loading.checkingOut && v?._id === prop.visitorData?._id
520
+ "
521
+ @click.stop="handleCheckout(v._id)"
522
+ />
274
523
  </template>
275
-
276
524
  </v-list-item>
277
525
  </v-list>
278
-
279
526
  </v-card-text>
280
527
  </v-card>
281
528
  </v-dialog>
@@ -283,9 +530,9 @@
283
530
  </template>
284
531
 
285
532
  <script setup lang="ts">
286
- import useBuildingUnit from '../composables/useBuildingUnit';
287
- import useWebUsb from '../composables/useWebUsb';
288
-
533
+ import { propsFactory } from "vuetify/lib/util/propsFactory.mjs";
534
+ import useBuildingUnit from "../composables/useBuildingUnit";
535
+ import useWebUsb from "../composables/useWebUsb";
289
536
 
290
537
  const prop = defineProps({
291
538
  type: {
@@ -308,21 +555,37 @@ const prop = defineProps({
308
555
  type: Object as PropType<Partial<TVisitor> | null>,
309
556
  default: null,
310
557
  },
558
+ currentUser: {
559
+ type: String,
560
+ default: "",
561
+ },
311
562
  });
312
563
 
313
564
  type AutofillSource = "nric" | "contact" | "vehicleNumber" | null;
314
565
  const currentAutofillSource = ref<AutofillSource>(null);
315
566
 
316
-
317
567
  const { requiredRule, debounce, UTCToLocalTIme } = useUtils();
318
568
  const { getSiteById } = useSiteSettings();
319
- const { getBlocksSelection, getLevelsSelection, getUnitSelection } = useBuilding();
320
- const { createVisitor, typeFieldMap, contractorTypes, getVisitors, updateVisitor } = useVisitor();
321
- const { getBySiteId: getEntryPassSettingsBySiteId } = useSiteEntryPassSettings();
569
+ const { getBlocksSelection, getLevelsSelection, getUnitSelection } =
570
+ useBuilding();
571
+ const {
572
+ createVisitor,
573
+ typeFieldMap,
574
+ contractorTypes,
575
+ getVisitors,
576
+ updateVisitor,
577
+ } = useVisitor();
578
+ const { getBySiteId: getEntryPassSettingsBySiteId } =
579
+ useSiteEntryPassSettings();
322
580
  const { createVisitorPass, signQr } = useAccessManagement();
323
581
  const { testConnection } = useWebUsb();
324
- const { findPersonByNRIC, findPersonByContact, searchCompanyList, findUsersByPlateNumber } = usePeople()
325
- const { getById: getUnitDataById } = useBuildingUnit()
582
+ const {
583
+ findPersonByNRIC,
584
+ findPersonByContact,
585
+ searchCompanyList,
586
+ findUsersByPlateNumber,
587
+ } = usePeople();
588
+ const { getById: getUnitDataById } = useBuildingUnit();
326
589
 
327
590
  const emit = defineEmits([
328
591
  "back",
@@ -331,7 +594,7 @@ const emit = defineEmits([
331
594
  "done:more",
332
595
  "error",
333
596
  "close",
334
- "close:all"
597
+ "close:all",
335
598
  ]);
336
599
 
337
600
  const visitor = reactive<Partial<TVisitorPayload>>({
@@ -350,14 +613,14 @@ const visitor = reactive<Partial<TVisitorPayload>>({
350
613
  attachments: [],
351
614
  members: [],
352
615
  visitorPass: [],
353
- passKeys: []
616
+ passKeys: [],
354
617
  });
355
618
 
356
619
  const passType = ref<string | null>(null);
357
620
  const passQuantity = ref<number | null>(1);
358
621
  const passCards = ref<{ _id: string; cardNo: string }[]>([]);
359
622
 
360
- const registeredUnitCompanyName = ref('N/A')
623
+ const registeredUnitCompanyName = ref("N/A");
361
624
 
362
625
  const dialog = reactive({
363
626
  vehicleNumberUsersList: false,
@@ -366,7 +629,7 @@ const dialog = reactive({
366
629
 
367
630
  const loading = reactive({
368
631
  checkingOut: false,
369
- })
632
+ });
370
633
 
371
634
  const validForm = ref(false);
372
635
  const formRef = ref<HTMLFormElement | null>(null);
@@ -382,7 +645,6 @@ const contractorStep = ref(1);
382
645
  const companyNameInput = ref("");
383
646
  const companyNameObj = ref<string | null>(null);
384
647
 
385
-
386
648
  const blocksArray = ref<TDefaultOptionObj[]>([]);
387
649
  const levelsArray = ref<TDefaultOptionObj[]>([]);
388
650
  const unitsArray = ref<TDefaultOptionObj[]>([]);
@@ -391,13 +653,13 @@ const deliveryCompany = ref("");
391
653
  const deliveryCompanyInput = ref("");
392
654
  const deliveryCompanyList = ref<string[]>([]);
393
655
 
394
- const matchingPlateNumberNonCheckedOutArr = ref<TVisitor[]>([])
395
-
396
-
397
- const vehicleNumberUserItems = ref<TPeople[]>([])
656
+ const matchingPlateNumberNonCheckedOutArr = ref<TVisitor[]>([]);
398
657
 
658
+ const vehicleNumberUserItems = ref<TPeople[]>([]);
399
659
 
400
- const shouldShowField = (fieldKey: keyof TVisitorPayload | 'delivery-company') => {
660
+ const shouldShowField = (
661
+ fieldKey: keyof TVisitorPayload | "delivery-company"
662
+ ) => {
401
663
  if ((!withStep2.value && !withStep3.value) || contractorStep.value === 1) {
402
664
  const visibleFields = typeFieldMap[prop.type];
403
665
  return visibleFields?.includes(fieldKey);
@@ -407,31 +669,39 @@ const shouldShowField = (fieldKey: keyof TVisitorPayload | 'delivery-company') =
407
669
  const withStep2 = computed(() => {
408
670
  const step2Types = ["guest", "walk-in"];
409
671
  return step2Types.includes(prop.type);
410
- })
672
+ });
411
673
 
412
674
  const withStep3 = computed(() => {
413
675
  const step3Types = ["contractor"];
414
676
  return step3Types.includes(prop.type);
415
- })
677
+ });
416
678
 
417
679
  const showNextButton = computed(() => {
418
680
  if (withStep3.value) {
419
- return contractorStep.value === 1 || contractorStep.value === 2
681
+ return contractorStep.value === 1 || contractorStep.value === 2;
420
682
  } else if (withStep2.value) {
421
- return contractorStep.value === 1
422
- } else return false
423
- })
683
+ return contractorStep.value === 1;
684
+ } else return false;
685
+ });
424
686
 
425
687
  const showShowKeysField = computed(() => {
426
- return prop.type === "contractor"
427
- })
688
+ return prop.type === "contractor";
689
+ });
428
690
 
429
691
  const requireNRIC = computed(() => {
430
- return prop.type !== 'walk-in' && prop.type !== 'guest';
431
- })
692
+ return prop.type !== "walk-in" && prop.type !== "guest";
693
+ });
432
694
 
433
- const companyNames = ref<string[]>([])
434
- const companyAutofillDataArray = ref<{ companyName: string[], unit: string, block: number, level: string, unitName: string }[]>([])
695
+ const companyNames = ref<string[]>([]);
696
+ const companyAutofillDataArray = ref<
697
+ {
698
+ companyName: string[];
699
+ unit: string;
700
+ block: number;
701
+ level: string;
702
+ unitName: string;
703
+ }[]
704
+ >([]);
435
705
 
436
706
  const formTitle = computed(() => {
437
707
  const isContractorForm = prop.type === "contractor";
@@ -461,21 +731,21 @@ function handleFocusedContractorType() {
461
731
  // }
462
732
  }
463
733
 
464
- const contractorTypeCombo = ref(null)
734
+ const contractorTypeCombo = ref(null);
465
735
 
466
736
  async function handleAddNewContractorType() {
467
- visitor.contractorType = contractorTypeInput.value
737
+ visitor.contractorType = contractorTypeInput.value;
468
738
 
469
- const combo = contractorTypeCombo.value as any
739
+ const combo = contractorTypeCombo.value as any;
470
740
  await nextTick();
471
741
 
472
742
  combo.isMenuActive = false;
473
- combo.$el.querySelector("input")?.blur(); ``
474
-
743
+ combo.$el.querySelector("input")?.blur();
744
+ ``;
475
745
  }
476
746
 
477
747
  async function handleSelectCompanyName(company: string) {
478
- visitor.company = company
748
+ visitor.company = company;
479
749
  // const selected = companyAutofillDataArray.value.find(x => x.companyName?.includes(company))
480
750
  // if (!selected) return
481
751
 
@@ -485,48 +755,46 @@ async function handleSelectCompanyName(company: string) {
485
755
  // visitor.unitName = selected.unitName || ""
486
756
  }
487
757
 
488
- const companyCombo = ref(null)
758
+ const companyCombo = ref(null);
489
759
 
490
760
  async function handleAddNewCompany() {
491
- visitor.company = companyNameInput.value
761
+ visitor.company = companyNameInput.value;
492
762
 
493
- const combo = companyCombo.value as any
763
+ const combo = companyCombo.value as any;
494
764
  await nextTick();
495
765
 
496
766
  combo.isMenuActive = false;
497
767
  combo.$el.querySelector("input")?.blur();
498
768
  }
499
769
 
500
-
501
770
  const {
502
771
  data: fetchPersonByNRICReq,
503
772
  refresh: fetchPersonByNRICRefresh,
504
773
  pending: fetchPersonByNRICPending,
505
774
  } = useLazyAsyncData(`fetch-person`, () => {
506
775
  const NRIC = visitor.nric;
507
- if (!NRIC) return Promise.resolve(null)
508
- return findPersonByNRIC(NRIC)
509
- }
510
- );
776
+ if (!NRIC) return Promise.resolve(null);
777
+ return findPersonByNRIC(NRIC);
778
+ });
511
779
 
512
780
  watch(fetchPersonByNRICReq, (obj) => {
513
781
  if (obj) {
514
782
  currentAutofillSource.value = "nric";
515
- companyNames.value = obj.companyName ?? []
516
- visitor.name = obj.name
517
- visitor.contact = obj.contact
783
+ companyNames.value = obj.companyName ?? [];
784
+ visitor.name = obj.name;
785
+ visitor.contact = obj.contact;
518
786
  if (!visitor.company) {
519
- visitor.company = companyNames.value?.[0]
787
+ visitor.company = companyNames.value?.[0];
520
788
  }
521
- visitor.block = obj.block ?? ""
522
- visitor.level = obj.level ?? ""
523
- visitor.unit = obj.unit ?? ""
789
+ visitor.block = obj.block ?? "";
790
+ visitor.level = obj.level ?? "";
791
+ visitor.unit = obj.unit ?? "";
524
792
 
525
793
  setTimeout(() => {
526
794
  currentAutofillSource.value = null;
527
795
  }, 1000);
528
796
  }
529
- })
797
+ });
530
798
 
531
799
  const {
532
800
  data: fetchPersonByContactReq,
@@ -534,82 +802,86 @@ const {
534
802
  pending: fetchPersonByContactPending,
535
803
  } = useLazyAsyncData(`fetch-contact`, () => {
536
804
  const contact = visitor.contact;
537
- if (!contact) return Promise.resolve(null)
538
- return findPersonByContact(contact)
539
- }
540
- );
805
+ if (!contact) return Promise.resolve(null);
806
+ return findPersonByContact(contact);
807
+ });
541
808
 
542
809
  watch(fetchPersonByContactReq, (obj: Partial<TPerson>) => {
543
810
  if (obj) {
544
811
  currentAutofillSource.value = "contact";
545
- companyNames.value = obj.companyName ?? []
546
- visitor.name = visitor.name ?? obj.name
812
+ companyNames.value = obj.companyName ?? [];
813
+ visitor.name = visitor.name ?? obj.name;
547
814
  if (!visitor.company) {
548
- visitor.company = companyNames.value?.[0]
815
+ visitor.company = companyNames.value?.[0];
549
816
  }
550
817
  // visitor.block = visitor.block ?? obj.block ?? ""
551
818
  // visitor.level = visitor.level ?? obj.level ?? ""
552
819
  // visitor.unit = visitor.unit ?? obj.unit ?? ""
553
- visitor.nric = visitor.nric ?? obj.nric ?? ""
820
+ visitor.nric = visitor.nric ?? obj.nric ?? "";
554
821
 
555
822
  setTimeout(() => {
556
823
  currentAutofillSource.value = null;
557
824
  }, 1000);
558
825
  }
559
- })
826
+ });
560
827
 
561
828
  const {
562
829
  data: fetchCompanyListReq,
563
830
  refresh: fetchCompanyListRefresh,
564
831
  pending: fetchCompanyListPending,
565
-
566
832
  } = useLazyAsyncData(`fetch-company-list`, () => {
567
- if (!companyNameInput.value) return Promise.resolve(null)
568
- return searchCompanyList(companyNameInput.value)
569
- })
833
+ if (!companyNameInput.value) return Promise.resolve(null);
834
+ return searchCompanyList(companyNameInput.value);
835
+ });
570
836
 
571
837
  watch(fetchCompanyListReq, (arr) => {
572
838
  if (Array.isArray(arr)) {
573
839
  companyAutofillDataArray.value = arr;
574
- companyNames.value = arr?.flatMap(x => x?.companyName)
840
+ companyNames.value = arr?.flatMap((x) => x?.companyName);
575
841
  }
576
- })
842
+ });
577
843
  const {
578
844
  data: fetchVisitorListByVehicleNumberReq,
579
845
  refresh: fetchVisitorListByVehicleNumberRefresh,
580
846
  pending: fetchVisitorListByVehicleNumberPending,
581
-
582
847
  } = useLazyAsyncData(`fetch-visitor-list-by-vehicle-number`, () => {
583
- if (!visitor.plateNumber) return Promise.resolve(null)
584
- return getVisitors({ page: 1, limit: 20, site: prop.site, plateNumber: visitor.plateNumber, checkedOut: false, status: "registered" })
585
- })
848
+ if (!visitor.plateNumber) return Promise.resolve(null);
849
+ return getVisitors({
850
+ page: 1,
851
+ limit: 20,
852
+ site: prop.site,
853
+ plateNumber: visitor.plateNumber,
854
+ checkedOut: false,
855
+ status: "registered",
856
+ });
857
+ });
586
858
 
587
859
  watch(fetchVisitorListByVehicleNumberReq, (arr: any) => {
588
- const itemsArray = arr?.items || []
589
- const isValidArray = Array.isArray(itemsArray)
590
- matchingPlateNumberNonCheckedOutArr.value = isValidArray ? itemsArray : []
860
+ const itemsArray = arr?.items || [];
861
+ const isValidArray = Array.isArray(itemsArray);
862
+ matchingPlateNumberNonCheckedOutArr.value = isValidArray ? itemsArray : [];
591
863
  if (matchingPlateNumberNonCheckedOutArr.value.length > 0) {
592
864
  dialog.showNonCheckedOutDialog = true;
593
865
  } else {
594
866
  dialog.showNonCheckedOutDialog = false;
595
867
  }
596
- })
597
-
868
+ });
598
869
 
599
870
  const debounceSearchVisitorsByPlateNumbers = debounce(() => {
600
871
  if (!visitor.plateNumber) {
601
- matchingPlateNumberNonCheckedOutArr.value = []
872
+ matchingPlateNumberNonCheckedOutArr.value = [];
602
873
  dialog.showNonCheckedOutDialog = false;
603
874
  return;
604
875
  }
605
876
  fetchVisitorListByVehicleNumberRefresh();
606
877
  }, 300);
607
878
 
608
- watch(() => visitor.plateNumber, (newVal) => {
609
- debounceSearchVisitorsByPlateNumbers();
610
- });
611
-
612
-
879
+ watch(
880
+ () => visitor.plateNumber,
881
+ (newVal) => {
882
+ debounceSearchVisitorsByPlateNumbers();
883
+ }
884
+ );
613
885
 
614
886
  async function handleCheckout(visitorId: string) {
615
887
  if (!visitorId) {
@@ -624,7 +896,6 @@ async function handleCheckout(visitorId: string) {
624
896
  });
625
897
  if (res) {
626
898
  await fetchVisitorListByVehicleNumberRefresh();
627
-
628
899
  }
629
900
  } catch (error: any) {
630
901
  const errorMessage = error?.response?._data?.message;
@@ -636,50 +907,42 @@ async function handleCheckout(visitorId: string) {
636
907
  }
637
908
  }
638
909
 
639
-
640
-
641
-
642
- const debounceFetchCompany = debounce(async () => fetchCompanyListRefresh(), 200)
910
+ const debounceFetchCompany = debounce(
911
+ async () => fetchCompanyListRefresh(),
912
+ 200
913
+ );
643
914
 
644
915
  watch(companyNameInput, async (val) => {
645
916
  if (!val) {
646
- companyNames.value = []
647
- return
917
+ companyNames.value = [];
918
+ return;
648
919
  }
649
- await debounceFetchCompany()
650
- })
651
-
652
-
653
-
654
-
920
+ await debounceFetchCompany();
921
+ });
655
922
 
656
923
  function handleAutofillDataViaVehicleNumber(item: TPeople) {
657
-
658
924
  currentAutofillSource.value = "vehicleNumber";
659
925
 
660
- visitor.name = item.name
661
- visitor.nric = item.nric
662
- visitor.contact = item.contact
663
- companyNames.value = item.companyName ?? []
926
+ visitor.name = item.name;
927
+ visitor.nric = item.nric;
928
+ visitor.contact = item.contact;
929
+ companyNames.value = item.companyName ?? [];
664
930
  if (!visitor.company) {
665
- visitor.company = companyNames.value?.[0]
931
+ visitor.company = companyNames.value?.[0];
666
932
  }
667
- visitor.block = item.block ?? ""
668
- visitor.level = item.level ?? ""
669
- visitor.unit = item.unit ?? ""
933
+ visitor.block = item.block ?? "";
934
+ visitor.level = item.level ?? "";
935
+ visitor.unit = item.unit ?? "";
670
936
 
671
937
  setTimeout(() => {
672
938
  currentAutofillSource.value = null;
673
939
  }, 1000);
674
940
  }
675
941
 
676
-
677
- const {
678
- data: entryPassSettings,
679
- pending: entryPassSettingsPending,
680
- } = useLazyAsyncData(`fetch-entrypass-settings-${prop.site}`, () =>
681
- getEntryPassSettingsBySiteId(prop.site)
682
- );
942
+ const { data: entryPassSettings, pending: entryPassSettingsPending } =
943
+ useLazyAsyncData(`fetch-entrypass-settings-${prop.site}`, () =>
944
+ getEntryPassSettingsBySiteId(prop.site)
945
+ );
683
946
 
684
947
  const {
685
948
  data: siteData,
@@ -690,18 +953,17 @@ const {
690
953
  getSiteById(prop.site)
691
954
  );
692
955
 
693
-
694
956
  const {
695
957
  data: blocksListData,
696
958
  refresh: refreshBlockListData,
697
959
  status: blocksListStatus,
698
960
  pending: blockListDataPending,
699
- } = useLazyAsyncData(`visitor-fetch-block-list-data-${prop.site}`, () =>
700
- getBlocksSelection({ siteId: prop.site }), {watch: [() => prop.site], deep: true }
961
+ } = useLazyAsyncData(
962
+ `visitor-fetch-block-list-data-${prop.site}`,
963
+ () => getBlocksSelection({ siteId: prop.site }),
964
+ { watch: [() => prop.site], deep: true }
701
965
  );
702
966
 
703
-
704
-
705
967
  const {
706
968
  data: levelsData,
707
969
  refresh: refreshLevelsData,
@@ -712,8 +974,12 @@ const {
712
974
  async () => {
713
975
  if (!visitor.block) return Promise.resolve(null);
714
976
  // return await getSiteWithLevels(prop.site, { block: Number(visitor.block) });
715
- return await getLevelsSelection({ siteId: prop.site, blockId: visitor.block });
716
- }, { watch: [() => visitor.block], deep: true }
977
+ return await getLevelsSelection({
978
+ siteId: prop.site,
979
+ blockId: visitor.block,
980
+ });
981
+ },
982
+ { watch: [() => visitor.block], deep: true }
717
983
  );
718
984
 
719
985
  const {
@@ -725,20 +991,26 @@ const {
725
991
  `visitor-fetch-units-data-${prop.site}-${visitor.level}`,
726
992
  async () => {
727
993
  if (!visitor.level) return Promise.resolve(null);
728
- return await getUnitSelection({ siteId: prop.site, block: visitor.block, level: visitor.level });
729
- },{ watch: [() => visitor.level], deep: true }
994
+ return await getUnitSelection({
995
+ siteId: prop.site,
996
+ block: visitor.block,
997
+ level: visitor.level,
998
+ });
999
+ },
1000
+ { watch: [() => visitor.level], deep: true }
730
1001
  );
731
1002
 
732
-
733
1003
  watch(
734
1004
  siteData,
735
1005
  (newVal) => {
736
1006
  const siteDataValue = newVal as TSite;
737
1007
  if (siteDataValue) {
738
-
739
- deliveryCompanyList.value = Array.isArray(siteDataValue?.deliveryCompanyList) ? siteDataValue.deliveryCompanyList : [];
740
-
741
- }
1008
+ deliveryCompanyList.value = Array.isArray(
1009
+ siteDataValue?.deliveryCompanyList
1010
+ )
1011
+ ? siteDataValue.deliveryCompanyList
1012
+ : [];
1013
+ }
742
1014
  },
743
1015
  { immediate: true }
744
1016
  );
@@ -746,83 +1018,96 @@ watch(
746
1018
  watch(
747
1019
  [blocksListData],
748
1020
  () => {
749
- if (blocksListStatus.value === 'pending') {
1021
+ if (blocksListStatus.value === "pending") {
750
1022
  blocksArray.value = [];
751
1023
  return;
752
1024
  }
753
1025
 
754
- const arr = Array.isArray(blocksListData.value?.data) ? blocksListData.value?.data : [];
1026
+ const arr = Array.isArray(blocksListData.value?.data)
1027
+ ? blocksListData.value?.data
1028
+ : [];
755
1029
  blocksArray.value = arr.map((block: any) => ({
756
1030
  title: block.name,
757
1031
  value: block._id,
758
1032
  }));
759
1033
  },
760
1034
  { immediate: true, deep: true }
761
- )
762
-
1035
+ );
763
1036
 
764
- watch([levelsData], () => {
765
- if (levelsStatus.value === 'pending') {
766
- levelsArray.value = [];
767
- return;
768
- }
1037
+ watch(
1038
+ [levelsData],
1039
+ () => {
1040
+ if (levelsStatus.value === "pending") {
1041
+ levelsArray.value = [];
1042
+ return;
1043
+ }
769
1044
 
770
- const arr = Array.isArray(levelsData.value?.data) ? levelsData.value?.data : [];
771
- const mappedLevels = arr.map((level: any) => ({
772
- title: level.name,
773
- value: level._id,
774
- }));
775
- levelsArray.value = mappedLevels;
776
- }, { immediate: true, deep: true})
1045
+ const arr = Array.isArray(levelsData.value?.data)
1046
+ ? levelsData.value?.data
1047
+ : [];
1048
+ const mappedLevels = arr.map((level: any) => ({
1049
+ title: level.name,
1050
+ value: level._id,
1051
+ }));
1052
+ levelsArray.value = mappedLevels;
1053
+ },
1054
+ { immediate: true, deep: true }
1055
+ );
777
1056
 
778
1057
  watch(
779
1058
  unitsData,
780
1059
  (newVal: any) => {
781
1060
  if (!newVal || !Array.isArray(newVal)) {
782
- unitsArray.value = []
783
- return
1061
+ unitsArray.value = [];
1062
+ return;
784
1063
  }
785
1064
 
786
1065
  const mapped = newVal.map((unit: any) => ({
787
1066
  title: unit.name,
788
1067
  value: unit._id,
789
- }))
1068
+ }));
790
1069
 
791
1070
  // keep custom unit pushed from autofill
792
- const selected = visitor.unit
793
- const exists = mapped.some((u: TDefaultOptionObj) => u.value === selected)
1071
+ const selected = visitor.unit;
1072
+ const exists = mapped.some((u: TDefaultOptionObj) => u.value === selected);
794
1073
 
795
1074
  if (!exists && visitor.unitName) {
796
1075
  mapped.push({
797
1076
  title: visitor.unitName,
798
1077
  value: selected,
799
- })
1078
+ });
800
1079
  }
801
1080
 
802
- unitsArray.value = mapped
1081
+ unitsArray.value = mapped;
803
1082
  },
804
1083
  { immediate: true, deep: true }
805
- )
806
-
1084
+ );
807
1085
 
808
- const { data: buildingUnitData, refresh: refreshBuildingUnitData, pending: buildingUnitDataPending } = useLazyAsyncData(`building-unit-data-${visitor.unit}`, () => {
1086
+ const {
1087
+ data: buildingUnitData,
1088
+ refresh: refreshBuildingUnitData,
1089
+ pending: buildingUnitDataPending,
1090
+ } = useLazyAsyncData(`building-unit-data-${visitor.unit}`, () => {
809
1091
  if (!visitor.unit) return Promise.resolve(null);
810
1092
  return getUnitDataById(visitor.unit);
811
- })
1093
+ });
812
1094
 
813
1095
  // trigger refresh of building unit data when unit changes, to get the latest unit name in case there are changes in the backend
814
- watch(() => visitor.unit, () => {
815
- if (visitor.unit) {
816
- refreshBuildingUnitData();
817
- } else {
818
- registeredUnitCompanyName.value = 'N/A';
1096
+ watch(
1097
+ () => visitor.unit,
1098
+ () => {
1099
+ if (visitor.unit) {
1100
+ refreshBuildingUnitData();
1101
+ } else {
1102
+ registeredUnitCompanyName.value = "N/A";
1103
+ }
819
1104
  }
820
- })
1105
+ );
821
1106
 
822
1107
  watch(buildingUnitData, (newVal: any) => {
823
- registeredUnitCompanyName.value = newVal?.data?.buildingUnit?.companyName || 'N/A';
824
- })
825
-
1108
+ registeredUnitCompanyName.value =
1109
+ newVal?.data?.buildingUnit?.companyName || "N/A";
1110
+ });
826
1111
 
827
1112
  function handleChangeBlock(value: any) {
828
1113
  visitor.level = "";
@@ -839,17 +1124,19 @@ function handleUpdateUnit(value: any) {
839
1124
  visitor.unitName = selectedUnit?.title || "";
840
1125
  }
841
1126
 
842
- const debounceFetchNRIC = debounce(fetchPersonByNRICRefresh, 500)
843
- const debounceFetchContact = debounce(fetchPersonByContactRefresh, 500)
1127
+ const debounceFetchNRIC = debounce(fetchPersonByNRICRefresh, 500);
1128
+ const debounceFetchContact = debounce(fetchPersonByContactRefresh, 500);
844
1129
 
845
1130
  function handleUpdateNRIC() {
846
- if (currentAutofillSource.value && currentAutofillSource.value !== "nric") return;
847
- debounceFetchNRIC()
1131
+ if (currentAutofillSource.value && currentAutofillSource.value !== "nric")
1132
+ return;
1133
+ debounceFetchNRIC();
848
1134
  }
849
1135
 
850
1136
  function handleUpdateContact() {
851
- if (currentAutofillSource.value && currentAutofillSource.value !== "contact") return;
852
- debounceFetchContact()
1137
+ if (currentAutofillSource.value && currentAutofillSource.value !== "contact")
1138
+ return;
1139
+ debounceFetchContact();
853
1140
  }
854
1141
 
855
1142
  function backToSelection() {
@@ -908,6 +1195,7 @@ async function submit() {
908
1195
  type: prop.type,
909
1196
  org: prop.org,
910
1197
  site: prop.site,
1198
+ createdBy: prop.currentUser,
911
1199
  };
912
1200
 
913
1201
  if (prop.mode === "add" || prop.mode === "register") {
@@ -928,11 +1216,8 @@ async function submit() {
928
1216
  payload.visitorPass = visitor.visitorPass;
929
1217
  payload.passKeys = visitor.passKeys;
930
1218
  }
931
-
932
1219
  }
933
1220
 
934
-
935
-
936
1221
  if (prop.type === "contractor") {
937
1222
  // contractor type logic payload
938
1223
  payload = {
@@ -944,21 +1229,24 @@ async function submit() {
944
1229
  if (prop.type === "delivery") {
945
1230
  payload = {
946
1231
  ...payload,
947
- company: deliveryCompany.value
948
- }
1232
+ company: deliveryCompany.value,
1233
+ };
949
1234
  }
950
1235
 
951
1236
  // add register status when registering unregistered visitor
952
- if (prop.mode === 'register') {
953
- payload.status = "registered"
1237
+ if (prop.mode === "register") {
1238
+ payload.status = "registered";
954
1239
  }
955
1240
 
956
1241
  try {
957
1242
  let res;
958
1243
  if (prop.mode === "add") {
959
1244
  res = await createVisitor(payload as TVisitorPayload);
960
- } else if ((prop.mode === "edit" || prop.mode === "register") && prop.visitorData?._id) {
961
- const { unitName, ...rest } = payload
1245
+ } else if (
1246
+ (prop.mode === "edit" || prop.mode === "register") &&
1247
+ prop.visitorData?._id
1248
+ ) {
1249
+ const { unitName, ...rest } = payload;
962
1250
  res = await updateVisitor(prop.visitorData._id, rest as TVisitorPayload);
963
1251
  }
964
1252
 
@@ -967,7 +1255,9 @@ async function submit() {
967
1255
  const visitorId = res as unknown as string;
968
1256
  const rawUrl = entryPassSettings.value?.data?.settings?.url;
969
1257
  const { encrypted: acmUrl } = await $fetch<{ encrypted: string }>(
970
- `/api/encrypt-acm-url${rawUrl ? `?url=${encodeURIComponent(rawUrl)}` : ""}`
1258
+ `/api/encrypt-acm-url${
1259
+ rawUrl ? `?url=${encodeURIComponent(rawUrl)}` : ""
1260
+ }`
971
1261
  );
972
1262
  if (visitorId && acmUrl) {
973
1263
  const passRes = await createVisitorPass({
@@ -982,7 +1272,8 @@ async function submit() {
982
1272
 
983
1273
  if (passType.value === "QR") {
984
1274
  console.log("[QR Print] passRes:", passRes);
985
- const accessCards: any[] = (passRes as any)?.data?.accessCards ?? [];
1275
+ const accessCards: any[] =
1276
+ (passRes as any)?.data?.accessCards ?? [];
986
1277
  console.log("[QR Print] accessCards:", accessCards);
987
1278
  const printer = entryPassSettings.value?.data?.settings?.printer;
988
1279
  console.log("[QR Print] printer config:", printer);
@@ -994,23 +1285,57 @@ async function submit() {
994
1285
  const vendorId = parseInt(printer.vendorId);
995
1286
  const productId = parseInt(printer.productId);
996
1287
  const companyName = visitor.company || "";
997
- const blockLabel = blocksArray.value.find((b: any) => b.value === visitor.block)?.title || "";
998
- const levelLabel = levelsArray.value.find((l: any) => l.value === visitor.level)?.title || "";
999
- const unitLabel = unitsArray.value.find((u: any) => u.value === visitor.unit)?.title || "";
1000
- const address = [blockLabel, levelLabel, unitLabel].filter(Boolean).join("/");
1001
- console.log("[QR Print] Printing", accessCards.length, "card(s). vendorId:", vendorId, "productId:", productId, "address:", address);
1288
+ const blockLabel =
1289
+ blocksArray.value.find((b: any) => b.value === visitor.block)
1290
+ ?.title || "";
1291
+ const levelLabel =
1292
+ levelsArray.value.find((l: any) => l.value === visitor.level)
1293
+ ?.title || "";
1294
+ const unitLabel =
1295
+ unitsArray.value.find((u: any) => u.value === visitor.unit)
1296
+ ?.title || "";
1297
+ const address = [blockLabel, levelLabel, unitLabel]
1298
+ .filter(Boolean)
1299
+ .join("/");
1300
+ console.log(
1301
+ "[QR Print] Printing",
1302
+ accessCards.length,
1303
+ "card(s). vendorId:",
1304
+ vendorId,
1305
+ "productId:",
1306
+ productId,
1307
+ "address:",
1308
+ address
1309
+ );
1002
1310
 
1003
1311
  await nextTick();
1004
1312
  for (const qrCode of accessCards) {
1005
1313
  console.log("[QR Print] Signing QR for card:", qrCode._id);
1006
- const signed = await signQr({ cardId: qrCode._id, purpose: "vms" });
1314
+ const signed = await signQr({
1315
+ cardId: qrCode._id,
1316
+ purpose: "vms",
1317
+ });
1007
1318
  const qrData = signed?.data;
1008
- console.log("[QR Print] signQr result:", signed, "| qrData:", qrData);
1319
+ console.log(
1320
+ "[QR Print] signQr result:",
1321
+ signed,
1322
+ "| qrData:",
1323
+ qrData
1324
+ );
1009
1325
  if (!qrData) {
1010
- console.warn("[QR Print] Skipping card", qrCode._id, "— signQr returned no data.");
1326
+ console.warn(
1327
+ "[QR Print] Skipping card",
1328
+ qrCode._id,
1329
+ "— signQr returned no data."
1330
+ );
1011
1331
  continue;
1012
1332
  }
1013
- console.log("[QR Print] Sending to printer — accessLevel:", qrCode.accessLevel, "liftLevel:", qrCode.liftAccessLevel);
1333
+ console.log(
1334
+ "[QR Print] Sending to printer — accessLevel:",
1335
+ qrCode.accessLevel,
1336
+ "liftLevel:",
1337
+ qrCode.liftAccessLevel
1338
+ );
1014
1339
  const printResult = await testConnection(
1015
1340
  vendorId,
1016
1341
  productId,
@@ -1019,9 +1344,14 @@ async function submit() {
1019
1344
  qrCode.accessLevel,
1020
1345
  qrCode.liftAccessLevel,
1021
1346
  companyName,
1022
- address,
1347
+ address
1348
+ );
1349
+ console.log(
1350
+ "[QR Print] Print result for card",
1351
+ qrCode._id,
1352
+ ":",
1353
+ printResult
1023
1354
  );
1024
- console.log("[QR Print] Print result for card", qrCode._id, ":", printResult);
1025
1355
  }
1026
1356
  }
1027
1357
  }
@@ -1035,7 +1365,8 @@ async function submit() {
1035
1365
  const err = error?.data?.message;
1036
1366
  errorMessage.value =
1037
1367
  err ||
1038
- `Failed to ${prop.mode === "add" ? "add" : "update"
1368
+ `Failed to ${
1369
+ prop.mode === "add" ? "add" : "update"
1039
1370
  } visitor. Please try again.`;
1040
1371
  } finally {
1041
1372
  processing.value = false;
@@ -1065,9 +1396,12 @@ onMounted(() => {
1065
1396
  contractorStep.value = 1;
1066
1397
  currentAutofillSource.value = null;
1067
1398
 
1068
- if (prop.mode === 'register' && prop.visitorData) {
1069
- console.log('Register mode, prefill visitor data', prop.visitorData?.plateNumber)
1070
- visitor.plateNumber = prop.visitorData?.plateNumber || ""
1399
+ if (prop.mode === "register" && prop.visitorData) {
1400
+ console.log(
1401
+ "Register mode, prefill visitor data",
1402
+ prop.visitorData?.plateNumber
1403
+ );
1404
+ visitor.plateNumber = prop.visitorData?.plateNumber || "";
1071
1405
  }
1072
1406
  });
1073
1407
  </script>