@7365admin1/layer-common 3.0.30 → 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/components/AddPassKeyToVisitor.vue +115 -53
- package/components/DashboardMain.vue +29 -33
- package/components/InvitationMain.vue +4 -3
- package/components/ManageChecklistMain.vue +32 -25
- package/components/PhotoUpload.vue +19 -4
- package/components/VisitorForm.vue +11 -3
- package/components/VisitorManagement.vue +109 -30
- package/composables/useCleaningSchedulePermission.ts +16 -51
- package/package.json +1 -1
- package/types/customer.d.ts +2 -1
- /package/components/{NFC → Nfc}/NFCPatrolReportMain.vue +0 -0
- /package/components/{NFC → Nfc}/NFCPatrolRouteForm.vue +0 -0
- /package/components/{NFC → Nfc}/NFCPatrolRouteMain.vue +0 -0
- /package/components/{NFC → Nfc}/NFCPatrolSettings.vue +0 -0
- /package/components/{NFC → Nfc}/NFCTagForm.vue +0 -0
- /package/components/{NFC → Nfc}/NFCTagMain.vue +0 -0
- /package/components/{NFC → Nfc}/PatrolReport/DailyReportTab.vue +0 -0
- /package/components/{NFC → Nfc}/PatrolReport/MonthlyReportTab.vue +0 -0
- /package/components/{NFC → Nfc}/PatrolReport/PatrolActivityTable.vue +0 -0
- /package/components/{NFC → Nfc}/PatrolReport/PatrolReportTab.vue +0 -0
- /package/components/{NFC → Nfc}/PatrolReport/PatrolRouteSummary.vue +0 -0
- /package/components/{NFC → Nfc}/PatrolReport/RemarksDialog.vue +0 -0
- /package/components/{NFC → Nfc}/PatrolReport/ReportEmptyState.vue +0 -0
- /package/components/{NFC → Nfc}/PatrolReport/ReportFilters.vue +0 -0
- /package/components/{NFC → Nfc}/PatrolReport/ReportLocationHeader.vue +0 -0
- /package/components/{NFC → Nfc}/PatrolReport/SummaryReportTable.vue +0 -0
|
@@ -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
|
|
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
|
-
|
|
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<{
|
|
217
|
-
const existingPassToBeReplaced = ref<{
|
|
213
|
+
const existingPass = ref<{
|
|
218
214
|
keyId: string;
|
|
219
215
|
prefixAndName: string;
|
|
216
|
+
status?: string;
|
|
220
217
|
} | null>(null);
|
|
221
|
-
|
|
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 = {
|
|
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
|
-
|
|
256
|
-
|
|
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
|
-
|
|
299
|
-
|
|
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
|
-
|
|
304
|
-
|
|
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,
|
|
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
|
-
|
|
317
|
-
(k
|
|
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
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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) => ({
|
|
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
|
|
|
@@ -1545,30 +1545,16 @@ const { userAppRole } = useLocalSetup();
|
|
|
1545
1545
|
const { downloadPDF } = usePDFDownload();
|
|
1546
1546
|
const route = useRoute();
|
|
1547
1547
|
|
|
1548
|
-
const dashboardWidgetPermissions: Record<string, string> = {
|
|
1549
|
-
activity: "dashboard:view-activity",
|
|
1550
|
-
recentActivity: "dashboard:view-activity",
|
|
1551
|
-
taskSchedule: "dashboard:view-task-schedule",
|
|
1552
|
-
staffStatus: "dashboard:view-attendance-widget",
|
|
1553
|
-
attendance: "dashboard:view-attendance-widget",
|
|
1554
|
-
feedbacks: "dashboard:view-feedbacks-widget",
|
|
1555
|
-
workOrderStatus: "dashboard:view-work-order-status",
|
|
1556
|
-
activePatrol: "dashboard:view-active-patrol",
|
|
1557
|
-
upcomingEvents: "dashboard:view-upcoming-events",
|
|
1558
|
-
todayReminders: "dashboard:view-today-reminders",
|
|
1559
|
-
todayAttentions: "dashboard:view-today-attentions",
|
|
1560
|
-
};
|
|
1561
|
-
|
|
1562
1548
|
const propertyWidgetPermissions: Record<string, string[]> = {
|
|
1563
1549
|
workOrders: [
|
|
1564
|
-
"
|
|
1550
|
+
"work_orders:see-all-work-orders",
|
|
1565
1551
|
"work-order:see-all-work-orders",
|
|
1566
1552
|
],
|
|
1567
1553
|
incidents: ["incident-reports:see-incident-reports"],
|
|
1568
1554
|
visitors: ["visitorManagement:see-all-visitor"],
|
|
1569
1555
|
facilityBookings: ["facility-booking-mgmt:see-all-facility-booking"],
|
|
1570
1556
|
activity: [
|
|
1571
|
-
"
|
|
1557
|
+
"work_orders:see-all-work-orders",
|
|
1572
1558
|
"work-order:see-all-work-orders",
|
|
1573
1559
|
],
|
|
1574
1560
|
upcomingEvents: ["event-mgmt:see-all-event"],
|
|
@@ -1578,7 +1564,7 @@ const propertyWidgetPermissions: Record<string, string[]> = {
|
|
|
1578
1564
|
"facility-booking-mgmt:see-all-facility-booking",
|
|
1579
1565
|
],
|
|
1580
1566
|
workOrderStatus: [
|
|
1581
|
-
"
|
|
1567
|
+
"work_orders:see-all-work-orders",
|
|
1582
1568
|
"work-order:see-all-work-orders",
|
|
1583
1569
|
],
|
|
1584
1570
|
feedbacks: ["feedbacks:see-all-feedback"],
|
|
@@ -1587,27 +1573,30 @@ const propertyWidgetPermissions: Record<string, string[]> = {
|
|
|
1587
1573
|
|
|
1588
1574
|
const moduleWidgetPermissions: Record<string, string[]> = {
|
|
1589
1575
|
openWorkOrder: [
|
|
1576
|
+
"work_orders:see-all-work-orders",
|
|
1590
1577
|
"work_order:see-all-work-orders",
|
|
1591
1578
|
"work-order:see-all-work-orders",
|
|
1592
1579
|
"work-orders:see-all-work-orders",
|
|
1593
1580
|
],
|
|
1594
1581
|
workOrders: [
|
|
1582
|
+
"work_orders:see-all-work-orders",
|
|
1595
1583
|
"work_order:see-all-work-orders",
|
|
1596
1584
|
"work-order:see-all-work-orders",
|
|
1597
1585
|
"work-orders:see-all-work-orders",
|
|
1598
1586
|
],
|
|
1599
1587
|
activity: [
|
|
1588
|
+
"work_orders:see-all-work-orders",
|
|
1600
1589
|
"work_order:see-all-work-orders",
|
|
1601
1590
|
"work-order:see-all-work-orders",
|
|
1602
1591
|
"work-orders:see-all-work-orders",
|
|
1592
|
+
"work_orders:see-all-work-orders",
|
|
1603
1593
|
],
|
|
1604
|
-
|
|
1605
|
-
"
|
|
1606
|
-
"
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
"
|
|
1610
|
-
"schedule-task-mgmt:see-all-schedule-tasks",
|
|
1594
|
+
recentActivity: [
|
|
1595
|
+
"work_orders:see-all-work-orders",
|
|
1596
|
+
"work_order:see-all-work-orders",
|
|
1597
|
+
"work-order:see-all-work-orders",
|
|
1598
|
+
"work-orders:see-all-work-orders",
|
|
1599
|
+
"work_orders:see-all-work-orders",
|
|
1611
1600
|
],
|
|
1612
1601
|
staffStatus: ["attendance-mgmt:see-all-attendance"],
|
|
1613
1602
|
attendance: ["attendance-mgmt:see-all-attendance"],
|
|
@@ -1630,9 +1619,14 @@ const moduleWidgetPermissions: Record<string, string[]> = {
|
|
|
1630
1619
|
activePatrol: ["virtual-patrol:see-all-virtual-patrol-logs"],
|
|
1631
1620
|
};
|
|
1632
1621
|
|
|
1622
|
+
function hasSchedulePermission(permissions: string[], action: string) {
|
|
1623
|
+
return permissions.some((permission) =>
|
|
1624
|
+
permission.endsWith(`-schedule-mgmt:${action}`)
|
|
1625
|
+
);
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1633
1628
|
function canViewWidget(key: string) {
|
|
1634
1629
|
const permissions = userAppRole.value?.permissions;
|
|
1635
|
-
const dashboardPermission = dashboardWidgetPermissions[key];
|
|
1636
1630
|
const modulePermissions = isPropertyMode.value
|
|
1637
1631
|
? propertyWidgetPermissions[key]
|
|
1638
1632
|
: moduleWidgetPermissions[key];
|
|
@@ -1640,20 +1634,22 @@ function canViewWidget(key: string) {
|
|
|
1640
1634
|
if (!permissions) return true;
|
|
1641
1635
|
if (permissions.includes("*")) return true;
|
|
1642
1636
|
|
|
1637
|
+
if (
|
|
1638
|
+
!isPropertyMode.value &&
|
|
1639
|
+
["taskSchedule", "taskCompleted"].includes(key)
|
|
1640
|
+
) {
|
|
1641
|
+
return hasSchedulePermission(permissions, "see-all-schedules");
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1643
1644
|
if (isPropertyMode.value && modulePermissions) {
|
|
1644
1645
|
return modulePermissions.some((permission) =>
|
|
1645
1646
|
permissions.includes(permission)
|
|
1646
1647
|
);
|
|
1647
1648
|
}
|
|
1648
1649
|
|
|
1649
|
-
if (
|
|
1650
|
-
return (
|
|
1651
|
-
|
|
1652
|
-
Boolean(
|
|
1653
|
-
modulePermissions?.some((permission) =>
|
|
1654
|
-
permissions.includes(permission)
|
|
1655
|
-
)
|
|
1656
|
-
)
|
|
1650
|
+
if (modulePermissions) {
|
|
1651
|
+
return modulePermissions.some((permission) =>
|
|
1652
|
+
permissions.includes(permission)
|
|
1657
1653
|
);
|
|
1658
1654
|
}
|
|
1659
1655
|
|
|
@@ -221,7 +221,7 @@ const headers = computed(() => {
|
|
|
221
221
|
title: "Status",
|
|
222
222
|
value: "status",
|
|
223
223
|
},
|
|
224
|
-
|
|
224
|
+
|
|
225
225
|
];
|
|
226
226
|
|
|
227
227
|
if (props.status === "pending" && props.cancelInvitation) {
|
|
@@ -270,10 +270,11 @@ const {
|
|
|
270
270
|
page: page.value,
|
|
271
271
|
status: props.status,
|
|
272
272
|
search: headerSearch.value,
|
|
273
|
-
type: "user-invite,member-invite",
|
|
273
|
+
// type: "user-invite,member-invite",
|
|
274
|
+
type: "member-invite",
|
|
274
275
|
app: props.app,
|
|
275
276
|
orgId: props.org,
|
|
276
|
-
siteId: props.siteId,
|
|
277
|
+
// siteId: props.siteId,
|
|
277
278
|
}),
|
|
278
279
|
{
|
|
279
280
|
watch: [() => props.status]
|
|
@@ -305,31 +305,38 @@
|
|
|
305
305
|
|
|
306
306
|
<v-divider />
|
|
307
307
|
|
|
308
|
-
<v-
|
|
309
|
-
<v-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
class="
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
308
|
+
<v-toolbar class="pa-0" density="compact">
|
|
309
|
+
<v-row no-gutters>
|
|
310
|
+
<v-col cols="6" class="pa-0">
|
|
311
|
+
<v-btn
|
|
312
|
+
block
|
|
313
|
+
variant="text"
|
|
314
|
+
class="text-none"
|
|
315
|
+
size="large"
|
|
316
|
+
height="48"
|
|
317
|
+
:disabled="rejectModal.submitting"
|
|
318
|
+
@click="closeRejectDialog"
|
|
319
|
+
>
|
|
320
|
+
Cancel
|
|
321
|
+
</v-btn>
|
|
322
|
+
</v-col>
|
|
323
|
+
|
|
324
|
+
<v-col cols="6" class="pa-0">
|
|
325
|
+
<v-btn
|
|
326
|
+
block
|
|
327
|
+
variant="flat"
|
|
328
|
+
color="black"
|
|
329
|
+
class="text-none font-weight-bold rounded-0"
|
|
330
|
+
height="48"
|
|
331
|
+
:loading="rejectModal.submitting"
|
|
332
|
+
:disabled="!isRejectModalValid || rejectModal.submitting"
|
|
333
|
+
@click="submitRejectDialog"
|
|
334
|
+
>
|
|
335
|
+
Confirm
|
|
336
|
+
</v-btn>
|
|
337
|
+
</v-col>
|
|
338
|
+
</v-row>
|
|
339
|
+
</v-toolbar>
|
|
333
340
|
</v-card>
|
|
334
341
|
</v-dialog>
|
|
335
342
|
|
|
@@ -59,6 +59,21 @@
|
|
|
59
59
|
</v-col>
|
|
60
60
|
</v-row>
|
|
61
61
|
|
|
62
|
+
<v-dialog v-model="showPhotoPreview" max-width="900">
|
|
63
|
+
<v-card>
|
|
64
|
+
<v-card-actions class="pa-2 justify-end">
|
|
65
|
+
<v-btn
|
|
66
|
+
icon="mdi-close"
|
|
67
|
+
variant="text"
|
|
68
|
+
@click="showPhotoPreview = false"
|
|
69
|
+
/>
|
|
70
|
+
</v-card-actions>
|
|
71
|
+
<v-card-text class="pa-2 pt-0">
|
|
72
|
+
<v-img :src="selectedPhoto" contain max-height="80vh" />
|
|
73
|
+
</v-card-text>
|
|
74
|
+
</v-card>
|
|
75
|
+
</v-dialog>
|
|
76
|
+
|
|
62
77
|
<v-dialog v-model="photoOptionsDialog" max-width="420">
|
|
63
78
|
<v-card>
|
|
64
79
|
<v-card-title class="d-flex align-center pa-4">
|
|
@@ -196,6 +211,8 @@ const photos = ref<string[]>([...props.modelValue]);
|
|
|
196
211
|
const photosIds = ref<string[]>([...props.photoIds]);
|
|
197
212
|
const photoOptionsDialog = ref(false);
|
|
198
213
|
const showCameraDialog = ref(false);
|
|
214
|
+
const showPhotoPreview = ref(false);
|
|
215
|
+
const selectedPhoto = ref("");
|
|
199
216
|
const videoRef = ref<HTMLVideoElement | null>(null);
|
|
200
217
|
const canvasRef = ref<HTMLCanvasElement | null>(null);
|
|
201
218
|
const fileInputRef = ref<HTMLInputElement | null>(null);
|
|
@@ -205,10 +222,8 @@ const uploading = ref(false);
|
|
|
205
222
|
const { addFile } = useFile();
|
|
206
223
|
|
|
207
224
|
function viewPhoto(photoData: string) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
link.target = "_blank";
|
|
211
|
-
link.click();
|
|
225
|
+
selectedPhoto.value = photoData;
|
|
226
|
+
showPhotoPreview.value = true;
|
|
212
227
|
}
|
|
213
228
|
|
|
214
229
|
watch(
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
<v-list-item v-for="(item, index) in nricSearchResults" :key="item._id || index"
|
|
67
67
|
@click="selectNricSearchResult(item)" class="cursor-pointer">
|
|
68
68
|
<v-list-item-title>{{ item.name || 'Unknown' }}</v-list-item-title>
|
|
69
|
-
<v-list-item-subtitle>{{ item.contact }}</v-list-item-subtitle>
|
|
69
|
+
<v-list-item-subtitle>NRIC: {{ item.nric }} | Contact No: {{ item.contact }} </v-list-item-subtitle>
|
|
70
70
|
</v-list-item>
|
|
71
71
|
</v-list>
|
|
72
72
|
</v-menu>
|
|
@@ -155,9 +155,13 @@
|
|
|
155
155
|
<v-col v-if="shouldShowField('plateNumber')" cols="12">
|
|
156
156
|
<v-row>
|
|
157
157
|
<v-col cols="12">
|
|
158
|
-
<InputLabel class="text-capitalize" title="Vehicle Number" required />
|
|
158
|
+
<InputLabel class="text-capitalize" title="Vehicle Number" :required="isVehicleRequired" />
|
|
159
159
|
<!-- <v-text-field v-model.trim.uppercase="visitor.plateNumber" density="comfortable" /> -->
|
|
160
|
-
<InputVehicleNumber
|
|
160
|
+
<InputVehicleNumber
|
|
161
|
+
v-model="visitor.plateNumber"
|
|
162
|
+
:rules="[isVehicleRequired ? requiredRule : () => true]"
|
|
163
|
+
density="comfortable"
|
|
164
|
+
/>
|
|
161
165
|
</v-col>
|
|
162
166
|
</v-row>
|
|
163
167
|
</v-col>
|
|
@@ -635,6 +639,10 @@ const requireNRIC = computed(() => {
|
|
|
635
639
|
return prop.type !== "walk-in" && prop.type !== "guest";
|
|
636
640
|
});
|
|
637
641
|
|
|
642
|
+
const isVehicleRequired = computed(() => {
|
|
643
|
+
return ["guest", "drop-off", "pick-up"].includes(prop.type);
|
|
644
|
+
});
|
|
645
|
+
|
|
638
646
|
const hidQrCodePassConfig = computed(() => {
|
|
639
647
|
return (siteData.value as any)?.metadata?.hidQrCodePass || {};
|
|
640
648
|
});
|
|
@@ -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
|
|
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"
|
|
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="
|
|
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="
|
|
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
|
|
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
|
|
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">
|
|
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
|
|
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
|
|
955
|
+
<v-text-field
|
|
956
|
+
v-model="selectedVisitorObject.location"
|
|
957
|
+
density="comfortable"
|
|
958
|
+
readonly
|
|
959
|
+
/>
|
|
928
960
|
</div>
|
|
929
|
-
<div
|
|
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">{{
|
|
968
|
+
<v-chip size="small" variant="tonal" color="purple">{{
|
|
969
|
+
card.cardNo
|
|
970
|
+
}}</v-chip>
|
|
933
971
|
</div>
|
|
934
|
-
<v-select
|
|
935
|
-
|
|
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"
|
|
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
|
|
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))
|
|
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())
|
|
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 =
|
|
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:
|
|
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 = [
|
|
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, {
|
|
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(
|
|
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();
|
|
@@ -1,58 +1,23 @@
|
|
|
1
1
|
export function useCleaningSchedulePermission() {
|
|
2
|
-
const { hasPermission } = usePermission();
|
|
3
|
-
const { permissions } = useCleaningPermission();
|
|
4
|
-
|
|
5
2
|
const { userAppRole } = useLocalSetup();
|
|
6
3
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return hasPermission(userAppRole.value, permissions, "cleaning-schedule-mgmt", "see-schedule-details");
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const canDownloadSchedule = computed(() => {
|
|
20
|
-
if (!userAppRole.value) return false;
|
|
21
|
-
if (userAppRole.value.permissions.includes("*")) return true;
|
|
22
|
-
return hasPermission(userAppRole.value, permissions, "cleaning-schedule-mgmt", "download-schedule");
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const canManageScheduleTasks = computed(() => {
|
|
26
|
-
if (!userAppRole.value) return false;
|
|
27
|
-
if (userAppRole.value.permissions.includes("*")) return true;
|
|
28
|
-
return hasPermission(userAppRole.value, permissions, "cleaning-schedule-mgmt", "manage-schedule-tasks");
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
const canGenerateChecklist = computed(() => {
|
|
32
|
-
if (!userAppRole.value) return false;
|
|
33
|
-
if (userAppRole.value.permissions.includes("*")) return true;
|
|
34
|
-
return hasPermission(userAppRole.value, permissions, "cleaning-schedule-mgmt", "generate-checklist");
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
const canViewHistory = computed(() => {
|
|
38
|
-
if (!userAppRole.value) return false;
|
|
39
|
-
if (userAppRole.value.permissions.includes("*")) return true;
|
|
40
|
-
return hasPermission(userAppRole.value, permissions, "cleaning-schedule-mgmt", "view-history");
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const canAddRemarks = computed(() => {
|
|
44
|
-
if (!userAppRole.value) return false;
|
|
45
|
-
if (userAppRole.value.permissions.includes("*")) return true;
|
|
46
|
-
return hasPermission(userAppRole.value, permissions, "cleaning-schedule-mgmt", "add-remarks");
|
|
47
|
-
});
|
|
4
|
+
const can = (action: string) =>
|
|
5
|
+
computed(() => {
|
|
6
|
+
const permissions = userAppRole.value?.permissions;
|
|
7
|
+
if (!permissions) return false;
|
|
8
|
+
if (permissions.includes("*")) return true;
|
|
9
|
+
return permissions.some((permission) =>
|
|
10
|
+
permission.endsWith(`-schedule-mgmt:${action}`),
|
|
11
|
+
);
|
|
12
|
+
});
|
|
48
13
|
|
|
49
14
|
return {
|
|
50
|
-
canViewSchedules,
|
|
51
|
-
canViewScheduleDetails,
|
|
52
|
-
canDownloadSchedule,
|
|
53
|
-
canManageScheduleTasks,
|
|
54
|
-
canGenerateChecklist,
|
|
55
|
-
canViewHistory,
|
|
56
|
-
canAddRemarks,
|
|
15
|
+
canViewSchedules: can("see-all-schedules"),
|
|
16
|
+
canViewScheduleDetails: can("see-schedule-details"),
|
|
17
|
+
canDownloadSchedule: can("download-schedule"),
|
|
18
|
+
canManageScheduleTasks: can("manage-schedule-tasks"),
|
|
19
|
+
canGenerateChecklist: can("generate-checklist"),
|
|
20
|
+
canViewHistory: can("view-history"),
|
|
21
|
+
canAddRemarks: can("add-remarks"),
|
|
57
22
|
};
|
|
58
23
|
}
|
package/package.json
CHANGED
package/types/customer.d.ts
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|