@eeplatform/nuxt-layer-common 1.2.2 → 1.2.4
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/InvitationForm.vue +206 -0
- package/components/InvitationMain.vue +46 -14
- package/components/MemberMain.vue +1 -6
- package/components/RolePermissionMain.vue +0 -1
- package/components/SchoolFormCreate.vue +216 -0
- package/components/SchoolFormEdit.vue +177 -0
- package/components/SchoolMain.vue +429 -0
- package/composables/useLocalAuth.ts +9 -20
- package/composables/useLocalSetup.ts +2 -36
- package/composables/useSchool.ts +3 -3
- package/middleware/01.auth.ts +2 -3
- package/nuxt.config.ts +1 -0
- package/package.json +1 -1
- package/plugins/API.ts +2 -39
- package/plugins/secure-member.client.ts +51 -0
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-card width="100%">
|
|
3
|
+
<v-toolbar>
|
|
4
|
+
<v-row no-gutters class="fill-height px-6" align="center">
|
|
5
|
+
<span class="font-weight-bold text-h5"> Invite </span>
|
|
6
|
+
</v-row>
|
|
7
|
+
</v-toolbar>
|
|
8
|
+
<v-card-text style="max-height: 100vh; overflow-y: auto" class="pb-0">
|
|
9
|
+
<v-form v-model="validInvite">
|
|
10
|
+
<v-row no-gutters>
|
|
11
|
+
<v-col cols="12">
|
|
12
|
+
<v-row no-gutters>
|
|
13
|
+
<InputLabel class="text-capitalize" title="E-mail" required />
|
|
14
|
+
<v-col cols="12">
|
|
15
|
+
<v-text-field
|
|
16
|
+
v-model="invite.email"
|
|
17
|
+
density="comfortable"
|
|
18
|
+
:rules="[requiredRule, emailRule]"
|
|
19
|
+
></v-text-field>
|
|
20
|
+
</v-col>
|
|
21
|
+
</v-row>
|
|
22
|
+
</v-col>
|
|
23
|
+
|
|
24
|
+
<v-col cols="12" class="my-2">
|
|
25
|
+
<v-row no-gutters>
|
|
26
|
+
<v-col cols="12">
|
|
27
|
+
<v-input
|
|
28
|
+
:error-messages="invite.role ? [] : ['Role is required']"
|
|
29
|
+
>
|
|
30
|
+
<v-menu z-index="10000">
|
|
31
|
+
<template #activator="{ props }">
|
|
32
|
+
<v-btn
|
|
33
|
+
block
|
|
34
|
+
variant="flat"
|
|
35
|
+
color="black"
|
|
36
|
+
class="text-none"
|
|
37
|
+
height="48"
|
|
38
|
+
v-bind="props"
|
|
39
|
+
>
|
|
40
|
+
{{ invite.role ? roleName : "Select Role" }}
|
|
41
|
+
</v-btn>
|
|
42
|
+
</template>
|
|
43
|
+
|
|
44
|
+
<v-list class="pa-0">
|
|
45
|
+
<v-list-item v-if="!roles.length"> No data </v-list-item>
|
|
46
|
+
|
|
47
|
+
<v-list-item
|
|
48
|
+
v-for="role in roles"
|
|
49
|
+
:key="role._id"
|
|
50
|
+
@click="invite.role = role._id"
|
|
51
|
+
>
|
|
52
|
+
<template #prepend>
|
|
53
|
+
<v-icon v-if="invite.role === role._id">
|
|
54
|
+
mdi-check
|
|
55
|
+
</v-icon>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<v-list-item-title
|
|
59
|
+
class="text-subtitle-2 font-weight-medium"
|
|
60
|
+
>
|
|
61
|
+
{{ role.name }}
|
|
62
|
+
</v-list-item-title>
|
|
63
|
+
</v-list-item>
|
|
64
|
+
</v-list>
|
|
65
|
+
</v-menu>
|
|
66
|
+
</v-input>
|
|
67
|
+
</v-col>
|
|
68
|
+
</v-row>
|
|
69
|
+
</v-col>
|
|
70
|
+
|
|
71
|
+
<v-col v-if="messageInvite" cols="12" class="text-center mb-4">
|
|
72
|
+
<span
|
|
73
|
+
class="text-none text-subtitle-2 font-weight-medium text-error"
|
|
74
|
+
>
|
|
75
|
+
{{ messageInvite }}
|
|
76
|
+
</span>
|
|
77
|
+
</v-col>
|
|
78
|
+
</v-row>
|
|
79
|
+
</v-form>
|
|
80
|
+
</v-card-text>
|
|
81
|
+
|
|
82
|
+
<v-toolbar class="pa-0" density="compact">
|
|
83
|
+
<v-row no-gutters>
|
|
84
|
+
<v-col cols="6" class="pa-0">
|
|
85
|
+
<v-btn
|
|
86
|
+
block
|
|
87
|
+
variant="text"
|
|
88
|
+
class="text-none"
|
|
89
|
+
size="large"
|
|
90
|
+
@click="cancel()"
|
|
91
|
+
height="48"
|
|
92
|
+
tile
|
|
93
|
+
>
|
|
94
|
+
Cancel
|
|
95
|
+
</v-btn>
|
|
96
|
+
</v-col>
|
|
97
|
+
|
|
98
|
+
<v-col cols="6">
|
|
99
|
+
<v-btn
|
|
100
|
+
block
|
|
101
|
+
variant="flat"
|
|
102
|
+
color="black"
|
|
103
|
+
class="text-none"
|
|
104
|
+
size="large"
|
|
105
|
+
@click="submitInvite()"
|
|
106
|
+
height="48"
|
|
107
|
+
tile
|
|
108
|
+
:disabled="!validInvite"
|
|
109
|
+
>
|
|
110
|
+
Submit
|
|
111
|
+
</v-btn>
|
|
112
|
+
</v-col>
|
|
113
|
+
</v-row>
|
|
114
|
+
</v-toolbar>
|
|
115
|
+
</v-card>
|
|
116
|
+
</template>
|
|
117
|
+
|
|
118
|
+
<script setup lang="ts">
|
|
119
|
+
const prop = defineProps({
|
|
120
|
+
app: {
|
|
121
|
+
type: String,
|
|
122
|
+
required: true,
|
|
123
|
+
default: "admin",
|
|
124
|
+
},
|
|
125
|
+
org: {
|
|
126
|
+
type: String,
|
|
127
|
+
default: "",
|
|
128
|
+
},
|
|
129
|
+
orgName: {
|
|
130
|
+
type: String,
|
|
131
|
+
default: "",
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const { requiredRule, emailRule } = useUtils();
|
|
136
|
+
|
|
137
|
+
const invite = ref({
|
|
138
|
+
email: "",
|
|
139
|
+
app: "",
|
|
140
|
+
role: "",
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const searchRole = ref("");
|
|
144
|
+
const roles = ref<Array<Record<string, any>>>([]);
|
|
145
|
+
|
|
146
|
+
const { getRoles } = useRole();
|
|
147
|
+
|
|
148
|
+
const { data: getRolesData, status: getRolesStatus } = await useLazyAsyncData(
|
|
149
|
+
"get-roles",
|
|
150
|
+
() =>
|
|
151
|
+
getRoles({
|
|
152
|
+
search: searchRole.value,
|
|
153
|
+
type: prop.app,
|
|
154
|
+
id: prop.org,
|
|
155
|
+
limit: 20,
|
|
156
|
+
})
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const loading = computed(() => {
|
|
160
|
+
return getRolesStatus.value === "pending";
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
watchEffect(() => {
|
|
164
|
+
if (getRolesData.value) {
|
|
165
|
+
roles.value = getRolesData.value.items;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const validInvite = ref(false);
|
|
170
|
+
|
|
171
|
+
const { inviteUser } = useUser();
|
|
172
|
+
|
|
173
|
+
const messageInvite = ref("");
|
|
174
|
+
|
|
175
|
+
const roleName = computed(() => {
|
|
176
|
+
return roles.value.find((i) => i._id === invite.value.role)?.name || "";
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const emit = defineEmits(["success", "cancel"]);
|
|
180
|
+
|
|
181
|
+
async function submitInvite() {
|
|
182
|
+
messageInvite.value = "";
|
|
183
|
+
try {
|
|
184
|
+
await inviteUser({
|
|
185
|
+
email: invite.value.email,
|
|
186
|
+
app: prop.app,
|
|
187
|
+
role: invite.value.role,
|
|
188
|
+
roleName: roleName.value,
|
|
189
|
+
org: prop.org,
|
|
190
|
+
orgName: prop.orgName,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
await emit("success");
|
|
194
|
+
} catch (error: any) {
|
|
195
|
+
messageInvite.value =
|
|
196
|
+
error.response?._data?.message || "Failed to invite user";
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function cancel() {
|
|
201
|
+
invite.value.email = "";
|
|
202
|
+
invite.value.app = prop.app;
|
|
203
|
+
invite.value.role = "";
|
|
204
|
+
emit("cancel");
|
|
205
|
+
}
|
|
206
|
+
</script>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
class="text-none mr-2"
|
|
7
7
|
rounded="pill"
|
|
8
8
|
variant="tonal"
|
|
9
|
-
|
|
9
|
+
@click="dialogInvite = true"
|
|
10
10
|
size="large"
|
|
11
11
|
v-if="props.inviteMember"
|
|
12
12
|
>
|
|
@@ -46,20 +46,14 @@
|
|
|
46
46
|
<template #extension>
|
|
47
47
|
<v-tabs>
|
|
48
48
|
<v-tab
|
|
49
|
+
v-for="status in statusFilter"
|
|
50
|
+
:key="status.text"
|
|
49
51
|
:to="{
|
|
50
|
-
name:
|
|
51
|
-
params:
|
|
52
|
+
name: props.baseRoute,
|
|
53
|
+
params: status.params,
|
|
52
54
|
}"
|
|
53
55
|
>
|
|
54
|
-
|
|
55
|
-
</v-tab>
|
|
56
|
-
<v-tab
|
|
57
|
-
:to="{
|
|
58
|
-
name: 'org-organization-invitations-status-status',
|
|
59
|
-
params: { status: 'expired', organization },
|
|
60
|
-
}"
|
|
61
|
-
>
|
|
62
|
-
Expired
|
|
56
|
+
{{ status.text }}
|
|
63
57
|
</v-tab>
|
|
64
58
|
</v-tabs>
|
|
65
59
|
</template>
|
|
@@ -86,6 +80,15 @@
|
|
|
86
80
|
</v-data-table>
|
|
87
81
|
</v-card>
|
|
88
82
|
</v-col>
|
|
83
|
+
|
|
84
|
+
<v-dialog v-model="dialogInvite" width="400" persistent>
|
|
85
|
+
<InvitationForm
|
|
86
|
+
:app="props.app"
|
|
87
|
+
:org="props.org"
|
|
88
|
+
@cancel="dialogInvite = false"
|
|
89
|
+
@success="inviteSuccess()"
|
|
90
|
+
/>
|
|
91
|
+
</v-dialog>
|
|
89
92
|
</v-row>
|
|
90
93
|
</template>
|
|
91
94
|
|
|
@@ -95,6 +98,10 @@ const props = defineProps({
|
|
|
95
98
|
type: String,
|
|
96
99
|
default: "active",
|
|
97
100
|
},
|
|
101
|
+
org: {
|
|
102
|
+
type: String,
|
|
103
|
+
default: "",
|
|
104
|
+
},
|
|
98
105
|
app: {
|
|
99
106
|
type: String,
|
|
100
107
|
default: "organization",
|
|
@@ -103,6 +110,10 @@ const props = defineProps({
|
|
|
103
110
|
type: Boolean,
|
|
104
111
|
default: false,
|
|
105
112
|
},
|
|
113
|
+
baseRoute: {
|
|
114
|
+
type: String,
|
|
115
|
+
default: "invitations-status-status",
|
|
116
|
+
},
|
|
106
117
|
inviteRoute: {
|
|
107
118
|
type: Object as PropType<Record<string, any>>,
|
|
108
119
|
default: () => ({
|
|
@@ -112,8 +123,6 @@ const props = defineProps({
|
|
|
112
123
|
},
|
|
113
124
|
});
|
|
114
125
|
|
|
115
|
-
const organization = (useRoute().params.organization as string) ?? "";
|
|
116
|
-
|
|
117
126
|
const headers = [
|
|
118
127
|
{
|
|
119
128
|
title: "Date",
|
|
@@ -129,6 +138,22 @@ const headers = [
|
|
|
129
138
|
},
|
|
130
139
|
];
|
|
131
140
|
|
|
141
|
+
const statusFilter = computed(() => {
|
|
142
|
+
const items = [
|
|
143
|
+
{ text: "Pending", params: { status: "pending" } },
|
|
144
|
+
{ text: "Expired", params: { status: "expired" } },
|
|
145
|
+
];
|
|
146
|
+
|
|
147
|
+
if (props.org) {
|
|
148
|
+
items.map((i) => ({
|
|
149
|
+
...i,
|
|
150
|
+
params: { ...i.params, organization: props.org },
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return items;
|
|
155
|
+
});
|
|
156
|
+
|
|
132
157
|
const { getVerifications } = useVerification();
|
|
133
158
|
|
|
134
159
|
const page = ref(1);
|
|
@@ -186,6 +211,13 @@ watch(selectAll, (curr) => {
|
|
|
186
211
|
selected.value.push(...ids);
|
|
187
212
|
}
|
|
188
213
|
});
|
|
214
|
+
|
|
215
|
+
const dialogInvite = ref(false);
|
|
216
|
+
|
|
217
|
+
function inviteSuccess() {
|
|
218
|
+
dialogInvite.value = false;
|
|
219
|
+
getInvitations();
|
|
220
|
+
}
|
|
189
221
|
</script>
|
|
190
222
|
|
|
191
223
|
<style scoped>
|
|
@@ -293,11 +293,6 @@ const props = defineProps({
|
|
|
293
293
|
|
|
294
294
|
value: "roleName",
|
|
295
295
|
},
|
|
296
|
-
{
|
|
297
|
-
title: "Organization",
|
|
298
|
-
|
|
299
|
-
value: "orgName",
|
|
300
|
-
},
|
|
301
296
|
{
|
|
302
297
|
title: "Action",
|
|
303
298
|
value: "action-table",
|
|
@@ -379,7 +374,7 @@ function setMember({
|
|
|
379
374
|
const roles = ref<Array<Record<string, any>>>([]);
|
|
380
375
|
const { getRoles } = useRole();
|
|
381
376
|
const { data: getAllRoleReq } = useLazyAsyncData("get-roles", () =>
|
|
382
|
-
getRoles({
|
|
377
|
+
getRoles({ id: props.orgId, type: props.type, limit: 20 })
|
|
383
378
|
);
|
|
384
379
|
|
|
385
380
|
watchEffect(() => {
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-card width="100%">
|
|
3
|
+
<v-toolbar>
|
|
4
|
+
<v-row no-gutters class="fill-height px-6" align="center">
|
|
5
|
+
<span class="font-weight-bold text-h5">
|
|
6
|
+
Create School
|
|
7
|
+
</span>
|
|
8
|
+
</v-row>
|
|
9
|
+
</v-toolbar>
|
|
10
|
+
<v-card-text style="max-height: 100vh; overflow-y: auto">
|
|
11
|
+
<v-form v-model="validForm" :disabled="disable">
|
|
12
|
+
<v-row no-gutters>
|
|
13
|
+
<v-col cols="12" class="mt-2">
|
|
14
|
+
<v-row no-gutters>
|
|
15
|
+
<InputLabel class="text-capitalize" title="School Name" required />
|
|
16
|
+
<v-col cols="12">
|
|
17
|
+
<v-text-field
|
|
18
|
+
v-model="name"
|
|
19
|
+
density="comfortable"
|
|
20
|
+
:rules="[requiredRule]"
|
|
21
|
+
placeholder="Enter school name"
|
|
22
|
+
></v-text-field>
|
|
23
|
+
</v-col>
|
|
24
|
+
</v-row>
|
|
25
|
+
</v-col>
|
|
26
|
+
|
|
27
|
+
<v-col cols="12" class="mt-2">
|
|
28
|
+
<v-row no-gutters>
|
|
29
|
+
<InputLabel class="text-capitalize" title="Division" required />
|
|
30
|
+
<v-col cols="12">
|
|
31
|
+
<v-select
|
|
32
|
+
v-model="selectedDivision"
|
|
33
|
+
:items="divisionOptions"
|
|
34
|
+
item-title="name"
|
|
35
|
+
item-value="_id"
|
|
36
|
+
density="comfortable"
|
|
37
|
+
:rules="[requiredRule]"
|
|
38
|
+
placeholder="Select a division"
|
|
39
|
+
:loading="divisionsLoading"
|
|
40
|
+
return-object
|
|
41
|
+
></v-select>
|
|
42
|
+
</v-col>
|
|
43
|
+
</v-row>
|
|
44
|
+
</v-col>
|
|
45
|
+
|
|
46
|
+
<v-col cols="12" class="mt-2">
|
|
47
|
+
<v-row no-gutters>
|
|
48
|
+
<InputLabel class="text-capitalize" title="Principal Name" />
|
|
49
|
+
<v-col cols="12">
|
|
50
|
+
<v-text-field
|
|
51
|
+
v-model="principalName"
|
|
52
|
+
density="comfortable"
|
|
53
|
+
placeholder="Enter principal name (optional)"
|
|
54
|
+
></v-text-field>
|
|
55
|
+
</v-col>
|
|
56
|
+
</v-row>
|
|
57
|
+
</v-col>
|
|
58
|
+
|
|
59
|
+
<v-col cols="12" class="mt-2">
|
|
60
|
+
<v-row no-gutters>
|
|
61
|
+
<InputLabel class="text-capitalize" title="Address" />
|
|
62
|
+
<v-col cols="12">
|
|
63
|
+
<v-textarea
|
|
64
|
+
v-model="address"
|
|
65
|
+
density="comfortable"
|
|
66
|
+
placeholder="Enter school address (optional)"
|
|
67
|
+
rows="3"
|
|
68
|
+
></v-textarea>
|
|
69
|
+
</v-col>
|
|
70
|
+
</v-row>
|
|
71
|
+
</v-col>
|
|
72
|
+
|
|
73
|
+
<v-col cols="12" class="mt-2">
|
|
74
|
+
<v-checkbox v-model="createMore" density="comfortable" hide-details>
|
|
75
|
+
<template #label>
|
|
76
|
+
<span class="text-subtitle-2 font-weight-bold">
|
|
77
|
+
Create more
|
|
78
|
+
</span>
|
|
79
|
+
</template>
|
|
80
|
+
</v-checkbox>
|
|
81
|
+
</v-col>
|
|
82
|
+
|
|
83
|
+
<v-col cols="12" class="my-2">
|
|
84
|
+
<v-row no-gutters>
|
|
85
|
+
<v-col cols="12" class="text-center">
|
|
86
|
+
<span
|
|
87
|
+
class="text-none text-subtitle-2 font-weight-medium text-error"
|
|
88
|
+
>
|
|
89
|
+
{{ message }}
|
|
90
|
+
</span>
|
|
91
|
+
</v-col>
|
|
92
|
+
</v-row>
|
|
93
|
+
</v-col>
|
|
94
|
+
</v-row>
|
|
95
|
+
</v-form>
|
|
96
|
+
</v-card-text>
|
|
97
|
+
|
|
98
|
+
<v-toolbar>
|
|
99
|
+
<v-row class="px-6">
|
|
100
|
+
<v-col cols="6">
|
|
101
|
+
<v-btn
|
|
102
|
+
block
|
|
103
|
+
variant="text"
|
|
104
|
+
class="text-none"
|
|
105
|
+
size="large"
|
|
106
|
+
@click="cancel"
|
|
107
|
+
:disabled="disable"
|
|
108
|
+
>
|
|
109
|
+
Cancel
|
|
110
|
+
</v-btn>
|
|
111
|
+
</v-col>
|
|
112
|
+
|
|
113
|
+
<v-col cols="6">
|
|
114
|
+
<v-btn
|
|
115
|
+
block
|
|
116
|
+
variant="flat"
|
|
117
|
+
color="black"
|
|
118
|
+
class="text-none"
|
|
119
|
+
size="large"
|
|
120
|
+
:disabled="!validForm || disable"
|
|
121
|
+
@click="submit"
|
|
122
|
+
:loading="disable"
|
|
123
|
+
>
|
|
124
|
+
Create School
|
|
125
|
+
</v-btn>
|
|
126
|
+
</v-col>
|
|
127
|
+
</v-row>
|
|
128
|
+
</v-toolbar>
|
|
129
|
+
</v-card>
|
|
130
|
+
</template>
|
|
131
|
+
|
|
132
|
+
<script setup lang="ts">
|
|
133
|
+
const emit = defineEmits(["cancel", "success", "success:create-more"]);
|
|
134
|
+
|
|
135
|
+
const validForm = ref(false);
|
|
136
|
+
|
|
137
|
+
const name = ref("");
|
|
138
|
+
const selectedDivision = ref<Record<string, any> | null>(null);
|
|
139
|
+
const principalName = ref("");
|
|
140
|
+
const address = ref("");
|
|
141
|
+
const createMore = ref(false);
|
|
142
|
+
const disable = ref(false);
|
|
143
|
+
|
|
144
|
+
const { requiredRule } = useUtils();
|
|
145
|
+
|
|
146
|
+
const message = ref("");
|
|
147
|
+
|
|
148
|
+
const { createSchool } = useSchool();
|
|
149
|
+
const { getAll: getDivisions } = useDivision();
|
|
150
|
+
|
|
151
|
+
// Load divisions for selection
|
|
152
|
+
const divisionOptions = ref<Array<Record<string, any>>>([]);
|
|
153
|
+
const divisionsLoading = ref(false);
|
|
154
|
+
|
|
155
|
+
onMounted(async () => {
|
|
156
|
+
divisionsLoading.value = true;
|
|
157
|
+
try {
|
|
158
|
+
const response = await getDivisions({ page: 1, limit: 100 });
|
|
159
|
+
divisionOptions.value = response.items || [];
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error('Failed to load divisions:', error);
|
|
162
|
+
} finally {
|
|
163
|
+
divisionsLoading.value = false;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
async function submit() {
|
|
168
|
+
disable.value = true;
|
|
169
|
+
try {
|
|
170
|
+
const payload: Record<string, any> = {
|
|
171
|
+
name: name.value,
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
if (selectedDivision.value) {
|
|
175
|
+
payload.division = selectedDivision.value._id;
|
|
176
|
+
payload.divisionName = selectedDivision.value.name;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (principalName.value.trim()) {
|
|
180
|
+
payload.principalName = principalName.value.trim();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (address.value.trim()) {
|
|
184
|
+
payload.address = address.value.trim();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
await createSchool(payload);
|
|
188
|
+
|
|
189
|
+
if (createMore.value) {
|
|
190
|
+
name.value = "";
|
|
191
|
+
selectedDivision.value = null;
|
|
192
|
+
principalName.value = "";
|
|
193
|
+
address.value = "";
|
|
194
|
+
message.value = "";
|
|
195
|
+
emit("success:create-more");
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
emit("success");
|
|
200
|
+
} catch (error: any) {
|
|
201
|
+
message.value = error.response?._data?.message || "Failed to create school";
|
|
202
|
+
} finally {
|
|
203
|
+
disable.value = false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function cancel() {
|
|
208
|
+
name.value = "";
|
|
209
|
+
selectedDivision.value = null;
|
|
210
|
+
principalName.value = "";
|
|
211
|
+
address.value = "";
|
|
212
|
+
createMore.value = false;
|
|
213
|
+
message.value = "";
|
|
214
|
+
emit("cancel");
|
|
215
|
+
}
|
|
216
|
+
</script>
|