@7365admin1/layer-common 3.0.30-staging.9 → 3.0.31-staging.10

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,11 @@
1
1
  # @iservice365/layer-common
2
2
 
3
+ ## 3.0.30
4
+
5
+ ### Patch Changes
6
+
7
+ - afdccc4: Build for Leftover changes from Benar's PR
8
+
3
9
  ## 3.0.29
4
10
 
5
11
  ### Patch Changes
@@ -32,11 +32,6 @@
32
32
  color="blue"
33
33
  variant="tonal"
34
34
  size="small"
35
- closable
36
- @click:close="
37
- existingPassToBeReplaced = existingPass;
38
- existingPass = null;
39
- "
40
35
  >
41
36
  {{ existingPass.prefixAndName }}
42
37
  </v-chip>
@@ -45,9 +40,9 @@
45
40
 
46
41
  <!-- New pass selector -->
47
42
  <v-autocomplete
48
- v-if="!existingPass"
49
43
  v-model="selectedPass"
50
44
  v-model:search="passInput"
45
+ :label="existingPass?.keyId ? 'Change pass' : undefined"
51
46
  :hide-no-data="false"
52
47
  :items="passItems"
53
48
  item-title="prefixAndName"
@@ -85,20 +80,20 @@
85
80
  class="d-flex flex-wrap ga-1 mb-2"
86
81
  >
87
82
  <v-chip
88
- v-for="key in existingKeys"
83
+ v-for="key in existingKeys.filter((k) => k.status != 'Removed')"
89
84
  :key="key.keyId"
90
85
  prepend-icon="mdi-key"
91
86
  color="orange"
92
87
  variant="tonal"
93
88
  size="small"
94
89
  closable
95
- @click:close="removeExistingKey(key.keyId)"
90
+ @click:close="removeExistingKey(key)"
96
91
  >
97
92
  {{ key.prefixAndName }}
98
93
  </v-chip>
99
- <span class="text-caption text-medium-emphasis align-self-center"
100
- >(current)</span
101
- >
94
+ <span class="text-caption text-medium-emphasis align-self-center">
95
+ (current)
96
+ </span>
102
97
  </div>
103
98
 
104
99
  <!-- New keys selector -->
@@ -116,6 +111,8 @@
116
111
  density="compact"
117
112
  small-chips
118
113
  :loading="fetchKeysPending"
114
+ clearable
115
+ @update:model-value="selectKeys"
119
116
  >
120
117
  <template v-slot:chip="{ props: chipProps, item }">
121
118
  <v-chip
@@ -205,7 +202,7 @@ const processing = ref(false);
205
202
  const errorMessage = ref("");
206
203
 
207
204
  // New selections
208
- const selectedPass = ref<string>("");
205
+ const selectedPass = ref<string | null>(null);
209
206
  const selectedKeys = ref<string[]>([]);
210
207
  const passInput = ref("");
211
208
  const keyInput = ref("");
@@ -213,12 +210,15 @@ const passItems = ref<TPassKey[]>([]);
213
210
  const keyItems = ref<TPassKey[]>([]);
214
211
 
215
212
  // Existing pass/keys (editable)
