@7365admin1/layer-common 1.11.39 → 1.11.41

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,18 @@
1
1
  # @iservice365/layer-common
2
2
 
3
+ ## 1.11.41
4
+
5
+ ### Patch Changes
6
+
7
+ - bc096ed: Fix navigation not get children item
8
+ - 5031c18: Update Vehicle Management
9
+
10
+ ## 1.11.40
11
+
12
+ ### Patch Changes
13
+
14
+ - 91ae5da: Update Verification Status
15
+
3
16
  ## 1.11.39
4
17
 
5
18
  ### Patch Changes
@@ -5,6 +5,96 @@
5
5
  :site-id="siteId"
6
6
  />
7
7
 
8
+ <!-- Assign to Person Dialog -->
9
+ <v-dialog :model-value="showAssignForm" width="420" persistent>
10
+ <v-card width="100%">
11
+ <v-toolbar density="compact" color="surface">
12
+ <v-row no-gutters class="fill-height px-4" align="center">
13
+ <span class="font-weight-bold">Assign Card to Person</span>
14
+ </v-row>
15
+ </v-toolbar>
16
+
17
+ <v-card-text class="pa-4">
18
+ <div class="text-caption text-grey mb-4">
19
+ Card: <strong class="text-body-2 text-black">{{ selectedCardInUnit?.cardNo }}</strong>
20
+ </div>
21
+
22
+ <!-- Person Type Filter -->
23
+ <div class="text-caption font-weight-bold mb-1 text-uppercase text-grey-darken-1">Person Type</div>
24
+ <v-btn-toggle
25
+ v-model="assignPersonType"
26
+ color="primary"
27
+ density="compact"
28
+ variant="outlined"
29
+ rounded="pill"
30
+ class="mb-4"
31
+ >
32
+ <v-btn value="" size="small" class="text-none px-3">All</v-btn>
33
+ <v-btn value="owner" size="small" class="text-none px-3">Unit Owner</v-btn>
34
+ <v-btn value="resident" size="small" class="text-none px-3">Resident</v-btn>
35
+ <v-btn value="tenant" size="small" class="text-none px-3">Tenant</v-btn>
36
+ </v-btn-toggle>
37
+
38
+ <!-- Person Selector -->
39
+ <div class="text-caption font-weight-bold mb-1 text-uppercase text-grey-darken-1">
40
+ Person <span class="text-error">*</span>
41
+ </div>
42
+ <v-autocomplete
43
+ v-model="assignPerson"
44
+ :items="filteredPeopleItems"
45
+ density="compact"
46
+ item-title="name"
47
+ item-value="_id"
48
+ hide-details="auto"
49
+ placeholder="Select person..."
50
+ persistent-placeholder
51
+ :loading="peopleLoading"
52
+ return-object
53
+ no-data-text="No residents or tenants found for this unit"
54
+ >
55
+ <template #item="{ props: itemProps, item }">
56
+ <v-list-item v-bind="itemProps" :subtitle="personTypeLabel(item.raw)" />
57
+ </template>
58
+ <template #selection="{ item }">
59
+ <span>{{ item.raw.name }}</span>
60
+ <v-chip size="x-small" class="ml-2" color="grey" variant="tonal">
61
+ {{ personTypeLabel(item.raw) }}
62
+ </v-chip>
63
+ </template>
64
+ </v-autocomplete>
65
+ </v-card-text>
66
+
67
+ <v-toolbar density="compact">
68
+ <v-row no-gutters>
69
+ <v-col cols="6" class="pa-0">
70
+ <v-btn
71
+ block
72
+ variant="text"
73
+ class="text-none"
74
+ height="48"
75
+ @click="cancelAssign"
76
+ >
77
+ Cancel
78
+ </v-btn>
79
+ </v-col>
80
+ <v-col cols="6" class="pa-0">
81
+ <v-btn
82
+ block
83
+ variant="flat"
84
+ color="black"
85
+ class="text-none"
86
+ height="48"
87
+ :disabled="!assignPerson"
88
+ @click="confirmAssign"
89
+ >
90
+ Assign
91
+ </v-btn>
92
+ </v-col>
93
+ </v-row>
94
+ </v-toolbar>
95
+ </v-card>
96
+ </v-dialog>
97
+
8
98
  <v-dialog :model-value="modelValue" width="450" persistent>
9
99
  <v-card width="100%">
10
100
  <v-card-text style="max-height: 100vh; overflow-y: auto" class="pb-0">
