@appcorp/fusion-storybook 0.2.39 → 0.2.42
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/base-modules/admission/constants.d.ts +5 -17
- package/base-modules/admission/constants.js +12 -7
- package/base-modules/admission/context/use-admission-module.js +11 -48
- package/base-modules/admission/filter.js +23 -3
- package/base-modules/admission/form.js +49 -19
- package/base-modules/attendance/context.js +3 -37
- package/base-modules/attendance/form.js +26 -10
- package/base-modules/attendance/more-actions.js +34 -25
- package/base-modules/campus/context.js +13 -44
- package/base-modules/class/cache.js +0 -1
- package/base-modules/class/context.js +10 -48
- package/base-modules/class/more-actions.js +0 -2
- package/base-modules/course/context.js +3 -37
- package/base-modules/course/form.js +91 -292
- package/base-modules/discount-code/constants.d.ts +5 -0
- package/base-modules/discount-code/constants.js +5 -0
- package/base-modules/discount-code/context.d.ts +1 -0
- package/base-modules/discount-code/context.js +40 -39
- package/base-modules/discount-code/form.js +21 -15
- package/base-modules/discount-code/more-actions.js +1 -1
- package/base-modules/enrollment/context.js +3 -37
- package/base-modules/enrollment/form.js +38 -11
- package/base-modules/enrollment/more-actions.js +0 -2
- package/base-modules/expense/constants.js +1 -1
- package/base-modules/expense/context.js +5 -32
- package/base-modules/expense/filter.js +50 -3
- package/base-modules/expense/form.js +82 -6
- package/base-modules/family/context.js +7 -38
- package/base-modules/family-member/context.js +7 -39
- package/base-modules/fee-structure/context.js +1 -25
- package/base-modules/fee-structure/form.js +77 -89
- package/base-modules/fee-structure/more-actions.js +0 -2
- package/base-modules/rbac/context.d.ts +1 -0
- package/base-modules/rbac/context.js +23 -32
- package/base-modules/school/context.js +1 -1
- package/base-modules/school/form.js +34 -14
- package/base-modules/section/context.d.ts +1 -0
- package/base-modules/section/context.js +40 -47
- package/base-modules/section/form.js +25 -80
- package/base-modules/section/more-actions.js +0 -2
- package/base-modules/section/view.js +9 -7
- package/base-modules/student-fee/context/use-student-fee-module.d.ts +1 -0
- package/base-modules/student-fee/context/use-student-fee-module.js +48 -32
- package/base-modules/student-fee/context.d.ts +1 -1
- package/base-modules/student-fee/context.js +1 -1
- package/base-modules/student-fee/filter.js +23 -3
- package/base-modules/student-fee/form.js +93 -174
- package/base-modules/student-fee/view.d.ts +7 -1
- package/base-modules/student-fee/view.js +17 -20
- package/base-modules/student-profile/constants.d.ts +0 -6
- package/base-modules/student-profile/constants.js +1 -3
- package/base-modules/student-profile/context/use-student-profile-module.d.ts +1 -0
- package/base-modules/student-profile/context/use-student-profile-module.js +62 -55
- package/base-modules/student-profile/context.d.ts +1 -1
- package/base-modules/student-profile/context.js +1 -1
- package/base-modules/student-profile/filter.js +23 -3
- package/base-modules/student-profile/form.js +35 -3
- package/base-modules/subject/context.d.ts +1 -0
- package/base-modules/subject/context.js +38 -47
- package/base-modules/subject/more-actions.js +0 -2
- package/base-modules/teacher/constants.d.ts +0 -6
- package/base-modules/teacher/constants.js +0 -2
- package/base-modules/teacher/context.d.ts +1 -0
- package/base-modules/teacher/context.js +58 -39
- package/base-modules/teacher/form.js +46 -11
- package/base-modules/teacher/more-actions.js +0 -2
- package/base-modules/user/context/use-user-module.d.ts +1 -0
- package/base-modules/user/context/use-user-module.js +36 -32
- package/base-modules/user/context.js +1 -1
- package/base-modules/user/filter.js +6 -4
- package/base-modules/user/form.js +29 -5
- package/base-modules/user/more-actions.js +9 -7
- package/base-modules/user/view.js +3 -1
- package/base-modules/workspace/form.js +18 -8
- package/base-modules/workspace-user/context.d.ts +2 -1
- package/base-modules/workspace-user/context.js +31 -29
- package/package.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/base-modules/admission/cache.d.ts +0 -14
- package/base-modules/admission/cache.js +0 -31
- package/base-modules/attendance/cache.d.ts +0 -14
- package/base-modules/attendance/cache.js +0 -31
- package/base-modules/campus/cache.d.ts +0 -14
- package/base-modules/campus/cache.js +0 -31
- package/base-modules/course/cache.d.ts +0 -14
- package/base-modules/course/cache.js +0 -31
- package/base-modules/enrollment/cache.d.ts +0 -14
- package/base-modules/enrollment/cache.js +0 -31
- package/base-modules/expense/cache.d.ts +0 -14
- package/base-modules/expense/cache.js +0 -31
- package/base-modules/family/cache.d.ts +0 -14
- package/base-modules/family/cache.js +0 -31
- package/base-modules/family-member/cache.d.ts +0 -14
- package/base-modules/family-member/cache.js +0 -31
- package/base-modules/rbac/cache.d.ts +0 -27
- package/base-modules/rbac/cache.js +0 -46
- package/base-modules/student-fee/cache.d.ts +0 -15
- package/base-modules/student-fee/cache.js +0 -21
- package/base-modules/workspace-user/cache.d.ts +0 -14
- package/base-modules/workspace-user/cache.js +0 -31
|
@@ -8,13 +8,9 @@ import { generateThemeToast, TOAST_VARIANT, } from "@appcorp/shadcn/lib/toast-ut
|
|
|
8
8
|
import { STUDENT_STATUS } from "../../../type";
|
|
9
9
|
import { formatNumber } from "@react-pakistan/util-functions/general/format-number";
|
|
10
10
|
import { formatPhoneDisplay } from "@react-pakistan/util-functions/general/format-phone-display";
|
|
11
|
-
import { STUDENT_PROFILE_API_ROUTES
|
|
11
|
+
import { STUDENT_PROFILE_API_ROUTES } from "../constants";
|
|
12
12
|
import { studentProfileFormValidation } from "../validate";
|
|
13
|
-
import { getCachedStudentProfiles, invalidateStudentProfilesCache, } from "../cache";
|
|
14
13
|
import { getCachedWorkspaceSync } from "../../workspace/cache";
|
|
15
|
-
import { invalidateFamiliesCache } from "../../family/cache";
|
|
16
|
-
import { invalidateFamilyMembersCache } from "../../family-member/cache";
|
|
17
|
-
import { invalidateAdmissionsCache } from "../../admission/cache";
|
|
18
14
|
import { useStudentProfileContext, STUDENT_PROFILE_ACTION_TYPES, STUDENT_PROFILE_DRAWER, } from "./module-base";
|
|
19
15
|
export const useStudentProfileModule = () => {
|
|
20
16
|
var _a;
|
|
@@ -71,12 +67,6 @@ export const useStudentProfileModule = () => {
|
|
|
71
67
|
]);
|
|
72
68
|
const byIdParams = useMemo(() => ({ id: state.id }), [state.id]);
|
|
73
69
|
const deleteParams = useMemo(() => ({ id: state.id }), [state.id]);
|
|
74
|
-
const isDefaultListState = state.currentPage === 1 &&
|
|
75
|
-
state.pageLimit === pageLimit &&
|
|
76
|
-
!debouncedQuery &&
|
|
77
|
-
state.filterEnabled === undefined &&
|
|
78
|
-
!state.filterGender &&
|
|
79
|
-
!state.filterStatus;
|
|
80
70
|
const showToast = useCallback((description, variant) => {
|
|
81
71
|
generateThemeToast({
|
|
82
72
|
description,
|
|
@@ -99,6 +89,46 @@ export const useStudentProfileModule = () => {
|
|
|
99
89
|
payload: { drawer: null },
|
|
100
90
|
});
|
|
101
91
|
}, [dispatch]);
|
|
92
|
+
const resetRecordFormState = useCallback(() => {
|
|
93
|
+
dispatch({
|
|
94
|
+
type: STUDENT_PROFILE_ACTION_TYPES.SET_ERRORS,
|
|
95
|
+
payload: { errors: {} },
|
|
96
|
+
});
|
|
97
|
+
dispatch({
|
|
98
|
+
type: STUDENT_PROFILE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
|
|
99
|
+
payload: { disabled: false },
|
|
100
|
+
});
|
|
101
|
+
dispatch({
|
|
102
|
+
type: STUDENT_PROFILE_ACTION_TYPES.SET_FORM_DATA,
|
|
103
|
+
payload: {
|
|
104
|
+
form: {
|
|
105
|
+
address: null,
|
|
106
|
+
avatar: null,
|
|
107
|
+
bloodGroup: null,
|
|
108
|
+
city: null,
|
|
109
|
+
country: null,
|
|
110
|
+
dateOfBirth: null,
|
|
111
|
+
email: null,
|
|
112
|
+
emergencyPhone: null,
|
|
113
|
+
enabled: true,
|
|
114
|
+
familyMemberId: "",
|
|
115
|
+
filterEnabled: undefined,
|
|
116
|
+
filterGender: undefined,
|
|
117
|
+
filterStatus: undefined,
|
|
118
|
+
firstName: "",
|
|
119
|
+
gender: null,
|
|
120
|
+
id: "",
|
|
121
|
+
lastName: "",
|
|
122
|
+
phone: null,
|
|
123
|
+
postalCode: null,
|
|
124
|
+
remarks: null,
|
|
125
|
+
state: null,
|
|
126
|
+
status: STUDENT_STATUS.ACTIVE,
|
|
127
|
+
studentCode: "",
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}, [dispatch]);
|
|
102
132
|
const listCallback = useCallback(({ data, error }) => {
|
|
103
133
|
var _a, _b;
|
|
104
134
|
if (error) {
|
|
@@ -121,9 +151,6 @@ export const useStudentProfileModule = () => {
|
|
|
121
151
|
}
|
|
122
152
|
if (data) {
|
|
123
153
|
const isCreated = isCreatedOrUpdated(data);
|
|
124
|
-
invalidateStudentProfilesCache();
|
|
125
|
-
invalidateFamiliesCache();
|
|
126
|
-
invalidateFamilyMembersCache();
|
|
127
154
|
showToast(isCreated ? t("messagesCreateSuccess") : t("messagesSaveSuccess"), TOAST_VARIANT.SUCCESS);
|
|
128
155
|
resetFormAndCloseDrawer();
|
|
129
156
|
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
@@ -176,7 +203,6 @@ export const useStudentProfileModule = () => {
|
|
|
176
203
|
return;
|
|
177
204
|
}
|
|
178
205
|
if (data) {
|
|
179
|
-
invalidateStudentProfilesCache();
|
|
180
206
|
showToast(t("messagesDeleteSuccess"), TOAST_VARIANT.SUCCESS);
|
|
181
207
|
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
182
208
|
}
|
|
@@ -223,21 +249,23 @@ export const useStudentProfileModule = () => {
|
|
|
223
249
|
});
|
|
224
250
|
}, [dispatch]);
|
|
225
251
|
const handleView = useCallback((row) => {
|
|
252
|
+
resetRecordFormState();
|
|
226
253
|
byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
|
|
227
254
|
dispatch({
|
|
228
255
|
type: STUDENT_PROFILE_ACTION_TYPES.SET_DRAWER,
|
|
229
256
|
payload: { drawer: STUDENT_PROFILE_DRAWER.VIEW_DRAWER },
|
|
230
257
|
});
|
|
231
|
-
}, [byIdFetchNow, dispatch]);
|
|
258
|
+
}, [byIdFetchNow, dispatch, resetRecordFormState]);
|
|
232
259
|
const handleEdit = useCallback((row) => {
|
|
260
|
+
resetRecordFormState();
|
|
233
261
|
byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
|
|
234
262
|
dispatch({
|
|
235
263
|
type: STUDENT_PROFILE_ACTION_TYPES.SET_DRAWER,
|
|
236
264
|
payload: { drawer: STUDENT_PROFILE_DRAWER.FORM_DRAWER },
|
|
237
265
|
});
|
|
238
|
-
}, [byIdFetchNow, dispatch]);
|
|
266
|
+
}, [byIdFetchNow, dispatch, resetRecordFormState]);
|
|
239
267
|
const handleDelete = useCallback((row) => {
|
|
240
|
-
if (!confirm(t("
|
|
268
|
+
if (!confirm(t("messagesDeleteConfirmation")))
|
|
241
269
|
return;
|
|
242
270
|
deleteFetchNow === null || deleteFetchNow === void 0 ? void 0 : deleteFetchNow(undefined, {
|
|
243
271
|
body: JSON.stringify({ id: row === null || row === void 0 ? void 0 : row.id }),
|
|
@@ -335,10 +363,6 @@ export const useStudentProfileModule = () => {
|
|
|
335
363
|
type: STUDENT_PROFILE_ACTION_TYPES.SET_INPUT_FIELD,
|
|
336
364
|
payload: { key: "enabled", value: false },
|
|
337
365
|
});
|
|
338
|
-
invalidateStudentProfilesCache();
|
|
339
|
-
invalidateFamiliesCache();
|
|
340
|
-
invalidateFamilyMembersCache();
|
|
341
|
-
invalidateAdmissionsCache();
|
|
342
366
|
}, [dispatch, t]);
|
|
343
367
|
const handleReAdmitStudent = useCallback(async (row) => {
|
|
344
368
|
var _a;
|
|
@@ -354,10 +378,6 @@ export const useStudentProfileModule = () => {
|
|
|
354
378
|
body: JSON.stringify({ studentProfileId: row === null || row === void 0 ? void 0 : row.id }),
|
|
355
379
|
});
|
|
356
380
|
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
357
|
-
invalidateStudentProfilesCache();
|
|
358
|
-
invalidateFamiliesCache();
|
|
359
|
-
invalidateFamilyMembersCache();
|
|
360
|
-
invalidateAdmissionsCache();
|
|
361
381
|
if (data) {
|
|
362
382
|
showToast(t("messagesReAdmitSuccess"), TOAST_VARIANT.SUCCESS);
|
|
363
383
|
}
|
|
@@ -395,19 +415,19 @@ export const useStudentProfileModule = () => {
|
|
|
395
415
|
{
|
|
396
416
|
enabled: false,
|
|
397
417
|
handleOnClick: handleMoreActions,
|
|
398
|
-
label: t("
|
|
418
|
+
label: t("actionsButtonMoreActions"),
|
|
399
419
|
order: 1,
|
|
400
420
|
},
|
|
401
421
|
{
|
|
402
422
|
enabled: true,
|
|
403
423
|
handleOnClick: handleFilters,
|
|
404
|
-
label: t("
|
|
424
|
+
label: t("actionsButtonFilters"),
|
|
405
425
|
order: 2,
|
|
406
426
|
},
|
|
407
427
|
{
|
|
408
428
|
enabled: false,
|
|
409
429
|
handleOnClick: handleCreate,
|
|
410
|
-
label: t("
|
|
430
|
+
label: t("actionsButtonAddStudentProfile"),
|
|
411
431
|
order: 3,
|
|
412
432
|
},
|
|
413
433
|
], [handleCreate, handleFilters, handleMoreActions, t]);
|
|
@@ -415,32 +435,32 @@ export const useStudentProfileModule = () => {
|
|
|
415
435
|
{
|
|
416
436
|
enabled: true,
|
|
417
437
|
handleOnClick: handleView,
|
|
418
|
-
label: t("
|
|
438
|
+
label: t("actionsButtonView"),
|
|
419
439
|
order: 1,
|
|
420
440
|
},
|
|
421
441
|
{
|
|
422
442
|
enabled: true,
|
|
423
443
|
handleOnClick: handleEdit,
|
|
424
|
-
label: t("
|
|
444
|
+
label: t("actionsButtonEdit"),
|
|
425
445
|
order: 2,
|
|
426
446
|
},
|
|
427
447
|
{
|
|
428
448
|
enabled: false,
|
|
429
449
|
handleOnClick: handleDelete,
|
|
430
|
-
label: t("
|
|
450
|
+
label: t("actionsButtonDelete"),
|
|
431
451
|
order: 3,
|
|
432
452
|
},
|
|
433
453
|
{
|
|
434
454
|
enabled: (row) => (row === null || row === void 0 ? void 0 : row.status) === STUDENT_STATUS.ACTIVE,
|
|
435
455
|
handleOnClick: handleWithdrawStudent,
|
|
436
|
-
label: t("
|
|
456
|
+
label: t("actionsButtonWithdrawStudent"),
|
|
437
457
|
order: 4,
|
|
438
458
|
variant: "destructive",
|
|
439
459
|
},
|
|
440
460
|
{
|
|
441
461
|
enabled: (row) => (row === null || row === void 0 ? void 0 : row.status) === STUDENT_STATUS.INACTIVE,
|
|
442
462
|
handleOnClick: handleReAdmitStudent,
|
|
443
|
-
label: t("
|
|
463
|
+
label: t("actionsButtonReAdmitStudent"),
|
|
444
464
|
order: 5,
|
|
445
465
|
},
|
|
446
466
|
], [
|
|
@@ -451,32 +471,18 @@ export const useStudentProfileModule = () => {
|
|
|
451
471
|
handleReAdmitStudent,
|
|
452
472
|
t,
|
|
453
473
|
]);
|
|
474
|
+
// ============================================================================
|
|
475
|
+
// 1.4.9 EFFECTS
|
|
476
|
+
// ============================================================================
|
|
477
|
+
useEffect(() => {
|
|
478
|
+
listFetchNowRef.current = listFetchNow;
|
|
479
|
+
}, [listFetchNow]);
|
|
454
480
|
useEffect(() => {
|
|
455
481
|
var _a;
|
|
456
482
|
if (!schoolId)
|
|
457
483
|
return;
|
|
458
|
-
if (isDefaultListState) {
|
|
459
|
-
(async () => {
|
|
460
|
-
try {
|
|
461
|
-
const { count, items } = await getCachedStudentProfiles({
|
|
462
|
-
params: listParams,
|
|
463
|
-
});
|
|
464
|
-
dispatch({
|
|
465
|
-
type: STUDENT_PROFILE_ACTION_TYPES.SET_ITEMS,
|
|
466
|
-
payload: { items: items || [], count: count || 0 },
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
catch (_a) {
|
|
470
|
-
showToast(t("messagesFetchFailed"), TOAST_VARIANT.ERROR);
|
|
471
|
-
}
|
|
472
|
-
})();
|
|
473
|
-
return;
|
|
474
|
-
}
|
|
475
484
|
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
476
|
-
}, [dispatch,
|
|
477
|
-
useEffect(() => {
|
|
478
|
-
listFetchNowRef.current = listFetchNow;
|
|
479
|
-
}, [listFetchNow]);
|
|
485
|
+
}, [dispatch, listParams, schoolId, showToast, t]);
|
|
480
486
|
return Object.assign(Object.assign({}, context), { applyFilters,
|
|
481
487
|
byIdLoading,
|
|
482
488
|
clearFilters,
|
|
@@ -500,6 +506,7 @@ export const useStudentProfileModule = () => {
|
|
|
500
506
|
headerActions,
|
|
501
507
|
listFetchNow,
|
|
502
508
|
listLoading,
|
|
509
|
+
resetRecordFormState,
|
|
503
510
|
rowActions,
|
|
504
511
|
toggleStatus,
|
|
505
512
|
updateLoading });
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Key responsibilities:
|
|
9
9
|
* - Expose `useStudentProfileModule()` which UI components call for actions
|
|
10
10
|
* - Keep module-specific `apiParams` and callbacks in one place
|
|
11
|
-
* - Ensure
|
|
11
|
+
* - Ensure toast notifications on mutation
|
|
12
12
|
*
|
|
13
13
|
* Exported utilities:
|
|
14
14
|
* - `StudentProfileProvider` — provider component used by the page
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Key responsibilities:
|
|
10
10
|
* - Expose `useStudentProfileModule()` which UI components call for actions
|
|
11
11
|
* - Keep module-specific `apiParams` and callbacks in one place
|
|
12
|
-
* - Ensure
|
|
12
|
+
* - Ensure toast notifications on mutation
|
|
13
13
|
*
|
|
14
14
|
* Exported utilities:
|
|
15
15
|
* - `StudentProfileProvider` — provider component used by the page
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { EnhancedRadio } from "@appcorp/shadcn/components/enhanced-radio";
|
|
4
|
-
import {
|
|
4
|
+
import { useEnhancedCombobox } from "@appcorp/shadcn/hooks/use-enhanced-combobox";
|
|
5
5
|
import { useTranslations } from "next-intl";
|
|
6
6
|
import { useStudentProfileModule } from "./context";
|
|
7
|
-
import { STATUS_OPTIONS } from "./constants";
|
|
7
|
+
import { STATUS_OPTIONS, STUDENT_PROFILE_API_ROUTES } from "./constants";
|
|
8
8
|
export const StudentProfileFilter = () => {
|
|
9
9
|
const t = useTranslations("studentProfile");
|
|
10
10
|
const context = useStudentProfileModule();
|
|
@@ -15,7 +15,27 @@ export const StudentProfileFilter = () => {
|
|
|
15
15
|
: filterEnabled
|
|
16
16
|
? "true"
|
|
17
17
|
: "false";
|
|
18
|
-
|
|
18
|
+
const statusLabelMap = {
|
|
19
|
+
ACTIVE: t("formOptionActive"),
|
|
20
|
+
INACTIVE: t("formOptionInactive"),
|
|
21
|
+
GRADUATED: t("formOptionGraduated"),
|
|
22
|
+
TRANSFERRED: t("formOptionTransferred"),
|
|
23
|
+
EXPELLED: t("formOptionExpelled"),
|
|
24
|
+
};
|
|
25
|
+
const { enhancedComboboxElement: filterStatusCombo } = useEnhancedCombobox({
|
|
26
|
+
id: "filterStatus",
|
|
27
|
+
label: t("filterOptionStatus"),
|
|
28
|
+
info: t("filterByStudentStatus"),
|
|
29
|
+
options: [...STATUS_OPTIONS].map((opt) => ({
|
|
30
|
+
id: opt.value,
|
|
31
|
+
name: statusLabelMap[opt.value] || opt.label,
|
|
32
|
+
})),
|
|
33
|
+
value: "filterStatus",
|
|
34
|
+
onValueChange: (value) => handleChange("filterStatus", value),
|
|
35
|
+
searchEndpoint: STUDENT_PROFILE_API_ROUTES.UNIT,
|
|
36
|
+
placeholder: "",
|
|
37
|
+
});
|
|
38
|
+
return (_jsx("div", { className: "space-y-4", children: _jsxs("div", { className: "grid grid-cols-1 gap-4", children: [filterStatusCombo, _jsx(EnhancedRadio, { label: t("filterOptionEnabled"), name: "filterEnabled", value: filterEnabledValue, options: [
|
|
19
39
|
{ label: t("filterOptionAll"), value: "undefined" },
|
|
20
40
|
{ label: t("filterOptionEnabled"), value: "true" },
|
|
21
41
|
{ label: t("filterOptionDisabled"), value: "false" },
|
|
@@ -1,19 +1,51 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { EnhancedInput } from "@appcorp/shadcn/components/enhanced-input";
|
|
4
|
-
import { EnhancedCombobox } from "@appcorp/shadcn/components/enhanced-combobox";
|
|
5
4
|
import { EnhancedCheckbox } from "@appcorp/shadcn/components/enhanced-checkbox";
|
|
6
5
|
import { EnhancedTextarea } from "@appcorp/shadcn/components/enhanced-textarea";
|
|
6
|
+
import { useEnhancedCombobox } from "@appcorp/shadcn/hooks/use-enhanced-combobox";
|
|
7
7
|
import { useTranslations } from "next-intl";
|
|
8
8
|
import { useStudentProfileModule } from "./context";
|
|
9
|
-
import { STATUS_OPTIONS, GENDER_OPTIONS } from "./constants";
|
|
9
|
+
import { STATUS_OPTIONS, GENDER_OPTIONS, STUDENT_PROFILE_API_ROUTES, } from "./constants";
|
|
10
10
|
export const StudentProfileForm = () => {
|
|
11
11
|
const t = useTranslations("studentProfile");
|
|
12
|
+
const genderLabelMap = {
|
|
13
|
+
MALE: t("formOptionMale"),
|
|
14
|
+
FEMALE: t("formOptionFemale"),
|
|
15
|
+
OTHER: t("formOptionOther"),
|
|
16
|
+
};
|
|
12
17
|
const context = useStudentProfileModule();
|
|
13
18
|
const { address, city, country, dateOfBirth, emergencyPhone, enabled, errors, firstName, gender, lastName, phone, postalCode, remarks, status, } = context.state;
|
|
14
19
|
const stateValue = context.state.state;
|
|
15
20
|
const { handleChange } = context;
|
|
21
|
+
const { enhancedComboboxElement: genderCombo } = useEnhancedCombobox({
|
|
22
|
+
id: "gender",
|
|
23
|
+
info: t("formGenderPlaceholder"),
|
|
24
|
+
label: t("formGenderLabel"),
|
|
25
|
+
onValueChange: (value) => handleChange("gender", value),
|
|
26
|
+
options: GENDER_OPTIONS.map((opt) => ({
|
|
27
|
+
id: opt.value,
|
|
28
|
+
name: genderLabelMap[opt.value] || opt.label,
|
|
29
|
+
})),
|
|
30
|
+
placeholder: "",
|
|
31
|
+
searchEndpoint: STUDENT_PROFILE_API_ROUTES.UNIT,
|
|
32
|
+
value: gender,
|
|
33
|
+
});
|
|
34
|
+
const { enhancedComboboxElement: statusCombo } = useEnhancedCombobox({
|
|
35
|
+
id: "status",
|
|
36
|
+
info: t("formStudentStatusPlaceholder"),
|
|
37
|
+
label: t("formOptionStatus"),
|
|
38
|
+
onValueChange: (value) => handleChange("status", value),
|
|
39
|
+
options: STATUS_OPTIONS.map((opt) => ({
|
|
40
|
+
id: opt.value,
|
|
41
|
+
name: opt.label,
|
|
42
|
+
})),
|
|
43
|
+
placeholder: "",
|
|
44
|
+
required: true,
|
|
45
|
+
searchEndpoint: STUDENT_PROFILE_API_ROUTES.UNIT,
|
|
46
|
+
value: status,
|
|
47
|
+
});
|
|
16
48
|
return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: t("formSectionPersonalInformation") }), _jsxs("div", { className: "grid grid-cols-1 gap-4", children: [_jsx(EnhancedInput, { error: errors.firstName, id: "firstName", info: t("formStudentsFirstNamePlaceholder"), label: t("formFirstNameLabel"), onChange: (e) => handleChange("firstName", e.target.value), placeholder: t("formFirstNamePlaceholder"), required: true, value: firstName }), _jsx(EnhancedInput, { error: errors.lastName, id: "lastName", info: t("formStudentsLastNamePlaceholder"), label: t("formLastNameLabel"), onChange: (e) => handleChange("lastName", e.target.value), placeholder: t("formLastNamePlaceholder"), required: true, value: lastName }), _jsx(EnhancedInput, { error: errors.dateOfBirth, id: "dateOfBirth", info: t("formDateOfBirthPlaceholder"), label: t("formDateOfBirthLabel"), onChange: (e) => handleChange("dateOfBirth", e.target.value), onClick: (e) => { var _a, _b; return (_b = (_a = e.currentTarget).showPicker) === null || _b === void 0 ? void 0 : _b.call(_a); }, type: "date", value: dateOfBirth
|
|
17
49
|
? new Date(dateOfBirth).toISOString().split("formTLabel")[0]
|
|
18
|
-
: "" }),
|
|
50
|
+
: "" }), genderCombo] })] }), _jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: t("formSectionContactInformation") }), _jsxs("div", { className: "grid grid-cols-1 gap-4", children: [_jsx(EnhancedInput, { error: errors.phone, id: "phone", info: t("formStudentsPhoneNumberPlaceholder"), label: t("formPhoneLabel"), onChange: (e) => handleChange("phone", e.target.value), placeholder: t("formPhonePlaceholder"), type: "tel", value: phone || "" }), _jsx(EnhancedInput, { error: errors.emergencyPhone, id: "emergencyPhone", info: t("formStudentsEmergencyPhoneNumberPlaceholder"), label: t("formEmergencyPhoneLabel"), onChange: (e) => handleChange("emergencyPhone", e.target.value), placeholder: t("formEmergencyPhonePlaceholder"), type: "tel", value: emergencyPhone || "" })] }), _jsx(EnhancedInput, { error: errors.address, id: "address", info: t("formStudentsAddressPlaceholder"), label: t("formAddressLabel"), onChange: (e) => handleChange("address", e.target.value), placeholder: t("formAddressPlaceholder"), value: address || "" }), _jsxs("div", { className: "grid grid-cols-1 gap-4", children: [_jsx(EnhancedInput, { error: errors.city, id: "city", info: t("formStudentsCityPlaceholder"), label: t("formCityLabel"), onChange: (e) => handleChange("city", e.target.value), placeholder: t("formCityPlaceholder"), value: city || "" }), _jsx(EnhancedInput, { error: errors.state, id: "state", info: t("formStudentsStateOrProvincePlaceholder"), label: t("formStateProvinceLabel"), onChange: (e) => handleChange("state", e.target.value), placeholder: t("formStatePlaceholder"), value: stateValue || "" }), _jsx(EnhancedInput, { error: errors.country, id: "country", info: t("formStudentsCountryPlaceholder"), label: t("formCountryLabel"), onChange: (e) => handleChange("country", e.target.value), placeholder: t("formCountryPlaceholder"), value: country || "" }), _jsx(EnhancedInput, { error: errors.postalCode, id: "postalCode", info: t("formStudentsPostalCodePlaceholder"), label: t("formPostalCodeLabel"), onChange: (e) => handleChange("postalCode", e.target.value), placeholder: t("formPostalCodePlaceholder"), value: postalCode || "" })] })] }), _jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: t("formSectionAcademicInformation") }), _jsxs("div", { className: "grid grid-cols-1 gap-4", children: [statusCombo, _jsx(EnhancedTextarea, { error: errors.remarks, id: "remarks", info: t("formAnyAdditionalRemarksPlaceholder"), label: t("formRemarksLabel"), onChange: (e) => handleChange("remarks", e.target.value), placeholder: t("formRemarksPlaceholder"), rows: 4, value: remarks || "" })] }), _jsx(EnhancedCheckbox, { checked: enabled, info: t("actionToggleActivateOrDeactivate"), label: t("formActiveStudentLabel"), onCheckedChange: (checked) => handleChange("enabled", checked) })] })] }));
|
|
19
51
|
};
|
|
@@ -127,6 +127,7 @@ export declare const useSubjectModule: () => {
|
|
|
127
127
|
icon: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
|
|
128
128
|
}[];
|
|
129
129
|
listLoading: boolean;
|
|
130
|
+
resetRecordFormState: () => void;
|
|
130
131
|
rowActions: RowAction[];
|
|
131
132
|
updateLoading: boolean;
|
|
132
133
|
handleCloseDrawer?: () => void;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Key responsibilities:
|
|
11
11
|
* - expose `useSubjectModule()` which UI components call for actions
|
|
12
12
|
* - keep the module-specific `apiParams` and callbacks in one place
|
|
13
|
-
* - ensure
|
|
13
|
+
* - ensure toast notifications on mutation
|
|
14
14
|
*
|
|
15
15
|
* Exported utilities:
|
|
16
16
|
* - `SubjectProvider` — provider component used by the page
|
|
@@ -25,7 +25,6 @@ import { useDebounce } from "@react-pakistan/util-functions/hooks/use-debounce";
|
|
|
25
25
|
import { createGenericModule } from "@react-pakistan/util-functions/factory/generic-module-factory";
|
|
26
26
|
import { DRAWER_TYPES } from "@react-pakistan/util-functions/factory/generic-component-factory";
|
|
27
27
|
import { SUBJECT_API_ROUTES, pageLimit } from "./constants";
|
|
28
|
-
import { getCachedSubjects, invalidateSubjectsCache } from "./cache";
|
|
29
28
|
import { subjectFormValidation } from "./validate";
|
|
30
29
|
import { generateThemeToast, TOAST_VARIANT, } from "@appcorp/shadcn/lib/toast-utils";
|
|
31
30
|
import { useTheme } from "next-themes";
|
|
@@ -87,10 +86,6 @@ export const useSubjectModule = () => {
|
|
|
87
86
|
const workspace = getCachedWorkspaceSync();
|
|
88
87
|
const listFetchNowRef = useRef(null);
|
|
89
88
|
const debouncedQuery = useDebounce(state.searchQuery, 800);
|
|
90
|
-
// ============================================================================
|
|
91
|
-
// CACHE MANAGEMENT
|
|
92
|
-
// ============================================================================
|
|
93
|
-
// Load cached data synchronously to prevent UI blocking
|
|
94
89
|
const schoolId = ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "";
|
|
95
90
|
// ============================================================================
|
|
96
91
|
// API PARAMETERS
|
|
@@ -139,6 +134,30 @@ export const useSubjectModule = () => {
|
|
|
139
134
|
payload: { drawer: null },
|
|
140
135
|
});
|
|
141
136
|
}, [dispatch]);
|
|
137
|
+
const resetRecordFormState = useCallback(() => {
|
|
138
|
+
dispatch({
|
|
139
|
+
type: SUBJECT_ACTION_TYPES.SET_ERRORS,
|
|
140
|
+
payload: { errors: {} },
|
|
141
|
+
});
|
|
142
|
+
dispatch({
|
|
143
|
+
type: SUBJECT_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
|
|
144
|
+
payload: { disabled: false },
|
|
145
|
+
});
|
|
146
|
+
dispatch({
|
|
147
|
+
type: SUBJECT_ACTION_TYPES.SET_FORM_DATA,
|
|
148
|
+
payload: {
|
|
149
|
+
form: {
|
|
150
|
+
code: "",
|
|
151
|
+
description: "",
|
|
152
|
+
enabled: true,
|
|
153
|
+
filterEnabled: undefined,
|
|
154
|
+
id: "",
|
|
155
|
+
name: "",
|
|
156
|
+
schoolId,
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
}, [dispatch, schoolId]);
|
|
142
161
|
// ============================================================================
|
|
143
162
|
// API CALLBACKS
|
|
144
163
|
// ============================================================================
|
|
@@ -165,7 +184,6 @@ export const useSubjectModule = () => {
|
|
|
165
184
|
}
|
|
166
185
|
if (data) {
|
|
167
186
|
showToast(t("messagesSaveSuccess"), TOAST_VARIANT.SUCCESS);
|
|
168
|
-
invalidateSubjectsCache();
|
|
169
187
|
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
170
188
|
resetFormAndCloseDrawer();
|
|
171
189
|
}
|
|
@@ -193,7 +211,6 @@ export const useSubjectModule = () => {
|
|
|
193
211
|
}
|
|
194
212
|
if (data) {
|
|
195
213
|
showToast(t("messagesDeleteSuccess"), TOAST_VARIANT.SUCCESS);
|
|
196
|
-
invalidateSubjectsCache();
|
|
197
214
|
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
198
215
|
}
|
|
199
216
|
}, [showToast, t]);
|
|
@@ -271,19 +288,21 @@ export const useSubjectModule = () => {
|
|
|
271
288
|
});
|
|
272
289
|
}, [dispatch]);
|
|
273
290
|
const handleView = useCallback((row) => {
|
|
291
|
+
resetRecordFormState();
|
|
274
292
|
byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
|
|
275
293
|
dispatch({
|
|
276
294
|
type: SUBJECT_ACTION_TYPES.SET_DRAWER,
|
|
277
295
|
payload: { drawer: SUBJECT_DRAWER.VIEW_DRAWER },
|
|
278
296
|
});
|
|
279
|
-
}, [dispatch,
|
|
297
|
+
}, [byIdFetchNow, dispatch, resetRecordFormState]);
|
|
280
298
|
const handleEdit = useCallback((row) => {
|
|
299
|
+
resetRecordFormState();
|
|
281
300
|
byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
|
|
282
301
|
dispatch({
|
|
283
302
|
type: SUBJECT_ACTION_TYPES.SET_DRAWER,
|
|
284
303
|
payload: { drawer: SUBJECT_DRAWER.FORM_DRAWER },
|
|
285
304
|
});
|
|
286
|
-
}, [dispatch,
|
|
305
|
+
}, [byIdFetchNow, dispatch, resetRecordFormState]);
|
|
287
306
|
const handleDelete = useCallback((row) => {
|
|
288
307
|
if (!confirm(t("messagesDeleteConfirmation")))
|
|
289
308
|
return;
|
|
@@ -355,21 +374,21 @@ export const useSubjectModule = () => {
|
|
|
355
374
|
{
|
|
356
375
|
enabled: true,
|
|
357
376
|
handleOnClick: handleMoreActions,
|
|
358
|
-
label: t("
|
|
377
|
+
label: t("actionsButtonMoreActions"),
|
|
359
378
|
order: 0,
|
|
360
379
|
icon: MoreHorizontal,
|
|
361
380
|
},
|
|
362
381
|
{
|
|
363
382
|
enabled: true,
|
|
364
383
|
handleOnClick: handleFilters,
|
|
365
|
-
label: t("
|
|
384
|
+
label: t("actionsButtonFilters"),
|
|
366
385
|
order: 2,
|
|
367
386
|
icon: Filter,
|
|
368
387
|
},
|
|
369
388
|
{
|
|
370
389
|
enabled: true,
|
|
371
390
|
handleOnClick: handleCreate,
|
|
372
|
-
label: t("
|
|
391
|
+
label: t("actionsButtonAdd"),
|
|
373
392
|
order: 3,
|
|
374
393
|
icon: Plus,
|
|
375
394
|
},
|
|
@@ -378,21 +397,21 @@ export const useSubjectModule = () => {
|
|
|
378
397
|
{
|
|
379
398
|
enabled: true,
|
|
380
399
|
handleOnClick: handleView,
|
|
381
|
-
label: t("
|
|
400
|
+
label: t("actionsButtonView"),
|
|
382
401
|
order: 1,
|
|
383
402
|
icon: Eye,
|
|
384
403
|
},
|
|
385
404
|
{
|
|
386
405
|
enabled: true,
|
|
387
406
|
handleOnClick: handleEdit,
|
|
388
|
-
label: t("
|
|
407
|
+
label: t("actionsButtonEdit"),
|
|
389
408
|
order: 2,
|
|
390
409
|
icon: Edit,
|
|
391
410
|
},
|
|
392
411
|
{
|
|
393
412
|
enabled: (row) => !(row === null || row === void 0 ? void 0 : row.enabled),
|
|
394
413
|
handleOnClick: handleDelete,
|
|
395
|
-
label: t("
|
|
414
|
+
label: t("actionsButtonDelete"),
|
|
396
415
|
order: 3,
|
|
397
416
|
icon: Trash2,
|
|
398
417
|
variant: "destructive",
|
|
@@ -408,43 +427,14 @@ export const useSubjectModule = () => {
|
|
|
408
427
|
// ============================================================================
|
|
409
428
|
// EFFECTS
|
|
410
429
|
// ============================================================================
|
|
411
|
-
// Keep the latest fetch function in a ref so the fetch effect can call it
|
|
412
|
-
// without depending on listFetchNow's unstable identity.
|
|
413
430
|
useEffect(() => {
|
|
414
431
|
listFetchNowRef.current = listFetchNow;
|
|
415
|
-
});
|
|
416
|
-
// Initial load via cache; re-fetch directly from API on page/pageLimit/filter/search changes.
|
|
432
|
+
}, [listFetchNow]);
|
|
417
433
|
useEffect(() => {
|
|
418
434
|
var _a;
|
|
419
435
|
if (!schoolId)
|
|
420
436
|
return;
|
|
421
|
-
|
|
422
|
-
const currentPageLimit = Number(listParams.pageLimit) || pageLimit;
|
|
423
|
-
const isDefaultLoad = currentPage === 1 &&
|
|
424
|
-
currentPageLimit === pageLimit &&
|
|
425
|
-
!listParams.searchQuery &&
|
|
426
|
-
listParams.filterEnabled === undefined;
|
|
427
|
-
if (isDefaultLoad) {
|
|
428
|
-
(async () => {
|
|
429
|
-
try {
|
|
430
|
-
const { count, items } = await getCachedSubjects({
|
|
431
|
-
params: listParams,
|
|
432
|
-
});
|
|
433
|
-
dispatch({
|
|
434
|
-
type: SUBJECT_ACTION_TYPES.SET_ITEMS,
|
|
435
|
-
payload: { items: items || [], count: count || 0 },
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
catch (_a) {
|
|
439
|
-
showToast(t("messagesFetchFailed"), TOAST_VARIANT.ERROR);
|
|
440
|
-
}
|
|
441
|
-
})();
|
|
442
|
-
}
|
|
443
|
-
else {
|
|
444
|
-
// Bypass cache for pagination, pageLimit, filter and search changes.
|
|
445
|
-
// Use ref to avoid the infinite-loop caused by listFetchNow's unstable identity.
|
|
446
|
-
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
447
|
-
}
|
|
437
|
+
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
448
438
|
}, [dispatch, listParams, schoolId, showToast, t]);
|
|
449
439
|
// ============================================================================
|
|
450
440
|
// RETURN
|
|
@@ -468,6 +458,7 @@ export const useSubjectModule = () => {
|
|
|
468
458
|
handleView,
|
|
469
459
|
headerActions,
|
|
470
460
|
listLoading,
|
|
461
|
+
resetRecordFormState,
|
|
471
462
|
rowActions,
|
|
472
463
|
updateLoading });
|
|
473
464
|
};
|
|
@@ -7,7 +7,6 @@ import converter from "json-2-csv";
|
|
|
7
7
|
import { Timeline } from "../../components/timeline";
|
|
8
8
|
import { useTranslations } from "next-intl";
|
|
9
9
|
import { SUBJECT_API_ROUTES, pageLimit } from "./constants";
|
|
10
|
-
import { invalidateSubjectsCache } from "./cache";
|
|
11
10
|
import { SUBJECT_ACTION_TYPES, useSubjectContext } from "./context";
|
|
12
11
|
import { useRef, useEffect, useCallback } from "react";
|
|
13
12
|
const workspace = getCachedWorkspaceSync();
|
|
@@ -165,7 +164,6 @@ export const SubjectMoreActions = () => {
|
|
|
165
164
|
else {
|
|
166
165
|
showSuccessToast("Bulk operation completed successfully");
|
|
167
166
|
}
|
|
168
|
-
invalidateSubjectsCache();
|
|
169
167
|
const schoolId = ((_f = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _f === void 0 ? void 0 : _f.id) || "";
|
|
170
168
|
fetch(`${SUBJECT_API_ROUTES.LIST}?currentPage=1&pageLimit=${pageLimit}&schoolId=${schoolId}`, {
|
|
171
169
|
headers: {
|
|
@@ -15,17 +15,11 @@ export declare const TEACHER_API_ROUTES: {
|
|
|
15
15
|
readonly BULK_STATUS: (jobId: string) => string;
|
|
16
16
|
};
|
|
17
17
|
export declare const GENDER_OPTIONS: readonly [{
|
|
18
|
-
readonly label: "Select Gender";
|
|
19
|
-
readonly value: "";
|
|
20
|
-
}, {
|
|
21
18
|
readonly label: "Male";
|
|
22
19
|
readonly value: "MALE";
|
|
23
20
|
}, {
|
|
24
21
|
readonly label: "Female";
|
|
25
22
|
readonly value: "FEMALE";
|
|
26
|
-
}, {
|
|
27
|
-
readonly label: "Other";
|
|
28
|
-
readonly value: "OTHER";
|
|
29
23
|
}, {
|
|
30
24
|
readonly label: "Prefer not to say";
|
|
31
25
|
readonly value: "PREFER_NOT_TO_SAY";
|
|
@@ -24,10 +24,8 @@ export const TEACHER_API_ROUTES = {
|
|
|
24
24
|
// GENDER OPTIONS
|
|
25
25
|
// ============================================================================
|
|
26
26
|
export const GENDER_OPTIONS = [
|
|
27
|
-
{ label: "Select Gender", value: "" },
|
|
28
27
|
{ label: "Male", value: "MALE" },
|
|
29
28
|
{ label: "Female", value: "FEMALE" },
|
|
30
|
-
{ label: "Other", value: "OTHER" },
|
|
31
29
|
{ label: "Prefer not to say", value: "PREFER_NOT_TO_SAY" },
|
|
32
30
|
];
|
|
33
31
|
// ============================================================================
|
|
@@ -214,6 +214,7 @@ export declare const useTeacherModule: () => {
|
|
|
214
214
|
}[];
|
|
215
215
|
listFetchNow: (url?: string, config?: import("@react-pakistan/util-functions/hooks/use-fetch").FetchConfig) => void;
|
|
216
216
|
listLoading: boolean;
|
|
217
|
+
resetRecordFormState: () => void;
|
|
217
218
|
rowActions: RowAction[];
|
|
218
219
|
toggleStatus: (row?: TableRow) => void;
|
|
219
220
|
updateLoading: boolean;
|