@7365admin1/layer-common 1.11.49 → 1.11.51

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @iservice365/layer-common
2
2
 
3
+ ## 1.11.51
4
+
5
+ ### Patch Changes
6
+
7
+ - 9e40a22: Update Vehicle Mgmt filter
8
+
9
+ ## 1.11.50
10
+
11
+ ### Patch Changes
12
+
13
+ - 92473a5: update useRole and useOrg
14
+
3
15
  ## 1.11.49
4
16
 
5
17
  ### Patch Changes
@@ -177,16 +177,16 @@ const hostRule = computed(() => {
177
177
  return (v: string | any) => {
178
178
  if (!v) return true;
179
179
 
180
- const isAnpr = prop.type === 'anpr';
181
-
180
+ const isAnpr = prop.type === "anpr";
181
+
182
182
  const anprRegex = /^http:\/\/[a-z0-9.-]+\.[a-z]{2,}(:\d+)?$/i;
183
183
  const defaultRegex = /^https:\/\/[a-z0-9.-]+\.[a-z]{2,}\/[a-z0-9._-]+$/i;
184
184
 
185
185
  if (isAnpr) {
186
- return anprRegex.test(v) || 'Format: http://domain:port';
186
+ return anprRegex.test(v) || "Format: http://domain:port";
187
187
  }
188
-
189
- return defaultRegex.test(v) || 'Format: https://domain/path';
188
+
189
+ return defaultRegex.test(v) || "Format: https://domain/path";
190
190
  };
191
191
  });
192
192
 
