@appcorp/fusion-storybook 0.3.85 → 0.3.86

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.
@@ -0,0 +1,3 @@
1
+ export { STUDENT_FEE_DRAWER, STUDENT_FEE_ACTION_TYPES, studentFeeModuleConfig, initialStudentFeeState, StudentFeeProvider, studentFeeReducer, useStudentFeeContext, } from "./shared";
2
+ export { StudentFeeApiProvider, useStudentFeeApiContext } from "./student-fee-api-provider";
3
+ export { useStudentFeeModule } from "./use-student-fee-module";
@@ -0,0 +1,3 @@
1
+ export { STUDENT_FEE_DRAWER, STUDENT_FEE_ACTION_TYPES, studentFeeModuleConfig, initialStudentFeeState, StudentFeeProvider, studentFeeReducer, useStudentFeeContext, } from "./shared";
2
+ export { StudentFeeApiProvider, useStudentFeeApiContext } from "./student-fee-api-provider";
3
+ export { useStudentFeeModule } from "./use-student-fee-module";
@@ -0,0 +1,16 @@
1
+ import type { FetchConfig } from "@react-pakistan/util-functions/hooks/use-fetch";
2
+ export interface StudentFeeApiContextType {
3
+ listFetchNow: (url?: string, config?: FetchConfig) => void;
4
+ listLoading: boolean;
5
+ updateFetchNow: (url?: string, config?: FetchConfig) => void;
6
+ updateLoading: boolean;
7
+ byIdFetchNow: (url?: string, config?: FetchConfig) => void;
8
+ byIdLoading: boolean;
9
+ deleteFetchNow?: (url?: string, config?: FetchConfig) => void;
10
+ deleteLoading: boolean;
11
+ resetFormAndCloseDrawer: () => void;
12
+ }
13
+ export declare const useStudentFeeApiContext: () => StudentFeeApiContextType;
14
+ export declare const StudentFeeApiProvider: ({ children, }: {
15
+ children: React.ReactNode;
16
+ }) => import("react").JSX.Element;
@@ -0,0 +1,233 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef } from "react";
4
+ import { useTheme } from "next-themes";
5
+ import { useTranslations } from "next-intl";
6
+ import { isCreatedOrUpdated } from "@react-pakistan/util-functions/general/is-created-or-updated";
7
+ import { useModuleEntityV2, } from "@react-pakistan/util-functions/hooks/use-module-entity-v2";
8
+ import { useDebounce } from "@react-pakistan/util-functions/hooks/use-debounce";
9
+ import { generateThemeToast, TOAST_VARIANT, } from "@appcorp/shadcn/lib/toast-utils";
10
+ import { STUDENT_FEE_API_ROUTES } from "../../../constants";
11
+ import { getCachedWorkspaceSync } from "../../workspace/cache";
12
+ import { STUDENT_FEE_ACTION_TYPES, useStudentFeeContext, } from "./shared";
13
+ // ============================================================================
14
+ // CONTEXT
15
+ // ============================================================================
16
+ const StudentFeeApiContext = createContext(null);
17
+ export const useStudentFeeApiContext = () => {
18
+ const ctx = useContext(StudentFeeApiContext);
19
+ if (!ctx) {
20
+ throw new Error("useStudentFeeApiContext must be used within StudentFeeApiProvider");
21
+ }
22
+ return ctx;
23
+ };
24
+ // ============================================================================
25
+ // PROVIDER
26
+ // ============================================================================
27
+ export const StudentFeeApiProvider = ({ children, }) => {
28
+ var _a;
29
+ const context = useStudentFeeContext();
30
+ const { dispatch } = context;
31
+ const state = context.state;
32
+ const t = useTranslations("studentFee");
33
+ const { theme } = useTheme();
34
+ const workspace = getCachedWorkspaceSync();
35
+ const debouncedQuery = useDebounce(state.searchQuery, 800);
36
+ const schoolId = ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "";
37
+ // ==========================================================================
38
+ // UTILITIES
39
+ // ==========================================================================
40
+ const showToast = useCallback((description, variant) => {
41
+ generateThemeToast({
42
+ description,
43
+ theme: theme,
44
+ variant,
45
+ });
46
+ }, [theme]);
47
+ const resetFormAndCloseDrawer = useCallback(() => {
48
+ dispatch({ type: STUDENT_FEE_ACTION_TYPES.RESET_FORM });
49
+ dispatch({
50
+ type: STUDENT_FEE_ACTION_TYPES.SET_ERRORS,
51
+ payload: { errors: {} },
52
+ });
53
+ dispatch({
54
+ type: STUDENT_FEE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
55
+ payload: { disabled: false },
56
+ });
57
+ dispatch({
58
+ type: STUDENT_FEE_ACTION_TYPES.SET_DRAWER,
59
+ payload: { drawer: null },
60
+ });
61
+ }, [dispatch]);
62
+ // ==========================================================================
63
+ // API PARAMETERS
64
+ // ==========================================================================
65
+ const listParams = useMemo(() => (Object.assign({ currentPage: state.currentPage, pageLimit: state.pageLimit, schoolId }, (debouncedQuery ? { searchQuery: debouncedQuery } : {}))), [state.currentPage, state.pageLimit, debouncedQuery, schoolId]);
66
+ const updateParams = useMemo(() => ({
67
+ amount: Number(state.amount),
68
+ amountDue: Number(state.amountDue),
69
+ amountPaid: Number(state.amountPaid),
70
+ discountAmount: Number(state.discountAmount),
71
+ discountCodeId: state.discountCodeId,
72
+ dueDate: state.dueDate,
73
+ enabled: state.enabled,
74
+ familyId: state.familyId,
75
+ feeStructureId: state.feeStructureId,
76
+ id: state.id,
77
+ paidAt: state.paidAt || null,
78
+ remarks: state.remarks || null,
79
+ schoolId,
80
+ status: state.status,
81
+ studentProfileId: state.studentProfileId,
82
+ }), [
83
+ state.amount,
84
+ state.amountDue,
85
+ state.amountPaid,
86
+ state.discountAmount,
87
+ state.discountCodeId,
88
+ state.dueDate,
89
+ state.enabled,
90
+ state.familyId,
91
+ state.feeStructureId,
92
+ state.id,
93
+ state.paidAt,
94
+ state.remarks,
95
+ state.status,
96
+ state.studentProfileId,
97
+ schoolId,
98
+ ]);
99
+ const byIdParams = useMemo(() => ({ id: state.id }), [state.id]);
100
+ const deleteParams = useMemo(() => ({ id: state.id }), [state.id]);
101
+ // ==========================================================================
102
+ // API CALLBACKS
103
+ // ==========================================================================
104
+ const listCallback = useCallback(({ data, error }) => {
105
+ var _a, _b;
106
+ if (error) {
107
+ showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
108
+ return;
109
+ }
110
+ if (data) {
111
+ const response = data;
112
+ dispatch({
113
+ type: STUDENT_FEE_ACTION_TYPES.SET_ITEMS,
114
+ payload: { items: (_a = response.items) !== null && _a !== void 0 ? _a : [], count: (_b = response.count) !== null && _b !== void 0 ? _b : 0 },
115
+ });
116
+ }
117
+ }, [dispatch, showToast, t]);
118
+ const listFetchNowRef = useRef(null);
119
+ const updateCallback = useCallback(({ data, error }) => {
120
+ var _a;
121
+ if (error) {
122
+ showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
123
+ return;
124
+ }
125
+ if (data) {
126
+ const isCreated = isCreatedOrUpdated(data);
127
+ showToast(isCreated
128
+ ? t("messagesStudentFeeCreated")
129
+ : t("messagesStudentFeeUpdated"), TOAST_VARIANT.SUCCESS);
130
+ resetFormAndCloseDrawer();
131
+ (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
132
+ }
133
+ }, [showToast, t, resetFormAndCloseDrawer]);
134
+ const byIdCallback = useCallback(({ data, error }) => {
135
+ if (error) {
136
+ showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
137
+ return;
138
+ }
139
+ if (data) {
140
+ const fee = data;
141
+ const rawDueDate = fee.dueDate;
142
+ const dueDate = rawDueDate instanceof Date
143
+ ? `${rawDueDate.getFullYear()}-${String(rawDueDate.getMonth() + 1).padStart(2, "0")}-${String(rawDueDate.getDate()).padStart(2, "0")}`
144
+ : String(rawDueDate).slice(0, 10);
145
+ const rawPaidAt = fee.paidAt;
146
+ const today = new Date();
147
+ const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(today.getDate()).padStart(2, "0")}`;
148
+ const paidAt = rawPaidAt instanceof Date
149
+ ? `${rawPaidAt.getFullYear()}-${String(rawPaidAt.getMonth() + 1).padStart(2, "0")}-${String(rawPaidAt.getDate()).padStart(2, "0")}`
150
+ : rawPaidAt
151
+ ? String(rawPaidAt).slice(0, 10)
152
+ : todayStr;
153
+ const originalFee = Number(fee.amount) + Number(fee.discountAmount || 0);
154
+ dispatch({
155
+ type: STUDENT_FEE_ACTION_TYPES.SET_FORM_DATA,
156
+ payload: {
157
+ form: Object.assign(Object.assign({}, fee), { dueDate,
158
+ paidAt,
159
+ originalFee }),
160
+ },
161
+ });
162
+ }
163
+ }, [dispatch, showToast, t]);
164
+ const deleteCallback = useCallback(({ data, error }) => {
165
+ var _a;
166
+ if (error) {
167
+ showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
168
+ return;
169
+ }
170
+ if (data) {
171
+ showToast(t("messagesStudentFeeDeleted"), TOAST_VARIANT.SUCCESS);
172
+ (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
173
+ }
174
+ }, [showToast, t]);
175
+ // ==========================================================================
176
+ // SINGLE API HOOK INSTANCE
177
+ // ==========================================================================
178
+ const { listFetchNow, listLoading, updateFetchNow, updateLoading, byIdFetchNow, deleteFetchNow, deleteLoading, byIdLoading, } = useModuleEntityV2({
179
+ byIdCallback,
180
+ byIdParams,
181
+ deleteCallback,
182
+ deleteParams,
183
+ listCallback,
184
+ listParams,
185
+ listUrl: STUDENT_FEE_API_ROUTES.UNIT,
186
+ searchQuery: debouncedQuery,
187
+ unitByIdUrl: STUDENT_FEE_API_ROUTES.UNIT,
188
+ unitUrl: STUDENT_FEE_API_ROUTES.UNIT,
189
+ updateCallback,
190
+ updateParams,
191
+ headers: {
192
+ "Content-Type": "application/json",
193
+ },
194
+ });
195
+ // ==========================================================================
196
+ // REF SYNC (for callbacks to always call the latest fetch)
197
+ // ==========================================================================
198
+ useEffect(() => {
199
+ listFetchNowRef.current = listFetchNow;
200
+ }, [listFetchNow]);
201
+ // ==========================================================================
202
+ // AUTO-FETCH EFFECT (runs once, not per child mount)
203
+ // ==========================================================================
204
+ useEffect(() => {
205
+ var _a;
206
+ (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
207
+ }, [listParams]);
208
+ // ==========================================================================
209
+ // CONTEXT VALUE
210
+ // ==========================================================================
211
+ const value = useMemo(() => ({
212
+ listFetchNow,
213
+ listLoading,
214
+ updateFetchNow,
215
+ updateLoading,
216
+ byIdFetchNow,
217
+ byIdLoading,
218
+ deleteFetchNow,
219
+ deleteLoading,
220
+ resetFormAndCloseDrawer,
221
+ }), [
222
+ listFetchNow,
223
+ listLoading,
224
+ updateFetchNow,
225
+ updateLoading,
226
+ byIdFetchNow,
227
+ byIdLoading,
228
+ deleteFetchNow,
229
+ deleteLoading,
230
+ resetFormAndCloseDrawer,
231
+ ]);
232
+ return (_jsx(StudentFeeApiContext.Provider, { value: value, children: children }));
233
+ };
@@ -1,13 +1,10 @@
1
1
  "use client";
2
- import { useCallback, useEffect, useMemo, useRef } from "react";
2
+ import { useCallback, useMemo } from "react";
3
3
  import { useTheme } from "next-themes";
4
4
  import { useTranslations } from "next-intl";
5
5
  import { validateForm } from "@react-pakistan/util-functions/general/validate-form";
6
- import { isCreatedOrUpdated } from "@react-pakistan/util-functions/general/is-created-or-updated";
7
6
  import { getStorageValue } from "@react-pakistan/util-functions/local-storage/get-storage-value";
8
7
  import { API_METHODS } from "@react-pakistan/util-functions/constants/api-methods";
9
- import { useModuleEntityV2, } from "@react-pakistan/util-functions/hooks/use-module-entity-v2";
10
- import { useDebounce } from "@react-pakistan/util-functions/hooks/use-debounce";
11
8
  import { generateThemeToast, TOAST_VARIANT, } from "@appcorp/shadcn/lib/toast-utils";
12
9
  import { PAYMENT_STATUS, DISCOUNT_TYPE, } from "../../../type";
13
10
  import { STUDENT_FEE_API_ROUTES } from "../../../constants";
@@ -16,6 +13,7 @@ import { getCachedWorkspaceSync } from "../../workspace/cache";
16
13
  import { getCachedFeeStructureById } from "../../fee-structure/cache";
17
14
  import { getCachedDiscountCodesSync } from "../../discount-code/cache";
18
15
  import { STUDENT_FEE_ACTION_TYPES, STUDENT_FEE_DRAWER, useStudentFeeContext, } from "./shared";
16
+ import { useStudentFeeApiContext } from "./student-fee-api-provider";
19
17
  // ============================================================================
20
18
  // AMOUNT CALCULATION HELPER
21
19
  // ============================================================================
@@ -29,59 +27,19 @@ const calculateAmounts = (originalFee, discountAmount, amountPaid) => {
29
27
  // ============================================================================
30
28
  export const useStudentFeeModule = () => {
31
29
  // ============================================================================
32
- // 1.4.1 STATE & CORE HOOKS
30
+ // 1.4.1 STATE, CONTEXT & API HOOKS
33
31
  // ============================================================================
34
32
  var _a, _b, _c, _d;
35
33
  const context = useStudentFeeContext();
36
34
  const { dispatch } = context;
37
35
  const state = context.state;
36
+ const { listFetchNow, listLoading, updateFetchNow, updateLoading, byIdFetchNow, byIdLoading, deleteFetchNow, deleteLoading, resetFormAndCloseDrawer, } = useStudentFeeApiContext();
38
37
  const t = useTranslations("studentFee");
39
38
  const { theme } = useTheme();
40
39
  const workspace = getCachedWorkspaceSync();
41
- const listFetchNowRef = useRef(null);
42
- const debouncedQuery = useDebounce(state.searchQuery, 800);
43
40
  const schoolId = ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "";
44
41
  // ============================================================================
45
- // 1.4.2 API PARAMETERS
46
- // ============================================================================
47
- const listParams = useMemo(() => (Object.assign({ currentPage: state.currentPage, pageLimit: state.pageLimit, schoolId }, (debouncedQuery ? { searchQuery: debouncedQuery } : {}))), [state.currentPage, state.pageLimit, debouncedQuery, schoolId]);
48
- const updateParams = useMemo(() => ({
49
- amount: Number(state.amount),
50
- amountDue: Number(state.amountDue),
51
- amountPaid: Number(state.amountPaid),
52
- discountAmount: Number(state.discountAmount),
53
- discountCodeId: state.discountCodeId,
54
- dueDate: state.dueDate,
55
- enabled: state.enabled,
56
- familyId: state.familyId,
57
- feeStructureId: state.feeStructureId,
58
- id: state.id,
59
- paidAt: state.paidAt || null,
60
- remarks: state.remarks || null,
61
- schoolId,
62
- status: state.status,
63
- studentProfileId: state.studentProfileId,
64
- }), [
65
- state.amount,
66
- state.amountDue,
67
- state.amountPaid,
68
- state.discountAmount,
69
- state.discountCodeId,
70
- state.dueDate,
71
- state.enabled,
72
- state.familyId,
73
- state.feeStructureId,
74
- state.id,
75
- state.paidAt,
76
- state.remarks,
77
- state.status,
78
- state.studentProfileId,
79
- schoolId,
80
- ]);
81
- const byIdParams = useMemo(() => ({ id: state.id }), [state.id]);
82
- const deleteParams = useMemo(() => ({ id: state.id }), [state.id]);
83
- // ============================================================================
84
- // 1.4.3 UTILITIES
42
+ // 1.4.2 UTILITIES
85
43
  // ============================================================================
86
44
  const showToast = useCallback((description, variant) => {
87
45
  generateThemeToast({
@@ -90,21 +48,6 @@ export const useStudentFeeModule = () => {
90
48
  variant,
91
49
  });
92
50
  }, [theme]);
93
- const resetFormAndCloseDrawer = useCallback(() => {
94
- dispatch({ type: STUDENT_FEE_ACTION_TYPES.RESET_FORM });
95
- dispatch({
96
- type: STUDENT_FEE_ACTION_TYPES.SET_ERRORS,
97
- payload: { errors: {} },
98
- });
99
- dispatch({
100
- type: STUDENT_FEE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
101
- payload: { disabled: false },
102
- });
103
- dispatch({
104
- type: STUDENT_FEE_ACTION_TYPES.SET_DRAWER,
105
- payload: { drawer: null },
106
- });
107
- }, [dispatch]);
108
51
  const resetRecordFormState = useCallback(() => {
109
52
  var _a, _b;
110
53
  const dueDay = (_a = workspace === null || workspace === void 0 ? void 0 : workspace.dueDateLength) !== null && _a !== void 0 ? _a : 1;
@@ -148,101 +91,43 @@ export const useStudentFeeModule = () => {
148
91
  });
149
92
  }, [dispatch, workspace === null || workspace === void 0 ? void 0 : workspace.dueDateLength, (_b = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _b === void 0 ? void 0 : _b.id]);
150
93
  // ============================================================================
151
- // 1.4.4 API CALLBACKS
152
- // ============================================================================
153
- const listCallback = useCallback(({ data, error }) => {
154
- var _a, _b;
155
- if (error) {
156
- showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
157
- return;
158
- }
159
- if (data) {
160
- const response = data;
161
- dispatch({
162
- type: STUDENT_FEE_ACTION_TYPES.SET_ITEMS,
163
- payload: { items: (_a = response.items) !== null && _a !== void 0 ? _a : [], count: (_b = response.count) !== null && _b !== void 0 ? _b : 0 },
164
- });
165
- }
166
- }, [dispatch, showToast, t]);
167
- const updateCallback = useCallback(({ data, error }) => {
168
- var _a;
169
- if (error) {
170
- showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
171
- return;
172
- }
173
- if (data) {
174
- const isCreated = isCreatedOrUpdated(data);
175
- showToast(isCreated
176
- ? t("messagesStudentFeeCreated")
177
- : t("messagesStudentFeeUpdated"), TOAST_VARIANT.SUCCESS);
178
- resetFormAndCloseDrawer();
179
- (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
180
- }
181
- }, [showToast, t, resetFormAndCloseDrawer]);
182
- const byIdCallback = useCallback(({ data, error }) => {
183
- if (error) {
184
- showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
185
- return;
186
- }
187
- if (data) {
188
- const fee = data;
189
- const rawDueDate = fee.dueDate;
190
- const dueDate = rawDueDate instanceof Date
191
- ? `${rawDueDate.getFullYear()}-${String(rawDueDate.getMonth() + 1).padStart(2, "0")}-${String(rawDueDate.getDate()).padStart(2, "0")}`
192
- : String(rawDueDate).slice(0, 10);
193
- const rawPaidAt = fee.paidAt;
194
- const today = new Date();
195
- const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(today.getDate()).padStart(2, "0")}`;
196
- const paidAt = rawPaidAt instanceof Date
197
- ? `${rawPaidAt.getFullYear()}-${String(rawPaidAt.getMonth() + 1).padStart(2, "0")}-${String(rawPaidAt.getDate()).padStart(2, "0")}`
198
- : rawPaidAt
199
- ? String(rawPaidAt).slice(0, 10)
200
- : todayStr;
201
- const originalFee = Number(fee.amount) + Number(fee.discountAmount || 0);
202
- dispatch({
203
- type: STUDENT_FEE_ACTION_TYPES.SET_FORM_DATA,
204
- payload: {
205
- form: Object.assign(Object.assign({}, fee), { dueDate,
206
- paidAt,
207
- originalFee }),
208
- },
209
- });
210
- }
211
- }, [dispatch, showToast, t]);
212
- const deleteCallback = useCallback(({ data, error }) => {
213
- var _a;
214
- if (error) {
215
- showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
216
- return;
217
- }
218
- if (data) {
219
- showToast(t("messagesStudentFeeDeleted"), TOAST_VARIANT.SUCCESS);
220
- (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
221
- }
222
- }, [showToast, t]);
223
- // ============================================================================
224
- // 1.4.5 API HOOKS
94
+ // 1.4.3 UPDATE PARAMS (used by handleSubmit for validation + fetch body)
225
95
  // ============================================================================
226
- const { listFetchNow, listLoading, updateFetchNow, updateLoading, byIdFetchNow, deleteFetchNow, deleteLoading, byIdLoading, } = useModuleEntityV2({
227
- byIdCallback,
228
- byIdParams,
229
- deleteCallback,
230
- deleteParams,
231
- listCallback,
232
- listParams,
233
- listUrl: STUDENT_FEE_API_ROUTES.UNIT,
234
- searchQuery: debouncedQuery,
235
- unitByIdUrl: STUDENT_FEE_API_ROUTES.UNIT,
236
- unitUrl: STUDENT_FEE_API_ROUTES.UNIT,
237
- updateCallback,
238
- updateParams,
239
- headers: {
240
- "Content-Type": "application/json",
241
- // "x-api-token": process.env.NEXT_PUBLIC_API_KEY!,
242
- },
243
- });
96
+ const updateParams = useMemo(() => ({
97
+ amount: Number(state.amount),
98
+ amountDue: Number(state.amountDue),
99
+ amountPaid: Number(state.amountPaid),
100
+ discountAmount: Number(state.discountAmount),
101
+ discountCodeId: state.discountCodeId,
102
+ dueDate: state.dueDate,
103
+ enabled: state.enabled,
104
+ familyId: state.familyId,
105
+ feeStructureId: state.feeStructureId,
106
+ id: state.id,
107
+ paidAt: state.paidAt || null,
108
+ remarks: state.remarks || null,
109
+ schoolId,
110
+ status: state.status,
111
+ studentProfileId: state.studentProfileId,
112
+ }), [
113
+ state.amount,
114
+ state.amountDue,
115
+ state.amountPaid,
116
+ state.discountAmount,
117
+ state.discountCodeId,
118
+ state.dueDate,
119
+ state.enabled,
120
+ state.familyId,
121
+ state.feeStructureId,
122
+ state.id,
123
+ state.paidAt,
124
+ state.remarks,
125
+ state.status,
126
+ state.studentProfileId,
127
+ schoolId,
128
+ ]);
244
129
  // ============================================================================
245
- // 1.4.6 HANDLERS
130
+ // 1.4.4 HANDLERS
246
131
  // ============================================================================
247
132
  const handleChange = useCallback(async (field, value) => {
248
133
  var _a, _b, _c;
@@ -515,15 +400,16 @@ export const useStudentFeeModule = () => {
515
400
  payload: { currentPage: 1 },
516
401
  });
517
402
  listFetchNow === null || listFetchNow === void 0 ? void 0 : listFetchNow(undefined, {
518
- params: Object.assign(Object.assign(Object.assign({}, listParams), (state.filterEnabled && { filterEnabled: state.filterEnabled })), (state.filterStatus && { filterStatus: state.filterStatus })),
403
+ params: Object.assign(Object.assign({ currentPage: 1, pageLimit: state.pageLimit, schoolId }, (state.filterEnabled && { filterEnabled: state.filterEnabled })), (state.filterStatus && { filterStatus: state.filterStatus })),
519
404
  });
520
405
  }, [
521
406
  closeDrawer,
522
407
  dispatch,
523
408
  listFetchNow,
524
- listParams,
409
+ schoolId,
525
410
  state.filterEnabled,
526
411
  state.filterStatus,
412
+ state.pageLimit,
527
413
  ]);
528
414
  const clearFilters = useCallback(() => {
529
415
  dispatch({
@@ -548,10 +434,10 @@ export const useStudentFeeModule = () => {
548
434
  });
549
435
  }, [dispatch]);
550
436
  // ============================================================================
551
- // 1.4.7 NETWORK ACTIONS
437
+ // 1.4.5 NETWORK ACTIONS
552
438
  // ============================================================================
553
439
  const handleProceedMonthlyCreation = useCallback(async () => {
554
- var _a, _b;
440
+ var _a;
555
441
  const schoolId = (_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id;
556
442
  if (!schoolId) {
557
443
  showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
@@ -574,9 +460,9 @@ export const useStudentFeeModule = () => {
574
460
  }
575
461
  showToast(t("messagesMonthlyJobQueued"), TOAST_VARIANT.SUCCESS);
576
462
  resetFormAndCloseDrawer();
577
- (_b = listFetchNowRef.current) === null || _b === void 0 ? void 0 : _b.call(listFetchNowRef);
463
+ listFetchNow === null || listFetchNow === void 0 ? void 0 : listFetchNow();
578
464
  }
579
- catch (_c) {
465
+ catch (_b) {
580
466
  showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
581
467
  }
582
468
  finally {
@@ -585,7 +471,7 @@ export const useStudentFeeModule = () => {
585
471
  payload: { disabled: false },
586
472
  });
587
473
  }
588
- }, [dispatch, showToast, t, (_c = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _c === void 0 ? void 0 : _c.id, resetFormAndCloseDrawer]);
474
+ }, [dispatch, showToast, t, (_c = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _c === void 0 ? void 0 : _c.id, resetFormAndCloseDrawer, listFetchNow]);
589
475
  const handleSubmit = useCallback(() => {
590
476
  dispatch({
591
477
  type: STUDENT_FEE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
@@ -613,13 +499,12 @@ export const useStudentFeeModule = () => {
613
499
  });
614
500
  }, [dispatch, updateParams, t, showToast, updateFetchNow]);
615
501
  const handleSubmitSingleEntry = useCallback(async (fees, amountPaid, remarks, paidAt) => {
616
- var _a, _b;
502
+ var _a;
617
503
  dispatch({
618
504
  type: STUDENT_FEE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
619
505
  payload: { disabled: true },
620
506
  });
621
507
  try {
622
- // const feeIds = fees.map((f) => f.id);
623
508
  const res = await fetch(STUDENT_FEE_API_ROUTES.SINGLE_ENTRY, {
624
509
  method: API_METHODS.POST,
625
510
  headers: { "Content-Type": "application/json" },
@@ -638,9 +523,9 @@ export const useStudentFeeModule = () => {
638
523
  }
639
524
  showToast(t("messagesStudentFeeUpdated"), TOAST_VARIANT.SUCCESS);
640
525
  resetFormAndCloseDrawer();
641
- (_b = listFetchNowRef.current) === null || _b === void 0 ? void 0 : _b.call(listFetchNowRef);
526
+ listFetchNow === null || listFetchNow === void 0 ? void 0 : listFetchNow();
642
527
  }
643
- catch (_c) {
528
+ catch (_b) {
644
529
  showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
645
530
  }
646
531
  finally {
@@ -649,9 +534,9 @@ export const useStudentFeeModule = () => {
649
534
  payload: { disabled: false },
650
535
  });
651
536
  }
652
- }, [dispatch, showToast, t, (_d = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _d === void 0 ? void 0 : _d.id, resetFormAndCloseDrawer]);
537
+ }, [dispatch, showToast, t, (_d = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _d === void 0 ? void 0 : _d.id, resetFormAndCloseDrawer, listFetchNow]);
653
538
  // ============================================================================
654
- // 1.4.8 HEADER & ROW ACTIONS
539
+ // 1.4.6 HEADER & ROW ACTIONS
655
540
  // ============================================================================
656
541
  const headerActions = useMemo(() => [
657
542
  {
@@ -695,17 +580,7 @@ export const useStudentFeeModule = () => {
695
580
  },
696
581
  ], [handleDelete, handleEdit, handleView, t]);
697
582
  // ============================================================================
698
- // 1.4.9 EFFECTS
699
- // ============================================================================
700
- useEffect(() => {
701
- listFetchNowRef.current = listFetchNow;
702
- }, [listFetchNow]);
703
- useEffect(() => {
704
- var _a;
705
- (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
706
- }, [listParams]);
707
- // ============================================================================
708
- // 1.4.10 RETURN
583
+ // 1.4.7 RETURN
709
584
  // ============================================================================
710
585
  return Object.assign(Object.assign({}, context), { applyFilters,
711
586
  byIdLoading,
@@ -6,30 +6,19 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
6
  * Filter UI for the student-fee list. Supports filterEnabled (radio) and
7
7
  * filterStatus (payment status combobox).
8
8
  *
9
- * NOTE: This component intentionally avoids useStudentFeeModule() because
10
- * that hook creates an independent useModuleEntityV2 instance with its own
11
- * listFetchNow + auto-fetch effect, causing a redundant API call on mount
12
- * (each time the filter drawer opens). We only need state + a simple
13
- * handleChange, which context provides directly.
9
+ * The API provider (StudentFeeApiProvider) manages a single useModuleEntityV2
10
+ * instance shared across all consumers, so calling useStudentFeeModule from
11
+ * child components no longer creates redundant API hooks or auto-fetch effects.
14
12
  */
15
- import { useCallback } from "react";
16
13
  import { EnhancedRadio } from "@appcorp/shadcn/components/enhanced-radio";
17
14
  import { useEnhancedCombobox } from "@appcorp/shadcn/hooks/use-enhanced-combobox";
18
- import { STUDENT_FEE_ACTION_TYPES, useStudentFeeContext, } from "./context/shared";
15
+ import { useStudentFeeModule } from "./context";
19
16
  import { PAYMENT_STATUS_OPTIONS } from "./constants";
20
17
  import { STUDENT_FEE_API_ROUTES } from "../../constants";
21
18
  import { useTranslations } from "next-intl";
22
19
  export const StudentFeeFilter = () => {
23
- const { state, dispatch } = useStudentFeeContext();
20
+ const { state, handleChange } = useStudentFeeModule();
24
21
  const { filterEnabled, filterStatus } = state;
25
- const handleChange = useCallback((field, value) => {
26
- if (field === "filterEnabled" || field === "filterStatus") {
27
- dispatch({
28
- type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
29
- payload: { key: field, value },
30
- });
31
- }
32
- }, [dispatch]);
33
22
  const t = useTranslations("studentFee");
34
23
  const paymentStatusLabelMap = {
35
24
  PENDING: t("formOptionPending"),
@@ -19,6 +19,7 @@ import { COMPONENT_TYPE } from "@appcorp/shadcn/components/enhanced-table";
19
19
  import { createGenericModulePage, } from "@react-pakistan/util-functions/factory/generic-component-factory";
20
20
  import { DATE_FORMATS, formatDate, } from "@react-pakistan/util-functions/general/format-date";
21
21
  import { useStudentFeeModule, StudentFeeProvider, STUDENT_FEE_ACTION_TYPES, } from "./context";
22
+ import { StudentFeeApiProvider } from "./context/student-fee-api-provider";
22
23
  import { StudentFeeFilter } from "./filter";
23
24
  import { StudentFeeForm } from "./form";
24
25
  import { StudentFeeMoreActions } from "./more-actions";
@@ -199,4 +200,4 @@ const StudentFeePageInner = (props) => {
199
200
  // ============================================================================
200
201
  // PAGE EXPORTS
201
202
  // ============================================================================
202
- export const StudentFeePage = (props) => (_jsx(StudentFeeProvider, { children: _jsx(StudentFeePageInner, Object.assign({}, props)) }));
203
+ export const StudentFeePage = (props) => (_jsx(StudentFeeProvider, { children: _jsx(StudentFeeApiProvider, { children: _jsx(StudentFeePageInner, Object.assign({}, props)) }) }));