@7365admin1/layer-common 1.10.0 → 1.10.2

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 (86) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/components/AcceptDialog.vue +44 -0
  3. package/components/AccessCard/AvailableStats.vue +55 -0
  4. package/components/AccessCardAddForm.vue +284 -19
  5. package/components/AccessCardAssignToUnitForm.vue +440 -0
  6. package/components/AccessManagement.vue +218 -85
  7. package/components/AddSupplyForm.vue +165 -0
  8. package/components/AreaChecklistHistoryLogs.vue +235 -0
  9. package/components/AreaChecklistHistoryMain.vue +176 -0
  10. package/components/AreaFormDialog.vue +266 -0
  11. package/components/AreaMain.vue +863 -0
  12. package/components/AttendanceCheckInOutDialog.vue +416 -0
  13. package/components/AttendanceDetailsDialog.vue +184 -0
  14. package/components/AttendanceMain.vue +155 -0
  15. package/components/AttendanceMapSearchDialog.vue +393 -0
  16. package/components/AttendanceSettingsDialog.vue +398 -0
  17. package/components/BuildingManagement/buildings.vue +5 -5
  18. package/components/BuildingManagement/units.vue +5 -5
  19. package/components/BulletinBoardManagement.vue +322 -0
  20. package/components/ChecklistItemRow.vue +54 -0
  21. package/components/CheckoutItemMain.vue +705 -0
  22. package/components/CleaningScheduleMain.vue +271 -0
  23. package/components/DocumentManagement.vue +4 -0
  24. package/components/EntryPass/QrTemplatePreview.vue +104 -0
  25. package/components/EntryPassMain.vue +252 -200
  26. package/components/HygieneUpdateMoreAction.vue +238 -0
  27. package/components/ManageChecklistMain.vue +384 -0
  28. package/components/MemberMain.vue +48 -20
  29. package/components/MyAttendanceMain.vue +224 -0
  30. package/components/OnlineFormsConfiguration.vue +9 -2
  31. package/components/PhotoUpload.vue +410 -0
  32. package/components/ScheduleAreaMain.vue +313 -0
  33. package/components/ScheduleTaskAreaFormDialog.vue +144 -0
  34. package/components/ScheduleTaskAreaUpdateMoreAction.vue +109 -0
  35. package/components/ScheduleTaskForm.vue +471 -0
  36. package/components/ScheduleTaskMain.vue +345 -0
  37. package/components/ScheduleTastTicketMain.vue +182 -0
  38. package/components/SignaturePad.vue +17 -5
  39. package/components/StockCard.vue +191 -0
  40. package/components/SupplyManagementMain.vue +557 -0
  41. package/components/TableHygiene.vue +617 -0
  42. package/components/UnitMain.vue +451 -0
  43. package/components/VisitorManagement.vue +28 -15
  44. package/composables/useAccessManagement.ts +163 -0
  45. package/composables/useAreaPermission.ts +51 -0
  46. package/composables/useAreas.ts +99 -0
  47. package/composables/useAttendance.ts +89 -0
  48. package/composables/useAttendancePermission.ts +68 -0
  49. package/composables/useBuilding.ts +2 -2
  50. package/composables/useBuildingUnit.ts +2 -2
  51. package/composables/useBulletin.ts +82 -0
  52. package/composables/useCard.ts +2 -0
  53. package/composables/useCheckout.ts +61 -0
  54. package/composables/useCheckoutPermission.ts +80 -0
  55. package/composables/useCleaningPermission.ts +229 -0
  56. package/composables/useCleaningSchedulePermission.ts +58 -0
  57. package/composables/useCleaningSchedules.ts +233 -0
  58. package/composables/useCountry.ts +8 -0
  59. package/composables/useDashboardData.ts +2 -2
  60. package/composables/useFeedback.ts +1 -1
  61. package/composables/useLocation.ts +78 -0
  62. package/composables/useOnlineForm.ts +16 -9
  63. package/composables/usePeople.ts +87 -72
  64. package/composables/useQR.ts +29 -0
  65. package/composables/useScheduleTask.ts +89 -0
  66. package/composables/useScheduleTaskArea.ts +85 -0
  67. package/composables/useScheduleTaskPermission.ts +68 -0
  68. package/composables/useSiteEntryPassSettings.ts +4 -15
  69. package/composables/useStock.ts +45 -0
  70. package/composables/useSupply.ts +63 -0
  71. package/composables/useSupplyPermission.ts +92 -0
  72. package/composables/useUnitPermission.ts +51 -0
  73. package/composables/useUnits.ts +82 -0
  74. package/composables/useWebUsb.ts +389 -0
  75. package/composables/useWorkOrder.ts +1 -1
  76. package/nuxt.config.ts +3 -0
  77. package/package.json +4 -1
  78. package/types/area.d.ts +22 -0
  79. package/types/attendance.d.ts +38 -0
  80. package/types/checkout-item.d.ts +27 -0
  81. package/types/cleaner-schedule.d.ts +54 -0
  82. package/types/location.d.ts +42 -0
  83. package/types/schedule-task.d.ts +18 -0
  84. package/types/stock.d.ts +16 -0
  85. package/types/supply.d.ts +11 -0
  86. package/utils/acm-crypto.ts +30 -0