@@ -211,6 +301,14 @@
211
301
  </v-btn>
212
302
  </template>
213
303
  <v-list class="pa-0">
304
+ <v-list-item
305
+ v-if="canAssignToPerson && isSelectedCardAvailable"
306
+ @click="openAssignForm"
307
+ >
308
+ <v-list-item-title class="text-subtitle-2">
309
+ Assign to Person
310
+ </v-list-item-title>
311
+ </v-list-item>
214
312
  <v-list-item
215
313
  :disabled="!isSelectedCardAssignedPhysical"
216
314
  @click="emit('replace')"
@@ -270,6 +368,10 @@ const props = defineProps({
270
368
  type: Boolean,
271
369
  default: true,
272
370
  },
371
+ canAssignToPerson: {
372
+ type: Boolean,
373
+ default: true,
374
+ },
273
375
  isSelectedCardAssignedPhysical: {
274
376
  type: Boolean,
275
377
  default: false,
@@ -289,9 +391,26 @@ const emit = defineEmits<{
289
391
  "update:selectedCardInUnit": [value: Record<string, any> | null];
290
392
  replace: [];
291
393
  delete: [];
394
+ "assign-to-person": [{ card: Record<string, any> | null; person: Record<string, any> | null }];
292
395
  }>();
293
396
 
397
+ const { getPeopleByUnit: _getPeopleByUnit } = usePeople();
398
+
294
399
  const historyDialog = ref(false);
400
+ const showAssignForm = ref(false);
401
+ const assignPersonType = ref<string>("");
402
+ const assignPerson = ref<Record<string, any> | null>(null);
403
+ const peopleItems = ref<Record<string, any>[]>([]);
404
+ const peopleLoading = ref(false);
405
+
406
+ const isSelectedCardAvailable = computed(() => {
407
+ if (!props.selectedCardInUnit?._id) return false;
408
+ const id = props.selectedCardInUnit._id;
409
+ return [
410
+ ...(props.unit?.available?.physical ?? []),
411
+ ...(props.unit?.available?.non_physical ?? []),
412
+ ].some((c) => c._id === id);
413
+ });
295
414
 
296
415
  const isSelectedCardDeletable = computed(() => {
297
416
  if (!props.selectedCardInUnit?._id) return false;
@@ -304,6 +423,51 @@ const isSelectedCardDeletable = computed(() => {
304
423
  ].some((c) => c._id === id);
305
424
  });
306
425
 
426
+ const filteredPeopleItems = computed(() => {
427
+ if (!assignPersonType.value) return peopleItems.value;
428
+ if (assignPersonType.value === "owner") return peopleItems.value.filter((p) => p.isOwner);
429
+ return peopleItems.value.filter((p) => p.type === assignPersonType.value && !p.isOwner);
430
+ });
431
+
432
+ const personTypeLabel = (person: Record<string, any>) => {
433
+ if (person.isOwner) return "Unit Owner";
434
+ if (person.type === "resident") return "Resident";
435
+ if (person.type === "tenant") return "Tenant";
436
+ return person.type ?? "";
437
+ };
438
+
439
+ async function openAssignForm() {
440
+ showAssignForm.value = true;
441
+ assignPerson.value = null;
442
+ assignPersonType.value = "";
443
+ peopleItems.value = [];
444
+
445
+ if (!props.unit?._id) return;
446
+ peopleLoading.value = true;
447
+ try {
448
+ const res = await _getPeopleByUnit(props.unit._id);
449
+ peopleItems.value = res?.data ?? [];
450
+ } catch {
451
+ peopleItems.value = [];
452
+ } finally {
453
+ peopleLoading.value = false;
454
+ }
455
+ }
456
+
457
+ function cancelAssign() {
458
+ showAssignForm.value = false;
459
+ assignPerson.value = null;
460
+ assignPersonType.value = "";
461
+ }
462
+
463
+ function confirmAssign() {
464
+ emit("assign-to-person", {
465
+ card: props.selectedCardInUnit,
466
+ person: assignPerson.value,
467
+ });
468
+ cancelAssign();
469
+ }
470
+
307
471
  function toggleCard(card: Record<string, any>) {
308
472
  emit(
309
473
  "update:selectedCardInUnit",
@@ -1,3 +1,4 @@
1
+ <!-- LayoutNavigationDrawer.vue -->
1
2
  <template>
2
3
  <v-navigation-drawer
3
4
  v-model="drawer"
@@ -19,26 +20,19 @@
19
20
  v-for="(item, index) in props.navigationItems"
20
21
  :key="`${item.title}-${index}`"
21
22
  location="right"
23
+ :disabled="!item.disabled"
22
24
  >
23
25
  <template #activator="{ props: tooltipProps }">
24
26
  <div v-bind="tooltipProps">
25
- <NavigationItem
26
- :title="item.title"
27
- :icon="item.icon"
28
- :route="item.route"
29
- :link="item.link"
30
- :class="{
27
+ <NavigationItem :title="item.title" :icon="item.icon" :route="item.route" :link="item.link"
28
+ :children="item.children" :class="{
31
29
  'opacity-50 pointer-events-none': item.disabled
32
- }"
33
- @click="() => handleClick(item)"
34
- />
30
+ }" @click="() => handleClick(item)" />
31
+
35
32
  </div>
36
33
  </template>
37
34
 
38
- <!-- TOOLTIP ONLY WHEN DISABLED -->
39
- <span v-if="item.disabled">
40
- Please complete onboarding first
41
- </span>
35
+ <span>Please complete onboarding first</span>
42
36
  </v-tooltip>
43
37
 
44
38
  <!-- SERVICES SLOT -->
@@ -58,9 +52,6 @@ const emit = defineEmits(['navigate'])
58
52
  const { drawer } = useLocal()
59
53
  const { APP_NAME } = useRuntimeConfig().public
60
54
 
61
- /**
62
- * GLOBAL CLICK CONTROL
63
- */
64
55
  const handleClick = (item: any) => {
65
56
  if (item.disabled) return
66
57
  emit('navigate', item)
@@ -53,14 +53,15 @@
53
53
  <v-col v-if="shouldShowField('nric')" cols="12">
54
54
  <InputLabel class="text-capitalize" title="NRIC" required />
55
55
  <InputNRICNumber v-model="vehicle.nric" density="comfortable" :rules="[requiredRule]"
56
- :disabled="disablePrefilledInputs && type !== 'blocklist'" />
56
+ :disabled="disablePrefilledInputs && type !== 'blocklist' && prop.mode !== 'edit'" />
57
57
  </v-col>
58
58
 
59
59
  <v-col v-if="shouldShowField('name')" cols="12">
60
60
  <v-row>
61
61
  <v-col cols="12">
62
62
  <InputLabel class="text-capitalize" title="Full Name" required />
63
- <v-text-field v-model.trim="vehicle.name" density="comfortable" :rules="[requiredRule]" />
63
+ <v-text-field v-model.trim="vehicle.name" density="comfortable" :rules="[requiredRule]"
64
+ :disabled="disablePrefilledInputs && type !== 'blocklist' && prop.mode !== 'edit'" />
64
65
  </v-col>
65
66
  </v-row>
66
67
  </v-col>
@@ -777,6 +778,7 @@ onMounted(() => {
777
778
  vehicle.start = prop.vehicleData.start || '';
778
779
  vehicle.plateNumber = prop.vehicleData.plateNumber
779
780
  vehicle.peopleId = prop.vehicleData.peopleId || '';
781
+ vehicle.block = prop.vehicleData.block === 0 ? null : prop.vehicleData.block || null;
780
782
 
781
783
  if(prop.type === "seasonpass"){
782
784
  showSubscriptionDateOptions.value = true;
@@ -924,6 +924,11 @@ async function submit() {
924
924
  }
925
925
  }
926
926
 
927
+ // add register status when registering unregistered visitor
928
+ if (prop.mode === 'register'){
929
+ payload.status = "registered"
930
+ }
931
+
927
932
  try {
928
933
  let res;
929
934
  if (prop.mode === "add") {
@@ -141,6 +141,13 @@ export default function useLocalAuth() {
141
141
  });
142
142
  }
143
143
 
144
+ async function updateVerificationStatus(id: string, status: string) {
145
+ return useNuxtApp().$api<Record<string, any>>(`/api/auth/verification/status`, {
146
+ method: "PATCH",
147
+ body: { id, status },
148
+ })
149
+ }
150
+
144
151
  function signUp(email: string, referral: string) {
145
152
  return useNuxtApp().$api<Record<string, any>>("/api/auth/sign-up", {
146
153
  method: "POST",
@@ -159,6 +166,7 @@ export default function useLocalAuth() {
159
166
  resetPassword,
160
167
  currentUser,
161
168
  verify,
169
+ updateVerificationStatus,
162
170
  signUp,
163
171
  };
164
172
  }
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.39",
5
+ "version": "1.11.41",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "publishConfig": {