@iservice365/layer-common 1.3.0 → 1.3.2

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.
@@ -11,49 +11,24 @@
11
11
  <div class="w-100 d-flex justify-space-between ga-2">
12
12
  <span class="text-subtitle-1 w-100 font-weight-bold mb-3">{{
13
13
  formTitle
14
- }}</span>
15
- <span
16
- v-if="prop.type === 'contractor'"
17
- class="text-subtitle-2 font-weight-bold"
18
- style="text-wrap: nowrap"
19
- >Step <span class="text-primary-button">{{ contractorStep }}</span
20
- >/3</span
21
- >
14
+ }}</span>
15
+ <span v-if="prop.type === 'contractor'" class="text-subtitle-2 font-weight-bold" style="text-wrap: nowrap">Step
16
+ <span class="text-primary-button">{{ contractorStep }}</span>/3</span>
22
17
  </div>
23
- <v-form
24
- ref="formRef"
25
- v-model="validForm"
26
- :disabled="processing"
27
- @click="errorMessage = ''"
28
- >
18
+ <v-form ref="formRef" v-model="validForm" :disabled="processing" @click="errorMessage = ''">
29
19
  <v-row no-gutters class="pt-4">
30
20
  <v-col v-if="shouldShowField('contractorType')" cols="12">
31
- <InputLabel
32
- class="text-capitalize"
33
- title="Contractor Type"
34
- required
35
- />
36
- <v-combobox
37
- v-model="contractorTypeObj"
38
- v-model:search="contractorTypeInput"
39
- :hide-no-data="false"
40
- @update:focused="handleFocusedContractorType"
41
- :items="contractorTypes"
42
- :rules="[requiredRule]"
43
- item-value="value"
44
- @update:model-value="handleSelectContractorType"
45
- variant="outlined"
46
- density="comfortable"
47
- persistent-hint
48
- small-chips
49
- >
21
+ <InputLabel class="text-capitalize" title="Contractor Type" required />
22
+ <v-combobox v-model="contractorTypeObj" v-model:search="contractorTypeInput" :hide-no-data="false"
23
+ @update:focused="handleFocusedContractorType" :items="contractorTypes" :rules="[requiredRule]"
24
+ item-value="value" @update:model-value="handleSelectContractorType" variant="outlined"
25
+ density="comfortable" persistent-hint small-chips>
50
26
  <template v-slot:no-data>
51
27
  <v-list-item>
52
28
  <v-list-item-title>
53
29
  No results matching "<strong>{{
54
30
  contractorTypeInput
55
- }}</strong
56
- >". This value will be added as new option.
31
+ }}</strong>". This value will be added as new option.
57
32
  </v-list-item-title>
58
33
  </v-list-item>
59
34
  </template>
@@ -68,29 +43,30 @@
68
43
  <v-col v-if="shouldShowField('name')" cols="12">
69
44
  <v-row>
70
45
  <v-col cols="12">
71
- <InputLabel
72
- class="text-capitalize"
73
- title="Full Name"
74
- required
75
- />
76
- <v-text-field
77
- v-model.trim="visitor.name"
78
- density="comfortable"
79
- :rules="[requiredRule]"
80
- />
46
+ <InputLabel class="text-capitalize" title="Full Name" required />
47
+ <v-text-field v-model.trim="visitor.name" density="comfortable" :rules="[requiredRule]" />
81
48
  </v-col>
82
49
  </v-row>
83
50
  </v-col>
84
51
 
52
+ <v-col v-if="shouldShowField('nric')" cols="12">
53
+ <v-row>
54
+ <v-col cols="12">
55
+ <InputLabel class="text-capitalize" title="NRIC/Passport/ID No." required />
56
+ <InputNRICNumber v-model.trim="visitor.nric" density="comfortable" :rules="[requiredRule]" @update:model-value="handleUpdateNRIC" :loading="fetchPersonByNRICPending" />
57
+ </v-col>
58
+ </v-row>
59
+ </v-col>
60
+
61
+ <v-col v-if="shouldShowField('contact')" cols="12">
62
+ <InputLabel class="text-capitalize" title="Phone Number" required />
63
+ <InputPhoneNumberV2 v-model="visitor.contact" :rules="[requiredRule]" density="comfortable" />
64
+ </v-col>
65
+
85
66
  <v-col v-if="shouldShowField('deliveryType')" cols="12">
86
67
  <v-row>
87
68
  <v-col cols="12">