@@ -0,0 +1,557 @@
1
+ <template>
2
+ <v-row no-gutters align="center" justify="center">
3
+ <v-col cols="12" lg="12">
4
+ <TableMain
5
+ :title="`${siteName} Units`"
6
+ :items="items"
7
+ :headers="headers"
8
+ :loading="loading"
9
+ :show-header="true"
10
+ v-model:page="page"
11
+ :pages="pages"
12
+ :pageRange="pageRange"
13
+ :no-data-text="`No supplies found for ${siteName}.`"
14
+ @refresh="getSuppliesRefresh"
15
+ :canCreate="canAddSupply"
16
+ createLabel="Add Supply"
17
+ @row-click="handleRowClick"
18
+ >
19
+ <template #actions>
20
+ <v-row no-gutters align="center" class="w-100">
21
+ <v-col cols="auto" v-if="canAddSupply">
22
+ <v-btn
23
+ class="text-none"
24
+ rounded="pill"
25
+ variant="tonal"
26
+ size="large"
27
+ @click="onCreateUnit()"
28
+ >
29
+ Add Supply
30
+ </v-btn>
31
+ </v-col>
32
+
33
+ <v-spacer />
34
+
35
+ <v-col cols="auto">
36
+ <v-text-field
37
+ v-model="searchInput"
38
+ density="compact"
39
+ placeholder="Search"
40
+ clearable
41
+ width="300"
42
+ append-inner-icon="mdi-magnify"
43
+ hide-details
44
+ />
45
+ </v-col>
46
+ </v-row>
47
+ </template>
48
+
49
+ <template #item.status="{ value }">
50
+ <v-chip class="text-capitalize">{{ value || "N/A" }}</v-chip>
51
+ </template>
52
+
53
+ <template #item.block="{ value }">
54
+ {{ value ? `blk ${value}` : "" }}
55
+ </template>
56
+ </TableMain>
57
+ </v-col>
58
+ </v-row>
59
+
60
+ <AddSupplyForm
61
+ v-model="dialogShowForm"
62
+ v-model:name="supplyName"
63
+ v-model:qty="supplyQuantity"
64
+ v-model:unitOfMeasurement="supplyUnit"
65
+ :mode="dialogMode"
66
+ :supplyData="editingSupply"
67
+ :site="props.site"
68
+ @saved="_createSupply"
69
+ />
70
+
71
+ <v-dialog v-model="dialogShowMoreActions" width="400" persistent>
72
+ <HygieneUpdateMoreAction
73
+ :title="selectedSupply?.name || 'Unit Actions'"
74
+ :canUpdate="canUpdateSupply"
75
+ :canDelete="canDeleteSupply"
76
+ :showAddStock="canAddStock"
77
+ :showViewStock="canViewStock"
78
+ :showRequestItem="canRequestItem"
79
+ :manageButtonLabel="''"
80
+ :editButtonLabel="'Edit Supply'"
81
+ :deleteButtonLabel="'Delete Supply'"
82
+ :addStockButtonLabel="'Add Stock'"
83
+ :viewButtonLabel="'View Stock'"
84
+ :requestItemButtonLabel="'Checkout Item'"
85
+ @close="dialogShowMoreActions = false"
86
+ @edit="onEditFromMoreAction"
87
+ @delete="onDeleteFromMoreAction"
88
+ @addstock="onAddStockFromMoreAction"
89
+ @view-stock="onViewStockFromMoreAction"
90
+ @requestItem="onRequestItemFromMoreAction"
91
+ >
92
+ <template #content>
93
+ <v-row no-gutters>
94
+ <v-col v-if="selectedSupply" cols="12" class="mb-2">
95
+ <v-row no-gutters class="mb-2">
96
+ <v-col cols="5" class="text-subtitle-2 font-weight-bold">
97
+ Name:
98
+ </v-col>
99
+ <v-col cols="7" class="text-subtitle-2">
100
+ {{ selectedSupply.name || "N/A" }}
101
+ </v-col>
102
+ </v-row>
103
+
104
+ <v-row no-gutters class="mb-2">
105
+ <v-col cols="5" class="text-subtitle-2 font-weight-bold">
106
+ Quantity:
107
+ </v-col>
108
+ <v-col cols="7" class="text-subtitle-2">
109
+ {{ selectedSupply.qty || "N/A" }}
110
+ </v-col>
111
+ </v-row>
112
+
113
+ <v-row no-gutters class="mb-2">
114
+ <v-col cols="5" class="text-subtitle-2 font-weight-bold">
115
+ Unit of Measurement:
116
+ </v-col>
117
+ <v-col cols="7" class="text-subtitle-2">
118
+ {{ selectedSupply.unitOfMeasurement || "N/A" }}
119
+ </v-col>
120
+ </v-row>
121
+
122
+ <v-col cols="12" class="my-2">
123
+ <span class="text-subtitle-2 text-error">{{ message }}</span>
124
+ </v-col>
125
+ </v-col>
126
+ </v-row>
127
+ </template>
128
+ </HygieneUpdateMoreAction>
129
+ </v-dialog>
130
+
131
+ <v-dialog v-model="dialogDeleteSupply" max-width="450">
132
+ <v-card>
133
+ <v-toolbar>
134
+ <v-row no-gutters class="fill-height px-6" align="center">
135
+ <span class="font-weight-bold text-h6 text-capitalize">
136
+ Delete {{ selectedSupply?.name || "Unit" }}
137
+ </span>
138
+ </v-row>
139
+ </v-toolbar>
140
+ <v-card-text>
141
+ <span class="text-subtitle-2"
142
+ >Are you sure you want to delete this unitOfMeasurement?</span
143
+ >
144
+ </v-card-text>
145
+
146
+ <v-toolbar class="pa-0" density="compact">
147
+ <v-row no-gutters>
148
+ <v-col cols="6" class="pa-0">
149
+ <v-btn
150
+ block
151
+ variant="text"
152
+ class="text-none"
153
+ size="large"
154
+ @click="dialogDeleteSupply = false"
155
+ height="48"
156
+ >
157
+ Cancel
158
+ </v-btn>
159
+ </v-col>
160
+
161
+ <v-col cols="6" class="pa-0">
162
+ <v-btn
163
+ block
164
+ variant="flat"
165
+ color="black"
166
+ class="text-none font-weight-bold"
167
+ height="48"
168
+ :loading="submitting"
169
+ @click="_deleteSupply"
170
+ >
171
+ Delete
172
+ </v-btn>
173
+ </v-col>
174
+ </v-row>
175
+ </v-toolbar>
176
+ </v-card>
177
+ </v-dialog>
178
+
179
+ <v-dialog v-model="dialogStockAction" max-width="450">
180
+ <v-card>
181
+ <v-toolbar>
182
+ <v-row no-gutters class="fill-height px-6" align="center">
183
+ <span class="font-weight-bold text-h6 text-capitalize">
184
+ {{ stockActionMode === "add" ? "Add Stock" : "Checkout Item" }}
185
+ </span>
186
+ </v-row>
187
+ </v-toolbar>
188
+ <v-card-text class="pa-4">
189
+ <v-form ref="stockActionFormRef" v-model="stockActionValid">
190
+ <v-row no-gutters>
191
+ <v-col cols="12" class="mb-4">
192
+ <InputLabel
193
+ for="stockActionQty"
194
+ title="Quantity"
195
+ required
196
+ class="mb-1"
197
+ />
198
+ <v-text-field
199
+ v-model.number="stockActionQuantity"
200
+ :rules="[requiredRule]"
201
+ density="comfortable"
202
+ variant="outlined"
203
+ type="number"
204
+ min="1"
205
+ placeholder="Enter quantity"
206
+ hide-details="auto"
207
+ />
208
+ </v-col>
209
+ </v-row>
210
+ </v-form>
211
+ </v-card-text>
212
+
213
+ <v-toolbar class="pa-0" density="compact">
214
+ <v-row no-gutters>
215
+ <v-col cols="6" class="pa-0">
216
+ <v-btn
217
+ block
218
+ variant="text"
219
+ class="text-none"
220
+ size="large"
221
+ @click="dialogStockAction = false"
222
+ height="48"
223
+ >
224
+ Cancel
225
+ </v-btn>
226
+ </v-col>
227
+
228
+ <v-col cols="6" class="pa-0">
229
+ <v-btn
230
+ block
231
+ variant="flat"
232
+ color="black"
233
+ class="text-none font-weight-bold rounded-0"
234
+ height="48"
235
+ :loading="submitting"
236
+ @click="stockActionMode === 'add' ? _addStock() : _requestItem()"
237
+ >
238
+ {{ stockActionMode === "add" ? "Add Stock" : "Checkout Item" }}
239
+ </v-btn>
240
+ </v-col>
241
+ </v-row>
242
+ </v-toolbar>
243
+ </v-card>
244
+ </v-dialog>
245
+
246
+ <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
247
+ </template>
248
+
249
+ <script setup lang="ts">
250
+ import useSupply from "../composables/useSupply";
251
+ import useStock from "../composables/useStock";
252
+ import { useSupplyPermission } from "../composables/useSupplyPermission";
253
+
254
+ const props = defineProps({
255
+ orgId: { type: String, default: "" },
256
+ site: { type: String, default: "" },
257
+ });
258
+
259
+ const {
260
+ canViewSupplies,
261
+ canAddSupply,
262
+ canUpdateSupply,
263
+ canDeleteSupply,
264
+ canAddStock,
265
+ canViewStock,
266
+ canRequestItem,
267
+ } = useSupplyPermission();
268
+
269
+ const items = ref<Array<Record<string, any>>>([]);
270
+ const siteName = ref<string>("");
271
+ const submitting = ref(false);
272
+
273
+ const headers = [
274
+ { title: "Name", value: "name" },
275
+ { title: "Available Stock Qty", value: "qty" },
276
+ { title: "Status", value: "status" },
277
+ ];
278
+
279
+ const { getSupplies, getSupplyById, createSupply, updateSupply, deleteSupply } =
280
+ useSupply();
281
+ const { debounce, requiredRule } = useUtils();
282
+
283
+ const searchInput = ref("");
284
+ const startDate = ref("");
285
+ const endDate = ref("");
286
+ const page = ref(1);
287
+ const pages = ref(0);
288
+ const pageRange = ref("-- - -- of --");
289
+
290
+ const {
291
+ data: getSuppliesReq,
292
+ refresh: getSuppliesRefresh,
293
+ pending: loading,
294
+ } = await useLazyAsyncData(
295
+ "get-all-supplies",
296
+ () =>
297
+ getSupplies({
298
+ page: page.value,
299
+ search: searchInput.value,
300
+ site: props.site,
301
+ }),
302
+ {
303
+ watch: [page, () => props.site],
304
+ }
305
+ );
306
+
307
+ watchEffect(() => {
308
+ if (getSuppliesReq.value) {
309
+ items.value = getSuppliesReq.value.items;
310
+ pages.value = getSuppliesReq.value.pages;
311
+ pageRange.value = getSuppliesReq.value.pageRange;
312
+ }
313
+ });
314
+
315
+ const debounceSearch = debounce(getSuppliesRefresh, 500);
316
+ watch(
317
+ [searchInput, endDate, startDate],
318
+ ([]) => {
319
+ debounceSearch();
320
+ },
321
+ { immediate: false, deep: true }
322
+ );
323
+
324
+ const selectedSupply = ref<Record<string, any>>({});
325
+ const message = ref("");
326
+ const messageSnackbar = ref(false);
327
+ const messageColor = ref("");
328
+ const fileInput = ref<HTMLInputElement | null>(null);
329
+
330
+ const dialogShowMoreActions = ref(false);
331
+ const dialogShowForm = ref(false);
332
+ const dialogDeleteSupply = ref(false);
333
+ const dialogStockAction = ref(false);
334
+ const stockActionMode = ref<"add" | "request">("add");
335
+ const dialogMode = ref<"add" | "edit">("add");
336
+
337
+ const editingSupply = ref<Record<string, any>>({});
338
+ const supplyName = ref("");
339
+ const supplyQuantity = ref(0);
340
+ const supplyUnit = ref("");
341
+
342
+ const stockActionFormRef = ref<any>(null);
343
+ const stockActionValid = ref(false);
344
+
345
+ function showMessage(msg: string, color: string = "error") {
346
+ message.value = msg;
347
+ messageColor.value = color;
348
+ messageSnackbar.value = true;
349
+ }
350
+
351
+ function onCreateUnit() {
352
+ dialogMode.value = "add";
353
+ editingSupply.value = {};
354
+ supplyName.value = "";
355
+ supplyQuantity.value = 0;
356
+ supplyUnit.value = "";
357
+ dialogShowForm.value = true;
358
+ }
359
+
360
+ function onSaveSupply(data: {
361
+ name: string;
362
+ qty: number;
363
+ unitOfMeasurement: string;
364
+ }) {
365
+ showMessage("Supply saved successfully", "success");
366
+ getSuppliesRefresh();
367
+ }
368
+
369
+ async function _createSupply() {
370
+ submitting.value = true;
371
+ try {
372
+ const payload: TSupplyCreate = {
373
+ name: supplyName.value,
374
+ unitOfMeasurement: supplyUnit.value,
375
+ };
376
+
377
+ let response;
378
+
379
+ if (dialogMode.value === "edit" && editingSupply.value) {
380
+ const id =
381
+ (editingSupply.value as any)._id || (editingSupply.value as any).id;
382
+ if (!id) throw new Error("Invalid supply id for update");
383
+ response = await updateSupply(id, payload);
384
+ } else {
385
+ response = await createSupply(payload, props.site);
386
+ }
387
+
388
+ showMessage(response?.message, "success");
389
+ dialogShowForm.value = false;
390
+ editingSupply.value = {};
391
+ supplyName.value = "";
392
+ supplyQuantity.value = 0;
393
+ supplyUnit.value = "";
394
+
395
+ await getSuppliesRefresh();
396
+ } catch (error: any) {
397
+ console.error(error);
398
+ showMessage(error?.data?.message, "error");
399
+ } finally {
400
+ submitting.value = false;
401
+ }
402
+ }
403
+
404
+ const selectedSupplyId = ref("");
405
+
406
+ const {
407
+ data: getSupplyByIdReq,
408
+ refresh: getSupplyByIdRefresh,
409
+ status: getSupplyByIdStatus,
410
+ } = await useLazyAsyncData(
411
+ "get-supply-by-id",
412
+ () => getSupplyById(selectedSupplyId.value),
413
+ {
414
+ watch: [selectedSupplyId],
415
+ immediate: false,
416
+ }
417
+ );
418
+
419
+ watchEffect(() => {
420
+ if (getSupplyByIdReq.value && getSupplyByIdStatus.value === "success") {
421
+ selectedSupply.value = getSupplyByIdReq.value;
422
+ }
423
+ });
424
+
425
+ async function handleRowClick(data: any) {
426
+ selectedSupply.value = data?.item;
427
+ message.value = "";
428
+
429
+ selectedSupplyId.value = selectedSupply.value._id;
430
+ await getSupplyByIdRefresh();
431
+
432
+ dialogShowMoreActions.value = true;
433
+ }
434
+
435
+ const onEditFromMoreAction = async () => {
436
+ dialogShowMoreActions.value = false;
437
+ if (!selectedSupply.value) return;
438
+
439
+ submitting.value = true;
440
+ selectedSupplyId.value = selectedSupply.value._id;
441
+ await getSupplyByIdRefresh();
442
+ submitting.value = false;
443
+
444
+ const response = getSupplyByIdReq.value;
445
+ if (!response) return;
446
+
447
+ dialogMode.value = "edit";
448
+ editingSupply.value = response;
449
+ supplyName.value = response.name || "";
450
+ supplyQuantity.value = response.qty || 0;
451
+ supplyUnit.value = response.unitOfMeasurement || "";
452
+ dialogShowForm.value = true;
453
+ };
454
+
455
+ const onDeleteFromMoreAction = () => {
456
+ dialogShowMoreActions.value = false;
457
+ dialogDeleteSupply.value = true;
458
+ };
459
+
460
+ const onAddStockFromMoreAction = () => {
461
+ dialogShowMoreActions.value = false;
462
+ stockActionMode.value = "add";
463
+ stockActionQuantity.value = 0;
464
+ stockActionRemarks.value = "";
465
+ dialogStockAction.value = true;
466
+ };
467
+
468
+ const onViewStockFromMoreAction = () => {
469
+ dialogShowMoreActions.value = false;
470
+ const org = props.orgId;
471
+ const site = props.site;
472
+ const id = selectedSupply.value._id;
473
+ useRouter().push(`/${org}/${site}/supply-management/stock/${id}`);
474
+ };
475
+
476
+ const onRequestItemFromMoreAction = () => {
477
+ dialogShowMoreActions.value = false;
478
+ stockActionMode.value = "request";
479
+ stockActionQuantity.value = 0;
480
+ stockActionRemarks.value = "";
481
+ dialogStockAction.value = true;
482
+ };
483
+
484
+ async function _deleteSupply() {
485
+ if (!selectedSupply.value) return;
486
+
487
+ try {
488
+ submitting.value = true;
489
+ const id =
490
+ (selectedSupply.value as any)._id || (selectedSupply.value as any).id;
491
+ if (!id) throw new Error("Invalid supply id");
492
+
493
+ const response = await deleteSupply(id);
494
+ dialogDeleteSupply.value = false;
495
+ showMessage(response?.message, "success");
496
+
497
+ await getSuppliesRefresh();
498
+ } catch (error: any) {
499
+ showMessage(error?.data?.message, "error");
500
+ } finally {
501
+ submitting.value = false;
502
+ }
503
+ }
504
+
505
+ const { createStock, requestItem } = useStock();
506
+
507
+ const stockActionQuantity = ref<number>(0);
508
+ const stockActionRemarks = ref("");
509
+
510
+ async function _addStock() {
511
+ submitting.value = true;
512
+ try {
513
+ const id = selectedSupply.value._id || selectedSupply.value.id;
514
+
515
+ const payload: TStockCreate = {
516
+ qty: stockActionQuantity.value,
517
+ remarks: stockActionRemarks.value,
518
+ };
519
+
520
+ const response = await createStock(props.site, id, payload);
521
+ showMessage(response?.message, "success");
522
+ dialogStockAction.value = false;
523
+ stockActionQuantity.value = 0;
524
+ stockActionRemarks.value = "";
525
+
526
+ await getSuppliesRefresh();
527
+ } catch (error: any) {
528
+ console.error(error);
529
+ showMessage(error?.data?.message, "error");
530
+ } finally {
531
+ submitting.value = false;
532
+ }
533
+ }
534
+
535
+ async function _requestItem() {
536
+ submitting.value = true;
537
+ try {
538
+ const id = selectedSupply.value._id || selectedSupply.value.id;
539
+
540
+ const payload: TStockCreate = {
541
+ qty: stockActionQuantity.value,
542
+ };
543
+
544
+ const response = await requestItem(props.site, id, payload);
545
+ showMessage(response?.message, "success");
546
+ dialogStockAction.value = false;
547
+ stockActionQuantity.value = 0;
548
+
549
+ await getSuppliesRefresh();
550
+ } catch (error: any) {
551
+ console.error(error);
552
+ showMessage(error?.data?.message, "error");
553
+ } finally {
554
+ submitting.value = false;
555
+ }
556
+ }
557
+ </script>