@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
|
@@ -0,0 +1,177 @@
|
|
|
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"> Edit School </span>
|
|
6
|
+
</v-row>
|
|
7
|
+
</v-toolbar>
|
|
8
|
+
<v-card-text style="max-height: 100vh; overflow-y: auto">
|
|
9
|
+
<v-form v-model="validForm" :disabled="disable">
|
|
10
|
+
<v-row no-gutters>
|
|
11
|
+
<v-col cols="12" class="mt-2">
|
|
12
|
+
<v-row no-gutters>
|
|
13
|
+
<InputLabel class="text-capitalize" title="School Name" required />
|
|
14
|
+
<v-col cols="12">
|
|
15
|
+
<v-text-field
|
|
16
|
+
v-model="name"
|
|
17
|
+
density="comfortable"
|
|
18
|
+
:rules="[requiredRule]"
|
|
19
|
+
placeholder="Enter school name"
|
|
20
|
+
></v-text-field>
|
|
21
|
+
</v-col>
|
|
22
|
+
</v-row>
|
|
23
|
+
</v-col>
|
|
24
|
+
|
|
25
|
+
<v-col cols="12" class="mt-2">
|
|
26
|
+
<v-row no-gutters>
|
|
27
|
+
<InputLabel class="text-capitalize" title="Principal Name" />
|
|
28
|
+
<v-col cols="12">
|
|
29
|
+
<v-text-field
|
|
30
|
+
v-model="principalName"
|
|
31
|
+
density="comfortable"
|
|
32
|
+
placeholder="Enter principal name (optional)"
|
|
33
|
+
></v-text-field>
|
|
34
|
+
</v-col>
|
|
35
|
+
</v-row>
|
|
36
|
+
</v-col>
|
|
37
|
+
|
|
38
|
+
<v-col cols="12" class="mt-2">
|
|
39
|
+
<v-row no-gutters>
|
|
40
|
+
<InputLabel class="text-capitalize" title="Address" />
|
|
41
|
+
<v-col cols="12">
|
|
42
|
+
<v-textarea
|
|
43
|
+
v-model="address"
|
|
44
|
+
density="comfortable"
|
|
45
|
+
placeholder="Enter school address (optional)"
|
|
46
|
+
rows="3"
|
|
47
|
+
></v-textarea>
|
|
48
|
+
</v-col>
|
|
49
|
+
</v-row>
|
|
50
|
+
</v-col>
|
|
51
|
+
|
|
52
|
+
<v-col cols="12" class="my-2">
|
|
53
|
+
<v-row no-gutters>
|
|
54
|
+
<v-col cols="12" class="text-center">
|
|
55
|
+
<span
|
|
56
|
+
class="text-none text-subtitle-2 font-weight-medium text-error"
|
|
57
|
+
>
|
|
58
|
+
{{ message }}
|
|
59
|
+
</span>
|
|
60
|
+
</v-col>
|
|
61
|
+
</v-row>
|
|
62
|
+
</v-col>
|
|
63
|
+
</v-row>
|
|
64
|
+
</v-form>
|
|
65
|
+
</v-card-text>
|
|
66
|
+
|
|
67
|
+
<v-toolbar>
|
|
68
|
+
<v-row class="px-6">
|
|
69
|
+
<v-col cols="6">
|
|
70
|
+
<v-btn
|
|
71
|
+
block
|
|
72
|
+
variant="text"
|
|
73
|
+
class="text-none"
|
|
74
|
+
size="large"
|
|
75
|
+
@click="cancel"
|
|
76
|
+
:disabled="disable"
|
|
77
|
+
>
|
|
78
|
+
Cancel
|
|
79
|
+
</v-btn>
|
|
80
|
+
</v-col>
|
|
81
|
+
|
|
82
|
+
<v-col cols="6">
|
|
83
|
+
<v-btn
|
|
84
|
+
block
|
|
85
|
+
variant="flat"
|
|
86
|
+
color="black"
|
|
87
|
+
class="text-none"
|
|
88
|
+
size="large"
|
|
89
|
+
:disabled="!validForm || disable || !hasChanges"
|
|
90
|
+
@click="submit"
|
|
91
|
+
:loading="disable"
|
|
92
|
+
>
|
|
93
|
+
Update School
|
|
94
|
+
</v-btn>
|
|
95
|
+
</v-col>
|
|
96
|
+
</v-row>
|
|
97
|
+
</v-toolbar>
|
|
98
|
+
</v-card>
|
|
99
|
+
</template>
|
|
100
|
+
|
|
101
|
+
<script setup lang="ts">
|
|
102
|
+
const props = defineProps({
|
|
103
|
+
school: {
|
|
104
|
+
type: Object as PropType<Record<string, any>>,
|
|
105
|
+
required: true,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const emit = defineEmits(["cancel", "success"]);
|
|
110
|
+
|
|
111
|
+
const validForm = ref(false);
|
|
112
|
+
|
|
113
|
+
const name = ref("");
|
|
114
|
+
const principalName = ref("");
|
|
115
|
+
const address = ref("");
|
|
116
|
+
const disable = ref(false);
|
|
117
|
+
|
|
118
|
+
const { requiredRule } = useUtils();
|
|
119
|
+
|
|
120
|
+
const message = ref("");
|
|
121
|
+
|
|
122
|
+
const { updateSchoolField } = useSchool();
|
|
123
|
+
|
|
124
|
+
// Initialize form with existing data
|
|
125
|
+
watchEffect(() => {
|
|
126
|
+
if (props.school) {
|
|
127
|
+
name.value = props.school.name || "";
|
|
128
|
+
principalName.value = props.school.principalName || "";
|
|
129
|
+
address.value = props.school.address || "";
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const hasChanges = computed(() => {
|
|
134
|
+
if (!props.school) return false;
|
|
135
|
+
return (
|
|
136
|
+
name.value !== (props.school.name || "") ||
|
|
137
|
+
principalName.value !== (props.school.principalName || "") ||
|
|
138
|
+
address.value !== (props.school.address || "")
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
async function submit() {
|
|
143
|
+
if (!props.school?._id) return;
|
|
144
|
+
|
|
145
|
+
disable.value = true;
|
|
146
|
+
try {
|
|
147
|
+
// Update fields that have changed
|
|
148
|
+
if (name.value !== (props.school.name || "")) {
|
|
149
|
+
await updateSchoolField(props.school._id, "name", name.value);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (principalName.value !== (props.school.principalName || "")) {
|
|
153
|
+
await updateSchoolField(props.school._id, "principalName", principalName.value);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (address.value !== (props.school.address || "")) {
|
|
157
|
+
await updateSchoolField(props.school._id, "address", address.value);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
emit("success");
|
|
161
|
+
} catch (error: any) {
|
|
162
|
+
message.value = error.response?._data?.message || "Failed to update school";
|
|
163
|
+
} finally {
|
|
164
|
+
disable.value = false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function cancel() {
|
|
169
|
+
// Reset to original values
|
|
170
|
+
name.value = props.school?.name || "";
|
|
171
|
+
principalName.value = props.school?.principalName || "";
|
|
172
|
+
address.value = props.school?.address || "";
|
|
173
|
+
message.value = "";
|
|
174
|
+
emit("cancel");
|
|
175
|
+
}
|
|
176
|
+
</script>
|
|
177
|
+
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-row no-gutters>
|
|
3
|
+
<v-col cols="12">
|
|
4
|
+
<v-card
|
|
5
|
+
width="100%"
|
|
6
|
+
variant="outlined"
|
|
7
|
+
border="thin"
|
|
8
|
+
rounded="lg"
|
|
9
|
+
:loading="loading"
|
|
10
|
+
>
|
|
11
|
+
<v-toolbar density="compact" color="grey-lighten-4">
|
|
12
|
+
<template #prepend>
|
|
13
|
+
<v-btn fab icon density="comfortable" @click="getSchools()">
|
|
14
|
+
<v-icon>mdi-refresh</v-icon>
|
|
15
|
+
</v-btn>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<template #append>
|
|
19
|
+
<v-row no-gutters justify="end" align="center">
|
|
20
|
+
<span class="mr-2 text-caption text-fontgray">
|
|
21
|
+
{{ pageRange }}
|
|
22
|
+
</span>
|
|
23
|
+
<local-pagination
|
|
24
|
+
v-model="page"
|
|
25
|
+
:length="pages"
|
|
26
|
+
@update:value="getSchools()"
|
|
27
|
+
/>
|
|
28
|
+
</v-row>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<template #extension>
|
|
32
|
+
<v-tabs v-model="theStatus">
|
|
33
|
+
<v-tab
|
|
34
|
+
v-for="status in statusFilter"
|
|
35
|
+
:key="status.text"
|
|
36
|
+
:to="{
|
|
37
|
+
name: prop.baseRoute,
|
|
38
|
+
params: status.params,
|
|
39
|
+
}"
|
|
40
|
+
class="text-capitalize"
|
|
41
|
+
>
|
|
42
|
+
{{ status.text }}
|
|
43
|
+
</v-tab>
|
|
44
|
+
</v-tabs>
|
|
45
|
+
</template>
|
|
46
|
+
</v-toolbar>
|
|
47
|
+
|
|
48
|
+
<v-data-table
|
|
49
|
+
:headers="headers"
|
|
50
|
+
:items="items"
|
|
51
|
+
item-value="_id"
|
|
52
|
+
items-per-page="20"
|
|
53
|
+
fixed-header
|
|
54
|
+
hide-default-footer
|
|
55
|
+
hide-default-header
|
|
56
|
+
@click:row="tableRowClickHandler"
|
|
57
|
+
style="max-height: calc(100vh - (180px))"
|
|
58
|
+
>
|
|
59
|
+
<template #item.createdAt="{ value }">
|
|
60
|
+
{{ new Date(value).toLocaleDateString() }}
|
|
61
|
+
</template>
|
|
62
|
+
</v-data-table>
|
|
63
|
+
</v-card>
|
|
64
|
+
</v-col>
|
|
65
|
+
|
|
66
|
+
<!-- Create Dialog -->
|
|
67
|
+
<v-dialog v-model="createDialog" width="500" persistent>
|
|
68
|
+
<SchoolFormCreate
|
|
69
|
+
@cancel="createDialog = false"
|
|
70
|
+
@success="successCreate()"
|
|
71
|
+
@success:create-more="getSchools()"
|
|
72
|
+
/>
|
|
73
|
+
</v-dialog>
|
|
74
|
+
|
|
75
|
+
<!-- Edit Dialog -->
|
|
76
|
+
<v-dialog v-model="editDialog" width="500" persistent>
|
|
77
|
+
<SchoolFormEdit
|
|
78
|
+
v-if="selectedSchool"
|
|
79
|
+
@cancel="editDialog = false"
|
|
80
|
+
@success="successUpdate()"
|
|
81
|
+
:school="selectedSchool"
|
|
82
|
+
/>
|
|
83
|
+
</v-dialog>
|
|
84
|
+
|
|
85
|
+
<!-- Preview Dialog -->
|
|
86
|
+
<v-dialog v-model="previewDialog" width="500" persistent>
|
|
87
|
+
<v-card width="100%">
|
|
88
|
+
<v-card-text style="max-height: 100vh; overflow-y: auto" class="pb-0">
|
|
89
|
+
<v-row no-gutters v-if="selectedSchool">
|
|
90
|
+
<v-col cols="12" class="mb-3">
|
|
91
|
+
<strong>Name:</strong> {{ selectedSchool.name }}
|
|
92
|
+
</v-col>
|
|
93
|
+
<v-col cols="12" class="mb-3">
|
|
94
|
+
<strong>Address:</strong>
|
|
95
|
+
{{
|
|
96
|
+
`${selectedSchool.address} ${
|
|
97
|
+
selectedSchool.continuedAddress || ""
|
|
98
|
+
}`
|
|
99
|
+
}}
|
|
100
|
+
{{ selectedSchool.city }} {{ selectedSchool.state }}
|
|
101
|
+
{{ selectedSchool.zipCode }}
|
|
102
|
+
</v-col>
|
|
103
|
+
<v-col cols="12" class="mb-3">
|
|
104
|
+
<strong>Region:</strong>
|
|
105
|
+
{{ selectedSchool.regionName || "Not assigned" }}
|
|
106
|
+
</v-col>
|
|
107
|
+
<v-col cols="12" class="mb-3">
|
|
108
|
+
<strong>Division:</strong>
|
|
109
|
+
{{ selectedSchool.divisionName || "Not assigned" }}
|
|
110
|
+
</v-col>
|
|
111
|
+
<v-col cols="12" class="mb-3">
|
|
112
|
+
<strong>Principal:</strong>
|
|
113
|
+
{{ selectedSchool.principalName || "Not assigned" }}
|
|
114
|
+
</v-col>
|
|
115
|
+
<v-col cols="12" class="mb-3">
|
|
116
|
+
<strong>Created:</strong>
|
|
117
|
+
{{
|
|
118
|
+
new Date(selectedSchool.createdAt || "").toLocaleDateString()
|
|
119
|
+
}}
|
|
120
|
+
</v-col>
|
|
121
|
+
<v-col cols="12" class="mb-3" v-if="selectedSchool.updatedAt">
|
|
122
|
+
<strong>Updated:</strong>
|
|
123
|
+
{{ new Date(selectedSchool.updatedAt).toLocaleDateString() }}
|
|
124
|
+
</v-col>
|
|
125
|
+
</v-row>
|
|
126
|
+
</v-card-text>
|
|
127
|
+
|
|
128
|
+
<v-toolbar class="pa-0" density="compact">
|
|
129
|
+
<v-row no-gutter>
|
|
130
|
+
<v-col cols="6" class="pa-0">
|
|
131
|
+
<v-btn
|
|
132
|
+
block
|
|
133
|
+
variant="text"
|
|
134
|
+
class="text-none"
|
|
135
|
+
height="48"
|
|
136
|
+
tile
|
|
137
|
+
@click="previewDialog = false"
|
|
138
|
+
>
|
|
139
|
+
Close
|
|
140
|
+
</v-btn>
|
|
141
|
+
</v-col>
|
|
142
|
+
|
|
143
|
+
<v-col cols="6" class="pa-0" v-if="canUpdate">
|
|
144
|
+
<v-menu>
|
|
145
|
+
<template #activator="{ props }">
|
|
146
|
+
<v-btn
|
|
147
|
+
block
|
|
148
|
+
variant="flat"
|
|
149
|
+
color="black"
|
|
150
|
+
class="text-none"
|
|
151
|
+
height="48"
|
|
152
|
+
v-bind="props"
|
|
153
|
+
tile
|
|
154
|
+
>
|
|
155
|
+
More actions
|
|
156
|
+
</v-btn>
|
|
157
|
+
</template>
|
|
158
|
+
|
|
159
|
+
<v-list class="pa-0">
|
|
160
|
+
<v-list-item
|
|
161
|
+
v-if="selectedSchool?.status === 'pending'"
|
|
162
|
+
@click="submitApproval()"
|
|
163
|
+
>
|
|
164
|
+
<v-list-item-title class="text-subtitle-2">
|
|
165
|
+
Approve School
|
|
166
|
+
</v-list-item-title>
|
|
167
|
+
</v-list-item>
|
|
168
|
+
|
|
169
|
+
<v-list-item @click="editFromPreview()">
|
|
170
|
+
<v-list-item-title class="text-subtitle-2">
|
|
171
|
+
Edit School
|
|
172
|
+
</v-list-item-title>
|
|
173
|
+
</v-list-item>
|
|
174
|
+
|
|
175
|
+
<v-list-item
|
|
176
|
+
@click="openDeleteDialog(selectedSchool?._id)"
|
|
177
|
+
class="text-red"
|
|
178
|
+
>
|
|
179
|
+
<v-list-item-title class="text-subtitle-2">
|
|
180
|
+
Delete School
|
|
181
|
+
</v-list-item-title>
|
|
182
|
+
</v-list-item>
|
|
183
|
+
</v-list>
|
|
184
|
+
</v-menu>
|
|
185
|
+
</v-col>
|
|
186
|
+
</v-row>
|
|
187
|
+
</v-toolbar>
|
|
188
|
+
</v-card>
|
|
189
|
+
</v-dialog>
|
|
190
|
+
|
|
191
|
+
<ConfirmDialog
|
|
192
|
+
v-model="confirmDialog"
|
|
193
|
+
:loading="deleteLoading"
|
|
194
|
+
@submit="handleDeleteSchool"
|
|
195
|
+
>
|
|
196
|
+
<template #title>
|
|
197
|
+
<span class="font-weight-medium text-h5">Delete School</span>
|
|
198
|
+
</template>
|
|
199
|
+
|
|
200
|
+
<template #description>
|
|
201
|
+
<p class="text-subtitle-2">
|
|
202
|
+
Are you sure you want to delete this school? This action cannot be
|
|
203
|
+
undone.
|
|
204
|
+
</p>
|
|
205
|
+
</template>
|
|
206
|
+
|
|
207
|
+
<template #footer>
|
|
208
|
+
<v-btn
|
|
209
|
+
variant="text"
|
|
210
|
+
@click="confirmDialog = false"
|
|
211
|
+
:disabled="deleteLoading"
|
|
212
|
+
class="text-none"
|
|
213
|
+
>
|
|
214
|
+
Close
|
|
215
|
+
</v-btn>
|
|
216
|
+
<v-btn
|
|
217
|
+
color="black"
|
|
218
|
+
variant="flat"
|
|
219
|
+
@click="handleDeleteSchool"
|
|
220
|
+
:loading="deleteLoading"
|
|
221
|
+
class="text-none"
|
|
222
|
+
>
|
|
223
|
+
Delete School
|
|
224
|
+
</v-btn>
|
|
225
|
+
</template>
|
|
226
|
+
</ConfirmDialog>
|
|
227
|
+
|
|
228
|
+
<Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
|
|
229
|
+
</v-row>
|
|
230
|
+
</template>
|
|
231
|
+
|
|
232
|
+
<script setup lang="ts">
|
|
233
|
+
const prop = defineProps({
|
|
234
|
+
status: {
|
|
235
|
+
type: String,
|
|
236
|
+
default: "active",
|
|
237
|
+
},
|
|
238
|
+
org: {
|
|
239
|
+
type: String,
|
|
240
|
+
default: "",
|
|
241
|
+
},
|
|
242
|
+
app: {
|
|
243
|
+
type: String,
|
|
244
|
+
default: "school",
|
|
245
|
+
},
|
|
246
|
+
baseRoute: {
|
|
247
|
+
type: String,
|
|
248
|
+
default: "index",
|
|
249
|
+
},
|
|
250
|
+
headers: {
|
|
251
|
+
type: Array as PropType<Array<Record<string, any>>>,
|
|
252
|
+
default: () => [
|
|
253
|
+
{
|
|
254
|
+
title: "Name",
|
|
255
|
+
value: "name",
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
title: "Region",
|
|
259
|
+
value: "regionName",
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
title: "Division",
|
|
263
|
+
value: "divisionName",
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
title: "Principal",
|
|
267
|
+
value: "principalName",
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
},
|
|
271
|
+
canCreate: {
|
|
272
|
+
type: Boolean,
|
|
273
|
+
default: true,
|
|
274
|
+
},
|
|
275
|
+
canUpdate: {
|
|
276
|
+
type: Boolean,
|
|
277
|
+
default: true,
|
|
278
|
+
},
|
|
279
|
+
canDelete: {
|
|
280
|
+
type: Boolean,
|
|
281
|
+
default: true,
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const statusFilter = computed(() => {
|
|
286
|
+
const items = [
|
|
287
|
+
{ text: "Active", params: { status: "active" } },
|
|
288
|
+
{ text: "Pending", params: { status: "pending" } },
|
|
289
|
+
{ text: "Suspended", params: { status: "suspended" } },
|
|
290
|
+
];
|
|
291
|
+
|
|
292
|
+
if (prop.org) {
|
|
293
|
+
items.map((i) => ({
|
|
294
|
+
...i,
|
|
295
|
+
params: { ...i.params, org: prop.org },
|
|
296
|
+
}));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return items;
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
const statuses = ["active", "pending", "suspended", "inactive"];
|
|
303
|
+
const theStatus = ref("active");
|
|
304
|
+
|
|
305
|
+
const { headerSearch } = useLocal();
|
|
306
|
+
const { getAll: _getSchools, approvedById } = useSchool();
|
|
307
|
+
|
|
308
|
+
const page = ref(1);
|
|
309
|
+
const pages = ref(0);
|
|
310
|
+
const pageRange = ref("-- - -- of --");
|
|
311
|
+
|
|
312
|
+
const message = ref("");
|
|
313
|
+
const messageSnackbar = ref(false);
|
|
314
|
+
const messageColor = ref("");
|
|
315
|
+
|
|
316
|
+
const items = ref<Array<Record<string, any>>>([]);
|
|
317
|
+
|
|
318
|
+
const propStatus = computed(() => prop.status);
|
|
319
|
+
|
|
320
|
+
const {
|
|
321
|
+
data: getSchoolReq,
|
|
322
|
+
refresh: getSchools,
|
|
323
|
+
status: getSchoolReqStatus,
|
|
324
|
+
} = useLazyAsyncData(
|
|
325
|
+
"schools-get-all-" + prop.status,
|
|
326
|
+
() =>
|
|
327
|
+
_getSchools({
|
|
328
|
+
page: page.value,
|
|
329
|
+
search: headerSearch.value,
|
|
330
|
+
status: prop.status,
|
|
331
|
+
org: prop.org,
|
|
332
|
+
app: prop.app,
|
|
333
|
+
}),
|
|
334
|
+
{
|
|
335
|
+
watch: [page, propStatus],
|
|
336
|
+
}
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
const loading = computed(() => getSchoolReqStatus.value === "pending");
|
|
340
|
+
|
|
341
|
+
watchEffect(() => {
|
|
342
|
+
if (getSchoolReq.value) {
|
|
343
|
+
items.value = getSchoolReq.value.items;
|
|
344
|
+
pages.value = getSchoolReq.value.pages;
|
|
345
|
+
pageRange.value = getSchoolReq.value.pageRange;
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
function tableRowClickHandler(_: any, data: any) {
|
|
350
|
+
selectedSchool.value = data.item;
|
|
351
|
+
previewDialog.value = true;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const createDialog = ref(false);
|
|
355
|
+
const editDialog = ref(false);
|
|
356
|
+
const previewDialog = ref(false);
|
|
357
|
+
const selectedSchool = ref<Record<string, any> | null>(null);
|
|
358
|
+
|
|
359
|
+
function successCreate() {
|
|
360
|
+
createDialog.value = false;
|
|
361
|
+
getSchools();
|
|
362
|
+
showMessage("School created successfully!", "success");
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function successUpdate() {
|
|
366
|
+
editDialog.value = false;
|
|
367
|
+
previewDialog.value = false;
|
|
368
|
+
getSchools();
|
|
369
|
+
showMessage("School updated successfully!", "success");
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function openEditDialog(school: Record<string, any>) {
|
|
373
|
+
selectedSchool.value = school;
|
|
374
|
+
editDialog.value = true;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function editFromPreview() {
|
|
378
|
+
previewDialog.value = false;
|
|
379
|
+
editDialog.value = true;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const confirmDialog = ref(false);
|
|
383
|
+
const selectedSchoolId = ref<string | null>(null);
|
|
384
|
+
const deleteLoading = ref(false);
|
|
385
|
+
|
|
386
|
+
function openDeleteDialog(id: string) {
|
|
387
|
+
selectedSchoolId.value = id;
|
|
388
|
+
confirmDialog.value = true;
|
|
389
|
+
if (previewDialog.value) {
|
|
390
|
+
previewDialog.value = false;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function showMessage(msg: string, color: string) {
|
|
395
|
+
message.value = msg;
|
|
396
|
+
messageColor.value = color;
|
|
397
|
+
messageSnackbar.value = true;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
async function handleDeleteSchool() {
|
|
401
|
+
if (!selectedSchoolId.value) return;
|
|
402
|
+
deleteLoading.value = true;
|
|
403
|
+
try {
|
|
404
|
+
confirmDialog.value = false;
|
|
405
|
+
getSchools();
|
|
406
|
+
} catch (error: any) {
|
|
407
|
+
const errorMessage =
|
|
408
|
+
error?.response?._data?.message || "Failed to delete school";
|
|
409
|
+
showMessage(errorMessage, "error");
|
|
410
|
+
} finally {
|
|
411
|
+
deleteLoading.value = false;
|
|
412
|
+
selectedSchoolId.value = null;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
async function submitApproval() {
|
|
417
|
+
try {
|
|
418
|
+
await approvedById(selectedSchool.value?._id ?? "");
|
|
419
|
+
getSchools();
|
|
420
|
+
} catch (error: any) {
|
|
421
|
+
const errorMessage =
|
|
422
|
+
error?.response?._data?.message || "Failed to delete school";
|
|
423
|
+
showMessage(errorMessage, "error");
|
|
424
|
+
} finally {
|
|
425
|
+
previewDialog.value = false;
|
|
426
|
+
selectedSchoolId.value = null;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
</script>
|
|
@@ -8,14 +8,6 @@ export default function useLocalAuth() {
|
|
|
8
8
|
return;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
// Get access token from cookies
|
|
12
|
-
const accessToken = useCookie("accessToken", cookieConfig).value;
|
|
13
|
-
|
|
14
|
-
if (!accessToken) {
|
|
15
|
-
// Redirect to login page if no access token
|
|
16
|
-
navigateTo({ name: "index" });
|
|
17
|
-
}
|
|
18
|
-
|
|
19
11
|
const user = useCookie("user", cookieConfig).value;
|
|
20
12
|
|
|
21
13
|
const { data: getCurrentUserReq, error: getCurrentUserErr } =
|
|
@@ -44,6 +36,11 @@ export default function useLocalAuth() {
|
|
|
44
36
|
});
|
|
45
37
|
}
|
|
46
38
|
|
|
39
|
+
function setSession({ sid = "", user = "" } = {}) {
|
|
40
|
+
useCookie("sid", cookieConfig).value = sid;
|
|
41
|
+
useCookie("user", cookieConfig).value = user;
|
|
42
|
+
}
|
|
43
|
+
|
|
47
44
|
function setToken({
|
|
48
45
|
refreshToken = "",
|
|
49
46
|
accessToken = "",
|
|
@@ -64,18 +61,9 @@ export default function useLocalAuth() {
|
|
|
64
61
|
}
|
|
65
62
|
|
|
66
63
|
async function logout() {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
await useNuxtApp().$api(`/api/auth/logout/${refreshToken}`, {
|
|
71
|
-
method: "DELETE",
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
clearCookies();
|
|
75
|
-
} catch (error) {
|
|
76
|
-
console.error("Logout failed:", error);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
64
|
+
return useNuxtApp().$api("/api/auth/logout", {
|
|
65
|
+
method: "DELETE",
|
|
66
|
+
});
|
|
79
67
|
}
|
|
80
68
|
|
|
81
69
|
function getCurrentUser() {
|
|
@@ -142,6 +130,7 @@ export default function useLocalAuth() {
|
|
|
142
130
|
return {
|
|
143
131
|
authenticate,
|
|
144
132
|
login,
|
|
133
|
+
setSession,
|
|
145
134
|
logout,
|
|
146
135
|
clearCookies,
|
|
147
136
|
getCurrentUser,
|
|
@@ -1,44 +1,10 @@
|
|
|
1
|
-
export function useLocalSetup(
|
|
2
|
-
const userId = computed(() => useCookie("user").value ?? "");
|
|
3
|
-
|
|
4
|
-
const { getByUserType } = useMember();
|
|
5
|
-
|
|
6
|
-
const { data: userMemberData, error: userMemberError } = useLazyAsyncData(
|
|
7
|
-
"get-member-by-id",
|
|
8
|
-
() => getByUserType(userId.value, type, org),
|
|
9
|
-
{ watch: [userId] }
|
|
10
|
-
);
|
|
11
|
-
|
|
12
|
-
watchEffect(() => {
|
|
13
|
-
if (userMemberError.value) {
|
|
14
|
-
navigateTo({
|
|
15
|
-
name: "index",
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const { getRoleById } = useRole();
|
|
21
|
-
|
|
22
|
-
const roleId = computed(() => userMemberData.value?.role ?? "");
|
|
23
|
-
|
|
1
|
+
export function useLocalSetup() {
|
|
24
2
|
const userAppRole = useState<Record<string, any> | null>(
|
|
25
3
|
"userAppRole",
|
|
26
4
|
() => null
|
|
27
5
|
);
|
|
28
6
|
|
|
29
|
-
const
|
|
30
|
-
"get-role-by-id",
|
|
31
|
-
() => getRoleById(roleId.value),
|
|
32
|
-
{ watch: [roleId], immediate: false }
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
watchEffect(() => {
|
|
36
|
-
if (getRoleByIdReq.value) {
|
|
37
|
-
userAppRole.value = getRoleByIdReq.value;
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const id = computed(() => userMemberData.value?.org ?? "id");
|
|
7
|
+
const id = useState<string | null>("memberShipOrgId", () => null);
|
|
42
8
|
|
|
43
9
|
return {
|
|
44
10
|
userAppRole,
|