88
- <v-radio-group
89
- v-model="visitor.deliveryType"
90
- inline
91
- color="primary"
92
- :rules="[requiredRule]"
93
- >
69
+ <v-radio-group v-model="visitor.deliveryType" inline color="primary" :rules="[requiredRule]">
94
70
  <v-radio label="Food" value="Food"></v-radio>
95
71
  <v-radio label="Parcel" value="Parcel"></v-radio>
96
72
  </v-radio-group>
@@ -99,158 +75,66 @@
99
75
  </v-col>
100
76
 
101
77
  <template v-if="shouldShowField('company')">
102
- <v-col v-if="prop.type === 'delivery'" cols="12">
103
- <InputLabel
104
- class="text-capitalize"
105
- title="Company Name"
106
- required
107
- />
108
- <v-combobox
109
- v-model="companyNameObj"
110
- v-model:search="companyNameInput"
111
- :hide-no-data="false"
112
- @update:focused="handleFocusedCompanyName"
113
- :items="companyNames"
114
- :rules="[requiredRule]"
115
- item-value="value"
116
- @update:model-value="handleSelectCompanyName"
117
- variant="outlined"
118
- density="comfortable"
119
- persistent-hint
120
- small-chips
121
- >
78
+ <v-col cols="12">
79
+ <InputLabel class="text-capitalize" title="Company Name" required />
80
+ <v-combobox v-model="visitor.company" v-model:search="companyNameInput" :hide-no-data="false"
81
+ :items="companyNames" :rules="[requiredRule]"
82
+ item-value="value" @update:model-value="handleSelectCompanyName" variant="outlined"
83
+ density="comfortable" persistent-hint small-chips>
122
84
  <template v-slot:no-data>
123
85
  <v-list-item>
124
- <v-list-item-title>
125
- No results matching "<strong>{{
126
- contractorTypeInput
127
- }}</strong
128
- >". This value will be added as new option.
86
+ <v-list-item-title v-if="companyNameInput">
87
+ No results matching "<strong>{{companyNameInput}}</strong>". This value will be added as new option.
88
+ </v-list-item-title>
89
+ <v-list-item-title v-else>
90
+ No companies available. Start typing to add a new one.
129
91
  </v-list-item-title>
130
92
  </v-list-item>
131
93
  </template>
132
94
  </v-combobox>
133
95
  </v-col>
134
-
135
- <v-col v-else cols="12">
136
- <v-row>
137
- <v-col cols="12">
138
- <InputLabel
139
- class="text-capitalize"
140
- title="Company Name"
141
- required
142
- />
143
- <v-text-field
144
- v-model.trim="visitor.company"
145
- density="comfortable"
146
- :rules="[requiredRule]"
147
- />
148
- </v-col>
149
- </v-row>
150
- </v-col>
151
96
  </template>
152
97
 
153
- <v-col v-if="shouldShowField('nric')" cols="12">
154
- <v-row>
155
- <v-col cols="12">
156
- <InputLabel
157
- class="text-capitalize"
158
- title="NRIC/Passport/ID No."
159
- required
160
- />
161
- <InputNRICNumber
162
- v-model.trim="visitor.nric"
163
- density="comfortable"
164
- :rules="[requiredRule]"
165
- />
166
- </v-col>
167
- </v-row>
168
- </v-col>
169
-
170
- <v-col v-if="shouldShowField('contact')" cols="12">
171
- <InputLabel class="text-capitalize" title="Phone Number" required />
172
- <InputPhoneNumberV2 v-model="visitor.contact" :rules="[requiredRule]" density="comfortable"/>
173
- </v-col>
174
98
 
175
99
  <v-col v-if="shouldShowField('plateNumber')" cols="12">
176
100
  <v-row>
177
101
  <v-col cols="12">
178
- <InputLabel
179
- class="text-capitalize"
180
- title="Vehicle Number"
181
- required
182
- />
102
+ <InputLabel class="text-capitalize" title="Vehicle Number" required />
183
103
  <!-- <v-text-field v-model.trim.uppercase="visitor.plateNumber" density="comfortable" /> -->
184
- <InputVehicleNumber
185
- v-model.trim="visitor.plateNumber"
186
- density="comfortable"
187
- :rules="[requiredRule]"
188
- />
104
+ <InputVehicleNumber v-model.trim="visitor.plateNumber" density="comfortable" :rules="[requiredRule]" />
189
105
  </v-col>
190
106
  </v-row>
191
107
  </v-col>
