@7365admin1/layer-common 3.0.18 → 3.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/components/BuildingManagement/buildings.vue +7 -4
- package/components/BuildingManagement/units.vue +187 -9
- package/components/CleaningScheduleMain.vue +4 -0
- package/components/ClientMain.vue +189 -39
- package/components/DashboardMain.vue +1 -7
- package/components/HidAccessLogDashboard.vue +184 -21
- package/components/HidReaderForm.vue +20 -12
- package/components/HidReaderManagement.vue +113 -80
- package/components/Input/DateTimePicker.vue +152 -137
- package/components/MemberInformation.vue +240 -163
- package/components/PassInformation.vue +6 -4
- package/components/ServiceProviderMain.vue +43 -20
- package/components/VisitorForm.vue +41 -18
- package/composables/useBuilding.ts +14 -0
- package/composables/useServiceProvider.ts +2 -1
- package/composables/useVisitor.ts +19 -15
- package/package.json +1 -1
- package/pages/[org]/[site]/access-mgmt/access-logs/index.vue +3 -1
- package/types/visitor.d.ts +1 -1
|
@@ -1,164 +1,234 @@
|
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
2
|
+
<v-row no-gutters class="w-100">
|
|
3
|
+
<v-card class="w-100">
|
|
4
|
+
<v-card-text>
|
|
5
|
+
<v-btn
|
|
6
|
+
block
|
|
7
|
+
color="primary-button"
|
|
8
|
+
:height="40"
|
|
9
|
+
text="Scan QR Code"
|
|
10
|
+
class="text-capitalize"
|
|
11
|
+
prepend-icon="mdi-qrcode"
|
|
12
|
+
@click="handleScanQRPass"
|
|
13
|
+
/>
|
|
14
|
+
<v-form
|
|
15
|
+
ref="formRef"
|
|
16
|
+
v-model="validForm"
|
|
17
|
+
:disabled="processing"
|
|
18
|
+
@click="errorScanPassMessage = ''"
|
|
19
|
+
>
|
|
20
|
+
<v-row no-gutters class="pt-5 ga-2">
|
|
21
|
+
<v-col cols="12">
|
|
22
|
+
<InputLabel class="text-capitalize" title="Full Name" required />
|
|
23
|
+
<v-text-field
|
|
24
|
+
v-model.trim="memberForm.name"
|
|
25
|
+
density="compact"
|
|
26
|
+
hide-details
|
|
27
|
+
:rules="[requiredRule]"
|
|
28
|
+
/>
|
|
29
|
+
</v-col>
|
|
30
|
+
|
|
31
|
+
<v-col cols="12">
|
|
32
|
+
<InputLabel class="text-capitalize" title="NRIC" required />
|
|
33
|
+
<InputNRICNumber
|
|
34
|
+
v-model.trim="memberForm.nric"
|
|
35
|
+
density="compact"
|
|
36
|
+
hide-details
|
|
37
|
+
:rules="[requiredRule]"
|
|
38
|
+
/>
|
|
39
|
+
</v-col>
|
|
40
|
+
|
|
41
|
+
<v-col cols="12">
|
|
42
|
+
<v-autocomplete
|
|
43
|
+
v-model="selectedPass"
|
|
44
|
+
v-model:search="passInput"
|
|
45
|
+
:hide-no-data="false"
|
|
46
|
+
class="mt-3"
|
|
47
|
+
:items="passItemsFilteredFinal"
|
|
48
|
+
item-title="prefixAndName"
|
|
49
|
+
item-value="_id"
|
|
50
|
+
label="Pass (optional)"
|
|
51
|
+
variant="outlined"
|
|
52
|
+
density="compact"
|
|
53
|
+
:error-messages="errorScanPassMessage"
|
|
54
|
+
persistent-hint
|
|
55
|
+
small-chips
|
|
56
|
+
:clearable="clearable"
|
|
57
|
+
@click="fetchPasses"
|
|
58
|
+
>
|
|
59
|
+
<template v-slot:no-data>
|
|
60
|
+
<v-list-item density="compact">
|
|
61
|
+
<v-list-item-title v-if="passInput">
|
|
62
|
+
No results matching "<strong>{{ passInput }}</strong
|
|
63
|
+
>". This value will be added as new option.
|
|
64
|
+
</v-list-item-title>
|
|
65
|
+
<v-list-item v-else>No data available</v-list-item>
|
|
66
|
+
</v-list-item>
|
|
67
|
+
</template>
|
|
68
|
+
|
|
69
|
+
<template v-slot:chip="{ props, item }">
|
|
70
|
+
<v-chip
|
|
71
|
+
v-if="selectedPass"
|
|
72
|
+
v-bind="props"
|
|
73
|
+
prepend-icon="mdi-card-bulleted-outline"
|
|
74
|
+
:text="item.raw?.prefixAndName"
|
|
75
|
+
></v-chip>
|
|
76
|
+
</template>
|
|
77
|
+
</v-autocomplete>
|
|
78
|
+
</v-col>
|
|
79
|
+
|
|
80
|
+
<v-col cols="12">
|
|
81
|
+
<InputLabel
|
|
82
|
+
class="text-capitalize"
|
|
83
|
+
title="Phone Number"
|
|
84
|
+
required
|
|
85
|
+
/>
|
|
86
|
+
<InputPhoneNumberV2
|
|
87
|
+
v-model="memberForm.contact"
|
|
88
|
+
density="compact"
|
|
89
|
+
default-country="SG"
|
|
90
|
+
hide-details
|
|
91
|
+
/>
|
|
92
|
+
</v-col>
|
|
93
|
+
|
|
94
|
+
<v-row class="pt-3" justify="space-between">
|
|
95
|
+
<v-col cols="6">
|
|
96
|
+
<v-btn
|
|
97
|
+
text="Add Member"
|
|
98
|
+
:disabled="!validForm"
|
|
99
|
+
prepend-icon="mdi-plus"
|
|
100
|
+
color="primary-button"
|
|
101
|
+
class="text-capitalize"
|
|
102
|
+
@click="handleAddMember"
|
|
103
|
+
/>
|
|
104
|
+
</v-col>
|
|
105
|
+
<v-col cols="6" align="end">
|
|
106
|
+
<v-btn
|
|
107
|
+
text="Clear Form"
|
|
108
|
+
prepend-icon="mdi-refresh"
|
|
109
|
+
color="primary-button"
|
|
110
|
+
class="text-capitalize"
|
|
111
|
+
@click.stop="handleClearForm"
|
|
112
|
+
/>
|
|
113
|
+
</v-col>
|
|
114
|
+
</v-row>
|
|
115
|
+
</v-row>
|
|
116
|
+
</v-form>
|
|
117
|
+
</v-card-text>
|
|
118
|
+
</v-card>
|
|
119
|
+
<visitor-pass-key-q-r-scanner
|
|
120
|
+
:dialog="dialog.scanQRCode"
|
|
121
|
+
v-model:scannedValue="scannedPassValue"
|
|
122
|
+
@close-dialog="dialog.scanQRCode = false"
|
|
123
|
+
/>
|
|
124
|
+
<v-divider class="my-3" />
|
|
125
|
+
<v-row
|
|
126
|
+
v-if="committedMembers.length > 0"
|
|
127
|
+
no-gutters
|
|
128
|
+
class="w-100 mt-5 ga-3"
|
|
129
|
+
>
|
|
130
|
+
<template v-for="(member, index) in committedMembers" :key="member.nric">
|
|
131
|
+
<CardMemberInfoSummary
|
|
132
|
+
:member="membersDisplayed[index]"
|
|
133
|
+
@remove="handleRemoveMember(index)"
|
|
134
|
+
/>
|
|
135
|
+
</template>
|
|
73
136
|
</v-row>
|
|
137
|
+
<!-- <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" /> -->
|
|
138
|
+
</v-row>
|
|
74
139
|
</template>
|
|
75
140
|
|
|
76
141
|
<script setup lang="ts">
|
|
77
|
-
import type { PropType } from
|
|
78
|
-
import usePassKey from
|
|
79
|
-
import useUtils from
|
|
80
|
-
|
|
142
|
+
import type { PropType } from "vue";
|
|
143
|
+
import usePassKey from "../composables/usePassKey";
|
|
144
|
+
import useUtils from "../composables/useUtils";
|
|
81
145
|
|
|
82
146
|
const props = defineProps({
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
147
|
+
type: {
|
|
148
|
+
type: String,
|
|
149
|
+
required: true,
|
|
150
|
+
},
|
|
151
|
+
contractorType: {
|
|
152
|
+
type: String,
|
|
153
|
+
required: false,
|
|
154
|
+
},
|
|
155
|
+
site: {
|
|
156
|
+
type: String,
|
|
157
|
+
required: true,
|
|
158
|
+
},
|
|
159
|
+
selectedVisitorPass: {
|
|
160
|
+
type: Array as PropType<TPassKeyPayload[]>,
|
|
161
|
+
default: () => [],
|
|
162
|
+
},
|
|
163
|
+
clearable: {
|
|
164
|
+
type: Boolean,
|
|
165
|
+
default: false,
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const { requiredRule } = useUtils();
|
|
170
|
+
const { getPassKeysByPageSearch } = usePassKey();
|
|
104
171
|
|
|
105
172
|
const memberForm = reactive<TMemberInfo>({
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
const validForm = ref(false)
|
|
113
|
-
const formRef = ref<HTMLFormElement>()
|
|
173
|
+
name: "",
|
|
174
|
+
nric: "",
|
|
175
|
+
visitorPass: [] as { keyId: string }[],
|
|
176
|
+
contact: "",
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const validForm = ref(false);
|
|
180
|
+
const formRef = ref<HTMLFormElement>();
|
|
114
181
|
const processing = ref(false);
|
|
115
|
-
const errorScanPassMessage = ref(
|
|
182
|
+
const errorScanPassMessage = ref("");
|
|
116
183
|
|
|
117
184
|
const message = ref("");
|
|
118
185
|
const messageColor = ref("");
|
|
119
186
|
const messageSnackbar = ref(false);
|
|
120
187
|
|
|
121
188
|
function showMessage(msg: string, color: string) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
189
|
+
message.value = msg;
|
|
190
|
+
messageColor.value = color;
|
|
191
|
+
messageSnackbar.value = true;
|
|
125
192
|
}
|
|
126
193
|
|
|
127
194
|
// pass
|
|
128
|
-
const passInput = ref(
|
|
129
|
-
const passItems = ref<TPassKey[]>([])
|
|
130
|
-
const scannedPassValue = ref<string>("")
|
|
195
|
+
const passInput = ref("");
|
|
196
|
+
const passItems = ref<TPassKey[]>([]);
|
|
197
|
+
const scannedPassValue = ref<string>("");
|
|
131
198
|
|
|
132
199
|
const dialog = reactive({
|
|
133
|
-
|
|
134
|
-
})
|
|
200
|
+
scanQRCode: false,
|
|
201
|
+
});
|
|
135
202
|
|
|
136
|
-
const selectedPass = ref<string>(
|
|
203
|
+
const selectedPass = ref<string>("");
|
|
137
204
|
|
|
138
|
-
const members = defineModel<TMemberInfo[]>({ required: true, default: [] })
|
|
139
|
-
const committedMembers = ref<TMemberInfo[]>([])
|
|
205
|
+
const members = defineModel<TMemberInfo[]>({ required: true, default: [] });
|
|
206
|
+
const committedMembers = ref<TMemberInfo[]>([]);
|
|
140
207
|
|
|
141
208
|
// Always keep the model in sync: committed members + current form draft
|
|
142
|
-
watch(
|
|
209
|
+
watch(
|
|
210
|
+
() => memberForm,
|
|
211
|
+
(newForm) => {
|
|
143
212
|
if (memberForm.name && memberForm.nric && memberForm.contact) {
|
|
144
|
-
|
|
213
|
+
members.value = [...committedMembers.value, { ...newForm }];
|
|
145
214
|
} else {
|
|
146
|
-
|
|
215
|
+
members.value = [...committedMembers.value];
|
|
147
216
|
}
|
|
148
|
-
},
|
|
149
|
-
|
|
217
|
+
},
|
|
218
|
+
{ deep: true }
|
|
219
|
+
);
|
|
150
220
|
|
|
151
221
|
const passTypesComputed = computed(() => {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
} else {
|
|
156
|
-
return ["contractor-pass"]
|
|
157
|
-
}
|
|
222
|
+
if (props.type === "contractor") {
|
|
223
|
+
if (props.contractorType === "property-agent") {
|
|
224
|
+
return ["agent-pass"];
|
|
158
225
|
} else {
|
|
159
|
-
|
|
226
|
+
return ["contractor-pass"];
|
|
160
227
|
}
|
|
161
|
-
}
|
|
228
|
+
} else {
|
|
229
|
+
return ["visitor-pass"];
|
|
230
|
+
}
|
|
231
|
+
});
|
|
162
232
|
|
|
163
233
|
const isPassListLoading = ref(false);
|
|
164
234
|
|
|
@@ -184,60 +254,67 @@ async function fetchPasses() {
|
|
|
184
254
|
}
|
|
185
255
|
|
|
186
256
|
const passItemsFilteredFinal = computed(() => {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
257
|
+
return passItems.value.filter((item: TPassKey) => {
|
|
258
|
+
return (
|
|
259
|
+
!props.selectedVisitorPass.some(
|
|
260
|
+
(pass: TPassKeyPayload) => pass.keyId === item._id
|
|
261
|
+
) &&
|
|
262
|
+
!committedMembers.value.some((member: TMemberInfo) =>
|
|
263
|
+
member.visitorPass?.some((pass) => pass.keyId === item._id)
|
|
264
|
+
)
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
191
268
|
|
|
192
269
|
const membersDisplayed = computed(() => {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
270
|
+
return committedMembers.value.map((member: TMemberInfo) => {
|
|
271
|
+
return {
|
|
272
|
+
...member,
|
|
273
|
+
visitorPass:
|
|
274
|
+
passItems.value.find(
|
|
275
|
+
(item: TPassKey) => item._id === member.visitorPass?.[0]?.keyId
|
|
276
|
+
)?.prefixAndName || "",
|
|
277
|
+
};
|
|
278
|
+
});
|
|
279
|
+
});
|
|
200
280
|
|
|
201
281
|
function handleScanQRPass() {
|
|
202
|
-
|
|
203
|
-
|
|
282
|
+
errorScanPassMessage.value = "";
|
|
283
|
+
dialog.scanQRCode = true;
|
|
204
284
|
}
|
|
205
285
|
|
|
206
286
|
watch(selectedPass, (newVal) => {
|
|
207
|
-
|
|
208
|
-
})
|
|
287
|
+
memberForm.visitorPass = [...(newVal ? [{ keyId: newVal }] : [])];
|
|
288
|
+
});
|
|
209
289
|
|
|
210
290
|
watch(scannedPassValue, (newVal) => {
|
|
211
|
-
|
|
291
|
+
if (!newVal) return;
|
|
212
292
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
selectedPass.value = matchedPass._id ?? ""
|
|
217
|
-
return
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
errorScanPassMessage.value = "Scanned pass not available"
|
|
221
|
-
showMessage("Scanned pass not available", "error")
|
|
222
|
-
})
|
|
293
|
+
const matchedPass = passItemsFilteredFinal.value.find(
|
|
294
|
+
(p) => p.prefixAndName === newVal
|
|
295
|
+
);
|
|
223
296
|
|
|
297
|
+
if (matchedPass) {
|
|
298
|
+
selectedPass.value = matchedPass._id ?? "";
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
224
301
|
|
|
302
|
+
errorScanPassMessage.value = "Scanned pass not available";
|
|
303
|
+
showMessage("Scanned pass not available", "error");
|
|
304
|
+
});
|
|
225
305
|
|
|
226
306
|
function handleClearForm() {
|
|
227
|
-
|
|
307
|
+
formRef.value?.reset();
|
|
228
308
|
}
|
|
229
309
|
|
|
230
310
|
async function handleAddMember() {
|
|
231
|
-
|
|
232
|
-
|
|
311
|
+
committedMembers.value.push({ ...memberForm });
|
|
312
|
+
handleClearForm();
|
|
233
313
|
}
|
|
234
314
|
|
|
235
315
|
function handleRemoveMember(index: number) {
|
|
236
|
-
|
|
316
|
+
committedMembers.value = committedMembers.value.filter((_, i) => i !== index);
|
|
237
317
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
318
|
</script>
|
|
242
319
|
|
|
243
|
-
<style scoped></style>
|
|
320
|
+
<style scoped></style>
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
density="compact"
|
|
58
58
|
persistent-hint
|
|
59
59
|
small-chips
|
|
60
|
+
closable-chips
|
|
60
61
|
:clearable="props.clearable"
|
|
61
62
|
@click="fetchKeys"
|
|
62
63
|
:loading="isKeyListLoading"
|
|
@@ -182,7 +183,7 @@ const isPassListLoading = ref(false);
|
|
|
182
183
|
|
|
183
184
|
async function fetchPasses() {
|
|
184
185
|
// load pass list
|
|
185
|
-
|
|
186
|
+
|
|
186
187
|
isPassListLoading.value = true;
|
|
187
188
|
try {
|
|
188
189
|
const result = await getPassKeysByPageSearch({
|
|
@@ -204,7 +205,6 @@ async function fetchPasses() {
|
|
|
204
205
|
const isKeyListLoading = ref(false);
|
|
205
206
|
|
|
206
207
|
async function fetchKeys() {
|
|
207
|
-
keyItems.value = [];
|
|
208
208
|
isKeyListLoading.value = true;
|
|
209
209
|
try {
|
|
210
210
|
const keys: any = await getPassKeysByPageSearch({
|
|
@@ -215,19 +215,21 @@ async function fetchKeys() {
|
|
|
215
215
|
statuses: ["Available"],
|
|
216
216
|
sortBy: { column: "prefixAndName", order: "1" },
|
|
217
217
|
});
|
|
218
|
-
|
|
218
|
+
|
|
219
|
+
const previouslySelectedKeys = keyItems.value.filter((item: any) => {
|
|
219
220
|
if (Array.isArray(props?.passKeys) && props.passKeys.length) {
|
|
220
221
|
return props.passKeys.includes(item._id);
|
|
221
222
|
}
|
|
222
223
|
return false;
|
|
223
224
|
});
|
|
225
|
+
|
|
224
226
|
const filteredArray = keys.items.filter((item: any) => {
|
|
225
227
|
if (Array.isArray(props?.passKeys) && props.passKeys.length) {
|
|
226
228
|
return !props.passKeys.includes(item._id);
|
|
227
229
|
}
|
|
228
230
|
return true;
|
|
229
231
|
});
|
|
230
|
-
keyItems.value = [...
|
|
232
|
+
keyItems.value = [...previouslySelectedKeys, ...filteredArray];
|
|
231
233
|
} catch (error) {
|
|
232
234
|
showMessage(errorConverter(error as string), "error");
|
|
233
235
|
} finally {
|
|
@@ -732,6 +732,7 @@ const {
|
|
|
732
732
|
add: addServiceProvider,
|
|
733
733
|
createServiceProviderInvite,
|
|
734
734
|
updateStatus: updateServiceProviderStatus,
|
|
735
|
+
invite
|
|
735
736
|
} = useServiceProvider();
|
|
736
737
|
const { getAll: getAllMembers } = useMember();
|
|
737
738
|
|
|
@@ -759,9 +760,10 @@ const createInviteDialog = ref(false);
|
|
|
759
760
|
// const serviceProviderInviteRoles = ref<Array<Record<string, any>>>([]);
|
|
760
761
|
|
|
761
762
|
const { getByUserType } = useMember();
|
|
763
|
+
const { getOrgs } = useOrg();
|
|
762
764
|
|
|
763
765
|
async function checkExistingAccount(email: string) {
|
|
764
|
-
|
|
766
|
+
existingAccount.value = null;
|
|
765
767
|
|
|
766
768
|
if (!email.trim() || emailRule(email) !== true) return;
|
|
767
769
|
|
|
@@ -772,19 +774,23 @@ async function checkExistingAccount(email: string) {
|
|
|
772
774
|
|
|
773
775
|
if (!user?._id) return;
|
|
774
776
|
|
|
775
|
-
const
|
|
776
|
-
|
|
777
|
-
|
|
777
|
+
const orgs = await getOrgs({
|
|
778
|
+
user: user._id,
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
const matchedOrg = orgs.items?.find(
|
|
782
|
+
(org: any) => org.type === serviceProviderInvite.value.app
|
|
783
|
+
);
|
|
784
|
+
|
|
785
|
+
if (matchedOrg) {
|
|
786
|
+
existingAccount.value = {
|
|
787
|
+
_id: matchedOrg.value,
|
|
788
|
+
text: matchedOrg.text,
|
|
789
|
+
...matchedOrg,
|
|
790
|
+
};
|
|
791
|
+
}
|
|
778
792
|
|
|
779
|
-
if (member?.onboardingCompleted) {
|
|
780
|
-
existingAccount.value = {
|
|
781
|
-
_id: member.org,
|
|
782
|
-
text: member.orgName,
|
|
783
|
-
...member,
|
|
784
|
-
};
|
|
785
|
-
}
|
|
786
793
|
} catch (error) {
|
|
787
|
-
console.error(error);
|
|
788
794
|
existingAccount.value = null;
|
|
789
795
|
} finally {
|
|
790
796
|
checkingExistingAccount.value = false;
|
|
@@ -799,6 +805,14 @@ watch(
|
|
|
799
805
|
await checkExistingAccount(value);
|
|
800
806
|
}
|
|
801
807
|
);
|
|
808
|
+
watch(
|
|
809
|
+
() => serviceProviderInvite.value.app,
|
|
810
|
+
() => {
|
|
811
|
+
if (serviceProviderInvite.value.email) {
|
|
812
|
+
checkExistingAccount(serviceProviderInvite.value.email);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
);
|
|
802
816
|
|
|
803
817
|
const serviceProviderInviteApps = computed(() =>
|
|
804
818
|
natureOfBusinessV3.map((item) => ({
|
|
@@ -1183,33 +1197,42 @@ async function submitServiceProviderAdd() {
|
|
|
1183
1197
|
disableServiceProvider.value = false;
|
|
1184
1198
|
}
|
|
1185
1199
|
}
|
|
1186
|
-
|
|
1187
1200
|
async function submitServiceProviderInvite() {
|
|
1188
1201
|
disableServiceProvider.value = true;
|
|
1189
1202
|
messageServiceProvider.value = "";
|
|
1203
|
+
|
|
1190
1204
|
try {
|
|
1191
|
-
|
|
1205
|
+
await invite({
|
|
1192
1206
|
email: serviceProviderInvite.value.email.trim(),
|
|
1193
|
-
name: "",
|
|
1194
|
-
app: serviceProviderInvite.value.app,
|
|
1195
1207
|
orgId: props.orgId,
|
|
1196
1208
|
siteId: serviceProviderInvite.value.siteId,
|
|
1197
1209
|
siteName:
|
|
1198
|
-
serviceProviderInvite.value.siteName ||
|
|
1199
|
-
|
|
1210
|
+
serviceProviderInvite.value.siteName ||
|
|
1211
|
+
site.value?.name ||
|
|
1212
|
+
props.siteName,
|
|
1213
|
+
|
|
1214
|
+
inviteType: existingAccount.value
|
|
1215
|
+
? "create-org"
|
|
1216
|
+
: "organization-invite",
|
|
1217
|
+
});
|
|
1200
1218
|
|
|
1201
|
-
await createServiceProviderInvite(payload);
|
|
1202
1219
|
showMessage("Invitation sent.", "success");
|
|
1220
|
+
|
|
1203
1221
|
if (createMoreServiceProvider.value) {
|
|
1204
1222
|
serviceProviderInvite.value.email = "";
|
|
1205
1223
|
} else {
|
|
1206
|
-
await setServiceProvider({
|
|
1224
|
+
await setServiceProvider({
|
|
1225
|
+
mode: "invite",
|
|
1226
|
+
dialog: false,
|
|
1227
|
+
});
|
|
1207
1228
|
}
|
|
1229
|
+
|
|
1208
1230
|
await loadList();
|
|
1209
1231
|
} catch (error: any) {
|
|
1210
1232
|
messageServiceProvider.value =
|
|
1211
1233
|
error?.response?._data?.message ??
|
|
1212
1234
|
"An error occurred while inviting the service provider.";
|
|
1235
|
+
|
|
1213
1236
|
showMessage(errorConverter(error), "error");
|
|
1214
1237
|
} finally {
|
|
1215
1238
|
disableServiceProvider.value = false;
|