@appcorp/fusion-storybook 0.2.40 → 0.2.44

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.
Files changed (100) hide show
  1. package/base-modules/admission/constants.d.ts +5 -17
  2. package/base-modules/admission/constants.js +12 -7
  3. package/base-modules/admission/context/use-admission-module.js +11 -48
  4. package/base-modules/admission/filter.js +23 -3
  5. package/base-modules/admission/form.js +49 -19
  6. package/base-modules/attendance/context.js +3 -37
  7. package/base-modules/attendance/filter.js +3 -1
  8. package/base-modules/attendance/form.js +26 -10
  9. package/base-modules/attendance/more-actions.js +34 -25
  10. package/base-modules/campus/context.js +7 -7
  11. package/base-modules/class/cache.js +0 -1
  12. package/base-modules/class/context.js +10 -48
  13. package/base-modules/class/more-actions.js +47 -24
  14. package/base-modules/course/context.js +3 -37
  15. package/base-modules/course/form.js +91 -292
  16. package/base-modules/discount-code/constants.d.ts +5 -0
  17. package/base-modules/discount-code/constants.js +5 -0
  18. package/base-modules/discount-code/context.d.ts +1 -0
  19. package/base-modules/discount-code/context.js +40 -39
  20. package/base-modules/discount-code/form.js +21 -15
  21. package/base-modules/discount-code/more-actions.js +1 -1
  22. package/base-modules/enrollment/context.js +3 -37
  23. package/base-modules/enrollment/form.js +38 -11
  24. package/base-modules/enrollment/more-actions.js +48 -25
  25. package/base-modules/expense/constants.js +1 -1
  26. package/base-modules/expense/context.js +5 -32
  27. package/base-modules/expense/filter.js +50 -3
  28. package/base-modules/expense/form.js +82 -6
  29. package/base-modules/family/context.js +7 -38
  30. package/base-modules/family-member/context.js +7 -39
  31. package/base-modules/fee-structure/context.js +1 -25
  32. package/base-modules/fee-structure/form.js +77 -89
  33. package/base-modules/fee-structure/more-actions.js +45 -22
  34. package/base-modules/rbac/context.d.ts +1 -0
  35. package/base-modules/rbac/context.js +24 -33
  36. package/base-modules/rbac/form.js +3 -1
  37. package/base-modules/school/context.js +1 -1
  38. package/base-modules/school/form.js +34 -14
  39. package/base-modules/section/context.d.ts +1 -0
  40. package/base-modules/section/context.js +40 -47
  41. package/base-modules/section/form.js +25 -80
  42. package/base-modules/section/more-actions.js +47 -24
  43. package/base-modules/section/view.js +9 -7
  44. package/base-modules/student-fee/context/use-student-fee-module.d.ts +1 -0
  45. package/base-modules/student-fee/context/use-student-fee-module.js +48 -32
  46. package/base-modules/student-fee/context.d.ts +1 -1
  47. package/base-modules/student-fee/context.js +1 -1
  48. package/base-modules/student-fee/filter.js +23 -3
  49. package/base-modules/student-fee/form.js +93 -174
  50. package/base-modules/student-fee/view.d.ts +7 -1
  51. package/base-modules/student-fee/view.js +17 -20
  52. package/base-modules/student-profile/constants.d.ts +0 -6
  53. package/base-modules/student-profile/constants.js +1 -3
  54. package/base-modules/student-profile/context/use-student-profile-module.d.ts +1 -0
  55. package/base-modules/student-profile/context/use-student-profile-module.js +62 -55
  56. package/base-modules/student-profile/context.d.ts +1 -1
  57. package/base-modules/student-profile/context.js +1 -1
  58. package/base-modules/student-profile/filter.js +24 -4
  59. package/base-modules/student-profile/form.js +35 -3
  60. package/base-modules/subject/context.d.ts +1 -0
  61. package/base-modules/subject/context.js +38 -47
  62. package/base-modules/subject/more-actions.js +47 -24
  63. package/base-modules/teacher/constants.d.ts +0 -6
  64. package/base-modules/teacher/constants.js +0 -2
  65. package/base-modules/teacher/context.d.ts +1 -0
  66. package/base-modules/teacher/context.js +58 -39
  67. package/base-modules/teacher/form.js +46 -11
  68. package/base-modules/teacher/more-actions.js +45 -22
  69. package/base-modules/user/context/use-user-module.d.ts +1 -0
  70. package/base-modules/user/context/use-user-module.js +36 -32
  71. package/base-modules/user/context.js +1 -1
  72. package/base-modules/user/filter.js +6 -4
  73. package/base-modules/user/form.js +29 -5
  74. package/base-modules/user/more-actions.js +9 -7
  75. package/base-modules/user/view.js +3 -1
  76. package/base-modules/workspace/form.js +18 -8
  77. package/base-modules/workspace-user/context.d.ts +2 -1
  78. package/base-modules/workspace-user/context.js +31 -29
  79. package/package.json +1 -1
  80. package/tsconfig.build.tsbuildinfo +1 -1
  81. package/base-modules/admission/cache.d.ts +0 -14
  82. package/base-modules/admission/cache.js +0 -31
  83. package/base-modules/attendance/cache.d.ts +0 -14
  84. package/base-modules/attendance/cache.js +0 -31
  85. package/base-modules/course/cache.d.ts +0 -14
  86. package/base-modules/course/cache.js +0 -31
  87. package/base-modules/enrollment/cache.d.ts +0 -14
  88. package/base-modules/enrollment/cache.js +0 -31
  89. package/base-modules/expense/cache.d.ts +0 -14
  90. package/base-modules/expense/cache.js +0 -31
  91. package/base-modules/family/cache.d.ts +0 -14
  92. package/base-modules/family/cache.js +0 -31
  93. package/base-modules/family-member/cache.d.ts +0 -14
  94. package/base-modules/family-member/cache.js +0 -31
  95. package/base-modules/rbac/cache.d.ts +0 -27
  96. package/base-modules/rbac/cache.js +0 -46
  97. package/base-modules/student-fee/cache.d.ts +0 -15
  98. package/base-modules/student-fee/cache.js +0 -21
  99. package/base-modules/workspace-user/cache.d.ts +0 -14
  100. 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, pageLimit } from "../constants";
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("actionDeleteConfirmation")))
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("actionHeaderMoreActions"),
418
+ label: t("actionsButtonMoreActions"),
399
419
  order: 1,