@@ -211,8 +211,18 @@ if (prop.mode === "edit") {
211
211
  console.log("prop.camera", prop?.camera);
212
212
  camera.value.site = prop.site;
213
213
  camera.value.type = prop.type;
214
- camera.value.category = prop.camera?.category && prop.title == "Edit Camera" ? prop.camera?.category : prop.type == "anpr" ? "resident" : "standard";
215
- camera.value.direction = prop.camera?.direction && prop.title == "Edit Camera" ? prop.camera?.direction : prop.type == "anpr" ? "both" : "none";
214
+ camera.value.category =
215
+ prop.camera?.category && prop.title == "Edit Camera"
216
+ ? prop.camera?.category
217
+ : prop.type == "anpr"
218
+ ? "resident"
219
+ : "standard";
220
+ camera.value.direction =
221
+ prop.camera?.direction && prop.title == "Edit Camera"
222
+ ? prop.camera?.direction
223
+ : prop.type == "anpr"
224
+ ? "both"
225
+ : "none";
216
226
 
217
227
  const validForm = ref(false);
218
228
  const formRef = ref<HTMLFormElement | null>(null);
@@ -289,6 +299,10 @@ async function submit() {
289
299
 
290
300
  emit("success", `${prop.title} added successfully!`);
291
301
  } catch (error: any) {
302
+ console.log(
303
+ "error",
304
+ error.response?._data?.message || "Failed to add camera"
305
+ );
292
306
  emit("error", error.response?._data?.message || "Failed to add camera");
293
307
  } finally {
294
308
  disable.value = false;
@@ -11,7 +11,7 @@
11
11
 
12
12
  <template #append>
13
13
  <v-btn
14
- v-if="!prop.readOnly"
14
+ v-if="!prop.readOnly"
15
15
  variant="flat"
16
16
  color="primary"
17
17
  class="text-none"
@@ -61,6 +61,7 @@
61
61
  :type="prop.type"
62
62
  @cancel="dialogAdd = false"
63
63
  @success="handleSuccess"
64
+ @error="handleError"
64
65
  />
65
66
  </v-dialog>
66
67
 
@@ -72,6 +73,7 @@
72
73
  :type="prop.type"
73
74
  @cancel="dialogEdit = false"
74
75
  @success="handleSuccess"
76
+ @error="handleError"
75
77
  mode="edit"
76
78
  :camera="camera"
77
79
  />
@@ -200,6 +202,13 @@
200
202
  </v-card>
201
203
  </v-dialog>
202
204
 
205
+ <Snackbar
206
+ v-model="messageSnackbar"
207
+ :text="message"
208
+ :color="messageColor"
209
+ style="z-index: 3000"
210
+ />
211
+
203
212
  <v-dialog v-model="dialogDelete" persistent width="540">
204
213
  <v-card width="100%">
205
214
  <v-card-text
@@ -319,6 +328,16 @@ const dialogEdit = ref(false);
319
328
  const dialogPreview = ref(false);
320
329
  const dialogDelete = ref(false);
321
330
 
331
+ const messageSnackbar = ref(false);
332
+ const message = ref("");
333
+ const messageColor = ref<"success" | "error" | "info">();
334
+
335
+ function showMessage(text: string, type: "success" | "error" | "info") {
336
+ messageSnackbar.value = true;
337
+ message.value = text;
338
+ messageColor.value = type;
339
+ }
340
+
322
341
  function openDialogEdit() {
323
342
  dialogEdit.value = true;
324
343
 
@@ -331,6 +350,11 @@ function openDialogDelete() {
331
350
  if (dialogPreview.value) dialogPreview.value = false;
332
351
  }
333
352
 
353
+ function handleError(msg: string) {
354
+ const text = prop.type === "ip" ? "CCTV camera already exist" : msg;
355
+ showMessage(text, "error");
356
+ }
357
+
334
358
  function handleSuccess() {
335
359
  if (dialogAdd.value) dialogAdd.value = false;
336
360
 
@@ -366,8 +390,11 @@ async function submitDelete() {
366
390
  await deleteSiteCameraById(camera.value._id ?? "");
367
391
  await getCameraRefresh();
368
392
  dialogDelete.value = false;
369
- } catch (error) {
370
- console.error("Error deleting camera:", error);
393
+ } catch (error: any) {
394
+ showMessage(
395
+ error?.response?._data?.message || "Failed to delete camera.",
396
+ "error"
397
+ );
371
398
  }
372
399
  }
373
400
  </script>
@@ -217,6 +217,46 @@
217
217
 
218
218
  <v-divider thickness="1"></v-divider>
219
219
 
220
+ <div class="d-flex w-100 mt-7 pb-10">
221
+ <p class="font-weight-medium flex-grow-1">
222
+ QR Code Validity
223
+ <span class="d-block text-caption text-grey-darken-1 mt-1">
224
+ Set how long a generated QR code remains valid before it expires.
225
+ </span>
226
+ <v-col cols="12" class="pr-0 mt-3">
227
+ <v-row no-gutters>
228
+ <v-col cols="12" md="4" class="mb-5">
229
+ <v-text-field
230
+ label="Validity (minutes)"
231
+ placeholder="e.g. 30"
232
+ hide-details
233
+ density="comfortable"
234
+ clearable
235
+ type="number"
236
+ min="1"
237
+ v-model.number="currentEntryPassSettings.qrCodeValidityMinutes"
238
+ ></v-text-field>
239
+ </v-col>
240
+ </v-row>
241
+ <v-row>
242
+ <v-col cols="12" md="3">
243
+ <v-btn
244
+ color="primary"
245
+ variant="flat"
246
+ prepend-icon="mdi-timer-outline"
247
+ block
248
+ @click="saveQrCodeValidity()"
249
+ >
250
+ Save
251
+ </v-btn>
252
+ </v-col>
253
+ </v-row>
254
+ </v-col>
255
+ </p>
256
+ </div>
257
+
258
+ <v-divider thickness="1"></v-divider>
259
+
220
260
  <div class="d-flex w-100 mt-7 pb-10">
221
261
  <p class="font-weight-medium flex-grow-1">
222
262
  Resident-app Disclaimer Message
@@ -326,6 +366,7 @@ const currentEntryPassSettings = ref<Record<string, any>>({
326
366
  qrCodeTemplateHeader: "",
327
367
  qrCodeTemplateHeaderSubText: "",
328
368
  qrCodeTemplateDate: "",
369
+ qrCodeValidityMinutes: null,
329
370
  disclaimerMessage: "",
330
371
  url: "",
331
372
  template: { id: "", name: "" },
@@ -489,6 +530,7 @@ watchEffect(() => {
489
530
  qrCodeTemplateHeader: data.settings?.qrTemplate?.header ?? "",
490
531
  qrCodeTemplateHeaderSubText: data.settings?.qrTemplate?.subText ?? "",
491
532
  qrCodeTemplateDate: data.settings?.qrTemplate?.date ?? "",
533
+ qrCodeValidityMinutes: data.settings?.validityMinutes ?? null,
492
534
  url: data.settings?.url ?? "",
493
535
  template: data.settings?.template ?? { id: "", name: "" },
494
536
  createdAt: data.createdAt ?? "",
@@ -518,6 +560,7 @@ function buildPayload() {
518
560
  subText: currentEntryPassSettings.value.qrCodeTemplateHeaderSubText,
519
561
  date: currentEntryPassSettings.value.qrCodeTemplateDate || null,
520
562
  },
563
+ validityMinutes: currentEntryPassSettings.value.qrCodeValidityMinutes || null,
521
564
  url: currentEntryPassSettings.value.url,
522
565
  template: currentEntryPassSettings.value.template?.id
523
566
  ? currentEntryPassSettings.value.template
@@ -550,6 +593,12 @@ async function saveQrCodeTemplate() {
550
593
  getSiteEntryPassSettings();
551
594
  }
552
595
 
596
+ async function saveQrCodeValidity() {
597
+ await _save(buildPayload());
598
+ showMessage("Entry Pass Settings updated successfully!", "success");
599
+ getSiteEntryPassSettings();
600
+ }
601
+
553
602
  async function saveResidentAppDisclaimerMsg() {
554
603
  await _save(buildPayload());
555
604
  showMessage("Entry Pass Settings updated successfully!", "success");
@@ -14,36 +14,73 @@
14
14
  <v-row>
15
15
  <!-- Cover Photo + Preview -->
16
16
  <v-col cols="12" lg="5" class="pt-0">
17
- <InputLabel title="Cover Photo (displayed in resident app)" class="d-block mb-2" />
18
- <InputFileV2 v-model="coverPhoto" accept="image/*" title="Upload cover photo" :height="120" />
17
+ <InputLabel
18
+ title="Cover Photo (displayed in resident app)"
19
+ class="d-block mb-2"
20
+ />
21
+ <InputFileV2
22
+ v-model="coverPhoto"
23
+ accept="image/*"
24
+ title="Upload cover photo"
25
+ :height="120"
26
+ />
19
27
  </v-col>
20
28
  <v-col cols="12" lg="7" class="pl-lg-4 pt-4 pt-lg-0">
21
29
  <InputLabel title="Preview" class="d-block mb-2" />
22
- <v-img v-if="coverPhotoUrl" :src="coverPhotoUrl" aspect-ratio="16/9" cover rounded="lg"
23
- class="w-100 border" />
24
- <div v-else
30
+ <v-img
31
+ v-if="coverPhotoUrl"
32
+ :src="coverPhotoUrl"
33
+ aspect-ratio="16/9"
34
+ cover
35
+ rounded="lg"
36
+ class="w-100 border"
37
+ />
38
+ <div
39
+ v-else
25
40
  class="w-100 d-flex align-center justify-center rounded-lg bg-grey-lighten-4 border border-dashed"
26
- style="aspect-ratio: 16/9">
27
- <span class="text-caption text-medium-emphasis">No cover photo uploaded</span>
41
+ style="aspect-ratio: 16/9"
42
+ >
43
+ <span class="text-caption text-medium-emphasis"
44
+ >No cover photo uploaded</span
45
+ >
28
46
  </div>
29
47
  </v-col>
30
48
 
31
49
  <!-- Description + Site Documents -->
32
50
  <v-col cols="12" lg="6" class="mt-2">
33
51
  <InputLabel title="Description" class="d-block mb-1" />
34
- <v-textarea v-model="description" variant="outlined" density="compact" rows="4" hide-details no-resize
35
- style="height: 119px" />
52
+ <v-textarea
53
+ v-model="description"
54
+ variant="outlined"
55
+ density="compact"
56
+ rows="4"
57
+ hide-details
58
+ no-resize
59
+ style="height: 119px"
60
+ />
36
61
  </v-col>
37
62
  <v-col cols="12" lg="6" class="mt-2 pl-lg-2">
38
63
  <InputLabel title="Site Documents" class="d-block mb-1" />
39
- <InputFileV2 v-model="siteDocuments" :multiple="true" accept="*/*" title="Upload documents"
40
- :height="104" />
64
+ <InputFileV2
65
+ v-model="siteDocuments"
66
+ :multiple="true"
67
+ accept="*/*"
68
+ title="Upload documents"
69
+ :height="104"
70
+ />
41
71
  </v-col>
42
72
 
43
73
  <!-- Submit -->
44
74
  <v-col cols="12" class="pt-0 d-flex justify-end">
45
- <v-btn color="primary-button" class="text-none" size="large" variant="flat" text="Save"
46
- :loading="savingSiteInfo" @click="saveSiteInfo" />
75
+ <v-btn
76
+ color="primary-button"
77
+ class="text-none"
78
+ size="large"
79
+ variant="flat"
80
+ text="Save"
81
+ :loading="savingSiteInfo"
82
+ @click="saveSiteInfo"
83
+ />
47
84
  </v-col>
48
85
 
49
86
  <!-- Divider -->
@@ -54,8 +91,14 @@
54
91
  <v-col cols="12">
55
92
  <v-row no-gutters>
56
93
  <v-col cols="12" lg="4" class="mt-2">
57
- <NumberSettingField v-model="blocks" title="No. of blocks" type="blocks" :site-id="siteId"
58
- :disabled="existingBlockNumber === blocks" @success="refreshSiteData" />
94
+ <NumberSettingField
95
+ v-model="blocks"
96
+ title="No. of blocks"
97
+ type="blocks"
98
+ :site-id="siteId"
99
+ :disabled="existingBlockNumber === blocks"
100
+ @success="refreshSiteData"
101
+ />
59
102
  </v-col>
60
103
  </v-row>
61
104
  </v-col>
@@ -63,9 +106,14 @@
63
106
  <v-col cols="12">
64
107
  <v-row no-gutters>
65
108
  <v-col cols="12" lg="4" class="mt-2">
66
- <NumberSettingField v-model="guardPosts" title="No. of guard posts" type="guard_posts"
67
- :site-id="siteId" :disabled="existingGuardPostNumber === guardPosts"
68
- @success="refreshSiteData" />
109
+ <NumberSettingField
110
+ v-model="guardPosts"
111
+ title="No. of guard posts"
112
+ type="guard_posts"
113
+ :site-id="siteId"
114
+ :disabled="existingGuardPostNumber === guardPosts"
115
+ @success="refreshSiteData"
116
+ />
69
117
  </v-col>
70
118
  </v-row>
71
119
  </v-col>
@@ -94,7 +142,7 @@
94
142
  hide-details
95
143
  ></v-switch>
96
144
  </v-col>
97
-
145
+
98
146
  <v-col cols="6">
99
147
  <v-switch
100
148
  v-model="ANPRSwitches.openBarrierPickUpDropOff"
@@ -133,8 +181,11 @@
133
181
 
134
182
  <v-divider class="my-4"></v-divider>
135
183
 
136
- <CameraMain :site="siteId" :read-only="!canManageSiteSettings"
137
- :guard-posts="siteData?.metadata?.guardPosts" />
184
+ <CameraMain
185
+ :site="siteId"
186
+ :read-only="!canManageSiteSettings"
187
+ :guard-posts="siteData?.metadata?.guardPosts"
188
+ />
138
189
  </v-expansion-panel-text>
139
190
  </v-expansion-panel>
140
191
 
@@ -146,7 +197,11 @@
146
197
  </v-expansion-panel-title>
147
198
 
148
199
  <v-expansion-panel-text>
149
- <CameraMain :site="siteId" type="ip" :read-only="!canManageSiteSettings" />
200
+ <CameraMain
201
+ :site="siteId"
202
+ type="ip"
203
+ :read-only="!canManageSiteSettings"
204
+ />
150
205
  </v-expansion-panel-text>
151
206
  </v-expansion-panel>
152
207
 
@@ -157,15 +212,39 @@
157
212
  </v-expansion-panel-title>
158
213
 
159
214
  <v-expansion-panel-text>
160
- <v-text-field v-model="prefix" label="Prefix" :disabled="isLoading || !canManageSiteSettings"
161
- @input="handleInput" />
162
-
163
- <v-select v-model="noOfDigits" :items="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" label="No. of Digits"
164
- :disabled="isLoading || !canManageSiteSettings" />
215
+ <v-autocomplete
216
+ v-if="!props.service"
217
+ v-model="selectedServiceProvider"
218
+ :items="serviceProviders"
219
+ :loading="isFetchingServiceProviders"
220
+ :disabled="!canManageSiteSettings"
221
+ label="Select Service Provider"
222
+ @click="fetchServiceProvidersBySiteService"
223
+ class="mt-4"
224
+ />
225
+
226
+ <v-text-field
227
+ v-model="prefix"
228
+ label="Prefix"
229
+ :disabled="isLoading || !canManageSiteSettings"
230
+ @input="handleInput"
231
+ />
232
+
233
+ <v-select
234
+ v-model="noOfDigits"
235
+ :items="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"
236
+ label="No. of Digits"
237
+ :disabled="isLoading || !canManageSiteSettings"
238
+ />
165
239
 
166
240
  <v-text-field v-model="orderNumberPreview" label="Preview" readonly />
167
241
 
168
- <v-btn v-if="canManageSiteSettings" class="mt-2" :loading="isLoading" @click="save">
242
+ <v-btn
243
+ v-if="canManageSiteSettings"
244
+ class="mt-2"
245
+ :loading="isLoading"
246
+ @click="save"
247
+ >
169
248
  Save
170
249
  </v-btn>
171
250
  </v-expansion-panel-text>
@@ -177,8 +256,13 @@
177
256
  Delivery Companies
178
257
  </v-expansion-panel-title>
179
258
  <v-expansion-panel-text class="">
180
- <DeliveryCompany :site="siteId" v-model:initial="deliveryCompanies" @refresh-site="refreshSiteData"
181
- @update:companiesValue="handleUpdateCompanies" :read-only="!canManageSiteSettings" />
259
+ <DeliveryCompany
260
+ :site="siteId"
261
+ v-model:initial="deliveryCompanies"
262
+ @refresh-site="refreshSiteData"
263
+ @update:companiesValue="handleUpdateCompanies"
264
+ :read-only="!canManageSiteSettings"
265
+ />
182
266
  </v-expansion-panel-text>
183
267
  </v-expansion-panel>
184
268
 
@@ -192,7 +276,11 @@
192
276
  </v-expansion-panel-text>
193
277
  </v-expansion-panel>
194
278
 
195
- <slot name="panels" :can-manage="canManageSiteSettings" :site-id="siteId" />
279
+ <slot
280
+ name="panels"
281
+ :can-manage="canManageSiteSettings"
282
+ :site-id="siteId"
283
+ />
196
284
  </v-expansion-panels>
197
285
 
198
286
  <Snackbar v-model="toast.show" :text="toast.message" :color="toast.color" />
@@ -200,11 +288,11 @@
200
288
  </template>
201
289
 
202
290
  <script setup lang="ts">
203
- import useFile from '../composables/useFile';
204
- import useSiteSettings from '../composables/useSiteSettings';
205
- import useUtils from '../composables/useUtils';
206
- import useWorkOrder from '../composables/useWorkOrder';
207
- import useANPRSettings from '../composables/useANPRSettings';
291
+ import useFile from "../composables/useFile";
292
+ import useSiteSettings from "../composables/useSiteSettings";
293
+ import useUtils from "../composables/useUtils";
294
+ import useWorkOrder from "../composables/useWorkOrder";
295
+ import useANPRSettings from "../composables/useANPRSettings";
208
296
 
209
297
  const props = defineProps({
210
298
  siteId: { type: String, required: true },
@@ -215,17 +303,17 @@ const props = defineProps({
215
303
  showWorkOrderSettings: { type: Boolean, default: false },
216
304
  showDeliveryCompanies: { type: Boolean, default: false },
217
305
  showResidentVisitors: { type: Boolean, default: false },
306
+ service: { type: String, default: false },
218
307
  });
219
308
 
220
-
221
309
  const openPanels = ref([]); // default open first
222
310
 
223
- const { getSiteById, updateSitebyId, updateSiteInformation } = useSiteSettings();
311
+ const { getSiteById, updateSitebyId, updateSiteInformation } =
312
+ useSiteSettings();
224
313
  const { requiredRule } = useUtils();
225
314
  const { getFileUrl } = useFile();
226
315
  const { getWorkOrderSettings, createWorkOrderSettings } = useWorkOrder();
227
316
 
228
-
229
317
  const blocks = ref(0);
230
318
  const guardPosts = ref(0);
231
319
  const gracePeriod = ref(0);
@@ -251,9 +339,8 @@ const siteDocuments = ref<string[]>([]);
251
339
  const siteDocumentsNames = ref<Record<string, string>>({});
252
340
  const savingSiteInfo = ref<boolean>(false);
253
341
 
254
-
255
342
  const coverPhotoUrl = computed(() =>
256
- coverPhoto.value.length > 0 ? getFileUrl(coverPhoto.value[0]) : "",
343
+ coverPhoto.value.length > 0 ? getFileUrl(coverPhoto.value[0]) : ""
257
344
  );
258
345
 
259
346
  const toast = reactive({
@@ -268,7 +355,6 @@ function showSnackbar(text: string, color = "success") {
268
355
  toast.show = true;
269
356
  }
270
357
 
271
-
272
358
  const { data: siteData, refresh: refreshSiteData } = await useLazyAsyncData(
273
359
  `site-${props.siteId}`,
274
360
  () => getSiteById(props.siteId)
@@ -285,7 +371,7 @@ watch(
285
371
  guardPosts.value = siteDataValue.metadata?.guardPosts || 0;
286
372
  existingGuardPostNumber.value = guardPosts.value;
287
373
  deliveryCompanies.value = Array.isArray(
288
- siteDataValue?.deliveryCompanyList,
374
+ siteDataValue?.deliveryCompanyList
289
375
  )
290
376
  ? [...siteDataValue.deliveryCompanyList]
291
377
  : [];
@@ -305,7 +391,6 @@ watch(
305
391
  { immediate: true }
306
392
  );
307
393
 
308
-
309
394
  async function handleSaveGracePeriod() {
310
395
  gracePeriodLoading.value = true;
311
396
  try {
@@ -372,6 +457,7 @@ const { data: workOrderSetting } = await useLazyAsyncData(
372
457
 
373
458
  watchEffect(() => {
374
459
  if (workOrderSetting.value) {
460
+ selectedServiceProvider.value = workOrderSetting.value?.service;
375
461
  prefix.value = workOrderSetting.value?.prefix;
376
462
  noOfDigits.value = workOrderSetting.value?.noOfDigits;
377
463
  }
@@ -389,12 +475,52 @@ const orderNumberPreview = computed(() => {
389
475
  return `${prefix.value}${"0".repeat(noOfDigits.value - 1)}1`;
390
476
  });
391
477
 
478
+ const route = useRoute();
479
+
480
+ const message = ref("");
481
+ const messageColor = ref("");
482
+ const messageSnackbar = ref(false);
483
+
484
+ function showMessage(msg: string, color: string) {
485
+ message.value = msg;
486
+ messageColor.value = color;
487
+ messageSnackbar.value = true;
488
+ }
489
+
490
+ const { getAll: getAllServiceProvider } = useServiceProvider();
491
+
492
+ const serviceProviders = ref<TServiceProvider[]>([]);
493
+ const isFetchingServiceProviders = ref(false);
494
+ let selectedServiceProvider = ref<string>("");
495
+ let providersArray = ref<string[]>([]);
496
+
497
+ async function fetchServiceProvidersBySiteService() {
498
+ isFetchingServiceProviders.value = true;
499
+
500
+ try {
501
+ const response = await getAllServiceProvider({
502
+ siteId: route.params.site as string,
503
+ limit: 1000,
504
+ });
505
+
506
+ providersArray.value = [];
507
+ serviceProviders.value = response.items.map((i: any) => {
508
+ providersArray.value.push(i);
509
+ return i.name;
510
+ });
511
+ } catch (error: any) {
512
+ return showMessage(errorConverter(error), "error");
513
+ } finally {
514
+ isFetchingServiceProviders.value = false;
515
+ }
516
+ }
517
+
392
518
  async function save() {
393
519
  try {
394
520
  isLoading.value = true;
395
521
  await createWorkOrderSettings({
396
522
  site: props.siteId,
397
- service: "Security",
523
+ service: props.service || selectedServiceProvider.value,
398
524
  prefix: prefix.value,
399
525
  noOfDigits: noOfDigits.value,
400
526
  });
@@ -412,36 +538,32 @@ function show(message: string, color: string) {
412
538
  toast.color = color;
413
539
  }
414
540
 
415
-
416
541
  // ANPR Settings
417
- const {getANPRSettingBySite, createUpdateANPRSettings} = useANPRSettings();
418
- const isSaving = ref(false)
542
+ const { getANPRSettingBySite, createUpdateANPRSettings } = useANPRSettings();
543
+ const isSaving = ref(false);
419
544
 
420
545
  // Reactive object to hold the state of the 3 switches
421
546
  const ANPRSwitches = ref({
422
547
  enableUnregistered: false,
423
548
  openBarrierPickUpDropOff: false,
424
- vehicleSnapshot: false
425
- })
549
+ vehicleSnapshot: false,
550
+ });
426
551
 
427
- await useLazyAsyncData(
428
- `anpr-settings-${props.siteId}`,
429
- async () => {
430
- const data = await getANPRSettingBySite({
431
- site: props.siteId,
432
- userType: "site",
433
- });
434
- console.log('data', data)
435
- if(typeof data?.ANPRSwitches == "object"){
436
- ANPRSwitches.value = data?.ANPRSwitches
437
- }
552
+ await useLazyAsyncData(`anpr-settings-${props.siteId}`, async () => {
553
+ const data = await getANPRSettingBySite({
554
+ site: props.siteId,
555
+ userType: "site",
556
+ });
557
+ console.log("data", data);
558
+ if (typeof data?.ANPRSwitches == "object") {
559
+ ANPRSwitches.value = data?.ANPRSwitches;
438
560
  }
439
- );
561
+ });
440
562
 
441
563
  const saveANPRSettings = async () => {
442
564
  try {
443
- isSaving.value = true
444
-
565
+ isSaving.value = true;
566
+
445
567
  // Replace this with your actual API endpoint / store action
446
568
  // await $fetch(`/api/sites/${siteId.value}/camera-settings`, {
447
569
  // method: 'POST',
@@ -453,14 +575,13 @@ const saveANPRSettings = async () => {
453
575
  updatedBy: props.createdBy,
454
576
  userType: "site",
455
577
  };
456
- console.log('saveANPRSettings data:', data)
578
+ console.log("saveANPRSettings data:", data);
457
579
  await createUpdateANPRSettings(data);
458
580
  show("Saved successfully", "success");
459
581
  } catch (error) {
460
- console.error('Failed to save settings:', error)
582
+ console.error("Failed to save settings:", error);
461
583
  } finally {
462
- isSaving.value = false
584
+ isSaving.value = false;
463
585
  }
464
- }
465
-
586
+ };
466
587
  </script>
@@ -34,19 +34,19 @@
34
34
 
35
35
  <v-col v-if="shouldShowField('block')" cols="12">
36
36
  <InputLabel class="text-capitalize" title="Block" required />
37
- <v-select v-model="vehicle.block" :items="blocksArray" item-value="value" item-title="title"
37
+ <v-autocomplete v-model="vehicle.block" :items="blocksArray" item-value="value" item-title="title"
38
38
  @update:model-value="handleChangeBlock" density="comfortable" :rules="[requiredRule]" />
39
39
  </v-col>
40
40
 
41
41
  <v-col v-if="shouldShowField('level')" cols="12">
42
42
  <InputLabel class="text-capitalize" title="Level" required />
43
- <v-select v-model="vehicle.level" :items="levelsArray" density="comfortable" :disabled="!vehicle.block"
43
+ <v-autocomplete v-model="vehicle.level" :items="levelsArray" density="comfortable" :disabled="!vehicle.block"
44
44
  @update:model-value="handleChangeLevel" :rules="[requiredRule]" />
45
45
  </v-col>
46
46
 
47
47
  <v-col v-if="shouldShowField('unit')" cols="12">
48
48
  <InputLabel class="text-capitalize" title="Unit" required />
49
- <v-select v-model="vehicle.unit" :items="unitsArray" density="comfortable" :disabled="!vehicle.level"
49
+ <v-autocomplete v-model="vehicle.unit" :items="unitsArray" density="comfortable" :disabled="!vehicle.level"
50
50
  :rules="[requiredRule]" />
51
51
  </v-col>
52
52
 
@@ -296,6 +296,7 @@ const { data: getVehiclesReq, refresh: getVehiclesRefresh, pending: getVehiclesP
296
296
  page: page.value,
297
297
  search: searchInput.value,
298
298
  type: vehicleTypeFilter.value ?? "",
299
+ site: props.site,
299
300
  }),
300
301
  {
301
302
  watch: [page],
@@ -152,21 +152,21 @@
152
152
 
153
153
  <v-col v-if="shouldShowField('block')" cols="12">
154
154
  <InputLabel class="text-capitalize" title="Block" required />
155
- <v-select v-model="visitor.block" :items="blocksArray" item-value="value" item-title="title"
155
+ <v-autocomplete v-model="visitor.block" :items="blocksArray" item-value="value" item-title="title"
156
156
  :loading="blockStatus === 'pending'" @update:model-value="handleChangeBlock" density="comfortable"
157
157
  :rules="[requiredRule]" />
158
158
  </v-col>
159
159
 
160
160
  <v-col v-if="shouldShowField('level')" cols="12">
161
161
  <InputLabel class="text-capitalize" title="Level" required />
162
- <v-select v-model="visitor.level" :items="levelsArray" density="comfortable" :disabled="!visitor.block"
162
+ <v-autocomplete v-model="visitor.level" :items="levelsArray" density="comfortable" :disabled="!visitor.block"
163
163
  :loading="levelsStatus === 'pending'" @update:model-value="handleChangeLevel" :rules="[requiredRule]" />
164
164
  </v-col>
165
165
 
166
166
 
167
167
  <v-col v-if="shouldShowField('unit')" cols="12">
168
168
  <InputLabel class="text-capitalize" title="Unit" required />
169
- <v-select v-model="visitor.unit" :items="unitsArray" density="comfortable" item-title="title"
169
+ <v-autocomplete v-model="visitor.unit" :items="unitsArray" density="comfortable" item-title="title"
170
170
  item-value="value" :disabled="!visitor.level" :loading="unitsStatus === 'pending'" :rules="[requiredRule]"
171
171
  @update:model-value="handleUpdateUnit" />
172
172
  </v-col>
@@ -546,9 +546,9 @@ watch(fetchPersonByContactReq, (obj: Partial<TPerson>) => {
546
546
  if (!visitor.company) {
547
547
  visitor.company = companyNames.value?.[0]
548
548
  }
549
- visitor.block = visitor.block ?? obj.block ?? ""
550
- visitor.level = visitor.level ?? obj.level ?? ""
551
- visitor.unit = visitor.unit ?? obj.unit ?? ""
549
+ // visitor.block = visitor.block ?? obj.block ?? ""
550
+ // visitor.level = visitor.level ?? obj.level ?? ""
551
+ // visitor.unit = visitor.unit ?? obj.unit ?? ""
552
552
  visitor.nric = visitor.nric ?? obj.nric ?? ""
553
553
 
554
554
  setTimeout(() => {
@@ -114,6 +114,7 @@ export default function useMember() {
114
114
  body: payload,
115
115
  })
116
116
  }
117
+
117
118
  function updateMemberSite(
118
119
  id: string,
119
120
  siteId: string,
@@ -80,6 +80,12 @@ export default function useOrg() {
80
80
  });
81
81
  }
82
82
 
83
+ function getOrgById(id = "") {
84
+ return useNuxtApp().$api<TOrg>(`/api/organizations/org/id/${id}`, {
85
+ method: "GET",
86
+ });
87
+ }
88
+
83
89
  const { currentUser } = useLocalAuth();
84
90
 
85
91
  const currentOrg = useState("currentOrg", () => "");
@@ -121,7 +127,7 @@ export default function useOrg() {
121
127
  value: Partial<Pick<TOrg, "name" | "type" | "email" | "nature" | "contact">>
122
128
  ) {
123
129
  return useNuxtApp()
124
- .$api<Record<string, any>>("/api/organizations", {
130
+ .$api<Record<string, any>>("/api/organizations/onboarding", {
125
131
  method: "POST",
126
132
  body: value,
127
133
  })
@@ -131,6 +137,20 @@ export default function useOrg() {
131
137
  ) as TOrg;
132
138
  });
133
139
  }
140
+
141
+ function completeOnboarding(id: string) {
142
+ return useNuxtApp()
143
+ .$api<Record<string, any>>(
144
+ `/api/organizations/onboarding/complete/${id}`,
145
+ {
146
+ method: "POST",
147
+ }
148
+ )
149
+ .then((response: Record<string, any>) => {
150
+ return (response?.data ?? response?.organization ?? response) as TOrg;
151
+ });
152
+ }
153
+
134
154
  function updateOrg(
135
155
  id: string,
136
156
  value: Partial<Pick<TOrg, "name" | "type" | "email" | "nature" | "contact">>
@@ -224,12 +244,14 @@ export default function useOrg() {
224
244
  getByName,
225
245
  currentOrg,
226
246
  getById,
247
+ getOrgById,
227
248
  getAll,
228
249
  getAllV2,
229
250
  add,
230
251
  addOnboardingOrg,
231
252
  updateOrg,
232
253
  getOrgsByEmail,
233
- getOrganizationsWithSubscription
254
+ getOrganizationsWithSubscription,
255
+ completeOnboarding
234
256
  };
235
257
  }
@@ -6,10 +6,11 @@ export default function useVehicle() {
6
6
  order = "desc",
7
7
  type = "",
8
8
  category = "",
9
+ site = "",
9
10
  } = {}) {
10
11
  return await useNuxtApp().$api<Record<string, any>>("/api/vehicles", {
11
12
  method: "GET",
12
- query: { search, page, limit, order, type, category },
13
+ query: { search, page, limit, order, type, category, site },
13
14
  });
14
15
  }
15
16
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@7365admin1/layer-common",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "1.11.49",
5
+ "version": "1.11.51",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "publishConfig": {
@@ -9,7 +9,7 @@ declare type TVehicle = {
9
9
  block: number | "";
10
10
  level: string;
11
11
  unit: string;
12
- uniName?: string; // For display purposes, the API will return the unit name if available
12
+ unitName?: string; // For display purposes, the API will return the unit name if available
13
13
  nric?: string | null;
14
14
  remarks?: string;
15
15
  seasonPassType?: string;