@7365admin1/layer-common 1.11.40 → 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,12 @@
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
+
3
10
  ## 1.11.40
4
11
 
5
12
  ### 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",
@@ -24,16 +24,11 @@
24
24
  >
25
25
  <template #activator="{ props: tooltipProps }">
26
26
  <div v-bind="tooltipProps">
27
- <NavigationItem
28
- :title="item.title"
29
- :icon="item.icon"
30
- :route="item.route"
31
- :link="item.link"
32
- :class="{
27
+ <NavigationItem :title="item.title" :icon="item.icon" :route="item.route" :link="item.link"
28
+ :children="item.children" :class="{
33
29
  'opacity-50 pointer-events-none': item.disabled
34
- }"
35
- @click="() => handleClick(item)"
36
- />
30
+ }" @click="() => handleClick(item)" />
31
+
37
32
  </div>
38
33
  </template>
39
34
 
@@ -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;
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.40",
5
+ "version": "1.11.41",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "publishConfig": {