400
420
  },
401
421
  {
402
422
  enabled: true,
403
423
  handleOnClick: handleFilters,
404
- label: t("actionHeaderFilters"),
424
+ label: t("actionsButtonFilters"),
405
425
  order: 2,
406
426
  },
407
427
  {
408
428
  enabled: false,
409
429
  handleOnClick: handleCreate,
410
- label: t("actionHeaderAddStudentProfile"),
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("actionRowView"),
438
+ label: t("actionsButtonView"),
419
439
  order: 1,
420
440
  },
421
441
  {
422
442
  enabled: true,
423
443
  handleOnClick: handleEdit,
424
- label: t("actionRowEdit"),
444
+ label: t("actionsButtonEdit"),
425
445
  order: 2,
426
446
  },
427
447
  {
428
448
  enabled: false,
429
449
  handleOnClick: handleDelete,
430
- label: t("actionRowDelete"),
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("actionRowWithdrawStudent"),
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("actionRowReAdmitStudent"),
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, isDefaultListState, listParams, schoolId, showToast, t]);
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 cache invalidation and toast notifications on mutation
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 cache invalidation and toast notifications on mutation
12
+ * - Ensure toast notifications on mutation
13
13
  *
14
14
  * Exported utilities:
15
15
  * - `StudentProfileProvider` — provider component used by the page
@@ -1,21 +1,41 @@
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 { EnhancedCombobox } from "@appcorp/shadcn/components/enhanced-combobox";
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();
11
- const { filterStatus, filterEnabled } = context.state;
11
+ const { filterEnabled } = context.state;
12
12
  const { handleChange } = context;
13
13
  const filterEnabledValue = filterEnabled === undefined
14
14
  ? "undefined"
15
15
  : filterEnabled
16
16
  ? "true"
17
17
  : "false";
18
- return (_jsx("div", { className: "space-y-4", children: _jsxs("div", { className: "grid grid-cols-1 gap-4", children: [_jsx(EnhancedCombobox, { id: "filterStatus", label: t("filterOptionStatus"), info: t("filterByStudentStatus"), options: [...STATUS_OPTIONS], value: filterStatus, onValueChange: (value) => handleChange("filterStatus", value) }), _jsx(EnhancedRadio, { label: t("filterOptionEnabled"), name: "filterEnabled", value: filterEnabledValue, options: [
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
- : "" }), _jsx(EnhancedCombobox, { error: errors.gender, id: "gender", info: t("formGenderPlaceholder"), label: t("formGenderLabel"), onValueChange: (value) => handleChange("gender", value), options: GENDER_OPTIONS.slice(1), value: gender })] })] }), _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: [_jsx(EnhancedCombobox, { error: errors.status, id: "status", info: t("formStudentStatusPlaceholder"), label: t("formOptionStatus"), onValueChange: (value) => handleChange("status", value), options: STATUS_OPTIONS.slice(1), required: true, value: status }), _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) })] })] }));
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 cache invalidation and toast notifications on mutation
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, byIdFetchNow]);
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, byIdFetchNow]);
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("actionHeaderMoreActions"),
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("actionHeaderFilters"),
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("actionHeaderAdd"),
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("actionRowView"),
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("actionRowEdit"),
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("actionRowDelete"),
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
- const currentPage = Number(listParams.currentPage) || 1;
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
  };