@appcorp/fusion-storybook 0.2.13 → 0.2.15

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