192
108
 
193
109
  <v-col v-if="shouldShowField('block')" cols="12">
194
110
  <InputLabel class="text-capitalize" title="Block" required />
195
- <v-select
196
- v-model="visitor.block"
197
- :items="blocksArray"
198
- item-value="value"
199
- item-title="title"
200
- :loading="blockStatus === 'pending'"
201
- @update:model-value="handleChangeBlock"
202
- density="comfortable"
203
- :rules="[requiredRule]"
204
- />
111
+ <v-select v-model="visitor.block" :items="blocksArray" item-value="value" item-title="title"
112
+ :loading="blockStatus === 'pending'" @update:model-value="handleChangeBlock" density="comfortable"
113
+ :rules="[requiredRule]" />
205
114
  </v-col>
206
115
 
207
116
  <v-col v-if="shouldShowField('level')" cols="12">
208
117
  <InputLabel class="text-capitalize" title="Level" required />
209
- <v-select
210
- v-model="visitor.level"
211
- :items="levelsArray"
212
- density="comfortable"
213
- :disabled="!visitor.block"
214
- :loading="levelsStatus === 'pending'"
215
- @update:model-value="handleChangeLevel"
216
- :rules="[requiredRule]"
217
- />
118
+ <v-select v-model="visitor.level" :items="levelsArray" density="comfortable" :disabled="!visitor.block"
119
+ :loading="levelsStatus === 'pending'" @update:model-value="handleChangeLevel" :rules="[requiredRule]" />
218
120
  </v-col>
219
121
 
220
122
  <v-col v-if="shouldShowField('unit')" cols="12">
221
123
  <InputLabel class="text-capitalize" title="Unit" required />
222
- <v-select
223
- v-model="visitor.unit"
224
- :items="unitsArray"
225
- density="comfortable"
226
- :disabled="!visitor.level"
227
- :loading="unitsStatus === 'pending'"
228
- :rules="[requiredRule]"
229
- @update:model-value="handleUpdateUnit"
230
- />
124
+ <v-select v-model="visitor.unit" :items="unitsArray" density="comfortable" :disabled="!visitor.level"
125
+ :loading="unitsStatus === 'pending'" :rules="[requiredRule]" @update:model-value="handleUpdateUnit" />
231
126
  </v-col>
232
127
 
233
128
  <v-col v-if="shouldShowField('remarks')" cols="12">
234
129
  <InputLabel class="text-capitalize" title="Remarks" />
235
- <v-textarea
236
- v-model="visitor.remarks"
237
- density="comfortable"
238
- :rows="3"
239
- no-resize
240
- />
130
+ <v-textarea v-model="visitor.remarks" density="comfortable" :rows="3" no-resize />
241
131
  </v-col>
242
132
 
243
- <v-col
244
- v-if="prop.type === 'contractor' && contractorStep === 2"
245
- cols="12"
246
- >
133
+ <v-col v-if="prop.type === 'contractor' && contractorStep === 2" cols="12">
247
134
  <PassInformation />
248
135
  </v-col>
249
136
 
250
- <v-col
251
- v-if="prop.type === 'contractor' && contractorStep === 3"
252
- cols="12"
253
- >
137
+ <v-col v-if="prop.type === 'contractor' && contractorStep === 3" cols="12">
254
138
  <MemberInformation v-model="visitor.members" />
255
139
  </v-col>
256
140
 
@@ -275,66 +159,20 @@
275
159
  <v-toolbar density="compact">
276
160
  <v-row no-gutters>
277
161
  <v-col cols="6">
278
- <v-btn
279
- v-if="
280
- prop.mode === 'add' &&
281
- prop.type === 'contractor' &&
282
- contractorStep > 1
283
- "
284
- tile
285
- block
286
- variant="text"
287
- class="text-none"
288
- size="48"
289
- @click="handleGoToPreviousPage"
290
- text="Back"
291
- />
292
- <v-btn
293
- v-else-if="prop.mode === 'add'"
294
- tile
295
- block
296
- variant="text"
297
- class="text-none"
298
- size="48"
299
- @click="backToSelection"
300
- text="Back to Selection"
301
- />
302
- <v-btn
303
- v-else
304
- tile
305
- block
306
- variant="text"
307
- class="text-none"
308
- size="48"
309
- @click="close"
310
- text="Close"
311
- />
162
+ <v-btn v-if="
163
+ prop.mode === 'add' &&
164
+ prop.type === 'contractor' &&
165
+ contractorStep > 1
166
+ " tile block variant="text" class="text-none" size="48" @click="handleGoToPreviousPage" text="Back" />
167
+ <v-btn v-else-if="prop.mode === 'add'" tile block variant="text" class="text-none" size="48"
168
+ @click="backToSelection" text="Back to Selection" />
169
+ <v-btn v-else tile block variant="text" class="text-none" size="48" @click="close" text="Close" />
312
170
  </v-col>
