@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
@@ -0,0 +1,771 @@
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, API_METHODS, fetchData, } 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 { ADMISSION_STATUS, GENDER, } from "../../../type";
10
+ import { ADMISSION_API_ROUTES, pageLimit } from "../constants";
11
+ import { admissionFormValidation } from "../validate";
12
+ import { getCachedAdmissions, invalidateAdmissionsCache } from "../cache";
13
+ import { getCachedWorkspaceSync } from "../../workspace/cache";
14
+ import { generateAdmissionReceiptPDF, } from "../../../utils/admission-pdf";
15
+ import { formatNumber } from "@react-pakistan/util-functions/general/format-number";
16
+ import { formatPhoneDisplay } from "@react-pakistan/util-functions/general/format-phone-display";
17
+ import { invalidateFamiliesCache } from "../../family/cache";
18
+ import { invalidateFamilyMembersCache } from "../../family-member/cache";
19
+ import { invalidateStudentProfilesCache } from "../../student-profile/cache";
20
+ import { Filter, Plus } from "lucide-react";
21
+ import { ADMISSION_DRAWER, ADMISSION_ACTION_TYPES, useAdmissionContext, } from "../context";
22
+ export const useAdmissionModule = () => {
23
+ var _a, _b, _c, _d, _e, _f;
24
+ // ============================================================================
25
+ // 1.4.1 STATE & CORE HOOKS
26
+ // ============================================================================
27
+ const context = useAdmissionContext();
28
+ const { dispatch } = context;
29
+ const state = context.state;
30
+ const t = useTranslations("admission");
31
+ const { theme } = useTheme();
32
+ const workspace = getCachedWorkspaceSync();
33
+ const listFetchNowRef = useRef(null);
34
+ const debouncedQuery = useDebounce(state.searchQuery, 800);
35
+ // ============================================================================
36
+ // 1.4.2 API PARAMETERS
37
+ // ============================================================================
38
+ const listParams = useMemo(() => {
39
+ var _a;
40
+ return (Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ currentPage: state.currentPage, pageLimit: state.pageLimit, schoolId: ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "" }, (debouncedQuery ? { searchQuery: debouncedQuery } : {})), (state.filterEnabled !== undefined
41
+ ? { filterEnabled: String(state.filterEnabled) }
42
+ : {})), (state.filterAdmissionStatus
43
+ ? { filterAdmissionStatus: state.filterAdmissionStatus }
44
+ : {})), (state.filterStartDate
45
+ ? { filterStartDate: state.filterStartDate }
46
+ : {})), (state.filterEndDate ? { filterEndDate: state.filterEndDate } : {})));
47
+ }, [
48
+ state.currentPage,
49
+ state.filterAdmissionStatus,
50
+ state.filterEnabled,
51
+ state.filterEndDate,
52
+ state.filterStartDate,
53
+ state.pageLimit,
54
+ debouncedQuery,
55
+ (_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id,
56
+ ]);
57
+ const updateParams = useMemo(() => {
58
+ var _a, _b, _c, _d;
59
+ return ({
60
+ address: state.address || "",
61
+ admissionNotes: state.admissionNotes || "",
62
+ admissionStatus: state.status || ADMISSION_STATUS.PENDING,
63
+ studentIdNumber: state.studentIdNumber || "",
64
+ city: state.city || "",
65
+ classForAdmission: state.classForAdmission || "",
66
+ country: state.country || "",
67
+ discountCode: state.discountCode || "",
68
+ dob: state.dob || null,
69
+ emergencyContact: state.emergencyContact || "",
70
+ enabled: (_a = state.enabled) !== null && _a !== void 0 ? _a : true,
71
+ fatherIdNumber: state.fatherIdNumber || "",
72
+ fatherFirstName: state.fatherFirstName || "",
73
+ fatherLastName: state.fatherLastName || "",
74
+ fatherMobile: formatNumber(state.fatherMobile),
75
+ fatherOccupation: state.fatherOccupation || "",
76
+ fatherOrganization: state.fatherOrganization || "",
77
+ firstName: state.firstName || "",
78
+ gender: state.gender || null,
79
+ hafiz: (_b = state.hafiz) !== null && _b !== void 0 ? _b : false,
80
+ id: state.id || "",
81
+ lastName: state.lastName || "",
82
+ motherIdNumber: state.motherIdNumber || "",
83
+ motherFirstName: state.motherFirstName || "",
84
+ motherLastName: state.motherLastName || "",
85
+ motherMobile: formatNumber(state.motherMobile),
86
+ notes: state.notes || "",
87
+ orphan: (_c = state.orphan) !== null && _c !== void 0 ? _c : false,
88
+ postalCode: state.postalCode || "",
89
+ previousSchool: state.previousSchool || "",
90
+ registrationCode: state.registrationCode || "",
91
+ schoolId: ((_d = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _d === void 0 ? void 0 : _d.id) || "",
92
+ siblings: state.siblings || "",
93
+ state: state.state || "",
94
+ });
95
+ }, [
96
+ state.address,
97
+ state.admissionNotes,
98
+ state.status,
99
+ state.studentIdNumber,
100
+ state.city,
101
+ state.classForAdmission,
102
+ state.country,
103
+ state.discountCode,
104
+ state.dob,
105
+ state.emergencyContact,
106
+ state.enabled,
107
+ state.fatherIdNumber,
108
+ state.fatherFirstName,
109
+ state.fatherLastName,
110
+ state.fatherMobile,
111
+ state.fatherOccupation,
112
+ state.fatherOrganization,
113
+ state.firstName,
114
+ state.gender,
115
+ state.hafiz,
116
+ state.id,
117
+ state.lastName,
118
+ state.motherIdNumber,
119
+ state.motherFirstName,
120
+ state.motherLastName,
121
+ state.motherMobile,
122
+ state.notes,
123
+ state.orphan,
124
+ state.postalCode,
125
+ state.previousSchool,
126
+ state.registrationCode,
127
+ state.siblings,
128
+ state.state,
129
+ (_b = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _b === void 0 ? void 0 : _b.id,
130
+ ]);
131
+ const byIdParams = useMemo(() => ({ id: state.id }), [state.id]);
132
+ const deleteParams = useMemo(() => ({ id: state.id }), [state.id]);
133
+ const isDefaultListState = state.currentPage === 1 &&
134
+ state.pageLimit === pageLimit &&
135
+ !debouncedQuery &&
136
+ state.filterAdmissionStatus === undefined &&
137
+ state.filterStartDate === undefined &&
138
+ state.filterEndDate === undefined;
139
+ // ============================================================================
140
+ // 1.4.3 UTILITIES
141
+ // ============================================================================
142
+ const showToast = useCallback((description, variant) => {
143
+ generateThemeToast({
144
+ description,
145
+ theme: theme,
146
+ variant,
147
+ });
148
+ }, [theme]);
149
+ const setField = useCallback((key, value) => {
150
+ var _a;
151
+ let formatted = value === null
152
+ ? undefined
153
+ : value;
154
+ if ((key === "fatherMobile" || key === "motherMobile") &&
155
+ typeof value === "string") {
156
+ formatted = (_a = formatPhoneDisplay(value)) !== null && _a !== void 0 ? _a : value;
157
+ }
158
+ dispatch({
159
+ type: ADMISSION_ACTION_TYPES.SET_INPUT_FIELD,
160
+ payload: { key, value: formatted || value },
161
+ });
162
+ }, [dispatch]);
163
+ const resetFormAndCloseDrawer = useCallback(() => {
164
+ dispatch({ type: ADMISSION_ACTION_TYPES.RESET_FORM });
165
+ dispatch({
166
+ type: ADMISSION_ACTION_TYPES.SET_ERRORS,
167
+ payload: { errors: {} },
168
+ });
169
+ dispatch({
170
+ type: ADMISSION_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
171
+ payload: { disabled: false },
172
+ });
173
+ dispatch({
174
+ type: ADMISSION_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
+ if (error) {
183
+ showToast(t("messagesFetchFailed"), TOAST_VARIANT.ERROR);
184
+ return;
185
+ }
186
+ if (data) {
187
+ dispatch({
188
+ type: ADMISSION_ACTION_TYPES.SET_ITEMS,
189
+ payload: { items: data.items || [], count: data.count || 0 },
190
+ });
191
+ }
192
+ }, [dispatch, showToast, t]);
193
+ const updateCallback = useCallback(({ data, error }) => {
194
+ var _a;
195
+ const isCreated = isCreatedOrUpdated(data);
196
+ if (error) {
197
+ showToast(isCreated ? t("messagesCreateFailed") : t("messagesUpdateFailed"), TOAST_VARIANT.ERROR);
198
+ return;
199
+ }
200
+ if (data) {
201
+ invalidateAdmissionsCache();
202
+ showToast(t("messagesSaveSuccess"), TOAST_VARIANT.SUCCESS);
203
+ resetFormAndCloseDrawer();
204
+ (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
205
+ }
206
+ }, [resetFormAndCloseDrawer, showToast, t]);
207
+ const byIdCallback = useCallback(({ data, error }) => {
208
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12;
209
+ if (error) {
210
+ showToast(t("messagesDetailsFetchFailed"), TOAST_VARIANT.ERROR);
211
+ return;
212
+ }
213
+ if (data) {
214
+ const admission = data;
215
+ if ((_a = admission === null || admission === void 0 ? void 0 : admission.fatherDetails) === null || _a === void 0 ? void 0 : _a.emergencyContact) {
216
+ setField("emergencyContact", "Father");
217
+ }
218
+ if ((_b = admission === null || admission === void 0 ? void 0 : admission.motherDetails) === null || _b === void 0 ? void 0 : _b.emergencyContact) {
219
+ setField("emergencyContact", "Mother");
220
+ }
221
+ setField("id", admission.id);
222
+ setField("firstName", (_c = admission.studentDetails) === null || _c === void 0 ? void 0 : _c.firstName);
223
+ setField("lastName", (_d = admission.studentDetails) === null || _d === void 0 ? void 0 : _d.lastName);
224
+ setField("studentIdNumber", (_e = admission.studentDetails) === null || _e === void 0 ? void 0 : _e.studentIdNumber);
225
+ // Normalise gender to match GENDER enum values (e.g. 'Male' → 'MALE')
226
+ const rawGender = (_f = admission.studentDetails) === null || _f === void 0 ? void 0 : _f.gender;
227
+ let normalizedGender = null;
228
+ if (typeof rawGender === "string" && rawGender.length > 0) {
229
+ const upper = rawGender.toUpperCase();
230
+ normalizedGender = Object.values(GENDER).includes(upper)
231
+ ? upper
232
+ : rawGender;
233
+ }
234
+ setField("gender", normalizedGender);
235
+ setField("dob", (_g = admission.studentDetails) === null || _g === void 0 ? void 0 : _g.dob);
236
+ setField("registrationCode", (_h = admission.studentDetails) === null || _h === void 0 ? void 0 : _h.registrationCode);
237
+ setField("discountCode", (_j = admission.studentDetails) === null || _j === void 0 ? void 0 : _j.discountCode);
238
+ setField("hafiz", (_k = admission.studentDetails) === null || _k === void 0 ? void 0 : _k.hafiz);
239
+ setField("orphan", (_l = admission.studentDetails) === null || _l === void 0 ? void 0 : _l.orphan);
240
+ setField("fatherFirstName", (_m = admission.fatherDetails) === null || _m === void 0 ? void 0 : _m.fatherFirstName);
241
+ setField("fatherLastName", (_o = admission.fatherDetails) === null || _o === void 0 ? void 0 : _o.fatherLastName);
242
+ setField("fatherIdNumber", (_p = admission.fatherDetails) === null || _p === void 0 ? void 0 : _p.fatherIdNumber);
243
+ setField("fatherMobile", (_r = formatPhoneDisplay((_q = admission.fatherDetails) === null || _q === void 0 ? void 0 : _q.fatherMobile)) !== null && _r !== void 0 ? _r : (_s = admission.fatherDetails) === null || _s === void 0 ? void 0 : _s.fatherMobile);
244
+ setField("fatherOccupation", (_t = admission.fatherDetails) === null || _t === void 0 ? void 0 : _t.fatherOccupation);
245
+ setField("fatherOrganization", (_u = admission.fatherDetails) === null || _u === void 0 ? void 0 : _u.fatherOrganization);
246
+ setField("motherFirstName", (_v = admission.motherDetails) === null || _v === void 0 ? void 0 : _v.motherFirstName);
247
+ setField("motherLastName", (_w = admission.motherDetails) === null || _w === void 0 ? void 0 : _w.motherLastName);
248
+ setField("motherIdNumber", (_x = admission.motherDetails) === null || _x === void 0 ? void 0 : _x.motherIdNumber);
249
+ setField("motherMobile", (_z = formatPhoneDisplay((_y = admission.motherDetails) === null || _y === void 0 ? void 0 : _y.motherMobile)) !== null && _z !== void 0 ? _z : (_0 = admission.motherDetails) === null || _0 === void 0 ? void 0 : _0.motherMobile);
250
+ setField("address", (_1 = admission.homeDetails) === null || _1 === void 0 ? void 0 : _1.address);
251
+ setField("city", (_2 = admission.homeDetails) === null || _2 === void 0 ? void 0 : _2.city);
252
+ setField("country", (_3 = admission.homeDetails) === null || _3 === void 0 ? void 0 : _3.country);
253
+ setField("postalCode", (_4 = admission.homeDetails) === null || _4 === void 0 ? void 0 : _4.postalCode);
254
+ setField("state", (_5 = admission.homeDetails) === null || _5 === void 0 ? void 0 : _5.state);
255
+ setField("notes", (_6 = admission.officeUse) === null || _6 === void 0 ? void 0 : _6.notes);
256
+ setField("admissionNotes", (_7 = admission.officeUse) === null || _7 === void 0 ? void 0 : _7.admissionNotes);
257
+ setField("previousSchool", (_8 = admission.admissionDetails) === null || _8 === void 0 ? void 0 : _8.previousSchool);
258
+ setField("siblings", (_9 = admission.admissionDetails) === null || _9 === void 0 ? void 0 : _9.siblings);
259
+ setField("classForAdmission", (_10 = admission.admissionDetails) === null || _10 === void 0 ? void 0 : _10.classForAdmission);
260
+ setField("status", admission.status || ADMISSION_STATUS.PENDING);
261
+ setField("enabled", (_11 = admission.enabled) !== null && _11 !== void 0 ? _11 : true);
262
+ // Populate AI analysis if present
263
+ const aiAnalysis = (_12 = admission
264
+ .aiAnalysis) !== null && _12 !== void 0 ? _12 : null;
265
+ dispatch({
266
+ type: ADMISSION_ACTION_TYPES.SET_FORM_DATA,
267
+ payload: { form: { aiAnalysis } },
268
+ });
269
+ }
270
+ }, [dispatch, showToast, t, setField]);
271
+ const deleteCallback = useCallback(({ data, error }) => {
272
+ var _a;
273
+ if (error) {
274
+ showToast(t("messagesDeleteFailed"), TOAST_VARIANT.ERROR);
275
+ return;
276
+ }
277
+ if (data) {
278
+ invalidateAdmissionsCache();
279
+ showToast(t("messagesDeleteSuccess"), TOAST_VARIANT.SUCCESS);
280
+ (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
281
+ }
282
+ }, [showToast, t]);
283
+ // ============================================================================
284
+ // 1.4.5 API HOOKS
285
+ // ============================================================================
286
+ const { byIdFetchNow, byIdLoading, deleteFetchNow, deleteLoading, listFetchNow, listLoading, updateFetchNow, updateLoading, } = useModuleEntityV2({
287
+ byIdCallback,
288
+ byIdParams,
289
+ deleteCallback,
290
+ deleteParams,
291
+ listCallback,
292
+ listParams,
293
+ listUrl: ADMISSION_API_ROUTES.UNIT,
294
+ searchQuery: debouncedQuery,
295
+ unitByIdUrl: ADMISSION_API_ROUTES.UNIT,
296
+ unitUrl: ADMISSION_API_ROUTES.UNIT,
297
+ updateCallback,
298
+ updateParams,
299
+ headers: {
300
+ "Content-Type": "application/json",
301
+ "x-api-token": process.env.NEXT_PUBLIC_API_KEY,
302
+ },
303
+ });
304
+ // ============================================================================
305
+ // 1.4.6 HANDLERS
306
+ // ============================================================================
307
+ const handleChange = useCallback((field, value) => {
308
+ dispatch({
309
+ type: ADMISSION_ACTION_TYPES.SET_ERRORS,
310
+ payload: { errors: {} },
311
+ });
312
+ dispatch({
313
+ type: ADMISSION_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
314
+ payload: { disabled: false },
315
+ });
316
+ setField(field, value);
317
+ }, [setField, dispatch]);
318
+ const handleCloseDrawer = useCallback(() => {
319
+ resetFormAndCloseDrawer();
320
+ }, [resetFormAndCloseDrawer]);
321
+ const handleCreate = useCallback(() => {
322
+ dispatch({
323
+ type: ADMISSION_ACTION_TYPES.SET_DRAWER,
324
+ payload: { drawer: ADMISSION_DRAWER.FORM_DRAWER },
325
+ });
326
+ }, [dispatch]);
327
+ const handleView = useCallback((row) => {
328
+ byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
329
+ dispatch({
330
+ type: ADMISSION_ACTION_TYPES.SET_DRAWER,
331
+ payload: { drawer: ADMISSION_DRAWER.VIEW_DRAWER },
332
+ });
333
+ }, [dispatch, byIdFetchNow]);
334
+ const handleEdit = useCallback((row) => {
335
+ byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
336
+ dispatch({
337
+ type: ADMISSION_ACTION_TYPES.SET_DRAWER,
338
+ payload: { drawer: ADMISSION_DRAWER.FORM_DRAWER },
339
+ });
340
+ }, [dispatch, byIdFetchNow]);
341
+ const handleDelete = useCallback((row) => {
342
+ if (!confirm(t("actionDeleteConfirmation")))
343
+ return;
344
+ deleteFetchNow === null || deleteFetchNow === void 0 ? void 0 : deleteFetchNow(undefined, {
345
+ body: JSON.stringify({ id: row === null || row === void 0 ? void 0 : row.id }),
346
+ });
347
+ }, [t, deleteFetchNow]);
348
+ const handleFilters = useCallback(() => {
349
+ dispatch({
350
+ type: ADMISSION_ACTION_TYPES.SET_DRAWER,
351
+ payload: { drawer: ADMISSION_DRAWER.FILTER_DRAWER },
352
+ });
353
+ }, [dispatch]);
354
+ const handlePageChange = useCallback((page) => {
355
+ const nextPage = typeof page === "number" ? page : state.currentPage + 1;
356
+ dispatch({
357
+ type: ADMISSION_ACTION_TYPES.SET_CURRENT_PAGE,
358
+ payload: { currentPage: nextPage },
359
+ });
360
+ }, [dispatch, state.currentPage]);
361
+ const handlePageLimitChange = useCallback((k, value) => {
362
+ const val = Object.assign({}, value);
363
+ dispatch({
364
+ type: ADMISSION_ACTION_TYPES.SET_PAGE_LIMIT,
365
+ payload: { pageLimit: Number(val.option) },
366
+ });
367
+ dispatch({
368
+ type: ADMISSION_ACTION_TYPES.SET_CURRENT_PAGE,
369
+ payload: { currentPage: 1 },
370
+ });
371
+ }, [dispatch]);
372
+ const handleSearch = useCallback((query) => {
373
+ dispatch({
374
+ type: ADMISSION_ACTION_TYPES.SET_SEARCH_QUERY,
375
+ payload: { searchQuery: query },
376
+ });
377
+ }, [dispatch]);
378
+ const handleSetStartDate = useCallback((startDate) => {
379
+ dispatch({
380
+ type: ADMISSION_ACTION_TYPES.SET_INPUT_FIELD,
381
+ payload: { key: "filterStartDate", value: startDate },
382
+ });
383
+ }, [dispatch]);
384
+ const handleSetEndDate = useCallback((endDate) => {
385
+ dispatch({
386
+ type: ADMISSION_ACTION_TYPES.SET_INPUT_FIELD,
387
+ payload: { key: "filterEndDate", value: endDate },
388
+ });
389
+ }, [dispatch]);
390
+ const clearFilters = useCallback(() => {
391
+ dispatch({
392
+ type: ADMISSION_ACTION_TYPES.SET_FILTERS,
393
+ payload: {
394
+ filters: {
395
+ filterEnabled: undefined,
396
+ filterAdmissionStatus: undefined,
397
+ filterStartDate: undefined,
398
+ filterEndDate: undefined,
399
+ appliedFilterEnabled: undefined,
400
+ appliedFilterAdmissionStatus: undefined,
401
+ appliedFilterStartDate: undefined,
402
+ appliedFilterEndDate: undefined,
403
+ },
404
+ },
405
+ });
406
+ dispatch({
407
+ type: ADMISSION_ACTION_TYPES.SET_CURRENT_PAGE,
408
+ payload: { currentPage: 1 },
409
+ });
410
+ }, [dispatch]);
411
+ const handlePrint = useCallback(async (row) => {
412
+ var _a, _b, _c, _d, _e;
413
+ if (!row)
414
+ return;
415
+ const logoBase64Res = await fetch(`/api/v1/auth/image-url-to-base64`, {
416
+ method: API_METHODS.POST,
417
+ body: JSON.stringify({ url: (_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.logo }),
418
+ headers: {
419
+ "Content-Type": "application/json",
420
+ "x-api-token": process.env.NEXT_PUBLIC_API_KEY,
421
+ },
422
+ });
423
+ const logoBase64 = await logoBase64Res.json();
424
+ try {
425
+ const rowRecord = row;
426
+ const studentDetails = rowRecord.studentDetails || {};
427
+ const admissionDetails = rowRecord.admissionDetails || {};
428
+ const fatherDetails = rowRecord.fatherDetails || {};
429
+ const motherDetails = rowRecord.motherDetails || {};
430
+ const homeDetails = rowRecord.homeDetails || {};
431
+ const pdfData = {
432
+ firstName: studentDetails.firstName || "",
433
+ lastName: studentDetails.lastName || "",
434
+ studentIdNumber: studentDetails.studentIdNumber || "",
435
+ gender: studentDetails.gender || "",
436
+ dob: studentDetails.dob || "",
437
+ registrationCode: studentDetails.registrationCode || "",
438
+ discountCode: studentDetails.discountCode,
439
+ fatherFirstName: fatherDetails.fatherFirstName || "",
440
+ fatherLastName: fatherDetails.fatherLastName || "",
441
+ fatherIdNumber: fatherDetails.fatherIdNumber || "",
442
+ fatherMobile: fatherDetails.fatherMobile || "",
443
+ fatherOccupation: fatherDetails.fatherOccupation,
444
+ fatherOrganization: fatherDetails.fatherOrganization,
445
+ motherFirstName: motherDetails.motherFirstName || "",
446
+ motherLastName: motherDetails.motherLastName || "",
447
+ motherIdNumber: motherDetails.motherIdNumber || "",
448
+ motherMobile: motherDetails.motherMobile || "",
449
+ address: homeDetails.address || "",
450
+ city: homeDetails.city || "",
451
+ state: homeDetails.state || "",
452
+ country: homeDetails.country || "",
453
+ classForAdmission: admissionDetails.classForAdmission || "",
454
+ previousSchool: admissionDetails.previousSchool,
455
+ siblings: admissionDetails.siblings,
456
+ notes: admissionDetails.notes,
457
+ admissionNotes: admissionDetails.admissionNotes,
458
+ schoolName: ((_b = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _b === void 0 ? void 0 : _b.name) || undefined,
459
+ schoolAddress: ((_c = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _c === void 0 ? void 0 : _c.address) || undefined,
460
+ schoolPhone: ((_d = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _d === void 0 ? void 0 : _d.phone) || undefined,
461
+ schoolEmail: ((_e = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _e === void 0 ? void 0 : _e.email) || undefined,
462
+ submissionDate: (row === null || row === void 0 ? void 0 : row.createdAt)
463
+ ? new Date(row === null || row === void 0 ? void 0 : row.createdAt).toLocaleDateString()
464
+ : undefined,
465
+ admissionStatus: admissionDetails.admissionStatus,
466
+ logo: logoBase64.base64,
467
+ };
468
+ await generateAdmissionReceiptPDF(pdfData);
469
+ }
470
+ catch (_f) {
471
+ showToast(t("messagesPrintFailed"), TOAST_VARIANT.ERROR);
472
+ }
473
+ }, [workspace, t, showToast]);
474
+ const handleAddStudent = useCallback(async (row) => {
475
+ var _a;
476
+ const tableRow = row;
477
+ const { data, error } = await fetchData({
478
+ url: "/api/v1/admit-student",
479
+ method: API_METHODS.POST,
480
+ headers: {
481
+ "Content-Type": "application/json",
482
+ "x-api-token": process.env.NEXT_PUBLIC_API_KEY,
483
+ },
484
+ body: JSON.stringify({ admissionId: tableRow === null || tableRow === void 0 ? void 0 : tableRow.id }),
485
+ });
486
+ (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
487
+ invalidateAdmissionsCache();
488
+ invalidateFamiliesCache();
489
+ invalidateFamilyMembersCache();
490
+ invalidateStudentProfilesCache();
491
+ if (data) {
492
+ showToast(t("messagesAdmitSuccess"), TOAST_VARIANT.SUCCESS);
493
+ }
494
+ if (error) {
495
+ showToast(t("messagesAdmitFailed"), TOAST_VARIANT.ERROR);
496
+ }
497
+ }, [t, showToast]);
498
+ // ============================================================================
499
+ // 1.4.7 NETWORK ACTIONS
500
+ // ============================================================================
501
+ const handleAnalyze = useCallback(async (row) => {
502
+ var _a, _b, _c, _d;
503
+ const tableRow = row;
504
+ if (!(tableRow === null || tableRow === void 0 ? void 0 : tableRow.id))
505
+ return;
506
+ const schoolId = (_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id;
507
+ if (!schoolId)
508
+ return;
509
+ dispatch({
510
+ type: ADMISSION_ACTION_TYPES.SET_INPUT_FIELD,
511
+ payload: { key: "analyzeLoading", value: true },
512
+ });
513
+ dispatch({
514
+ type: ADMISSION_ACTION_TYPES.SET_FORM_DATA,
515
+ payload: { form: { analyzeError: null } },
516
+ });
517
+ // Open view drawer so user can watch progress
518
+ await (byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: tableRow.id } }));
519
+ dispatch({
520
+ type: ADMISSION_ACTION_TYPES.SET_DRAWER,
521
+ payload: { drawer: ADMISSION_DRAWER.VIEW_DRAWER },
522
+ });
523
+ const { data, error } = await fetchData({
524
+ url: `/api/v1/admission/analyze`,
525
+ method: API_METHODS.POST,
526
+ headers: {
527
+ "Content-Type": "application/json",
528
+ "x-api-token": process.env.NEXT_PUBLIC_API_KEY,
529
+ },
530
+ body: JSON.stringify({ id: tableRow.id, schoolId }),
531
+ });
532
+ dispatch({
533
+ type: ADMISSION_ACTION_TYPES.SET_INPUT_FIELD,
534
+ payload: { key: "analyzeLoading", value: false },
535
+ });
536
+ if (error) {
537
+ dispatch({
538
+ type: ADMISSION_ACTION_TYPES.SET_FORM_DATA,
539
+ payload: { form: { analyzeError: t("messagesAnalyzeFailed") } },
540
+ });
541
+ showToast(t("messagesAnalyzeFailed"), TOAST_VARIANT.ERROR);
542
+ return;
543
+ }
544
+ const result = data;
545
+ if (result === null || result === void 0 ? void 0 : result.aiAnalysis) {
546
+ dispatch({
547
+ type: ADMISSION_ACTION_TYPES.SET_FORM_DATA,
548
+ payload: { form: { aiAnalysis: result.aiAnalysis } },
549
+ });
550
+ }
551
+ invalidateAdmissionsCache();
552
+ (_b = listFetchNowRef.current) === null || _b === void 0 ? void 0 : _b.call(listFetchNowRef);
553
+ generateThemeToast({
554
+ description: `${t("messagesAnalyzeSuccess")} ${(_c = result === null || result === void 0 ? void 0 : result.score) !== null && _c !== void 0 ? _c : "N/A"} — ${(_d = result === null || result === void 0 ? void 0 : result.status) !== null && _d !== void 0 ? _d : ""}`,
555
+ variant: TOAST_VARIANT.SUCCESS,
556
+ });
557
+ }, [(_c = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _c === void 0 ? void 0 : _c.id, t, showToast, byIdFetchNow, dispatch]);
558
+ const handleSubmit = useCallback(() => {
559
+ dispatch({
560
+ type: ADMISSION_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
561
+ payload: { disabled: true },
562
+ });
563
+ validateForm({
564
+ params: updateParams,
565
+ schema: admissionFormValidation,
566
+ successCallback: () => {
567
+ var _a;
568
+ updateFetchNow(undefined, {
569
+ body: JSON.stringify({
570
+ schoolId: (_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id,
571
+ admissionDetails: {
572
+ classForAdmission: updateParams.classForAdmission,
573
+ previousSchool: updateParams.previousSchool,
574
+ siblings: updateParams.siblings,
575
+ },
576
+ fatherDetails: {
577
+ fatherIdNumber: updateParams.fatherIdNumber,
578
+ fatherFirstName: updateParams.fatherFirstName,
579
+ fatherLastName: updateParams.fatherLastName,
580
+ fatherMobile: updateParams.fatherMobile,
581
+ fatherOccupation: updateParams.fatherOccupation,
582
+ fatherOrganization: updateParams.fatherOrganization,
583
+ emergencyContact: updateParams.emergencyContact === "Father",
584
+ },
585
+ motherDetails: {
586
+ motherIdNumber: updateParams.motherIdNumber || "",
587
+ motherFirstName: updateParams.motherFirstName || "N/A",
588
+ motherLastName: updateParams.motherLastName || "N/A",
589
+ motherMobile: updateParams.motherMobile,
590
+ emergencyContact: updateParams.emergencyContact === "Mother",
591
+ },
592
+ homeDetails: {
593
+ address: updateParams.address,
594
+ city: updateParams.city,
595
+ country: updateParams.country,
596
+ postalCode: updateParams.postalCode,
597
+ state: updateParams.state,
598
+ },
599
+ officeUse: {
600
+ notes: updateParams.notes,
601
+ admissionNotes: updateParams.admissionNotes,
602
+ },
603
+ studentDetails: {
604
+ studentIdNumber: updateParams.studentIdNumber,
605
+ discountCode: updateParams.discountCode,
606
+ dob: updateParams.dob,
607
+ firstName: updateParams.firstName,
608
+ gender: updateParams.gender,
609
+ hafiz: updateParams.hafiz,
610
+ lastName: updateParams.lastName,
611
+ orphan: updateParams.orphan,
612
+ registrationCode: updateParams.registrationCode,
613
+ },
614
+ }),
615
+ });
616
+ },
617
+ errorCallback: (errors) => {
618
+ dispatch({
619
+ type: ADMISSION_ACTION_TYPES.SET_ERRORS,
620
+ payload: { errors },
621
+ });
622
+ dispatch({
623
+ type: ADMISSION_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
624
+ payload: { disabled: false },
625
+ });
626
+ showToast(t("messagesFormErrors"), TOAST_VARIANT.ERROR);
627
+ },
628
+ });
629
+ }, [
630
+ dispatch,
631
+ updateParams,
632
+ t,
633
+ showToast,
634
+ updateFetchNow,
635
+ (_d = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _d === void 0 ? void 0 : _d.id,
636
+ ]);
637
+ // ============================================================================
638
+ // 1.4.8 HEADER & ROW ACTIONS
639
+ // ============================================================================
640
+ const hasGeminiSecrets = Boolean(((_e = workspace === null || workspace === void 0 ? void 0 : workspace.secrets) === null || _e === void 0 ? void 0 : _e.GEMINI_API_KEY) && ((_f = workspace === null || workspace === void 0 ? void 0 : workspace.secrets) === null || _f === void 0 ? void 0 : _f.GEMINI_MODEL));
641
+ const headerActions = useMemo(() => [
642
+ {
643
+ enabled: true,
644
+ handleOnClick: handleFilters,
645
+ label: t("actionHeaderFilters"),
646
+ order: 1,
647
+ icon: Filter,
648
+ },
649
+ {
650
+ enabled: true,
651
+ handleOnClick: handleCreate,
652
+ label: t("actionHeaderAddAdmission"),
653
+ order: 2,
654
+ icon: Plus,
655
+ },
656
+ ], [handleFilters, handleCreate, t]);
657
+ const rowActions = useMemo(() => [
658
+ {
659
+ enabled: true,
660
+ handleOnClick: handleView,
661
+ label: t("actionRowView"),
662
+ order: 1,
663
+ },
664
+ {
665
+ enabled: (row) => (row === null || row === void 0 ? void 0 : row.status) === ADMISSION_STATUS.PENDING,
666
+ handleOnClick: handleEdit,
667
+ label: t("actionRowEdit"),
668
+ order: 2,
669
+ },
670
+ {
671
+ enabled: (row) => (row === null || row === void 0 ? void 0 : row.status) === ADMISSION_STATUS.PENDING,
672
+ handleOnClick: handleDelete,
673
+ label: t("actionRowDelete"),
674
+ order: 3,
675
+ variant: "destructive",
676
+ },
677
+ {
678
+ enabled: true,
679
+ handleOnClick: handlePrint,
680
+ label: t("actionRowPrintPdf"),
681
+ order: 4,
682
+ },
683
+ {
684
+ enabled: (row) => hasGeminiSecrets &&
685
+ (row === null || row === void 0 ? void 0 : row.status) === ADMISSION_STATUS.PENDING,
686
+ handleOnClick: handleAnalyze,
687
+ label: t("actionRowAnalyzeWithAi"),
688
+ order: 5,
689
+ },
690
+ {
691
+ enabled: (row) => (row === null || row === void 0 ? void 0 : row.status) !== ADMISSION_STATUS.APPROVED,
692
+ handleOnClick: handleAddStudent,
693
+ label: t("actionRowAddStudent"),
694
+ order: 6,
695
+ },
696
+ ], [
697
+ handleView,
698
+ handleEdit,
699
+ handleDelete,
700
+ handlePrint,
701
+ handleAnalyze,
702
+ handleAddStudent,
703
+ hasGeminiSecrets,
704
+ t,
705
+ ]);
706
+ const applyFilters = useCallback(() => {
707
+ dispatch({
708
+ type: ADMISSION_ACTION_TYPES.SET_CURRENT_PAGE,
709
+ payload: { currentPage: 1 },
710
+ });
711
+ handleCloseDrawer();
712
+ }, [dispatch, handleCloseDrawer]);
713
+ // ============================================================================
714
+ // 1.4.9 EFFECTS
715
+ // ============================================================================
716
+ // Initial load + re-fetch on page/search/filter change via cache
717
+ useEffect(() => {
718
+ var _a;
719
+ if (!(workspace === null || workspace === void 0 ? void 0 : workspace.id))
720
+ return;
721
+ if (isDefaultListState) {
722
+ (async () => {
723
+ try {
724
+ const { count, items } = await getCachedAdmissions({
725
+ params: listParams,
726
+ });
727
+ dispatch({
728
+ type: ADMISSION_ACTION_TYPES.SET_ITEMS,
729
+ payload: { items: items || [], count: count || 0 },
730
+ });
731
+ }
732
+ catch (_a) {
733
+ showToast(t("messagesFetchFailed"), TOAST_VARIANT.ERROR);
734
+ }
735
+ })();
736
+ return;
737
+ }
738
+ (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
739
+ }, [dispatch, isDefaultListState, listParams, workspace === null || workspace === void 0 ? void 0 : workspace.id, t, showToast]);
740
+ // Sync ref to always point at latest listFetchNow (avoids stale closure in callbacks)
741
+ useEffect(() => {
742
+ listFetchNowRef.current = listFetchNow;
743
+ }, [listFetchNow]);
744
+ // ============================================================================
745
+ // 1.4.10 RETURN
746
+ // ============================================================================
747
+ return Object.assign(Object.assign({}, context), { applyFilters,
748
+ byIdLoading,
749
+ clearFilters,
750
+ deleteLoading,
751
+ handleAddStudent,
752
+ handleAnalyze,
753
+ handleChange,
754
+ handleCloseDrawer,
755
+ handleCreate,
756
+ handleDelete,
757
+ handleEdit,
758
+ handleFilters,
759
+ handlePageChange,
760
+ handlePageLimitChange,
761
+ handlePrint,
762
+ handleSearch,
763
+ handleSetEndDate,
764
+ handleSetStartDate,
765
+ handleSubmit,
766
+ handleView,
767
+ headerActions,
768
+ listLoading,
769
+ rowActions,
770
+ updateLoading });
771
+ };