@eeplatform/nuxt-layer-common 1.5.1 → 1.6.0

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @eeplatform/nuxt-layer-common
2
2
 
3
+ ## 1.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 205e4b2: Section management follow up release
8
+
3
9
  ## 1.5.1
4
10
 
5
11
  ### Patch Changes
@@ -0,0 +1,269 @@
1
+ <template>
2
+ <v-row no-gutters class="pa-4">
3
+ <v-col v-if="localProps.canAdd" cols="12" class="mb-2">
4
+ <v-row no-gutters>
5
+ <v-btn
6
+ class="text-none"
7
+ rounded="pill"
8
+ variant="tonal"
9
+ @click="dialogCreate = true"
10
+ size="large"
11
+ >
12
+ Add Curriculum
13
+ </v-btn>
14
+ </v-row>
15
+ </v-col>
16
+
17
+ <v-col cols="12">
18
+ <v-card width="100%" variant="outlined" border="thin" rounded="lg">
19
+ <v-toolbar density="compact" color="grey-lighten-4">
20
+ <template #prepend>
21
+ <v-btn fab icon density="comfortable" @click="">
22
+ <v-icon>mdi-refresh</v-icon>
23
+ </v-btn>
24
+ </template>
25
+
26
+ <template #append>
27
+ <v-row no-gutters justify="end" align="center">
28
+ <span class="mr-2 text-caption text-fontgray">
29
+ {{ pageRange }}
30
+ </span>
31
+ <local-pagination
32
+ v-model="page"
33
+ :length="pages"
34
+ @update:value=""
35
+ />
36
+ </v-row>
37
+ </template>
38
+ </v-toolbar>
39
+
40
+ <v-data-table
41
+ :headers="headers"
42
+ :items="items"
43
+ item-value="_id"
44
+ items-per-page="20"
45
+ fixed-header
46
+ hide-default-footer
47
+ hide-default-header
48
+ @click:row="tableRowClickHandler"
49
+ style="max-height: calc(100vh - (200px))"
50
+ >
51
+ </v-data-table>
52
+ </v-card>
53
+ </v-col>
54
+
55
+ <!-- dialog -->
56
+ <v-dialog v-model="dialogCreate" persistent width="450">
57
+ <CurriculumForm
58
+ title="Add curriculum"
59
+ :school="school"
60
+ @cancel="dialogCreate = false"
61
+ @success="successHandler()"
62
+ />
63
+ </v-dialog>
64
+
65
+ <v-dialog v-model="dialogView" persistent width="450">
66
+ <CurriculumForm
67
+ title="View curriculum details"
68
+ :school="school"
69
+ @cancel="dialogView = false"
70
+ @edit="handleEdit()"
71
+ @delete="dialogDelete = true"
72
+ :data="curriculum"
73
+ mode="view"
74
+ :can-edit="localProps.canEdit"
75
+ :can-delete="localProps.canDelete"
76
+ />
77
+ </v-dialog>
78
+
79
+ <v-dialog v-model="dialogUpdate" persistent width="450">
80
+ <CurriculumForm
81
+ title="Update curriculum details"
82
+ :school="school"
83
+ @cancel="dialogUpdate = false"
84
+ :data="curriculum"
85
+ mode="edit"
86
+ :can-edit="localProps.canEdit"
87
+ :can-delete="localProps.canDelete"
88
+ />
89
+ </v-dialog>
90
+
91
+ <v-dialog
92
+ v-model="dialogDelete"
93
+ :loading="loadingDelete"
94
+ width="450"
95
+ persistent
96
+ >
97
+ <v-card width="100%">
98
+ <v-toolbar density="compact" class="pl-4">
99
+ <span class="font-weight-medium text-h5">Delete Curriculum</span>
100
+ </v-toolbar>
101
+
102
+ <v-card-text>
103
+ <p class="text-subtitle-2 text-center">
104
+ Are you sure you want to delete this curriculum? This action cannot
105
+ be undone.
106
+ </p>
107
+
108
+ <v-row v-if="message" no-gutters justify="center" class="mt-4">
109
+ <span class="text-caption text-error text-center">
110
+ {{ message }}
111
+ </span>
112
+ </v-row>
113
+ </v-card-text>
114
+
115
+ <v-toolbar density="compact">
116
+ <v-row no-gutters>
117
+ <v-col cols="6">
118
+ <v-btn
119
+ tile
120
+ block
121
+ size="48"
122
+ variant="text"
123
+ class="text-none"
124
+ @click="dialogDelete = false"
125
+ :disabled="loadingDelete"
126
+ >
127
+ Cancel
128
+ </v-btn>
129
+ </v-col>
130
+ <v-col cols="6">
131
+ <v-btn
132
+ tile
133
+ block
134
+ size="48"
135
+ color="black"
136
+ variant="flat"
137
+ class="text-none"
138
+ @click="submitDelete()"
139
+ :loading="loadingDelete"
140
+ >
141
+ Delete Curriculum
142
+ </v-btn>
143
+ </v-col>
144
+ </v-row>
145
+ </v-toolbar>
146
+ </v-card>
147
+ </v-dialog>
148
+ </v-row>
149
+ </template>
150
+
151
+ <script setup lang="ts">
152
+ const localProps = defineProps({
153
+ school: {
154
+ type: String,
155
+ default: "",
156
+ required: true,
157
+ },
158
+ status: {
159
+ type: String,
160
+ default: "active",
161
+ required: true,
162
+ },
163
+ canAdd: {
164
+ type: Boolean,
165
+ default: false,
166
+ },
167
+ canEdit: {
168
+ type: Boolean,
169
+ default: false,
170
+ },
171
+ canDelete: {
172
+ type: Boolean,
173
+ default: false,
174
+ },
175
+ });
176
+
177
+ const school = localProps.school;
178
+
179
+ const headers = [
180
+ {
181
+ title: "Curriculum",
182
+ value: "name",
183
+ },
184
+ {
185
+ title: "Effective School Year",
186
+ value: "effectiveSchoolYear",
187
+ },
188
+ {
189
+ title: "Maximum Teaching Hours Per Day",
190
+ value: "maxTeachingHoursPerDay",
191
+ },
192
+ ];
193
+
194
+ const page = ref(1);
195
+ const pages = ref(0);
196
+ const pageRange = ref("-- - -- of --");
197
+
198
+ const items = ref<Array<Record<string, any>>>([]);
199
+
200
+ const { getAll, deleteById } = useCurriculum();
201
+
202
+ const { data: getCurriculumReq, refresh: refreshCurriculumItems } =
203
+ await useLazyAsyncData(
204
+ `curriculums-page-${page.value}-${localProps.status}-${
205
+ localProps.school ?? "all"
206
+ }`,
207
+ () =>
208
+ getAll({
209
+ page: page.value,
210
+ limit: 20,
211
+ status: localProps.status,
212
+ school: localProps.school,
213
+ }),
214
+ {
215
+ watch: [page, () => localProps.status],
216
+ }
217
+ );
218
+
219
+ watchEffect(() => {
220
+ if (getCurriculumReq.value) {
221
+ items.value = getCurriculumReq.value.items;
222
+ pages.value = getCurriculumReq.value.pages;
223
+ pageRange.value = getCurriculumReq.value.pageRange;
224
+ }
225
+ });
226
+
227
+ const curriculum = ref<TCurriculum>();
228
+
229
+ function tableRowClickHandler(_: any, data: any) {
230
+ dialogView.value = true;
231
+ curriculum.value = data.item;
232
+ }
233
+
234
+ const dialogCreate = ref(false);
235
+ const dialogView = ref(false);
236
+
237
+ function successHandler() {
238
+ dialogCreate.value = false;
239
+ refreshCurriculumItems();
240
+ }
241
+
242
+ const dialogUpdate = ref(false);
243
+
244
+ function handleEdit() {
245
+ dialogView.value = false;
246
+ dialogUpdate.value = true;
247
+ }
248
+
249
+ const dialogDelete = ref(false);
250
+ const loadingDelete = ref(false);
251
+ const message = ref("");
252
+
253
+ async function submitDelete() {
254
+ loadingDelete.value = true;
255
+ message.value = "";
256
+ try {
257
+ if (curriculum.value && curriculum.value._id) {
258
+ await deleteById(curriculum.value._id);
259
+ }
260
+ dialogDelete.value = false;
261
+ dialogView.value = false;
262
+ refreshCurriculumItems();
263
+ } catch (error: any) {
264
+ message.value = error.response._data.message;
265
+ } finally {
266
+ loadingDelete.value = false;
267
+ }
268
+ }
269
+ </script>
@@ -0,0 +1,347 @@
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
+ {{ props.title }}
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
16
+ class="text-capitalize"
17
+ title="Name"
18
+ :required="props.mode === 'create'"
19
+ />
20
+ <v-col cols="12">
21
+ <v-text-field
22
+ v-model="curriculum.name"
23
+ density="comfortable"
24
+ :rules="[requiredRule]"
25
+ :readonly="props.mode === 'view'"
26
+ ></v-text-field>
27
+ </v-col>
28
+ </v-row>
29
+ </v-col>
30
+
31
+ <v-col cols="12" class="mt-2">
32
+ <v-row no-gutters>
33
+ <InputLabel
34
+ class="text-capitalize"
35
+ title="Effective School Year"
36
+ :required="props.mode === 'create'"
37
+ />
38
+ <v-col cols="12">
39
+ <v-autocomplete
40
+ v-model="curriculum.effectiveSchoolYear"
41
+ density="comfortable"
42
+ :rules="[requiredRule]"
43
+ :items="effectiveSchoolYearOptions"
44
+ :readonly="props.mode === 'view'"
45
+ ></v-autocomplete>
46
+ </v-col>
47
+ </v-row>
48
+ </v-col>
49
+
50
+ <v-col cols="12" class="mt-2">
51
+ <v-row no-gutters>
52
+ <InputLabel
53
+ class="text-capitalize"
54
+ title="Max Teaching Hours Per Day"
55
+ :required="props.mode === 'create'"
56
+ />
57
+ <v-col cols="12">
58
+ <v-text-field
59
+ v-model.number="curriculum.maxTeachingHoursPerDay"
60
+ density="comfortable"
61
+ :rules="[
62
+ requiredRule,
63
+ (v) => (v && v <= 8) || 'Must be less than 8 hours',
64
+ ]"
65
+ type="number"
66
+ :readonly="props.mode === 'view'"
67
+ ></v-text-field>
68
+ </v-col>
69
+ </v-row>
70
+ </v-col>
71
+
72
+ <v-col v-if="props.mode === 'create'" cols="12">
73
+ <v-checkbox v-model="createMore" density="comfortable" hide-details>
74
+ <template #label>
75
+ <span class="text-subtitle-2 font-weight-bold">
76
+ Create more
77
+ </span>
78
+ </template>
79
+ </v-checkbox>
80
+ </v-col>
81
+
82
+ <v-col v-if="message" cols="12" class="my-2">
83
+ <v-row no-gutters>
84
+ <v-col cols="12" class="text-center">
85
+ <span
86
+ class="text-none text-subtitle-2 font-weight-medium text-error"
87
+ >
88
+ {{ message }}
89
+ </span>
90
+ </v-col>
91
+ </v-row>
92
+ </v-col>
93
+ </v-row>
94
+ </v-form>
95
+ </v-card-text>
96
+
97
+ <v-toolbar density="compact">
98
+ <v-row no-gutters>
99
+ <v-col
100
+ v-if="modeViewEdit"
101
+ :cols="props.canEdit || props.canDelete ? 6 : 12"
102
+ >
103
+ <v-btn
104
+ tile
105
+ block
106
+ variant="text"
107
+ class="text-none"
108
+ size="48"
109
+ @click="emit('cancel')"
110
+ >
111
+ Close
112
+ </v-btn>
113
+ </v-col>
114
+
115
+ <v-col
116
+ v-if="modeViewEdit && props.canEdit && !props.canDelete"
117
+ :cols="props.canEdit ? 6 : 12"
118
+ >
119
+ <v-btn
120
+ tile
121
+ block
122
+ variant="flat"
123
+ color="black"
124
+ class="text-none"
125
+ size="48"
126
+ @click="emit('cancel')"
127
+ >
128
+ Edit curriculum
129
+ </v-btn>
130
+ </v-col>
131
+
132
+ <v-col
133
+ v-if="modeViewEdit && props.canDelete && !props.canEdit"
134
+ :cols="props.canDelete ? 6 : 12"
135
+ >
136
+ <v-btn
137
+ tile
138
+ block
139
+ variant="flat"
140
+ class="text-none text-error"
141
+ size="48"
142
+ @click="emit('cancel')"
143
+ >
144
+ Delete curriculum
145
+ </v-btn>
146
+ </v-col>
147
+
148
+ <v-col v-if="hasMoreActions" cols="6">
149
+ <v-menu>
150
+ <template #activator="{ props }">
151
+ <v-btn
152
+ block
153
+ variant="flat"
154
+ color="black"
155
+ class="text-none"
156
+ height="48"
157
+ v-bind="props"
158
+ tile
159
+ >
160
+ More actions
161
+ </v-btn>
162
+ </template>
163
+
164
+ <v-list class="pa-0">
165
+ <v-list-item @click="emit('edit')">
166
+ <v-list-item-title class="text-subtitle-2">
167
+ Edit curriculum
168
+ </v-list-item-title>
169
+ </v-list-item>
170
+
171
+ <v-list-item @click="emit('delete')" class="text-red">
172
+ <v-list-item-title class="text-subtitle-2">
173
+ Delete curriculum
174
+ </v-list-item-title>
175
+ </v-list-item>
176
+ </v-list>
177
+ </v-menu>
178
+ </v-col>
179
+
180
+ <v-col v-if="props.mode === 'edit'" cols="6">
181
+ <v-btn
182
+ tile
183
+ block
184
+ variant="flat"
185
+ color="black"
186
+ class="text-none"
187
+ size="48"
188
+ :disabled="!validForm"
189
+ @click="submitUpdate"
190
+ >
191
+ Submit update
192
+ </v-btn>
193
+ </v-col>
194
+
195
+ <v-col v-if="props.mode === 'create'" cols="6">
196
+ <v-btn
197
+ tile
198
+ block
199
+ variant="text"
200
+ class="text-none"
201
+ size="48"
202
+ @click="emit('cancel')"
203
+ >
204
+ Cancel
205
+ </v-btn>
206
+ </v-col>
207
+
208
+ <v-col v-if="props.mode === 'create'" cols="6">
209
+ <v-btn
210
+ tile
211
+ block
212
+ variant="flat"
213
+ color="black"
214
+ class="text-none"
215
+ size="48"
216
+ :disabled="!validForm"
217
+ @click="submit"
218
+ >
219
+ Submit
220
+ </v-btn>
221
+ </v-col>
222
+ </v-row>
223
+ </v-toolbar>
224
+ </v-card>
225
+ </template>
226
+
227
+ <script setup lang="ts">
228
+ const props = defineProps({
229
+ title: {
230
+ type: String,
231
+ default: "Curriculum Form",
232
+ },
233
+ school: {
234
+ type: String,
235
+ default: "",
236
+ },
237
+ mode: {
238
+ type: String,
239
+ default: "create",
240
+ },
241
+ data: {
242
+ type: Object as PropType<TCurriculum>,
243
+ default: () => ({}),
244
+ },
245
+ canEdit: {
246
+ type: Boolean,
247
+ default: false,
248
+ },
249
+ canDelete: {
250
+ type: Boolean,
251
+ default: false,
252
+ },
253
+ });
254
+
255
+ const emit = defineEmits([
256
+ "cancel",
257
+ "edit",
258
+ "delete",
259
+ "success",
260
+ "success:create-more",
261
+ ]);
262
+
263
+ const validForm = ref(false);
264
+
265
+ const curriculum = ref<TCurriculum>({
266
+ name: "",
267
+ effectiveSchoolYear: "",
268
+ maxTeachingHoursPerDay: 0,
269
+ });
270
+
271
+ if (["view", "edit"].includes(props.mode) && props.data) {
272
+ Object.assign(curriculum.value, JSON.parse(JSON.stringify(props.data)));
273
+ }
274
+
275
+ const { generateSchoolYears } = useBasicEdu();
276
+
277
+ const effectiveSchoolYearOptions = computed(() =>
278
+ generateSchoolYears(5, "future")
279
+ );
280
+
281
+ const createMore = ref(false);
282
+ const disable = ref(false);
283
+
284
+ const { requiredRule } = useUtils();
285
+
286
+ const message = ref("");
287
+ const type = defineModel("type", {
288
+ type: String,
289
+ default: "",
290
+ });
291
+
292
+ const { add, updateById } = useCurriculum();
293
+
294
+ async function submit() {
295
+ disable.value = true;
296
+ try {
297
+ await add(curriculum.value);
298
+ if (createMore.value) {
299
+ message.value = "";
300
+ emit("success:create-more");
301
+ return;
302
+ }
303
+
304
+ emit("success");
305
+ } catch (error: any) {
306
+ message.value = error.response._data.message;
307
+ } finally {
308
+ disable.value = false;
309
+ }
310
+ }
311
+
312
+ function cancel() {
313
+ createMore.value = false;
314
+ message.value = "";
315
+ emit("cancel");
316
+ }
317
+
318
+ const modeViewEdit = computed(() => {
319
+ return ["view", "edit"].includes(props.mode);
320
+ });
321
+
322
+ async function submitUpdate() {
323
+ disable.value = true;
324
+ try {
325
+ await updateById(curriculum.value._id ?? "", {
326
+ name: curriculum.value.name,
327
+ effectiveSchoolYear: curriculum.value.effectiveSchoolYear,
328
+ maxTeachingHoursPerDay: curriculum.value.maxTeachingHoursPerDay,
329
+ });
330
+ if (createMore.value) {
331
+ message.value = "";
332
+ emit("success:create-more");
333
+ return;
334
+ }
335
+
336
+ emit("success");
337
+ } catch (error: any) {
338
+ message.value = error.response._data.message;
339
+ } finally {
340
+ disable.value = false;
341
+ }
342
+ }
343
+
344
+ const hasMoreActions = computed(() => {
345
+ return props.mode === "view" && props.canEdit && props.canDelete;
346
+ });
347
+ </script>