313
171
  <v-col cols="6">
314
- <v-btn
315
- v-if="prop.type === 'contractor'"
316
- tile
317
- block
318
- variant="flat"
319
- color="primary-button"
320
- class="text-none"
321
- size="48"
322
- :disabled="processing"
323
- @click="handleNextPage"
324
- :text="contractorStep === 3 ? 'Submit' : 'Next'"
325
- />
326
- <v-btn
327
- v-else
328
- tile
329
- block
330
- variant="flat"
331
- color="black"
332
- class="text-none"
333
- size="48"
334
- :disabled="!validForm || processing"
335
- @click="submit"
336
- :text="prop.mode == 'add' ? 'Submit' : 'Update'"
337
- />
172
+ <v-btn v-if="prop.type === 'contractor'" tile block variant="flat" color="primary-button" class="text-none"
173
+ size="48" :disabled="processing" @click="handleNextPage" :text="contractorStep === 3 ? 'Submit' : 'Next'" />
174
+ <v-btn v-else tile block variant="flat" color="black" class="text-none" size="48"
175
+ :disabled="!validForm || processing" @click="submit" :text="prop.mode == 'add' ? 'Submit' : 'Update'" />
338
176
  </v-col>
339
177
  </v-row>
340
178
  </v-toolbar>
@@ -366,9 +204,10 @@ const prop = defineProps({
366
204
  },
367
205
  });
368
206
 
369
- const { requiredRule, formatDateISO8601 } = useUtils();
207
+ const { requiredRule, debounce } = useUtils();
370
208
  const { getSiteById, getSiteLevels, getSiteUnits } = useSiteSettings();
371
209
  const { createVisitor, typeFieldMap, contractorTypes } = useVisitor();
210
+ const { findPersonByNRIC } = usePeople()
372
211
 