216
- const existingPass = ref<{ keyId: string; prefixAndName: string } | null>(null);
217
- const existingPassToBeReplaced = ref<{
213
+ const existingPass = ref<{
218
214
  keyId: string;
219
215
  prefixAndName: string;
216
+ status?: string;
220
217
  } | null>(null);
221
- const existingKeys = ref<{ keyId: string; prefixAndName: string }[]>([]);
218
+
219
+ const existingKeys = ref<
220
+ { keyId: string; prefixAndName: string; status?: string }[]
221
+ >([]);
222
222
 
223
223
  const isEditMode = computed(() => prop.mode === "edit");
224
224
  const showKeys = computed(() => prop.visitor.type === "contractor");
@@ -237,28 +237,82 @@ const passTypesComputed = computed(() => {
237
237
  // Initialise existing values in edit mode
238
238
  onMounted(() => {
239
239
  if (isEditMode.value) {
240
- const vPass = prop.visitor.visitorPass;
240
+ const vPass = prop.visitor.visitorPass?.filter(
241
+ (i) => i.status != "Removed"
242
+ );
241
243
  if (Array.isArray(vPass) && vPass.length > 0) {
242
244
  const p = vPass[0] as any;
243
- existingPass.value = { keyId: p.keyId, prefixAndName: p.prefixAndName };
245
+ existingPass.value = {
246
+ keyId: p.keyId,
247
+ prefixAndName: p.prefixAndName,
248
+ status: p.status,
249
+ };
244
250
  }
245
- const vKeys = prop.visitor.passKeys;
251
+ const vKeys = prop.visitor.passKeys?.filter((i) => i.status != "Removed");
246
252
  if (Array.isArray(vKeys) && vKeys.length > 0) {
247
253
  existingKeys.value = (vKeys as any[]).map((k) => ({
248
254
  keyId: k.keyId,
249
255
  prefixAndName: k.prefixAndName,
256
+ status: k.status,
250
257
  }));
251
258
  }
252
259
  }
253
260
  });
254
261
 
255
- function removeExistingKey(keyId: string) {
256
- existingKeys.value = existingKeys.value.filter((k) => k.keyId !== keyId);
262
+ const previouslyRemovedKeys = ref<any>([]);
263
+
264
+ function removeExistingKey(key: Record<string, any>) {
265
+ const originalKey = existingKeys.value.find((k) => k.keyId === key.keyId);
266
+
267
+ if (
268
+ originalKey &&
269
+ !previouslyRemovedKeys.value.some((k: any) => k.keyId === key.keyId)
270
+ ) {
271
+ previouslyRemovedKeys.value.push({ ...originalKey });
272
+ }
273
+
274
+ existingKeys.value = existingKeys.value.map((i) => {
275
+ if (i.keyId === key.keyId) {
276
+ return {
277
+ ...i,
278
+ status: "Removed",
279
+ };
280
+ }
281
+ return i;
282
+ });
283
+ }
284
+
285
+ function selectKeys() {
286
+ const currentSelections = [...selectedKeys.value];
287
+
288
+ currentSelections.forEach((selectedId) => {
289
+ const removedMatch = previouslyRemovedKeys.value.find(
290
+ (k: any) => k.keyId === selectedId
291
+ );
292
+
293
+ if (removedMatch) {
294
+ existingKeys.value = existingKeys.value.map((i) => {
295
+ if (i.keyId === selectedId) {
296
+ return {
297
+ ...i,
298
+ status: removedMatch.status,
299
+ };
300
+ }
301
+ return i;
302
+ });
303
+
304
+ previouslyRemovedKeys.value = previouslyRemovedKeys.value.filter(
305
+ (k: any) => k.keyId !== selectedId
306
+ );
307
+
308
+ selectedKeys.value = selectedKeys.value.filter((id) => id !== selectedId);
309
+ }
310
+ });
257
311
  }
258
312
 
259
313
  // Exclude already-held pass/keys from selectable lists
260
314
  const existingPassId = computed(() => existingPass.value?.keyId);
261
- const existingKeyIds = computed(() => existingKeys.value.map((k) => k.keyId));
315
+ // const existingKeyIds = computed(() => existingKeys.value.map((k) => k.keyId));
262
316
 
263
317
  const {
264
318
  data: passesData,
@@ -294,43 +348,50 @@ const {
294
348
  })
295
349
  );
296
350
 
297
- watch(passesData, (data: any) => {
298
- const all: TPassKey[] = Array.isArray(data?.items) ? data.items : [];
299
- passItems.value = all.filter((p) => p._id !== existingPassId.value);
300
- });
351
+ // watch(passesData, (data: any) => {
352
+ // const all: TPassKey[] = Array.isArray(data?.items) ? data.items : [];
353
+ // passItems.value = all.filter((p) => p._id !== existingPassId.value);
354
+ // });
301
355
 
302
- watch(keysData, (data: any) => {
303
- const all: TPassKey[] = Array.isArray(data?.items) ? data.items : [];
304
- keyItems.value = all.filter((k) => !existingKeyIds.value.includes(k._id!));
305
- });
356
+ // watch(keysData, (data: any) => {
357
+ // const all: TPassKey[] = Array.isArray(data?.items) ? data.items : [];
358
+ // keyItems.value = all.filter((k) => !existingKeyIds.value.includes(k._id!));
359
+ // });
306
360
 
307
361
  // Re-filter when existing items change
308
362
  watch(
309
- [existingPassId, existingKeyIds],
363
+ [existingPassId, existingKeys, passesData, keysData],
310
364
  () => {
311
365
  const rawPasses = (passesData.value as any)?.items ?? [];
312
366
  passItems.value = rawPasses.filter(
313
367
  (p: TPassKey) => p._id !== existingPassId.value
314
368
  );
369
+
315
370
  const rawKeys = (keysData.value as any)?.items ?? [];
316
- keyItems.value = rawKeys.filter(
317
- (k: TPassKey) => !existingKeyIds.value.includes(k._id!)
371
+ const manuallyRemovedKeys = existingKeys.value
372
+ .filter((k) => k.status === "Removed")
373
+ .map((k) => ({
374
+ _id: k.keyId,
375
+ prefixAndName: k.prefixAndName,
376
+ }));
377
+
378
+ const allExistingKeyIds = existingKeys.value.map((k) => k.keyId);
379
+
380
+ const filteredRawKeys = rawKeys.filter(
381
+ (k: TPassKey) => !allExistingKeyIds.includes(k._id!)
318
382
  );
383
+
384
+ keyItems.value = [...filteredRawKeys, ...manuallyRemovedKeys];
385
+ console.log("keyItems: ", keyItems.value);
319
386
  },
320
- { deep: true }
387
+ { deep: true, immediate: true }
321
388
  );
322
389
 
323
390
  const canSubmit = computed(() => {
324
- if (isEditMode.value) {
325
- // allow save if anything changed: existing items modified OR new items selected
326
- return (
327
- existingPass.value !== null ||
328
- selectedPass.value ||
329
- existingKeys.value.length > 0 ||
330
- selectedKeys.value.length > 0
331
- );
332
- }
333
- return !!selectedPass.value || selectedKeys.value.length > 0;
391
+ const hasRemovedKeys = existingKeys.value.some((k) => k.status === "Removed");
392
+ return (
393
+ !!selectedPass.value || selectedKeys.value.length > 0 || hasRemovedKeys
394
+ );
334
395
  });
335
396
 
336
397
  async function handleSubmit() {
@@ -343,16 +404,13 @@ async function handleSubmit() {
343
404
 
344
405
  // Build final pass list: kept existing + newly selected
345
406
  const finalPasses: { keyId: string; status?: string; add?: boolean }[] = [];
346
- if (existingPass.value) {
347
- finalPasses.push({ keyId: existingPass.value.keyId, status: "Removed" });
348
- }
349
- if (existingPassToBeReplaced.value) {
350
- finalPasses.push({
351
- keyId: existingPassToBeReplaced.value.keyId,
352
- status: "Removed",
353
- });
354
- }
355
407
  if (selectedPass.value) {
408
+ if (existingPass.value) {
409
+ finalPasses.push({
410
+ keyId: existingPass.value.keyId,
411
+ status: "Removed",
412
+ });
413
+ }
356
414
  finalPasses.push({
357
415
  keyId: selectedPass.value,
358
416
  status: "Not Returned",
@@ -364,13 +422,17 @@ async function handleSubmit() {
364
422
  // Build final keys list: kept existing + newly selected
365
423
  if (showKeys.value) {
366
424
  const finalKeys: { keyId: string; status?: string; add?: boolean }[] = [
367
- ...existingKeys.value.map((k) => ({ keyId: k.keyId })),
425
+ ...existingKeys.value.map((k) => ({
426
+ keyId: k.keyId,
427
+ status: k.status,
428
+ })),
368
429
  ...selectedKeys.value.map((keyId) => ({
369
430
  keyId,
370
431
  status: "Not Returned",
371
432
  add: true,
372
433
  })),
373
434
  ];
435
+
374
436
  payload.passKeys = finalKeys;
375
437
  }
376
438
 
@@ -315,7 +315,9 @@
315
315
  style="cursor: pointer"
316
316
  >
317
317
  <v-chip
318
- v-for="pass in item.visitorPass"
318
+ v-for="pass in item.visitorPass.filter(
319
+ (i) => i.status != 'Removed'
320
+ )"
319
321
  :key="(pass as any)._id ?? (pass as any).keyId"
320
322
  prepend-icon="mdi-card-bulleted-outline"
321
323
  size="x-small"
@@ -325,7 +327,9 @@
325
327
  {{ (pass as any)?.prefixAndName }}
326
328
  </v-chip>
327
329
  <v-chip
328
- v-for="key in item.passKeys"
330
+ v-for="key in item.passKeys.filter(
331
+ (i) => i.status != 'Removed'
332
+ )"
329
333
  :key="(key as any)._id ?? (key as any).keyId"
330
334
  prepend-icon="mdi-key"
331
335
  size="x-small"
@@ -404,9 +408,16 @@
404
408
  </v-menu>
405
409
 
406
410
  <!-- QRCODE identifier -->
407
- <div v-if="item.accessCards?.type === 'QRCODE' && item.accessCards?.cardNo" class="d-flex align-center ga-1 mt-1">
411
+ <div
412
+ v-if="
413
+ item.accessCards?.type === 'QRCODE' && item.accessCards?.cardNo
414
+ "
415
+ class="d-flex align-center ga-1 mt-1"
416
+ >
408
417
  <v-icon size="15" icon="mdi-qrcode" color="teal" />
409
- <v-chip size="x-small" variant="tonal" color="teal">QR · ({{ item.cards?.flat().length ?? 1 }})</v-chip>
418
+ <v-chip size="x-small" variant="tonal" color="teal"
419
+ >QR · ({{ item.cards?.flat().length ?? 1 }})</v-chip
420
+ >
410
421
  </div>
411
422
  </v-row>
412
423
  </template>
@@ -814,7 +825,9 @@
814
825
  item-title="label"
815
826
  item-value="value"
816
827
  v-model="pass.status"
817
- :disabled="selectedVisitorObject.checkOut"
828
+ :disabled="
829
+ selectedVisitorObject.checkOut || pass.status == 'Removed'
830
+ "
818
831
  ></v-select>
819
832
  <v-textarea
820
833
  v-if="pass.status === 'Lost' || pass.status === 'Damaged'"
@@ -851,7 +864,9 @@
851
864
  item-title="label"
852
865
  item-value="value"
853
866
  v-model="key.status"
854
- :disabled="selectedVisitorObject.checkOut"
867
+ :disabled="
868
+ selectedVisitorObject.checkOut || key.status == 'Removed'
869
+ "
855
870
  ></v-select>
856
871
  <v-textarea
857
872
  v-if="key.status === 'Lost' || key.status === 'Damaged'"
@@ -911,37 +926,87 @@
911
926
  <v-dialog v-model="dialog.returnNfcCard" max-width="450" persistent>
912
927
  <v-card>
913
928
  <v-toolbar density="compact" color="">
914
- <v-row no-gutters class="d-flex fill-height justify-space-between align-center px-4">
929
+ <v-row
930
+ no-gutters
931
+ class="d-flex fill-height justify-space-between align-center px-4"
932
+ >
915
933
  <span class="font-weight-bold">Return NFC Card</span>
916
- <v-btn icon="mdi-close" variant="text" @click="dialog.returnNfcCard = false" />
934
+ <v-btn
935
+ icon="mdi-close"
936
+ variant="text"
937
+ @click="dialog.returnNfcCard = false"
938
+ />
917
939
  </v-row>
918
940
  </v-toolbar>
919
941
  <v-card-text class="px-4 pb-2">
920
- <p class="text-body-2 mb-3">Please indicate the status of the NFC card before checking out.</p>
942
+ <p class="text-body-2 mb-3">
943
+ Please indicate the status of the NFC card before checking out.
944
+ </p>
921
945
  <div>
922
946
  <InputLabel class="text-capitalize" title="Full Name" />
923
- <v-text-field v-model="selectedVisitorObject.name" density="comfortable" readonly />
947
+ <v-text-field
948
+ v-model="selectedVisitorObject.name"
949
+ density="comfortable"
950
+ readonly
951
+ />
924
952
  </div>
925
953
  <div>
926
954
  <InputLabel class="text-capitalize" title="Location" />
927
- <v-text-field v-model="selectedVisitorObject.location" density="comfortable" readonly />
955
+ <v-text-field
956
+ v-model="selectedVisitorObject.location"
957
+ density="comfortable"
958
+ readonly
959
+ />
928
960
  </div>
929
- <div v-for="(card, idx) in nfcCardReturnStatuses" :key="card.cardId" class="mb-4">
961
+ <div
962
+ v-for="(card, idx) in nfcCardReturnStatuses"
963
+ :key="card.cardId"
964
+ class="mb-4"
965
+ >
930
966
  <div class="d-flex align-center ga-2 mb-2">
931
967
  <v-icon size="18" icon="mdi-credit-card-outline" color="purple" />
932
- <v-chip size="small" variant="tonal" color="purple">{{ card.cardNo }}</v-chip>
968
+ <v-chip size="small" variant="tonal" color="purple">{{
969
+ card.cardNo
970
+ }}</v-chip>
933
971
  </div>
934
- <v-select v-model="nfcCardReturnStatuses[idx].status" :items="nfcPassStatusOptions" item-title="label" item-value="value" density="comfortable" hide-details />
935
- <v-textarea v-if="card.status === 'Lost' || card.status === 'Damage'" v-model="nfcCardReturnStatuses[idx].remarks" label="Remarks (required)" no-resize rows="3" class="mt-2" density="compact" />
972
+ <v-select
973
+ v-model="nfcCardReturnStatuses[idx].status"
974
+ :items="nfcPassStatusOptions"
975
+ item-title="label"
976
+ item-value="value"
977
+ density="comfortable"
978
+ hide-details
979
+ />
980
+ <v-textarea
981
+ v-if="card.status === 'Lost' || card.status === 'Damage'"
982
+ v-model="nfcCardReturnStatuses[idx].remarks"
983
+ label="Remarks (required)"
984
+ no-resize
985
+ rows="3"
986
+ class="mt-2"
987
+ density="compact"
988
+ />
936
989
  </div>
937
990
  </v-card-text>
938
991
  <v-toolbar class="pa-0" density="compact">
939
992
  <v-row no-gutters>
940
993
  <v-col cols="6">
941
- <v-btn variant="text" block @click="dialog.returnNfcCard = false">Close</v-btn>
994
+ <v-btn variant="text" block @click="dialog.returnNfcCard = false"
995
+ >Close</v-btn
996
+ >
942
997
  </v-col>
943
998
  <v-col cols="6">
944
- <v-btn color="red" variant="flat" height="48" rounded="0" block :loading="loading.checkingOut" :disabled="!canConfirmNfcCheckout" @click="handleNfcCheckout">Confirm Checkout</v-btn>
999
+ <v-btn
1000
+ color="red"
1001
+ variant="flat"
1002
+ height="48"
1003
+ rounded="0"
1004
+ block
1005
+ :loading="loading.checkingOut"
1006
+ :disabled="!canConfirmNfcCheckout"
1007
+ @click="handleNfcCheckout"
1008
+ >Confirm Checkout</v-btn
1009
+ >
945
1010
  </v-col>
946
1011
  </v-row>
947
1012
  </v-toolbar>
@@ -971,7 +1036,7 @@
971
1036
  @close="dialog.editPassKey = false"
972
1037
  @done="
973
1038
  () => {
974
- dialog.editPassKey = false;
1039
+ // dialog.editPassKey = false;
975
1040
  getVisitorRefresh();
976
1041
  }
977
1042
  "
@@ -1826,7 +1891,8 @@ const nfcCardReturnStatuses = ref<
1826
1891
  const canConfirmCheckout = computed(() => {
1827
1892
  const allEntries = [...passReturnStatuses.value, ...keyReturnStatuses.value];
1828
1893
  return allEntries.every((entry) => {
1829
- if (!entry.status || ["In Use","Not Returned"].includes(entry.status)) return false;
1894
+ if (!entry.status || ["In Use", "Not Returned"].includes(entry.status))
1895
+ return false;
1830
1896
  if (
1831
1897
  (entry.status === "Lost" || entry.status === "Damaged") &&
1832
1898
  !entry.remarks.trim()
@@ -1840,7 +1906,8 @@ const canConfirmNfcCheckout = computed(() => {
1840
1906
  if (nfcCardReturnStatuses.value.length === 0) return false;
1841
1907
  return nfcCardReturnStatuses.value.every(({ status, remarks }) => {
1842
1908
  if (!status || status === "In Use") return false;
1843
- if ((status === "Lost" || status === "Damage") && !remarks.trim()) return false;
1909
+ if ((status === "Lost" || status === "Damage") && !remarks.trim())
1910
+ return false;
1844
1911
  return true;
1845
1912
  });
1846
1913
  });
@@ -1883,17 +1950,28 @@ function handleCheckout(userId: string) {
1883
1950
  return;
1884
1951
  }
1885
1952
 
1886
- const hasNfc = visitor?.accessCards?.type === "NFC" && !!visitor?.accessCards?.cardNo;
1953
+ const hasNfc =
1954
+ visitor?.accessCards?.type === "NFC" && !!visitor?.accessCards?.cardNo;
1887
1955
  if (hasNfc) {
1888
1956
  const allCards: any[] = visitor.cards?.flat() ?? [];
1889
1957
  nfcCardReturnStatuses.value = allCards.map((card: any) => ({
1890
1958
  cardId: card._id,
1891
- cardNo: card._id === visitor.accessCards._id ? visitor.accessCards.cardNo : card._id,
1959
+ cardNo:
1960
+ card._id === visitor.accessCards._id
1961
+ ? visitor.accessCards.cardNo
1962
+ : card._id,
1892
1963
  status: "In Use",
1893
1964
  remarks: "",
1894
1965
  }));
1895
1966
  if (nfcCardReturnStatuses.value.length === 0) {
1896
- nfcCardReturnStatuses.value = [{ cardId: visitor.accessCards._id, cardNo: visitor.accessCards.cardNo, status: "In Use", remarks: "" }];
1967
+ nfcCardReturnStatuses.value = [
1968
+ {
1969
+ cardId: visitor.accessCards._id,
1970
+ cardNo: visitor.accessCards.cardNo,
1971
+ status: "In Use",
1972
+ remarks: "",
1973
+ },
1974
+ ];
1897
1975
  }
1898
1976
  dialog.returnNfcCard = true;
1899
1977
  return;
@@ -1961,7 +2039,9 @@ async function handleNfcCheckout() {
1961
2039
  })),
1962
2040
  });
1963
2041
  if (res) {
1964
- await updateVisitor(userId as string, { checkOut: new Date().toISOString() });
2042
+ await updateVisitor(userId as string, {
2043
+ checkOut: new Date().toISOString(),
2044
+ });
1965
2045
  showMessage("Visitor successfully checked-out!", "info");
1966
2046
  await getVisitorRefresh();
1967
2047
  dialog.returnNfcCard = false;
@@ -1969,7 +2049,10 @@ async function handleNfcCheckout() {
1969
2049
  }
1970
2050
  } catch (error: any) {
1971
2051
  const errorMessage = error?.response?._data?.message;
1972
- showMessage(errorMessage || "Something went wrong. Please try again later.", "error");
2052
+ showMessage(
2053
+ errorMessage || "Something went wrong. Please try again later.",
2054
+ "error"
2055
+ );
1973
2056
  } finally {
1974
2057
  loading.checkingOut = false;
1975
2058
  }
@@ -2241,11 +2324,7 @@ const syncVisitorFiltersFromRoute = () => {
2241
2324
 
2242
2325
  onMounted(syncVisitorFiltersFromRoute);
2243
2326
 
2244
- watch(
2245
- () => route.query,
2246
- syncVisitorFiltersFromRoute,
2247
- { deep: true }
2248
- );
2327
+ watch(() => route.query, syncVisitorFiltersFromRoute, { deep: true });
2249
2328
 
2250
2329
  const { socketUnregisteredVisitorTrigger, visitorSocketData } =
2251
2330
  useVisitorSocket();
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@7365admin1/layer-common",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "3.0.30-staging.9",
5
+ "version": "3.0.31-staging.10",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "publishConfig": {