@appcorp/fusion-storybook 0.2.12 → 0.2.14

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 (173) hide show
  1. package/base-modules/admission/context/use-admission-module.d.ts +88 -0
  2. package/base-modules/admission/context/use-admission-module.js +771 -0
  3. package/base-modules/admission/context.d.ts +1 -87
  4. package/base-modules/admission/context.js +3 -769
  5. package/base-modules/admission/filter.d.ts +1 -1
  6. package/base-modules/admission/form.d.ts +1 -1
  7. package/base-modules/admission/more-actions.d.ts +1 -1
  8. package/base-modules/admission/page.d.ts +8 -1
  9. package/base-modules/admission/page.js +25 -4
  10. package/base-modules/admission/view.d.ts +1 -1
  11. package/base-modules/attendance/form.d.ts +1 -1
  12. package/base-modules/attendance/page.d.ts +8 -1
  13. package/base-modules/attendance/page.js +25 -4
  14. package/base-modules/attendance/view.d.ts +1 -1
  15. package/base-modules/campus/filter.d.ts +1 -1
  16. package/base-modules/campus/form.d.ts +1 -1
  17. package/base-modules/campus/more-actions.d.ts +1 -1
  18. package/base-modules/campus/more-actions.js +0 -1
  19. package/base-modules/campus/page.d.ts +8 -1
  20. package/base-modules/campus/page.js +25 -4
  21. package/base-modules/campus/view.d.ts +1 -1
  22. package/base-modules/class/filter.d.ts +1 -1
  23. package/base-modules/class/form.d.ts +1 -1
  24. package/base-modules/class/more-actions.d.ts +1 -1
  25. package/base-modules/class/more-actions.js +1 -6
  26. package/base-modules/class/page.d.ts +8 -1
  27. package/base-modules/class/page.js +25 -4
  28. package/base-modules/class/view.d.ts +1 -1
  29. package/base-modules/course/filter.d.ts +1 -1
  30. package/base-modules/course/form.d.ts +1 -1
  31. package/base-modules/course/more-actions.d.ts +1 -1
  32. package/base-modules/course/page.d.ts +8 -1
  33. package/base-modules/course/page.js +25 -4
  34. package/base-modules/course/view.d.ts +1 -1
  35. package/base-modules/discount-code/filter.d.ts +2 -1
  36. package/base-modules/discount-code/form.d.ts +1 -1
  37. package/base-modules/discount-code/page.d.ts +8 -1
  38. package/base-modules/discount-code/page.js +25 -4
  39. package/base-modules/discount-code/view.d.ts +1 -1
  40. package/base-modules/enrollment/filter.d.ts +1 -1
  41. package/base-modules/enrollment/form.d.ts +1 -1
  42. package/base-modules/enrollment/more-actions.d.ts +1 -1
  43. package/base-modules/enrollment/page.d.ts +8 -1
  44. package/base-modules/enrollment/page.js +25 -4
  45. package/base-modules/enrollment/view.d.ts +1 -1
  46. package/base-modules/expense/filter.d.ts +1 -1
  47. package/base-modules/expense/form.d.ts +1 -1
  48. package/base-modules/expense/more-actions.d.ts +1 -1
  49. package/base-modules/expense/more-actions.js +1 -6
  50. package/base-modules/expense/page.d.ts +8 -1
  51. package/base-modules/expense/page.js +25 -4
  52. package/base-modules/expense/view.d.ts +1 -1
  53. package/base-modules/family/filter.d.ts +1 -1
  54. package/base-modules/family/form.d.ts +1 -1
  55. package/base-modules/family/more-actions.d.ts +1 -1
  56. package/base-modules/family/page.d.ts +8 -1
  57. package/base-modules/family/page.js +25 -4
  58. package/base-modules/family/view.d.ts +1 -1
  59. package/base-modules/family-member/filter.d.ts +1 -1
  60. package/base-modules/family-member/form.d.ts +1 -1
  61. package/base-modules/family-member/more-actions.d.ts +1 -1
  62. package/base-modules/family-member/page.d.ts +8 -1
  63. package/base-modules/family-member/page.js +25 -4
  64. package/base-modules/family-member/view.d.ts +1 -1
  65. package/base-modules/fee-structure/filter.d.ts +1 -1
  66. package/base-modules/fee-structure/form.d.ts +1 -1
  67. package/base-modules/fee-structure/more-actions.d.ts +1 -1
  68. package/base-modules/fee-structure/more-actions.js +1 -6
  69. package/base-modules/fee-structure/page.d.ts +8 -1
  70. package/base-modules/fee-structure/page.js +25 -4
  71. package/base-modules/fee-structure/view.d.ts +1 -1
  72. package/base-modules/rbac/assign-permissions.d.ts +1 -1
  73. package/base-modules/rbac/filter.d.ts +1 -1
  74. package/base-modules/rbac/form.d.ts +1 -1
  75. package/base-modules/rbac/more-actions.d.ts +1 -1
  76. package/base-modules/rbac/page.d.ts +8 -1
  77. package/base-modules/rbac/page.js +25 -4
  78. package/base-modules/rbac/view.d.ts +7 -1
  79. package/base-modules/school/drawer.d.ts +1 -1
  80. package/base-modules/school/filter.d.ts +1 -1
  81. package/base-modules/school/form.d.ts +1 -1
  82. package/base-modules/school/more-actions.d.ts +1 -1
  83. package/base-modules/school/view.d.ts +1 -1
  84. package/base-modules/section/filter.d.ts +1 -1
  85. package/base-modules/section/form.d.ts +1 -1
  86. package/base-modules/section/more-actions.d.ts +1 -1
  87. package/base-modules/section/page.d.ts +8 -1
  88. package/base-modules/section/page.js +25 -4
  89. package/base-modules/section/view.d.ts +1 -1
  90. package/base-modules/student-fee/context/shared.d.ts +178 -0
  91. package/base-modules/student-fee/context/shared.js +59 -0
  92. package/base-modules/student-fee/context/use-student-fee-module.d.ts +64 -0
  93. package/base-modules/student-fee/context/use-student-fee-module.js +610 -0
  94. package/base-modules/student-fee/context.d.ts +21 -235
  95. package/base-modules/student-fee/context.js +2 -674
  96. package/base-modules/student-fee/filter.d.ts +1 -1
  97. package/base-modules/student-fee/form.d.ts +1 -1
  98. package/base-modules/student-fee/more-actions.d.ts +1 -1
  99. package/base-modules/student-fee/more-actions.js +1 -6
  100. package/base-modules/student-fee/page.d.ts +8 -1
  101. package/base-modules/student-fee/page.js +25 -4
  102. package/base-modules/student-fee/view.d.ts +1 -1
  103. package/base-modules/student-profile/context/module-base.d.ts +187 -0
  104. package/base-modules/student-profile/context/module-base.js +50 -0
  105. package/base-modules/student-profile/context/use-student-profile-module.d.ts +70 -0
  106. package/base-modules/student-profile/context/use-student-profile-module.js +506 -0
  107. package/base-modules/student-profile/context.d.ts +20 -256
  108. package/base-modules/student-profile/context.js +2 -601
  109. package/base-modules/student-profile/filter.d.ts +1 -1
  110. package/base-modules/student-profile/form.d.ts +1 -1
  111. package/base-modules/student-profile/more-actions.d.ts +1 -1
  112. package/base-modules/student-profile/page.d.ts +8 -1
  113. package/base-modules/student-profile/page.js +25 -4
  114. package/base-modules/student-profile/view.d.ts +1 -1
  115. package/base-modules/subject/filter.d.ts +1 -1
  116. package/base-modules/subject/form.d.ts +1 -1
  117. package/base-modules/subject/more-actions.d.ts +1 -1
  118. package/base-modules/subject/page.d.ts +8 -1
  119. package/base-modules/subject/page.js +25 -4
  120. package/base-modules/subject/view.d.ts +1 -1
  121. package/base-modules/teacher/avatar-upload.js +1 -4
  122. package/base-modules/teacher/filter.d.ts +1 -1
  123. package/base-modules/teacher/form.d.ts +1 -1
  124. package/base-modules/teacher/more-actions.d.ts +1 -1
  125. package/base-modules/teacher/more-actions.js +1 -6
  126. package/base-modules/teacher/page.d.ts +8 -1
  127. package/base-modules/teacher/page.js +25 -4
  128. package/base-modules/teacher/view.d.ts +1 -1
  129. package/base-modules/user/context/use-user-module.d.ts +53 -0
  130. package/base-modules/user/context/use-user-module.js +546 -0
  131. package/base-modules/user/context.d.ts +1 -52
  132. package/base-modules/user/context.js +5 -547
  133. package/base-modules/user/drawer.d.ts +1 -1
  134. package/base-modules/user/filter.d.ts +1 -1
  135. package/base-modules/user/form.d.ts +1 -1
  136. package/base-modules/user/more-actions.d.ts +1 -1
  137. package/base-modules/user/page.d.ts +8 -1
  138. package/base-modules/user/page.js +25 -4
  139. package/base-modules/user/view.d.ts +1 -1
  140. package/base-modules/workspace/context.d.ts +1 -1
  141. package/base-modules/workspace/drawer.d.ts +1 -1
  142. package/base-modules/workspace/filter.d.ts +1 -1
  143. package/base-modules/workspace/form.d.ts +1 -1
  144. package/base-modules/workspace/more-actions.d.ts +1 -1
  145. package/base-modules/workspace/view.d.ts +1 -1
  146. package/base-modules/workspace-user/filter.d.ts +1 -1
  147. package/base-modules/workspace-user/form.d.ts +1 -1
  148. package/base-modules/workspace-user/more-actions.d.ts +1 -1
  149. package/base-modules/workspace-user/more-actions.js +1 -6
  150. package/base-modules/workspace-user/page.d.ts +8 -1
  151. package/base-modules/workspace-user/page.js +25 -4
  152. package/base-modules/workspace-user/view.d.ts +1 -1
  153. package/components/module-error.d.ts +9 -0
  154. package/components/module-error.js +3 -0
  155. package/components/timeline.d.ts +1 -1
  156. package/package.json +6 -5
  157. package/tsconfig.build.tsbuildinfo +1 -1
  158. package/type.d.ts +3 -1242
  159. package/type.js +3 -445
  160. package/types/academics.d.ts +264 -0
  161. package/types/academics.js +8 -0
  162. package/types/admission.d.ts +85 -0
  163. package/types/admission.js +6 -0
  164. package/types/communication.d.ts +165 -0
  165. package/types/communication.js +7 -0
  166. package/types/enums.d.ts +411 -0
  167. package/types/enums.js +442 -0
  168. package/types/finance.d.ts +126 -0
  169. package/types/finance.js +7 -0
  170. package/types/index.d.ts +12 -0
  171. package/types/index.js +12 -0
  172. package/types/user-management.d.ts +236 -0
  173. package/types/user-management.js +7 -0