373
212
  const emit = defineEmits([
374
213
  "back",
@@ -408,7 +247,7 @@ const contractorTypeObj = ref<TDefaultOptionObj | null>(null);
408
247
  const contractorStep = ref(1);
409
248
 
410
249
  const companyNameInput = ref("");
411
- const companyNameObj = ref<TDefaultOptionObj | null>(null);
250
+ const companyNameObj = ref<string | null>(null);
412
251
 
413
252
 
414
253
  const blocksArray = ref<TDefaultOptionObj[]>([]);
@@ -422,40 +261,7 @@ const shouldShowField = (fieldKey: keyof TVisitorPayload) => {
422
261
  }
423
262
  };
424
263
 
425
- const companyNames = computed(() => {
426
- const arr: string[] = [
427
- "Foodpanda",
428
- "GrabFood",
429
- "Deliveroo",
430
- "Lazada",
431
- "Amazon",
432
- "RedMart",
433
- "J&T",
434
- "NTUC FairPrice",
435
- "NinjaVan",
436
- "Lalamove",
437
- "SingPost",
438
- "EasyParcel",
439
- "DHL",
440
- "FedEx",
441
- "Oddle",
442
- "UParcel",
443
- "UPS",
444
- "Park N Parcel",
445
- "ParkXL",
446
- "Airpak Express",
447
- "Pandago",
448
- "Qdelivery",
449
- "iXpress Logistics",
450
- "Blue Dart",
451
- "GogoX",
452
- "Others (Type in remarks)",
453
- ];
454
- return arr.map((x) => ({
455
- title: x,
456
- value: x,
457
- }));
458
- });
264
+ const companyNames = ref<string[]>([])
459
265
 
460
266
  const formTitle = computed(() => {
461
267
  const isContractorForm = prop.type === "contractor";
@@ -478,26 +284,50 @@ function handleFocusedContractorType() {
478
284
  );
479
285
  if (!matched) {
480
286
  contractorTypeObj.value = null;
481
- contractorTypeInput.value = "";
287
+ contractorTypeInput.value = ""
482
288
  visitor.contractorType = "";
483
289
  }
484
290
  }
485
291
 
486
- function handleSelectCompanyName(obj: { title: string; value: string }) {
487
- visitor.company = obj.value ?? "";
292
+ function handleSelectCompanyName(company: string) {
293
+ visitor.company = company
488
294
  }
489
295
 
490
- function handleFocusedCompanyName() {
491
- const obj = companyNameObj.value;
492
- const matched = companyNames.value.some(
493
- (x) => x.value === obj?.value && x.title === obj?.title
494
- );
495
- if (!matched) {
496
- companyNameObj.value = null;
497
- companyNameInput.value = "";
498
- visitor.company = "";
499
- }
296
+ // function handleFocusedCompanyName() {
297
+ // const companyNameSelected = companyNameObj.value;
298
+ // const matched = companyNames.value.some((x) => x === companyNameSelected);
299
+ // if (!matched) {
300
+ // companyNameObj.value = null;
301
+ // companyNameInput.value = "";
302
+ // visitor.company = "";
303
+ // }
304
+ // }
305
+
306
+ const {
307
+ data: fetchPersonByNRICReq,
308
+ refresh: fetchPersonByNRICRefresh,
309
+ pending: fetchPersonByNRICPending,
310
+ } = useLazyAsyncData(`fetch-company-list`, () =>{
311
+ const NRIC = visitor.nric;
312
+ if(!NRIC) return Promise.resolve(null)
313
+ return findPersonByNRIC(NRIC)
500
314
  }
315
+ );
316
+
317
+ watch(fetchPersonByNRICReq, (obj) => {
318
+ if(obj){
319
+ companyNames.value = obj.companyName ?? []
320
+ visitor.name = obj.name
321
+ visitor.contact = obj.contact
322
+ if(!visitor.company){
323
+ visitor.company = companyNames.value?.[0]
324
+ }
325
+ visitor.plateNumber = obj.plateNumber ?? ""
326
+ visitor.block = obj.block ?? ""
327
+ visitor.level = obj.level ?? ""
328
+ visitor.unit = obj.unit ?? ""
329
+ }
330
+ })
501
331
 
502
332
  const {
503
333
  data: siteData,
@@ -516,7 +346,7 @@ const {
516
346
  async () => {
517
347
  if (!visitor.block) return Promise.resolve(null);
518
348
  return await getSiteLevels(prop.site, { block: Number(visitor.block) });
519
- }
349
+ }, {watch: [() => visitor.block]}
520
350
  );
521
351
 
522
352
  const {
@@ -528,7 +358,7 @@ const {
528
358
  async () => {
529
359
  if (!visitor.level) return Promise.resolve(null);
530
360
  return await getSiteUnits(prop.site, Number(visitor.block), visitor.level);
531
- }
361
+ }, {watch: [() => visitor.level]}
532
362
  );
533
363
 
534
364
  watch(
@@ -586,12 +416,10 @@ watch(
586
416
  function handleChangeBlock(value: any) {
587
417
  visitor.level = "";
588
418
  visitor.unit = "";
589
- refreshLevelsData();
590
419
  }
591
420
 
592
421
  function handleChangeLevel(value: any) {
593
422
  visitor.unit = "";
594
- refreshUnitsData();
595
423
  }
596
424
 
597
425
  function handleUpdateUnit(value: any) {
@@ -599,6 +427,12 @@ function handleUpdateUnit(value: any) {
599
427
  visitor.unitName = selectedUnit?.title || "";
600
428
  }
601
429
 
430
+ const debounceFetchNRIC = debounce(fetchPersonByNRICRefresh, 500)
431
+
432
+ function handleUpdateNRIC(){
433
+ debounceFetchNRIC()
434
+ }
435
+
602
436
  function backToSelection() {
603
437
  emit("back");
604
438
  message.value = "";
@@ -617,6 +451,8 @@ function close() {
617
451
 
618
452
  function formatVisitorType(type: TVisitorType): string {
619
453
  switch (type) {
454
+ case "guest":
455
+ return "Guest";
620
456
  case "contractor":
621
457
  return "Contractor";
622
458
  case "delivery":
@@ -686,8 +522,7 @@ async function submit() {
686
522
  const err = error?.data?.message;
687
523
  errorMessage.value =
688
524
  err ||
689
- `Failed to ${
690
- prop.mode === "add" ? "add" : "update"
525
+ `Failed to ${prop.mode === "add" ? "add" : "update"
691
526
  } visitor. Please try again.`;
692
527
  } finally {
693
528
  processing.value = false;