@7365admin1/layer-common 3.2.1-staging.75 → 3.2.2-staging.100
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/.changeset/notification-preferences.md +17 -0
- package/.changeset/pm-sidebar-grouping-and-list-scaffold.md +27 -0
- package/CHANGELOG.md +6 -0
- package/assets/css/primitives.css +680 -0
- package/assets/css/screens.css +541 -0
- package/assets/css/shell.css +258 -0
- package/assets/css/tokens.css +220 -0
- package/components/AccessCardQrTagging.vue +1 -1
- package/components/AccessManagement.vue +53 -72
- package/components/AppButton.vue +52 -0
- package/components/AppCard.vue +20 -0
- package/components/AppDateField.vue +35 -0
- package/components/AppField.vue +46 -0
- package/components/AppKpiTile.vue +65 -0
- package/components/AppSegmented.vue +38 -0
- package/components/AppSelect.vue +203 -0
- package/components/AreaChecklistHistoryMain.vue +6 -2
- package/components/AreaMain.vue +9 -17
- package/components/AttendanceMain.vue +4 -3
- package/components/Avatar/Main.vue +54 -2
- package/components/BillingMain.vue +26 -30
- package/components/BuildingManagement/buildings.vue +27 -38
- package/components/BuildingManagement/units.vue +26 -42
- package/components/BulletinBoardManagement.vue +23 -10
- package/components/CardToolbar.vue +37 -0
- package/components/CleaningScheduleMain.vue +29 -46
- package/components/ClientMain.vue +90 -78
- package/components/DashboardEmptyState.vue +11 -1
- package/components/DashboardMain.vue +285 -207
- package/components/DocumentManagement.vue +129 -93
- package/components/EntryPassMain.vue +49 -27
- package/components/EquipmentItemMain.vue +4 -6
- package/components/EquipmentManagementMain.vue +9 -7
- package/components/FeedbackMain.vue +35 -49
- package/components/FormDialog.vue +60 -21
- package/components/HidIntercomManagement.vue +40 -24
- package/components/HidQrCodeConfiguration.vue +24 -2
- package/components/HidUserEnrollment.vue +68 -31
- package/components/InvitationMain.vue +46 -61
- package/components/Layout/Header.vue +289 -37
- package/components/Layout/NavigationDrawer.vue +299 -30
- package/components/ManageChecklistMain.vue +17 -17
- package/components/MemberMain.vue +79 -60
- package/components/MyAttendanceMain.vue +3 -5
- package/components/Nfc/NFCPatrolRouteMain.vue +64 -96
- package/components/NotificationSettings.vue +361 -0
- package/components/OnlineFormsConfiguration.vue +1 -1
- package/components/PageHeader.vue +43 -0
- package/components/PassInformation.vue +104 -45
- package/components/RolePermissionMain.vue +184 -91
- package/components/ScanVisitorQRCode.vue +35 -7
- package/components/ScheduleAreaMain.vue +15 -49
- package/components/ScheduleTaskMain.vue +23 -26
- package/components/ScheduleTastTicketMain.vue +18 -43
- package/components/ServiceProviderMain.vue +113 -168
- package/components/SiteSettings.vue +21 -8
- package/components/SpecificAttr.vue +10 -2
- package/components/StatusChip.vue +93 -0
- package/components/SwitchContext.vue +33 -1
- package/components/TableHygiene.vue +29 -46
- package/components/TableList.vue +1 -1
- package/components/TableListSecondary.vue +1 -1
- package/components/TableMain.vue +161 -77
- package/components/TableV3.vue +61 -66
- package/components/UnitMain.vue +9 -17
- package/components/VehicleManagement.vue +20 -9
- package/components/VisitorForm.vue +100 -7
- package/components/VisitorManagement.vue +219 -68
- package/components/WorkOrder/Main.vue +42 -51
- package/composables/useHidAmico.ts +26 -2
- package/composables/useNotificationPreference.ts +87 -0
- package/composables/useOrg.ts +1 -1
- package/composables/useRole.ts +22 -0
- package/composables/useSipWebPhone.ts +28 -3
- package/composables/useThemePreference.ts +63 -0
- package/composables/useVisitor.ts +6 -1
- package/nuxt.config.ts +31 -0
- package/package.json +3 -2
- package/pages/notification-settings.vue +19 -0
- package/plugins/vuetify.ts +32 -1
- package/types/org.d.ts +2 -0
- package/utils/nav-sections.test.ts +190 -0
- package/utils/nav-sections.ts +151 -0
- package/utils/status.test.ts +77 -0
- package/utils/status.ts +90 -0
- package/utils/theme.test.ts +325 -7
- package/utils/theme.ts +268 -137
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<template #extension>
|
|
22
22
|
<v-row no-gutters class="w-100 d-flex flex-column">
|
|
23
23
|
<v-card
|
|
24
|
-
class="w-100
|
|
24
|
+
class="w-100 filter-bar d-flex align-center ga-5"
|
|
25
25
|
flat
|
|
26
26
|
:height="60"
|
|
27
27
|
>
|
|
@@ -68,20 +68,18 @@
|
|
|
68
68
|
<v-spacer />
|
|
69
69
|
|
|
70
70
|
<v-col cols="auto">
|
|
71
|
-
<
|
|
71
|
+
<StatusChip
|
|
72
72
|
v-if="isScheduleClosed"
|
|
73
|
-
|
|
74
|
-
variant="tonal"
|
|
73
|
+
status="Closed"
|
|
75
74
|
class="text-capitalize mr-2"
|
|
76
75
|
>
|
|
77
|
-
<v-icon
|
|
76
|
+
<v-icon size="14">mdi-lock</v-icon>
|
|
78
77
|
Closed – View Only
|
|
79
|
-
</
|
|
78
|
+
</StatusChip>
|
|
80
79
|
<v-btn
|
|
81
80
|
v-if="canViewHistory"
|
|
82
|
-
class="text-none mr-2"
|
|
83
|
-
|
|
84
|
-
color="primary"
|
|
81
|
+
class="text-none mr-2 screen-btn-primary"
|
|
82
|
+
variant="flat"
|
|
85
83
|
aria-label="History"
|
|
86
84
|
@click="openHistory"
|
|
87
85
|
>
|
|
@@ -89,9 +87,8 @@
|
|
|
89
87
|
</v-btn>
|
|
90
88
|
<v-btn
|
|
91
89
|
v-if="canGenerateChecklist"
|
|
92
|
-
class="text-none"
|
|
93
|
-
|
|
94
|
-
color="primary"
|
|
90
|
+
class="text-none screen-btn-primary"
|
|
91
|
+
variant="flat"
|
|
95
92
|
aria-label="Generate"
|
|
96
93
|
@click="_generateChecklist"
|
|
97
94
|
:loading="submitting"
|
|
@@ -114,20 +111,13 @@
|
|
|
114
111
|
</span>
|
|
115
112
|
</div>
|
|
116
113
|
<div v-else-if="isScheduleClosed">
|
|
117
|
-
<
|
|
118
|
-
size="small"
|
|
119
|
-
color="error"
|
|
120
|
-
variant="tonal"
|
|
121
|
-
class="text-capitalize"
|
|
122
|
-
>Closed</v-chip
|
|
123
|
-
>
|
|
114
|
+
<StatusChip status="Closed" class="text-capitalize" />
|
|
124
115
|
</div>
|
|
125
116
|
<div v-else>
|
|
126
117
|
<v-btn
|
|
127
118
|
v-if="canManageScheduleTasks"
|
|
128
119
|
variant="outlined"
|
|
129
|
-
|
|
130
|
-
class="text-capitalize px-4 py-2"
|
|
120
|
+
class="text-capitalize screen-btn-ghost"
|
|
131
121
|
@click.stop="() => _acceptAreaChecklist(item._id)"
|
|
132
122
|
>
|
|
133
123
|
Accept
|
|
@@ -146,14 +136,11 @@
|
|
|
146
136
|
</template>
|
|
147
137
|
|
|
148
138
|
<template #item.status="{ value }">
|
|
149
|
-
<
|
|
139
|
+
<StatusChip
|
|
150
140
|
class="text-capitalize"
|
|
151
|
-
:
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
>
|
|
155
|
-
{{ value || "No Status" }}
|
|
156
|
-
</v-chip>
|
|
141
|
+
:status="value"
|
|
142
|
+
:label="value || 'No Status'"
|
|
143
|
+
/>
|
|
157
144
|
</template>
|
|
158
145
|
</TableMain></v-col
|
|
159
146
|
>
|
|
@@ -262,27 +249,6 @@ watchEffect(() => {
|
|
|
262
249
|
}
|
|
263
250
|
});
|
|
264
251
|
|
|
265
|
-
const getStatusColor = (status: unknown): string => {
|
|
266
|
-
if (!status) return "grey";
|
|
267
|
-
|
|
268
|
-
const normalized = String(status).toLowerCase();
|
|
269
|
-
|
|
270
|
-
switch (normalized) {
|
|
271
|
-
case "open":
|
|
272
|
-
return "grey";
|
|
273
|
-
case "ongoing":
|
|
274
|
-
return "primary";
|
|
275
|
-
case "completed":
|
|
276
|
-
case "accepted":
|
|
277
|
-
return "success";
|
|
278
|
-
case "closed":
|
|
279
|
-
case "rejected":
|
|
280
|
-
return "error";
|
|
281
|
-
default:
|
|
282
|
-
return "secondary";
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
|
|
286
252
|
function showMessage(msg: string, color: string = "error") {
|
|
287
253
|
message.value = msg;
|
|
288
254
|
messageColor.value = color;
|
|
@@ -21,10 +21,8 @@
|
|
|
21
21
|
<v-row no-gutters align="center" class="w-100">
|
|
22
22
|
<v-col cols="auto" v-if="canCreateScheduleTask">
|
|
23
23
|
<v-btn
|
|
24
|
-
class="text-none"
|
|
25
|
-
|
|
26
|
-
variant="tonal"
|
|
27
|
-
size="large"
|
|
24
|
+
class="text-none screen-btn-primary"
|
|
25
|
+
variant="flat"
|
|
28
26
|
@click="openFormDialog"
|
|
29
27
|
>
|
|
30
28
|
Create Schedule Task
|
|
@@ -33,7 +31,7 @@
|
|
|
33
31
|
|
|
34
32
|
<v-spacer />
|
|
35
33
|
|
|
36
|
-
<v-col cols="auto">
|
|
34
|
+
<v-col cols="auto" class="filter-field">
|
|
37
35
|
<v-text-field
|
|
38
36
|
v-model="searchInput"
|
|
39
37
|
density="compact"
|
|
@@ -49,28 +47,31 @@
|
|
|
49
47
|
|
|
50
48
|
<template #item.areas="{ value }">
|
|
51
49
|
<div v-if="value && value.length > 0">
|
|
52
|
-
<
|
|
50
|
+
<StatusChip
|
|
53
51
|
v-for="(area, idx) in value.slice(0, 2)"
|
|
54
52
|
:key="idx"
|
|
55
|
-
size="small"
|
|
56
53
|
class="mr-1 mb-1"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
54
|
+
:dot="false"
|
|
55
|
+
tone="neutral"
|
|
56
|
+
:label="area.name"
|
|
57
|
+
/>
|
|
58
|
+
<StatusChip
|
|
59
|
+
v-if="value.length > 2"
|
|
60
|
+
class="mb-1"
|
|
61
|
+
:dot="false"
|
|
62
|
+
tone="neutral"
|
|
63
|
+
:label="`+${value.length - 2} more`"
|
|
64
|
+
/>
|
|
63
65
|
</div>
|
|
64
66
|
<span v-else>N/A</span>
|
|
65
67
|
</template>
|
|
66
68
|
|
|
67
69
|
<template #item.status="{ value }">
|
|
68
|
-
<
|
|
69
|
-
:color="value === 'active' ? 'success' : 'default'"
|
|
70
|
+
<StatusChip
|
|
70
71
|
class="text-capitalize"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
:status="value"
|
|
73
|
+
:label="value || 'N/A'"
|
|
74
|
+
/>
|
|
74
75
|
</template>
|
|
75
76
|
</TableMain>
|
|
76
77
|
|
|
@@ -270,15 +271,11 @@
|
|
|
270
271
|
Status:
|
|
271
272
|
</v-col>
|
|
272
273
|
<v-col cols="7" class="text-subtitle-2">
|
|
273
|
-
<
|
|
274
|
-
:color="
|
|
275
|
-
selectedTask.status === 'active' ? 'success' : 'default'
|
|
276
|
-
"
|
|
277
|
-
size="small"
|
|
274
|
+
<StatusChip
|
|
278
275
|
class="text-capitalize"
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
276
|
+
:status="selectedTask.status"
|
|
277
|
+
:label="selectedTask.status || 'N/A'"
|
|
278
|
+
/>
|
|
282
279
|
</v-col>
|
|
283
280
|
</v-row>
|
|
284
281
|
|
|
@@ -32,13 +32,18 @@
|
|
|
32
32
|
</template>
|
|
33
33
|
|
|
34
34
|
<template #item.createdBy="{ item }">
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
<!--
|
|
36
|
+
THE 3.12:1 `HS` CHIP.
|
|
37
|
+
|
|
38
|
+
This was a hand-rolled copy of `AvatarMain` with two problems: its
|
|
39
|
+
fill was Vuetify's MATERIAL `blue`/`purple`/`grey` (not a theme
|
|
40
|
+
token, so no `on-*` pair applied to it) and its `white--text` is
|
|
41
|
+
Vuetify 2 syntax that does nothing in Vuetify 3 - leaving Vuetify to
|
|
42
|
+
derive WHITE, which reads 3.12:1 on that blue in BOTH themes.
|
|
43
|
+
`AvatarMain` draws the same circle with the same initials and now
|
|
44
|
+
guarantees its label clears 4.5:1.
|
|
45
|
+
-->
|
|
46
|
+
<AvatarMain :name="item.createdBy" :size="32" class="mr-2" />
|
|
42
47
|
{{ item.createdBy || "N/A" }}
|
|
43
48
|
</template>
|
|
44
49
|
|
|
@@ -47,13 +52,7 @@
|
|
|
47
52
|
</template>
|
|
48
53
|
|
|
49
54
|
<template #item.status="{ value }">
|
|
50
|
-
<
|
|
51
|
-
:color="getStatusColor(value)"
|
|
52
|
-
class="font-weight-bold"
|
|
53
|
-
style="background: #ffe6c2; color: #ff9800"
|
|
54
|
-
>
|
|
55
|
-
{{ value || "To-Do" }}
|
|
56
|
-
</v-chip>
|
|
55
|
+
<StatusChip :status="value || 'To-Do'" :label="value || 'To-Do'" />
|
|
57
56
|
</template>
|
|
58
57
|
<!-- Completion Date/Time -->
|
|
59
58
|
<template #item.completionDate="{ value }">
|
|
@@ -61,7 +60,11 @@
|
|
|
61
60
|
</template>
|
|
62
61
|
<!-- Action (Accept button) -->
|
|
63
62
|
<template #item.action="{ item }">
|
|
64
|
-
<v-btn
|
|
63
|
+
<v-btn
|
|
64
|
+
variant="outlined"
|
|
65
|
+
class="text-none screen-btn-ghost"
|
|
66
|
+
@click.stop="acceptTask(item)"
|
|
67
|
+
>
|
|
65
68
|
Accept
|
|
66
69
|
</v-btn>
|
|
67
70
|
</template>
|
|
@@ -133,24 +136,6 @@ const headers = [
|
|
|
133
136
|
|
|
134
137
|
const { formatDate } = useUtils();
|
|
135
138
|
|
|
136
|
-
function getInitials(name: string) {
|
|
137
|
-
if (!name) return "";
|
|
138
|
-
return name
|
|
139
|
-
.split(" ")
|
|
140
|
-
.map((n) => n[0])
|
|
141
|
-
.join("")
|
|
142
|
-
.toUpperCase();
|
|
143
|
-
}
|
|
144
|
-
function getAvatarColor(name: string) {
|
|
145
|
-
if (name === "Demo Smith") return "purple";
|
|
146
|
-
if (name === "Hygiene SP") return "blue";
|
|
147
|
-
return "grey";
|
|
148
|
-
}
|
|
149
|
-
function getStatusColor(status: string) {
|
|
150
|
-
if (status === "To-Do") return "orange";
|
|
151
|
-
if (status === "Completed") return "green";
|
|
152
|
-
return "grey";
|
|
153
|
-
}
|
|
154
139
|
function acceptTask(item: any) {
|
|
155
140
|
selectedTask.value = item;
|
|
156
141
|
showAcceptDialog.value = true;
|
|
@@ -170,13 +155,3 @@ function onRowClick(data: any) {
|
|
|
170
155
|
}
|
|
171
156
|
}
|
|
172
157
|
</script>
|
|
173
|
-
|
|
174
|
-
<style scoped>
|
|
175
|
-
.accept-btn {
|
|
176
|
-
border: 1px solid #333;
|
|
177
|
-
background: #fff;
|
|
178
|
-
border-radius: 4px;
|
|
179
|
-
cursor: pointer;
|
|
180
|
-
min-width: 80px;
|
|
181
|
-
}
|
|
182
|
-
</style>
|
|
@@ -1,115 +1,91 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
<v-card
|
|
61
|
-
width="100%"
|
|
62
|
-
variant="outlined"
|
|
63
|
-
border="thin"
|
|
64
|
-
rounded="lg"
|
|
65
|
-
:loading="loading"
|
|
66
|
-
>
|
|
67
|
-
<div class="sp-table-header">
|
|
68
|
-
<!-- No fixed colour: `grey-lighten-4` is a light-mode grey in both
|
|
69
|
-
themes, which is what made this strip a white slab in dark
|
|
70
|
-
mode. `transparent` lets the themed .sp-table-header show. -->
|
|
71
|
-
<v-toolbar
|
|
72
|
-
density="compact"
|
|
73
|
-
color="transparent"
|
|
74
|
-
flat
|
|
75
|
-
class="sp-toolbar-top px-2"
|
|
76
|
-
>
|
|
77
|
-
<v-btn
|
|
78
|
-
icon
|
|
79
|
-
variant="text"
|
|
80
|
-
density="comfortable"
|
|
81
|
-
@click="loadList()"
|
|
82
|
-
>
|
|
83
|
-
<v-icon>mdi-refresh</v-icon>
|
|
84
|
-
</v-btn>
|
|
85
|
-
|
|
86
|
-
<v-spacer />
|
|
87
|
-
|
|
88
|
-
<template v-if="canViewServiceProviders">
|
|
89
|
-
<span class="mr-2 text-caption text-medium-emphasis">{{
|
|
90
|
-
pageRange
|
|
91
|
-
}}</span>
|
|
92
|
-
<local-pagination
|
|
93
|
-
v-model="page"
|
|
94
|
-
:length="pages"
|
|
95
|
-
@update:value="loadList()"
|
|
96
|
-
/>
|
|
97
|
-
</template>
|
|
98
|
-
</v-toolbar>
|
|
99
|
-
|
|
100
|
-
<v-tabs
|
|
101
|
-
v-model="listTab"
|
|
102
|
-
color="primary"
|
|
103
|
-
density="comfortable"
|
|
104
|
-
class="sp-tabs"
|
|
105
|
-
align-tabs="start"
|
|
2
|
+
<div>
|
|
3
|
+
<!--
|
|
4
|
+
THE DESIGN'S PAGE SCAFFOLD (same shape as Members).
|
|
5
|
+
|
|
6
|
+
The screen had no title at all, its primary actions sat top-LEFT, the
|
|
7
|
+
search box floated outside the card, and the refresh + pager sat on one
|
|
8
|
+
row with the tabs stacked on a second row below. The design draws a 22px
|
|
9
|
+
title with the actions on the right of that line, then ONE row inside the
|
|
10
|
+
card: tabs left, search / refresh / count / pager right.
|
|
11
|
+
|
|
12
|
+
Placement only. The same buttons open the same dialogs under the same
|
|
13
|
+
permission conditions, the same three tabs load the same three lists, the
|
|
14
|
+
same search feeds the same debounced `loadList()`, and the table, its
|
|
15
|
+
columns and its row menu are untouched.
|
|
16
|
+
-->
|
|
17
|
+
<PageHeader title="Service Providers">
|
|
18
|
+
<template #actions>
|
|
19
|
+
<AppButton
|
|
20
|
+
v-if="showBillingButton"
|
|
21
|
+
variant="ghost"
|
|
22
|
+
@click="
|
|
23
|
+
useRouter().push({
|
|
24
|
+
name: 'org-site-service-provider-mgmt-billing',
|
|
25
|
+
})
|
|
26
|
+
"
|
|
27
|
+
>
|
|
28
|
+
Billing
|
|
29
|
+
</AppButton>
|
|
30
|
+
<AppButton
|
|
31
|
+
v-if="showAddButton && canAddServiceProvider"
|
|
32
|
+
variant="ghost"
|
|
33
|
+
@click="(createDialog = true), setServiceProvider({ mode: 'add' })"
|
|
34
|
+
>
|
|
35
|
+
Add
|
|
36
|
+
</AppButton>
|
|
37
|
+
<AppButton
|
|
38
|
+
v-if="canInviteServiceProvider"
|
|
39
|
+
@click="
|
|
40
|
+
(createInviteDialog = true), setServiceProvider({ mode: 'invite' })
|
|
41
|
+
"
|
|
42
|
+
>
|
|
43
|
+
Invite
|
|
44
|
+
</AppButton>
|
|
45
|
+
</template>
|
|
46
|
+
</PageHeader>
|
|
47
|
+
|
|
48
|
+
<AppCard class="table-card">
|
|
49
|
+
<CardToolbar :count="canViewServiceProviders ? pageRange : ''">
|
|
50
|
+
<template #tabs>
|
|
51
|
+
<button
|
|
52
|
+
v-for="tab in listTabs"
|
|
53
|
+
:key="tab.value"
|
|
54
|
+
type="button"
|
|
55
|
+
role="tab"
|
|
56
|
+
class="app-tab"
|
|
57
|
+
:class="{ 'app-tab--active': listTab === tab.value }"
|
|
58
|
+
:aria-selected="listTab === tab.value"
|
|
59
|
+
@click="listTab = tab.value"
|
|
106
60
|
>
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
61
|
+
{{ tab.label }}
|
|
62
|
+
</button>
|
|
63
|
+
</template>
|
|
64
|
+
|
|
65
|
+
<template #right>
|
|
66
|
+
<AppField
|
|
67
|
+
v-model="searchText"
|
|
68
|
+
search
|
|
69
|
+
compact
|
|
70
|
+
placeholder="Search"
|
|
71
|
+
klass="app-toolbar__search"
|
|
72
|
+
/>
|
|
73
|
+
<AppButton
|
|
74
|
+
variant="icon"
|
|
75
|
+
icon="mdi-refresh"
|
|
76
|
+
aria-label="Refresh"
|
|
77
|
+
@click="loadList()"
|
|
78
|
+
/>
|
|
79
|
+
<local-pagination
|
|
80
|
+
v-if="canViewServiceProviders"
|
|
81
|
+
v-model="page"
|
|
82
|
+
:length="pages"
|
|
83
|
+
@update:value="loadList()"
|
|
84
|
+
/>
|
|
85
|
+
</template>
|
|
86
|
+
</CardToolbar>
|
|
87
|
+
|
|
88
|
+
<div class="app-table-scroll">
|
|
113
89
|
<v-data-table
|
|
114
90
|
v-if="canViewServiceProviders"
|
|
115
91
|
:headers="headers"
|
|
@@ -118,6 +94,7 @@
|
|
|
118
94
|
:items-per-page="pageSize"
|
|
119
95
|
fixed-header
|
|
120
96
|
hide-default-footer
|
|
97
|
+
:loading="loading"
|
|
121
98
|
class="sp-table"
|
|
122
99
|
style="max-height: calc(100vh - 280px)"
|
|
123
100
|
>
|
|
@@ -147,14 +124,11 @@
|
|
|
147
124
|
4.5:1 a 12px label needs. Filled puts the colour in the
|
|
148
125
|
background and lets Vuetify pick a readable foreground for it.
|
|
149
126
|
-->
|
|
150
|
-
<
|
|
151
|
-
:color="statusChipColor(item.status, item.statusRaw)"
|
|
152
|
-
size="small"
|
|
153
|
-
:variant="item.source === 'invite' ? 'flat' : 'tonal'"
|
|
127
|
+
<StatusChip
|
|
154
128
|
class="text-none"
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
129
|
+
:status="item.statusRaw || item.status"
|
|
130
|
+
:label="item.status"
|
|
131
|
+
/>
|
|
158
132
|
<div
|
|
159
133
|
v-if="item.rejectionReason"
|
|
160
134
|
class="text-caption text-medium-emphasis mt-1 sp-reject-reason"
|
|
@@ -232,12 +206,16 @@
|
|
|
232
206
|
</v-menu>
|
|
233
207
|
</template>
|
|
234
208
|
</v-data-table>
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
209
|
+
</div>
|
|
210
|
+
|
|
211
|
+
<div
|
|
212
|
+
v-if="!canViewServiceProviders"
|
|
213
|
+
class="pa-4 text-body-2 text-medium-emphasis"
|
|
214
|
+
>
|
|
215
|
+
You do not have permission to view service providers.
|
|
216
|
+
</div>
|
|
217
|
+
</AppCard>
|
|
218
|
+
</div>
|
|
241
219
|
|
|
242
220
|
<v-dialog v-model="viewDialog" max-width="514">
|
|
243
221
|
<v-card rounded="lg" class="sp-members-card">
|
|
@@ -520,7 +498,7 @@
|
|
|
520
498
|
|
|
521
499
|
<v-dialog v-model="createInviteDialog" width="580" persistent>
|
|
522
500
|
<v-card width="100%" rounded="lg" class="sp-invite-card">
|
|
523
|
-
<v-toolbar flat color="
|
|
501
|
+
<v-toolbar flat color="transparent" class="table-card__toolbar" height="76">
|
|
524
502
|
<v-row no-gutters class="fill-height px-6" align="center">
|
|
525
503
|
<span class="font-weight-bold text-h5">
|
|
526
504
|
Invite Service Provider
|
|
@@ -801,6 +779,12 @@ const { requiredRule, emailRule, debounce } = useUtils();
|
|
|
801
779
|
const { getUserByEmail } = useUser();
|
|
802
780
|
|
|
803
781
|
const listTab = ref<ListTab>("active");
|
|
782
|
+
/** The same three tabs, in the same order, with the same labels. */
|
|
783
|
+
const listTabs: Array<{ value: ListTab; label: string }> = [
|
|
784
|
+
{ value: "active", label: "Service Providers" },
|
|
785
|
+
{ value: "pending", label: "Pending" },
|
|
786
|
+
{ value: "inactive", label: "In-Active" },
|
|
787
|
+
];
|
|
804
788
|
const page = ref(1);
|
|
805
789
|
const pages = ref(0);
|
|
806
790
|
const pageRange = ref("-- - -- of --");
|
|
@@ -1147,24 +1131,9 @@ function statusDisplay(raw: string, source: TableRow["source"]) {
|
|
|
1147
1131
|
return raw.charAt(0).toUpperCase() + raw.slice(1).toLowerCase();
|
|
1148
1132
|
}
|
|
1149
1133
|
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
complete: "success",
|
|
1154
|
-
rejected: "error",
|
|
1155
|
-
declined: "default",
|
|
1156
|
-
cancelled: "default",
|
|
1157
|
-
expired: "default",
|
|
1158
|
-
};
|
|
1159
|
-
|
|
1160
|
-
function statusChipColor(statusLabel: string, statusRaw?: string) {
|
|
1161
|
-
if (statusRaw) return INVITE_STATUS_COLOURS[statusRaw] ?? "primary";
|
|
1162
|
-
const s = statusLabel.toLowerCase();
|
|
1163
|
-
if (s === "active") return "success";
|
|
1164
|
-
if (s === "pending") return "warning";
|
|
1165
|
-
if (s === "in-active" || s === "inactive") return "default";
|
|
1166
|
-
return "primary";
|
|
1167
|
-
}
|
|
1134
|
+
/* The status chips read their tone from the shared mapping in
|
|
1135
|
+
`utils/status.ts` now - which carries every raw invitation status this map
|
|
1136
|
+
carried, with the same tone. */
|
|
1168
1137
|
|
|
1169
1138
|
// async function loadInviteRoles() {
|
|
1170
1139
|
// loadingInviteRoles.value = true;
|
|
@@ -1514,32 +1483,8 @@ async function submitServiceProviderInvite() {
|
|
|
1514
1483
|
</script>
|
|
1515
1484
|
|
|
1516
1485
|
<style scoped>
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
align-items: center;
|
|
1520
|
-
flex-wrap: nowrap;
|
|
1521
|
-
gap: 4px;
|
|
1522
|
-
}
|
|
1523
|
-
|
|
1524
|
-
.sp-table-header {
|
|
1525
|
-
/* Was a hardcoded #f5f5f5 with a black border: in dark mode the tab strip
|
|
1526
|
-
became a white slab and the tab labels and the page range disappeared
|
|
1527
|
-
into it. These take the colour of whichever theme they are in. */
|
|
1528
|
-
background: rgb(var(--v-theme-surface-light, var(--v-theme-surface)));
|
|
1529
|
-
border-bottom: 1px solid
|
|
1530
|
-
rgba(var(--v-border-color), var(--v-border-opacity));
|
|
1531
|
-
}
|
|
1532
|
-
|
|
1533
|
-
.sp-tabs {
|
|
1534
|
-
width: 100%;
|
|
1535
|
-
min-height: 40px;
|
|
1536
|
-
}
|
|
1537
|
-
|
|
1538
|
-
.sp-tabs :deep(.v-tab) {
|
|
1539
|
-
min-width: 120px;
|
|
1540
|
-
justify-content: flex-start;
|
|
1541
|
-
text-transform: none;
|
|
1542
|
-
}
|
|
1486
|
+
/* The tab strip's own theming went with the strip: the tabs are the card's
|
|
1487
|
+
first row now and take `.app-tab` from the shared primitives. */
|
|
1543
1488
|
|
|
1544
1489
|
.sp-col-company {
|
|
1545
1490
|
max-width: 220px;
|