@@ -0,0 +1,610 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useMemo, useRef } from "react";
3
+ import { useTheme } from "next-themes";
4
+ import { useTranslations } from "next-intl";
5
+ import { validateForm, isCreatedOrUpdated, } from "@react-pakistan/util-functions";
6
+ import { useModuleEntityV2, } from "@react-pakistan/util-functions/hooks/use-module-entity-v2";
7
+ import { useDebounce } from "@react-pakistan/util-functions/hooks/use-debounce";
8
+ import { generateThemeToast, TOAST_VARIANT, } from "@appcorp/shadcn/lib/toast-utils";
9
+ import { PAYMENT_STATUS, DISCOUNT_TYPE, } from "../../../type";
10
+ import { STUDENT_FEE_API_ROUTES, pageLimit } from "../constants";
11
+ import { studentFeeFormValidation } from "../validate";
12
+ import { getCachedStudentFees, invalidateStudentFeesCache } from "../cache";
13
+ import { getCachedWorkspaceSync } from "../../workspace/cache";
14
+ import { getCachedFeeStructureById } from "../../fee-structure/cache";
15
+ import { getCachedStudentProfilesSync } from "../../student-profile/cache";
16
+ import { getCachedDiscountCodesSync } from "../../discount-code/cache";
17
+ import { STUDENT_FEE_ACTION_TYPES, STUDENT_FEE_DRAWER, useStudentFeeContext, } from "./shared";
18
+ // ============================================================================
19
+ // AMOUNT CALCULATION HELPER
20
+ // ============================================================================
21
+ const calculateAmounts = (originalFee, discountAmount, amountPaid) => {
22
+ const amount = Math.max(0, originalFee - discountAmount);
23
+ const amountDue = Math.max(0, amount - amountPaid);
24
+ return { amount, amountDue };
25
+ };
26
+ // ============================================================================
27
+ // ENHANCED STUDENT FEE HOOK WITH API INTEGRATION
28
+ // ============================================================================
29
+ export const useStudentFeeModule = () => {
30
+ // ============================================================================
31
+ // 1.4.1 STATE & CORE HOOKS
32
+ // ============================================================================
33
+ var _a;
34
+ const context = useStudentFeeContext();
35
+ const { dispatch } = context;
36
+ const state = context.state;
37
+ const t = useTranslations("studentFee");
38
+ const { theme } = useTheme();
39
+ const workspace = getCachedWorkspaceSync();
40
+ const schoolId = ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "";
41
+ const listFetchNowRef = useRef(null);
42
+ const debouncedQuery = useDebounce(state.searchQuery, 800);
43
+ // ============================================================================
44
+ // 1.4.2 API PARAMETERS
45
+ // ============================================================================
46
+ const listParams = useMemo(() => (Object.assign(Object.assign(Object.assign({ currentPage: state.currentPage, pageLimit: state.pageLimit, schoolId }, (debouncedQuery ? { searchQuery: debouncedQuery } : {})), (state.filterEnabled !== undefined
47
+ ? { filterEnabled: state.filterEnabled }
48
+ : {})), (state.filterStatus ? { status: state.filterStatus } : {}))), [
49
+ state.currentPage,
50
+ state.filterEnabled,
51
+ state.filterStatus,
52
+ state.pageLimit,
53
+ debouncedQuery,
54
+ schoolId,
55
+ ]);
56
+ const updateParams = useMemo(() => ({
57
+ amount: Number(state.amount),
58
+ amountDue: Number(state.amountDue),
59
+ amountPaid: Number(state.amountPaid),
60
+ discountAmount: Number(state.discountAmount),
61
+ discountCodeId: state.discountCodeId,
62
+ dueDate: state.dueDate,
63
+ enabled: state.enabled,
64
+ familyId: state.familyId,
65
+ feeStructureId: state.feeStructureId,
66
+ id: state.id,
67
+ remarks: state.remarks || null,
68
+ schoolId,
69
+ status: state.status,
70
+ studentProfileId: state.studentProfileId,
71
+ }), [state, schoolId]);
72
+ const byIdParams = useMemo(() => ({ id: state.id }), [state.id]);
73
+ 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.filterStatus;
79
+ // ============================================================================
80
+ // 1.4.3 UTILITIES
81
+ // ============================================================================
82
+ const showToast = useCallback((description, variant) => {
83
+ generateThemeToast({
84
+ description,
85
+ theme: theme,
86
+ variant,
87
+ });
88
+ }, [theme]);
89
+ const resetFormAndCloseDrawer = useCallback(() => {
90
+ dispatch({ type: STUDENT_FEE_ACTION_TYPES.RESET_FORM });
91
+ dispatch({
92
+ type: STUDENT_FEE_ACTION_TYPES.SET_ERRORS,
93
+ payload: { errors: {} },
94
+ });
95
+ dispatch({
96
+ type: STUDENT_FEE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
97
+ payload: { disabled: false },
98
+ });
99
+ dispatch({
100
+ type: STUDENT_FEE_ACTION_TYPES.SET_DRAWER,
101
+ payload: { drawer: null },
102
+ });
103
+ }, [dispatch]);
104
+ // ============================================================================
105
+ // 1.4.4 API CALLBACKS
106
+ // ============================================================================
107
+ const listCallback = useCallback(({ data, error }) => {
108
+ var _a, _b;
109
+ if (error) {
110
+ showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
111
+ return;
112
+ }
113
+ if (data) {
114
+ const response = data;
115
+ dispatch({
116
+ type: STUDENT_FEE_ACTION_TYPES.SET_ITEMS,
117
+ payload: { items: (_a = response.items) !== null && _a !== void 0 ? _a : [], count: (_b = response.count) !== null && _b !== void 0 ? _b : 0 },
118
+ });
119
+ }
120
+ }, [dispatch, showToast, t]);
121
+ const updateCallback = useCallback(({ data, error }) => {
122
+ var _a;
123
+ if (error) {
124
+ showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
125
+ return;
126
+ }
127
+ if (data) {
128
+ const isCreated = isCreatedOrUpdated(data);
129
+ invalidateStudentFeesCache();
130
+ showToast(isCreated
131
+ ? t("messagesStudentFeeCreated")
132
+ : t("messagesStudentFeeUpdated"), TOAST_VARIANT.SUCCESS);
133
+ resetFormAndCloseDrawer();
134
+ (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
135
+ }
136
+ }, [showToast, t, resetFormAndCloseDrawer]);
137
+ const byIdCallback = useCallback(({ data, error }) => {
138
+ if (error) {
139
+ showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
140
+ return;
141
+ }
142
+ if (data) {
143
+ const fee = data;
144
+ const rawDueDate = fee.dueDate;
145
+ const dueDate = rawDueDate instanceof Date
146
+ ? rawDueDate.toISOString().slice(0, 10)
147
+ : String(rawDueDate).slice(0, 10);
148
+ const originalFee = Number(fee.amount) + Number(fee.discountAmount || 0);
149
+ dispatch({
150
+ type: STUDENT_FEE_ACTION_TYPES.SET_FORM_DATA,
151
+ payload: {
152
+ form: Object.assign(Object.assign({}, fee), { dueDate,
153
+ originalFee, filterEnabled: undefined, filterStatus: state.filterStatus }),
154
+ },
155
+ });
156
+ }
157
+ }, [dispatch, showToast, t, state.filterStatus]);
158
+ const deleteCallback = useCallback(({ data, error }) => {
159
+ var _a;
160
+ if (error) {
161
+ showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
162
+ return;
163
+ }
164
+ if (data) {
165
+ invalidateStudentFeesCache();
166
+ showToast(t("messagesStudentFeeDeleted"), TOAST_VARIANT.SUCCESS);
167
+ (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
168
+ }
169
+ }, [showToast, t]);
170
+ // ============================================================================
171
+ // 1.4.5 API HOOKS
172
+ // ============================================================================
173
+ const { listFetchNow, listLoading, updateFetchNow, updateLoading, byIdFetchNow, deleteFetchNow, deleteLoading, byIdLoading, } = useModuleEntityV2({
174
+ byIdCallback,
175
+ byIdParams,
176
+ deleteCallback,
177
+ deleteParams,
178
+ listCallback,
179
+ listParams,
180
+ listUrl: STUDENT_FEE_API_ROUTES.UNIT,
181
+ searchQuery: debouncedQuery,
182
+ unitByIdUrl: STUDENT_FEE_API_ROUTES.UNIT,
183
+ unitUrl: STUDENT_FEE_API_ROUTES.UNIT,
184
+ updateCallback,
185
+ updateParams,
186
+ headers: {
187
+ "Content-Type": "application/json",
188
+ "x-api-token": process.env.NEXT_PUBLIC_API_KEY,
189
+ },
190
+ });
191
+ // ============================================================================
192
+ // 1.4.6 HANDLERS
193
+ // ============================================================================
194
+ const handleChange = useCallback((field, value) => {
195
+ var _a, _b, _c, _d, _e;
196
+ dispatch({
197
+ type: STUDENT_FEE_ACTION_TYPES.SET_ERRORS,
198
+ payload: { errors: {} },
199
+ });
200
+ dispatch({
201
+ type: STUDENT_FEE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
202
+ payload: { disabled: false },
203
+ });
204
+ const currentState = Object.assign({}, state);
205
+ dispatch({
206
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
207
+ payload: { key: field, value },
208
+ });
209
+ const discountCodes = getCachedDiscountCodesSync();
210
+ if (field === "feeStructureId" && typeof value === "string" && value) {
211
+ try {
212
+ const feeStructure = getCachedFeeStructureById(value);
213
+ if (feeStructure && typeof feeStructure.amount === "number") {
214
+ const originalFee = Number(feeStructure.amount);
215
+ dispatch({
216
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
217
+ payload: { key: "originalFee", value: originalFee },
218
+ });
219
+ let discountAmount = Number(currentState.discountAmount) || 0;
220
+ if (currentState.discountCodeId) {
221
+ const discountCode = (_a = discountCodes.items) === null || _a === void 0 ? void 0 : _a.find((code) => code.id === currentState.discountCodeId && code.enabled);
222
+ if (discountCode) {
223
+ discountAmount =
224
+ discountCode.discountType === DISCOUNT_TYPE.PERCENTAGE
225
+ ? (originalFee * discountCode.discountValue) / 100
226
+ : discountCode.discountValue;
227
+ discountAmount = Math.min(discountAmount, originalFee);
228
+ dispatch({
229
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
230
+ payload: { key: "discountAmount", value: discountAmount },
231
+ });
232
+ }
233
+ }
234
+ const { amount, amountDue } = calculateAmounts(originalFee, discountAmount, Number(currentState.amountPaid) || 0);
235
+ dispatch({
236
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
237
+ payload: { key: "amount", value: amount },
238
+ });
239
+ dispatch({
240
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
241
+ payload: { key: "amountDue", value: amountDue },
242
+ });
243
+ }
244
+ }
245
+ catch (_f) {
246
+ // silent fallback
247
+ }
248
+ }
249
+ if (field === "studentProfileId" && typeof value === "string" && value) {
250
+ try {
251
+ const studentProfile = (_b = getCachedStudentProfilesSync().items) === null || _b === void 0 ? void 0 : _b.find((s) => s.id === value);
252
+ dispatch({
253
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
254
+ payload: {
255
+ key: "familyId",
256
+ value: (_c = studentProfile === null || studentProfile === void 0 ? void 0 : studentProfile.familyMember) === null || _c === void 0 ? void 0 : _c.familyId,
257
+ },
258
+ });
259
+ if (studentProfile === null || studentProfile === void 0 ? void 0 : studentProfile.discountCode) {
260
+ const discountCode = (_d = discountCodes.items) === null || _d === void 0 ? void 0 : _d.find((code) => code.code === studentProfile.discountCode && code.enabled);
261
+ if (discountCode) {
262
+ dispatch({
263
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
264
+ payload: { key: "discountCodeId", value: discountCode.id },
265
+ });
266
+ const originalFee = Number(currentState.originalFee) || 0;
267
+ let discountAmount = 0;
268
+ if (originalFee > 0) {
269
+ discountAmount =
270
+ discountCode.discountType === DISCOUNT_TYPE.PERCENTAGE
271
+ ? (originalFee * discountCode.discountValue) / 100
272
+ : discountCode.discountValue;
273
+ discountAmount = Math.min(discountAmount, originalFee);
274
+ const { amount, amountDue } = calculateAmounts(originalFee, discountAmount, Number(currentState.amountPaid) || 0);
275
+ dispatch({
276
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
277
+ payload: { key: "amount", value: amount },
278
+ });
279
+ dispatch({
280
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
281
+ payload: { key: "amountDue", value: amountDue },
282
+ });
283
+ }
284
+ dispatch({
285
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
286
+ payload: { key: "discountAmount", value: discountAmount },
287
+ });
288
+ }
289
+ }
290
+ }
291
+ catch (_g) {
292
+ // silent fallback
293
+ }
294
+ }
295
+ if (field === "discountCodeId" && typeof value === "string" && value) {
296
+ try {
297
+ const discountCode = (_e = discountCodes.items) === null || _e === void 0 ? void 0 : _e.find((code) => code.id === value && code.enabled);
298
+ if (discountCode) {
299
+ const originalFee = Number(currentState.originalFee) || 0;
300
+ let discountAmount = discountCode.discountType === DISCOUNT_TYPE.PERCENTAGE
301
+ ? (originalFee * discountCode.discountValue) / 100
302
+ : discountCode.discountValue;
303
+ discountAmount = Math.min(discountAmount, originalFee);
304
+ dispatch({
305
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
306
+ payload: { key: "discountAmount", value: discountAmount },
307
+ });
308
+ const { amount, amountDue } = calculateAmounts(originalFee, discountAmount, Number(currentState.amountPaid) || 0);
309
+ dispatch({
310
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
311
+ payload: { key: "amount", value: amount },
312
+ });
313
+ dispatch({
314
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
315
+ payload: { key: "amountDue", value: amountDue },
316
+ });
317
+ }
318
+ }
319
+ catch (_h) {
320
+ // silent fallback
321
+ }
322
+ }
323
+ if (field === "discountAmount" && typeof value === "number") {
324
+ const originalFee = Number(currentState.originalFee) || 0;
325
+ const validatedDiscount = Math.min(Number(value) || 0, originalFee);
326
+ if (validatedDiscount !== value) {
327
+ dispatch({
328
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
329
+ payload: { key: "discountAmount", value: validatedDiscount },
330
+ });
331
+ }
332
+ const amountPaid = Number(currentState.amountPaid) || 0;
333
+ const { amount, amountDue } = calculateAmounts(originalFee, validatedDiscount, amountPaid);
334
+ dispatch({
335
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
336
+ payload: { key: "amount", value: amount },
337
+ });
338
+ dispatch({
339
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
340
+ payload: { key: "amountDue", value: amountDue },
341
+ });
342
+ const newStatus = amountPaid === 0
343
+ ? PAYMENT_STATUS.PENDING
344
+ : amountPaid >= amount
345
+ ? PAYMENT_STATUS.PAID
346
+ : PAYMENT_STATUS.PARTIAL;
347
+ dispatch({
348
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
349
+ payload: { key: "status", value: newStatus },
350
+ });
351
+ }
352
+ if (field === "amountPaid" && typeof value === "number") {
353
+ const originalFee = Number(currentState.originalFee) || 0;
354
+ const discountAmount = Number(currentState.discountAmount) || 0;
355
+ const maxAllowed = Math.max(0, originalFee - discountAmount);
356
+ const validatedPaid = Math.min(Number(value) || 0, maxAllowed);
357
+ if (validatedPaid !== value) {
358
+ dispatch({
359
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
360
+ payload: { key: "amountPaid", value: validatedPaid },
361
+ });
362
+ }
363
+ const { amountDue } = calculateAmounts(originalFee, discountAmount, validatedPaid);
364
+ dispatch({
365
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
366
+ payload: { key: "amountDue", value: amountDue },
367
+ });
368
+ const totalAmount = Math.max(0, originalFee - discountAmount);
369
+ const newStatus = validatedPaid === 0
370
+ ? PAYMENT_STATUS.PENDING
371
+ : validatedPaid >= totalAmount
372
+ ? PAYMENT_STATUS.PAID
373
+ : PAYMENT_STATUS.PARTIAL;
374
+ dispatch({
375
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
376
+ payload: { key: "status", value: newStatus },
377
+ });
378
+ }
379
+ if (field === "amount" && typeof value === "number") {
380
+ const amountPaid = Number(currentState.amountPaid) || 0;
381
+ const amountDue = Math.max(0, Number(value) - amountPaid);
382
+ dispatch({
383
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
384
+ payload: { key: "amountDue", value: amountDue },
385
+ });
386
+ }
387
+ }, [dispatch, state]);
388
+ const handlePageChange = useCallback((page) => {
389
+ const nextPage = typeof page === "number" ? page : state.currentPage + 1;
390
+ dispatch({
391
+ type: STUDENT_FEE_ACTION_TYPES.SET_CURRENT_PAGE,
392
+ payload: { currentPage: nextPage },
393
+ });
394
+ }, [dispatch, state.currentPage]);
395
+ const handlePageLimitChange = useCallback((k, value) => {
396
+ const { option } = Object.assign({}, value);
397
+ dispatch({
398
+ type: STUDENT_FEE_ACTION_TYPES.SET_PAGE_LIMIT,
399
+ payload: { pageLimit: Number(option) },
400
+ });
401
+ dispatch({
402
+ type: STUDENT_FEE_ACTION_TYPES.SET_CURRENT_PAGE,
403
+ payload: { currentPage: 1 },
404
+ });
405
+ }, [dispatch]);
406
+ const closeDrawer = useCallback(() => {
407
+ resetFormAndCloseDrawer();
408
+ }, [resetFormAndCloseDrawer]);
409
+ const clearSearch = useCallback(() => {
410
+ dispatch({
411
+ type: STUDENT_FEE_ACTION_TYPES.SET_SEARCH_QUERY,
412
+ payload: { searchQuery: "" },
413
+ });
414
+ }, [dispatch]);
415
+ const toggleStatus = useCallback((row) => {
416
+ updateFetchNow(undefined, {
417
+ body: JSON.stringify(Object.assign(Object.assign({}, row), { enabled: !(row === null || row === void 0 ? void 0 : row.enabled) })),
418
+ });
419
+ }, [updateFetchNow]);
420
+ const handleCreate = useCallback(() => {
421
+ dispatch({
422
+ type: STUDENT_FEE_ACTION_TYPES.SET_DRAWER,
423
+ payload: { drawer: STUDENT_FEE_DRAWER.FORM_DRAWER },
424
+ });
425
+ }, [dispatch]);
426
+ const handleView = useCallback((row) => {
427
+ byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
428
+ dispatch({
429
+ type: STUDENT_FEE_ACTION_TYPES.SET_DRAWER,
430
+ payload: { drawer: STUDENT_FEE_DRAWER.VIEW_DRAWER },
431
+ });
432
+ }, [dispatch, byIdFetchNow]);
433
+ const handleEdit = useCallback((row) => {
434
+ byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
435
+ dispatch({
436
+ type: STUDENT_FEE_ACTION_TYPES.SET_DRAWER,
437
+ payload: { drawer: STUDENT_FEE_DRAWER.FORM_DRAWER },
438
+ });
439
+ }, [dispatch, byIdFetchNow]);
440
+ const handleDelete = useCallback((row) => {
441
+ if (!confirm(t("messagesDeleteConfirmation")))
442
+ return;
443
+ deleteFetchNow === null || deleteFetchNow === void 0 ? void 0 : deleteFetchNow(undefined, {
444
+ body: JSON.stringify({ id: row === null || row === void 0 ? void 0 : row.id }),
445
+ });
446
+ }, [t, deleteFetchNow]);
447
+ const handleFilters = useCallback(() => {
448
+ dispatch({
449
+ type: STUDENT_FEE_ACTION_TYPES.SET_DRAWER,
450
+ payload: { drawer: STUDENT_FEE_DRAWER.FILTER_DRAWER },
451
+ });
452
+ }, [dispatch]);
453
+ const handleMoreActions = useCallback(() => {
454
+ dispatch({
455
+ type: STUDENT_FEE_ACTION_TYPES.SET_DRAWER,
456
+ payload: { drawer: STUDENT_FEE_DRAWER.MORE_ACTIONS_DRAWER },
457
+ });
458
+ }, [dispatch]);
459
+ const applyFilters = useCallback(() => {
460
+ dispatch({
461
+ type: STUDENT_FEE_ACTION_TYPES.SET_CURRENT_PAGE,
462
+ payload: { currentPage: 1 },
463
+ });
464
+ closeDrawer();
465
+ }, [dispatch, closeDrawer]);
466
+ const clearFilters = useCallback(() => {
467
+ dispatch({
468
+ type: STUDENT_FEE_ACTION_TYPES.SET_CURRENT_PAGE,
469
+ payload: { currentPage: 1 },
470
+ });
471
+ dispatch({
472
+ type: STUDENT_FEE_ACTION_TYPES.SET_FILTERS,
473
+ payload: { filters: { filterEnabled: undefined, filterStatus: "" } },
474
+ });
475
+ }, [dispatch]);
476
+ const handleSearch = useCallback((query) => {
477
+ dispatch({
478
+ type: STUDENT_FEE_ACTION_TYPES.SET_SEARCH_QUERY,
479
+ payload: { searchQuery: query },
480
+ });
481
+ }, [dispatch]);
482
+ // ============================================================================
483
+ // 1.4.7 NETWORK ACTIONS
484
+ // ============================================================================
485
+ const handleSubmit = useCallback(() => {
486
+ dispatch({
487
+ type: STUDENT_FEE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
488
+ payload: { disabled: true },
489
+ });
490
+ validateForm({
491
+ params: updateParams,
492
+ schema: studentFeeFormValidation,
493
+ successCallback: () => {
494
+ updateFetchNow(undefined, {
495
+ body: JSON.stringify(updateParams),
496
+ });
497
+ },
498
+ errorCallback: (errors) => {
499
+ dispatch({
500
+ type: STUDENT_FEE_ACTION_TYPES.SET_ERRORS,
501
+ payload: { errors },
502
+ });
503
+ dispatch({
504
+ type: STUDENT_FEE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
505
+ payload: { disabled: false },
506
+ });
507
+ showToast(t("messagesFormErrors"), TOAST_VARIANT.ERROR);
508
+ },
509
+ });
510
+ }, [dispatch, updateParams, t, showToast, updateFetchNow]);
511
+ // ============================================================================
512
+ // 1.4.8 HEADER & ROW ACTIONS
513
+ // ============================================================================
514
+ const headerActions = useMemo(() => [
515
+ {
516
+ enabled: false,
517
+ handleOnClick: handleMoreActions,
518
+ label: t("actionsButtonMoreActions"),
519
+ order: 0,
520
+ },
521
+ {
522
+ enabled: true,
523
+ handleOnClick: handleFilters,
524
+ label: t("actionsButtonFilters"),
525
+ order: 1,
526
+ },
527
+ {
528
+ enabled: true,
529
+ handleOnClick: handleCreate,
530
+ label: t("actionsButtonAdd"),
531
+ order: 2,
532
+ },
533
+ ], [handleMoreActions, handleFilters, handleCreate, t]);
534
+ const rowActions = useMemo(() => [
535
+ {
536
+ enabled: true,
537
+ handleOnClick: handleView,
538
+ label: t("actionsButtonView"),
539
+ order: 1,
540
+ },
541
+ {
542
+ enabled: true,
543
+ handleOnClick: handleEdit,
544
+ label: t("actionsButtonEdit"),
545
+ order: 2,
546
+ },
547
+ {
548
+ enabled: false,
549
+ handleOnClick: handleDelete,
550
+ label: t("actionsButtonDelete"),
551
+ order: 3,
552
+ variant: "destructive",
553
+ },
554
+ ], [handleDelete, handleEdit, handleView, t]);
555
+ // ============================================================================
556
+ // 1.4.9 EFFECTS
557
+ // ============================================================================
558
+ useEffect(() => {
559
+ var _a;
560
+ if (!schoolId)
561
+ return;
562
+ if (isDefaultListState) {
563
+ (async () => {
564
+ try {
565
+ const { count, items } = await getCachedStudentFees({
566
+ params: listParams,
567
+ });
568
+ dispatch({
569
+ type: STUDENT_FEE_ACTION_TYPES.SET_ITEMS,
570
+ payload: { items: items || [], count: count || 0 },
571
+ });
572
+ }
573
+ catch (_a) {
574
+ showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
575
+ }
576
+ })();
577
+ return;
578
+ }
579
+ (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
580
+ }, [dispatch, isDefaultListState, listParams, schoolId, showToast, t]);
581
+ useEffect(() => {
582
+ listFetchNowRef.current = listFetchNow;
583
+ }, [listFetchNow]);
584
+ // ============================================================================
585
+ // 1.4.10 RETURN
586
+ // ============================================================================
587
+ return Object.assign(Object.assign({}, context), { applyFilters,
588
+ byIdLoading,
589
+ clearFilters,
590
+ clearSearch,
591
+ closeDrawer,
592
+ deleteLoading,
593
+ handleChange,
594
+ handleCreate,
595
+ handleDelete,
596
+ handleEdit,
597
+ handleFilters,
598
+ handleMoreActions,
599
+ handlePageChange,
600
+ handlePageLimitChange,
601
+ handleSearch,
602
+ handleSubmit,
603
+ handleView,
604
+ headerActions,
605
+ listFetchNow,
606
+ listLoading,
607
+ rowActions,
608
+ toggleStatus,
609
+ updateLoading });
610
+ };