@7365admin1/layer-common 1.10.7 → 1.10.8

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.
Files changed (32) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/components/{AddSupplyForm.vue → AddEqupmentForm.vue} +5 -5
  3. package/components/BuildingManagement/units.vue +2 -2
  4. package/components/BuildingUnitFormAdd.vue +4 -4
  5. package/components/BuildingUnitFormEdit.vue +114 -68
  6. package/components/EntryPassInformation.vue +251 -23
  7. package/components/{CheckoutItemMain.vue → EquipmentItemMain.vue} +88 -85
  8. package/components/{SupplyManagement.vue → EquipmentManagement.vue} +3 -3
  9. package/components/Input/DateTimePicker.vue +17 -11
  10. package/components/ManageChecklistMain.vue +379 -41
  11. package/components/TableHygiene.vue +42 -452
  12. package/components/UnitPersonCard.vue +74 -14
  13. package/components/VisitorForm.vue +77 -21
  14. package/components/VisitorFormSelection.vue +13 -2
  15. package/components/VisitorManagement.vue +83 -55
  16. package/composables/useCleaningPermission.ts +7 -7
  17. package/composables/useDashboardData.ts +2 -2
  18. package/composables/{useSupply.ts → useEquipment.ts} +11 -11
  19. package/composables/{useCheckout.ts → useEquipmentItem.ts} +7 -7
  20. package/composables/{useCheckoutPermission.ts → useEquipmentItemPermission.ts} +13 -13
  21. package/composables/useEquipmentManagementPermission.ts +96 -0
  22. package/composables/{useSupplyPermission.ts → useEquipmentPermission.ts} +9 -9
  23. package/composables/useVehicle.ts +21 -2
  24. package/composables/useVisitor.ts +3 -3
  25. package/composables/useWorkOrder.ts +25 -3
  26. package/package.json +1 -1
  27. package/types/building.d.ts +1 -1
  28. package/types/{checkout-item.d.ts → equipment-item.d.ts} +3 -3
  29. package/types/{supply.d.ts → equipment.d.ts} +2 -2
  30. package/types/people.d.ts +3 -1
  31. package/types/vehicle.d.ts +2 -0
  32. package/types/visitor.d.ts +2 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @iservice365/layer-common
2
2
 
3
+ ## 1.10.8
4
+
5
+ ### Patch Changes
6
+
7
+ - 8d61e72: Update layer-common changes as of March 17, 2028
8
+
3
9
  ## 1.10.7
4
10
 
5
11
  ### Patch Changes
@@ -4,7 +4,7 @@
4
4
  <v-toolbar>
5
5
  <v-row no-gutters class="fill-height px-6" align="center">
6
6
  <span class="font-weight-bold text-h6 text-capitalize">
7
- {{ prop.mode === "edit" ? "Edit Supply" : "Add New Supply" }}
7
+ {{ prop.mode === "edit" ? "Edit Equipment" : "Add New Equipment" }}
8
8
  </span>
9
9
  </v-row>
10
10
  </v-toolbar>
@@ -19,7 +19,7 @@
19
19
  :rules="[requiredRule]"
20
20
  density="comfortable"
21
21
  variant="outlined"
22
- placeholder="Enter supply name"
22
+ placeholder="Enter equipment name"
23
23
  hide-details="auto"
24
24
  class="mb-0"
25
25
  />
@@ -94,7 +94,7 @@ const prop = defineProps({
94
94
  type: String,
95
95
  default: "add",
96
96
  },
97
- supplyData: {
97
+ equipmentData: {
98
98
  type: Object,
99
99
  default: null,
100
100
  },
@@ -122,8 +122,8 @@ const unitOfMeasurementOptions = [
122
122
  ];
123
123
 
124
124
  watchEffect(() => {
125
- nameModel.value = prop.supplyData?.name || "";
126
- unitOfMeasurementModel.value = prop.supplyData?.unitOfMeasurement || "";
125
+ nameModel.value = prop.equipmentData?.name || "";
126
+ unitOfMeasurementModel.value = prop.equipmentData?.unitOfMeasurement || "";
127
127
  });
128
128
 
129
129
  function close() {
@@ -98,11 +98,11 @@ const props = defineProps({
98
98
  type: Array as PropType<Array<Record<string, any>>>,
99
99
  default: () => [
100
100
  {
101
- title: "Name",
101
+ title: "Unit Name",
102
102
  value: "name",
103
103
  },
104
104
  {
105
- title: "Floor",
105
+ title: "Level",
106
106
  value: "level",
107
107
  },
108
108
  {
@@ -63,7 +63,7 @@
63
63
  </v-row>
64
64
  </v-col>
65
65
 
66
- <v-col cols="12" md="6" class="mt-2">
66
+ <!-- <v-col cols="12" md="6" class="mt-2">
67
67
  <v-row no-gutters>
68
68
  <InputLabel class="text-capitalize" title="Category" required />
69
69
  <v-col cols="12">
@@ -71,7 +71,7 @@
71
71
  :rules="[requiredRule]"></v-autocomplete>
72
72
  </v-col>
73
73
  </v-row>
74
- </v-col>
74
+ </v-col> -->
75
75
  </v-row>
76
76
  </v-col>
77
77
 
@@ -282,7 +282,7 @@ const buildingUnit = ref<TBuildingUnit>({
282
282
  buildingName: "",
283
283
  block: 0,
284
284
  level: "",
285
- category: "",
285
+ // category: "",
286
286
  status: "active",
287
287
  buildingUnitFiles: [],
288
288
  companyName: "",
@@ -344,7 +344,7 @@ function setBuildingUnit() {
344
344
  buildingUnit.value.building = "";
345
345
  buildingUnit.value.buildingName = "";
346
346
  buildingUnit.value.level = "";
347
- buildingUnit.value.category = "";
347
+ // buildingUnit.value.category = "";
348
348
  buildingUnit.value.status = "active";
349
349
  buildingUnit.value.buildingUnitFiles = [];
350
350
  buildingUnitQty.value = 1;
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <v-card width="100%" :loading="getUnitPeoplePending">
2
+ <v-card width="100%" :loading="getUnitPeoplePending || loading.ownerProcessing" :disabled="loading.ownerProcessing">
3
3
  <v-toolbar>
4
4
  <v-row no-gutters class="fill-height px-6" align="center">
5
5
  <span class="font-weight-bold text-h5"> Unit Info ( {{ buildingUnit.name }} ) </span>
@@ -58,7 +58,7 @@
58
58
  <v-row no-gutters>
59
59
  <InputLabel class="text-capitalize font-weight-bold" title="Billing Address Line 1" />
60
60
  <v-col cols="12">
61
- <v-text-field :model-value="siteData?.address?.line1" density="compact" readonly
61
+ <v-text-field :model-value="buildingUnit?.site?.address?.line1" density="compact" readonly
62
62
  class="no-pointer"></v-text-field>
63
63
  </v-col>
64
64
  </v-row>
@@ -67,7 +67,7 @@
67
67
  <v-row no-gutters>
68
68
  <InputLabel class="text-capitalize font-weight-bold" title="Billing Address Line 2" />
69
69
  <v-col cols="12">
70
- <v-text-field :model-value="siteData?.address?.line2" density="compact" readonly
70
+ <v-text-field :model-value="buildingUnit?.site?.address?.line2" density="compact" readonly
71
71
  class="no-pointer"></v-text-field>
72
72
  </v-col>
73
73
  </v-row>
@@ -76,7 +76,7 @@
76
76
  <v-row no-gutters>
77
77
  <InputLabel class="text-capitalize font-weight-bold" title="City" />
78
78
  <v-col cols="12">
79
- <v-text-field :model-value="siteData?.address?.city" density="compact" readonly
79
+ <v-text-field :model-value="buildingUnit?.site?.address?.city" density="compact" readonly
80
80
  class="no-pointer"></v-text-field>
81
81
  </v-col>
82
82
  </v-row>
@@ -85,7 +85,7 @@
85
85
  <v-row no-gutters>
86
86
  <InputLabel class="text-capitalize font-weight-bold" title="State" />
87
87
  <v-col cols="12">
88
- <v-text-field :model-value="siteData?.address?.state" density="compact" readonly
88
+ <v-text-field :model-value="buildingUnit?.site?.address?.state" density="compact" readonly
89
89
  class="no-pointer"></v-text-field>
90
90
  </v-col>
91
91
  </v-row>
@@ -94,7 +94,7 @@
94
94
  <v-row no-gutters>
95
95
  <InputLabel class="text-capitalize font-weight-bold" title="Country" />
96
96
  <v-col cols="12">
97
- <v-text-field :model-value="siteData?.address?.country" density="compact" readonly
97
+ <v-text-field :model-value="buildingUnit?.site?.address?.country" density="compact" readonly
98
98
  class="no-pointer"></v-text-field>
99
99
  </v-col>
100
100
  </v-row>
@@ -103,7 +103,7 @@
103
103
  <v-row no-gutters>
104
104
  <InputLabel class="text-capitalize font-weight-bold" title="Postal Code" />
105
105
  <v-col cols="12">
106
- <v-text-field :model-value="siteData?.address?.postalCode" density="compact" readonly
106
+ <v-text-field :model-value="buildingUnit?.site?.address?.postalCode" density="compact" readonly
107
107
  class="no-pointer"></v-text-field>
108
108
  </v-col>
109
109
  </v-row>
@@ -114,7 +114,7 @@
114
114
 
115
115
  <template v-else-if="tab === 'residents'">
116
116
  <v-card width="100%">
117
- <v-expansion-panels v-model="panels" variant="accordion" >
117
+ <v-expansion-panels v-model="panels" variant="accordion">
118
118
 
119
119
  <!-- Residents -->
120
120
  <v-expansion-panel value="residents">
@@ -123,10 +123,12 @@
123
123
  </v-expansion-panel-title>
124
124
 
125
125
  <v-expansion-panel-text>
126
- <template v-if="unitResidentsArray.length" v-for="resident, residentIndex in unitResidentsArray" :key="residentIndex">
127
- <UnitPersonCard
128
- :person="resident" :readOnly="true" />
129
- <v-divider v-if="(residentIndex + 1) !== unitResidentsArray.length" thickness="2" color="primary" class="my-4" />
126
+ <template v-if="unitResidentsArray.length" v-for="resident, residentIndex in unitResidentsArray"
127
+ :key="residentIndex">
128
+ <UnitPersonCard :person="resident" :readOnly="true" show-owner-option
129
+ @update:owner="handleUpdateOwner" :loading-owner-processing="loading.ownerProcessing" />
130
+ <v-divider v-if="(residentIndex + 1) !== unitResidentsArray.length" thickness="2" color="primary"
131
+ class="my-4" />
130
132
  </template>
131
133
  <p v-else class="font-weight-semibold text-caption ml-2 mt-5">
132
134
  **No residents to display**
@@ -141,42 +143,32 @@
141
143
  </v-expansion-panel-title>
142
144
 
143
145
  <v-expansion-panel-text>
144
- <template v-if="unitTenantsArray.length" v-for="(tenant, tenantIndex) in unitTenantsArray" :key="tenant._id || tenantIndex">
145
- <UnitPersonCard :person="tenant" :readOnly="true" />
146
- <v-divider v-if="(tenantIndex + 1) !== unitTenantsArray.length" thickness="2" color="primary" class="my-4" />
146
+ <template v-if="unitTenantsArray.length" v-for="(tenant, tenantIndex) in unitTenantsArray"
147
+ :key="tenant._id || tenantIndex">
148
+ <UnitPersonCard :person="tenant" :readOnly="true" />
149
+ <v-divider v-if="(tenantIndex + 1) !== unitTenantsArray.length" thickness="2" color="primary"
150
+ class="my-4" />
147
151
  </template>
148
152
  <p v-else class=" font-weight-semibold text-caption ml-2 mt-5">
149
153
  **No tenants to display**
150
154
  </p>
151
155
  </v-expansion-panel-text>
152
156
  </v-expansion-panel>
153
-
154
- <!-- Guests -->
155
- <v-expansion-panel value="guests">
156
- <v-expansion-panel-title class="bg-primary">
157
- Guests ({{ unitGuestsArray.length }})
158
- </v-expansion-panel-title>
159
-
160
- <v-expansion-panel-text>
161
- <template v-if="unitGuestsArray.length" v-for="(guest, guestIndex) in unitGuestsArray" :key="guest._id || guestIndex">
162
- <UnitPersonCard :person="guest" :readOnly="true" />
163
- <v-divider v-if="(guestIndex + 1) !== unitGuestsArray.length" thickness="2" color="primary" class="my-4" />
164
- </template>
165
- <p v-else class=" font-weight-semibold text-caption ml-2 mt-5">
166
- **No guests to display**
167
- </p>
168
- </v-expansion-panel-text>
169
- </v-expansion-panel>
170
-
171
157
  </v-expansion-panels>
172
158
  </v-card>
173
159
  </template>
174
160
  <template v-else-if="tab === 'vehicles'">
175
- <p class="font-weight-semibold text-caption ml-2 mt-5">
176
- **No vehicles to display**
177
- </p>
178
- </template>
179
-
161
+ <TableMain :headers="vehicleHeaders" :show-header="true" :page="vehiclePage" :pages="vehicleTotalPages"
162
+ :pageRange="vehiclePageRange" :items="unitVehicleItems" @refresh="getUnitVehiclesRefresh" @update:page="handleUpdateVehiclePage">
163
+
164
+ <template #item.status="{value}">
165
+ <v-chip :color="formatVehicleStatus(value).color" class="ma-0" small>
166
+ {{ formatVehicleStatus(value).label }}
167
+ </v-chip>
168
+ </template>
169
+ </TableMain>
170
+ </template>
171
+
180
172
  <template v-else-if="tab === 'others'">
181
173
  <v-row>
182
174
  <!-- <v-col cols="12" md="6" class="mt-2">
@@ -294,24 +286,7 @@ const prop = defineProps({
294
286
  },
295
287
  roomFacility: {
296
288
  type: Object as PropType<TBuildingUnit>,
297
- default: () => ({
298
- _id: "",
299
- site: "",
300
- name: "",
301
- owner: "",
302
- ownerName: "",
303
- building: "",
304
- buildingName: "",
305
- // category: "",
306
- block: null,
307
- level: 0,
308
- status: "active",
309
- buildingUnitFiles: [],
310
- companyName: "",
311
- companyRegistrationNumber: "",
312
- leaseStart: "",
313
- leaseEnd: "",
314
- }),
289
+ required: true,
315
290
  },
316
291
  canUpdateUnit: {
317
292
  type: Boolean,
@@ -325,7 +300,18 @@ const prop = defineProps({
325
300
 
326
301
  const buildingUnit = ref({
327
302
  _id: "",
328
- site: "",
303
+ site: {
304
+ _id: "",
305
+ name: "",
306
+ address: {
307
+ line1: "",
308
+ line2: "",
309
+ city: "",
310
+ state: "",
311
+ country: "",
312
+ postalCode: "",
313
+ },
314
+ },
329
315
  name: "",
330
316
  owner: "",
331
317
  ownerName: "",
@@ -343,8 +329,6 @@ const buildingUnit = ref({
343
329
  });
344
330
 
345
331
 
346
- const siteData = ref<TSite | null>(null);
347
-
348
332
  buildingUnit.value = JSON.parse(JSON.stringify(prop.roomFacility));
349
333
 
350
334
  const emit = defineEmits(["cancel", "success", "success:create-more", "delete-unit"]);
@@ -358,11 +342,29 @@ const tab = ref('general')
358
342
  const validForm = ref(false);
359
343
 
360
344
  const { getAll } = useBuilding();
361
- const { getPeopleByUnit } = usePeople();
345
+ const { getPeopleByUnit, updateById: updatePeopleById } = usePeople();
362
346
  const { debounce } = useUtils();
347
+ const { searchMultipleVehiclesByUnitId, formatVehicleStatus } = useVehicle();
348
+
349
+ const loading = reactive({
350
+ ownerProcessing: false,
351
+ })
363
352
 
364
353
  const buildings = ref<Record<string, any>[]>([]);
365
354
  const peopleItems = ref<TPeople[]>([]);
355
+ const unitVehicleItems = ref<TVehicle[]>([]);
356
+
357
+ const vehiclePage = ref(1);
358
+ const vehiclePageRange = ref("-- - -- of --");
359
+ const vehicleTotalPages = ref(0);
360
+
361
+ const vehicleHeaders = [
362
+ { title: "Plate Number", value: "plateNumber" },
363
+ { title: "Owner Name", value: "name" },
364
+ { title: "NRIC", value: "nric" },
365
+ { title: "Type", value: "type" },
366
+ { title: "Status", value: "status" },
367
+ ];
366
368
 
367
369
  const { data: getBuildingReq } = useLazyAsyncData(
368
370
  "get-all-buildings",
@@ -388,6 +390,18 @@ watch(getUnitPeople, (newData: TPeople[]) => {
388
390
  peopleItems.value = newData ?? [];
389
391
  });
390
392
 
393
+ const { data: getUnitVehicles, refresh: getUnitVehiclesRefresh } = useLazyAsyncData(
394
+ "get-unit-vehicles",
395
+ async () => await searchMultipleVehiclesByUnitId({unitId: buildingUnit.value._id, page: 1, limit: 10})
396
+ );
397
+
398
+ watch(getUnitVehicles, (newData) => {
399
+ unitVehicleItems.value = Array.isArray(newData?.items) ? newData.items : [];
400
+ vehiclePage.value = newData?.page || 1;
401
+ vehiclePageRange.value = newData?.pageRange || "-- - -- of --";
402
+ vehicleTotalPages.value = newData?.totalPages || 0;
403
+ });
404
+
391
405
  const unitResidentsArray = computed(() => {
392
406
  return peopleItems.value.filter((person) => person?.type === 'resident');
393
407
  });
@@ -396,21 +410,19 @@ const unitTenantsArray = computed(() => {
396
410
  return peopleItems.value.filter((person) => person?.type === 'tenant');
397
411
  });
398
412
 
399
- const unitGuestsArray = computed(() => {
400
- return peopleItems.value.filter((person) => person?.type === 'guest');
401
- });
402
413
 
403
- buildingUnit.value.site = prop.site;
414
+ // buildingUnit.value.site = prop.site;
404
415
 
405
416
  const selectedBuilding = computed(() => {
406
417
  return buildings.value.find((b) => b.value === buildingUnit.value.building);
407
418
  });
408
419
 
409
420
  const buildingLevels = computed(() => {
410
- return Array.from(
411
- { length: selectedBuilding.value?.levels || 0 },
412
- (_, i) => i + 1
413
- );
421
+ const levels = selectedBuilding.value?.levels ?? [];
422
+ return levels.map((level: string) => ({
423
+ title: level,
424
+ value: level,
425
+ }))
414
426
  });
415
427
 
416
428
  const disable = ref(false);
@@ -468,6 +480,40 @@ async function submit() {
468
480
  }
469
481
  }
470
482
 
483
+
484
+ const handleUpdateOwner = async ({ person, isOwner }: { person: TPeople; isOwner: boolean }) => {
485
+ const owners = peopleItems.value.filter(p => p.isOwner)
486
+ message.value = ""
487
+ // console.log('Updating owner status for', person._id, 'to', isOwner)
488
+
489
+ const userId = person._id ?? null;
490
+
491
+ if (!isOwner && owners.length <= 1 && owners[0]._id === person._id) {
492
+ message.value = "There must be at least one owner for this unit."
493
+ return
494
+ }
495
+
496
+ if (!userId) return message.value = "Resident user ID is missing."
497
+
498
+
499
+ try {
500
+ loading.ownerProcessing = true;
501
+ await updatePeopleById(userId, { isOwner })
502
+ getUnitPeopleRefresh();
503
+ } catch (error: any) {
504
+ message.value = error.response?._data?.message || "Failed to update owner status."
505
+ } finally {
506
+ loading.ownerProcessing = false;
507
+
508
+ }
509
+
510
+ }
511
+
512
+ function handleUpdateVehiclePage(newPageNum: number) {
513
+ vehiclePage.value = newPageNum;
514
+ }
515
+
516
+
471
517
  function cancel() {
472
518
  message.value = "";
473
519
  emit("cancel");