@appcorp/fusion-storybook 0.1.35 → 0.1.37

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 (56) hide show
  1. package/base-modules/attendance/cache.d.ts +14 -0
  2. package/base-modules/attendance/cache.js +31 -0
  3. package/base-modules/attendance/constants.d.ts +17 -0
  4. package/base-modules/attendance/constants.js +29 -0
  5. package/base-modules/attendance/context.d.ts +167 -0
  6. package/base-modules/attendance/context.js +412 -0
  7. package/base-modules/attendance/filter.d.ts +8 -0
  8. package/base-modules/attendance/filter.js +21 -0
  9. package/base-modules/attendance/form.d.ts +1 -0
  10. package/base-modules/attendance/form.js +22 -0
  11. package/base-modules/attendance/more-actions.d.ts +19 -0
  12. package/base-modules/attendance/more-actions.js +40 -0
  13. package/base-modules/attendance/page.d.ts +46 -0
  14. package/base-modules/attendance/page.js +179 -0
  15. package/base-modules/attendance/validate.d.ts +9 -0
  16. package/base-modules/attendance/validate.js +9 -0
  17. package/base-modules/attendance/view.d.ts +4 -0
  18. package/base-modules/attendance/view.js +29 -0
  19. package/base-modules/course/cache.d.ts +14 -0
  20. package/base-modules/course/cache.js +31 -0
  21. package/base-modules/course/constants.d.ts +11 -0
  22. package/base-modules/course/constants.js +17 -0
  23. package/base-modules/course/context.d.ts +155 -0
  24. package/base-modules/course/context.js +432 -0
  25. package/base-modules/course/filter.d.ts +1 -0
  26. package/base-modules/course/filter.js +27 -0
  27. package/base-modules/course/form.d.ts +1 -0
  28. package/base-modules/course/form.js +36 -0
  29. package/base-modules/course/more-actions.d.ts +1 -0
  30. package/base-modules/course/more-actions.js +59 -0
  31. package/base-modules/course/page.d.ts +31 -0
  32. package/base-modules/course/page.js +138 -0
  33. package/base-modules/course/validate.d.ts +13 -0
  34. package/base-modules/course/validate.js +16 -0
  35. package/base-modules/course/view.d.ts +1 -0
  36. package/base-modules/course/view.js +40 -0
  37. package/base-modules/enrollment/cache.d.ts +14 -0
  38. package/base-modules/enrollment/cache.js +31 -0
  39. package/base-modules/enrollment/constants.d.ts +11 -0
  40. package/base-modules/enrollment/constants.js +17 -0
  41. package/base-modules/enrollment/context.d.ts +167 -0
  42. package/base-modules/enrollment/context.js +416 -0
  43. package/base-modules/enrollment/filter.d.ts +1 -0
  44. package/base-modules/enrollment/filter.js +30 -0
  45. package/base-modules/enrollment/form.d.ts +1 -0
  46. package/base-modules/enrollment/form.js +43 -0
  47. package/base-modules/enrollment/more-actions.d.ts +1 -0
  48. package/base-modules/enrollment/more-actions.js +62 -0
  49. package/base-modules/enrollment/page.d.ts +32 -0
  50. package/base-modules/enrollment/page.js +145 -0
  51. package/base-modules/enrollment/validate.d.ts +13 -0
  52. package/base-modules/enrollment/validate.js +19 -0
  53. package/base-modules/enrollment/view.d.ts +1 -0
  54. package/base-modules/enrollment/view.js +44 -0
  55. package/package.json +1 -1
  56. package/tsconfig.build.tsbuildinfo +1 -1
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Attendance Module Cache Utilities
3
+ *
4
+ * Provides localStorage-based caching for attendances using generic cache system.
5
+ */
6
+ import { AttendanceBE } from "../../type";
7
+ export declare const getCachedAttendancesSync: () => import("@react-pakistan/util-functions").ListResponse<AttendanceBE>;
8
+ export declare const getCachedAttendances: ({ params, }: {
9
+ params: Record<string, unknown>;
10
+ }) => Promise<import("@react-pakistan/util-functions").ListResponse<AttendanceBE>>;
11
+ export declare const getCachedAttendanceById: (attendanceId: string) => AttendanceBE | null;
12
+ export declare const invalidateAttendancesCache: () => void;
13
+ export declare const preloadAttendances: () => Promise<import("@react-pakistan/util-functions").ListResponse<AttendanceBE>>;
14
+ export declare const isAttendancesCacheStale: () => boolean;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Attendance Module Cache Utilities
3
+ *
4
+ * Provides localStorage-based caching for attendances using generic cache system.
5
+ */
6
+ import { LS_KEYS } from "../../constants";
7
+ import { ATTENDANCE_API_ROUTES } from "./constants";
8
+ import { getCachedData, getCachedDataSync, getCachedItemById, invalidateCache, isCacheStale, preloadCache, } from "@react-pakistan/util-functions";
9
+ // ============================================================================
10
+ // CACHE CONFIGURATION
11
+ // ============================================================================
12
+ const ATTENDANCE_CACHE_CONFIG = {
13
+ cacheKey: LS_KEYS.ATTENDANCES,
14
+ apiUrl: ATTENDANCE_API_ROUTES.UNIT,
15
+ };
16
+ // ============================================================================
17
+ // ATTENDANCE-SPECIFIC CACHE FUNCTIONS
18
+ // ============================================================================
19
+ export const getCachedAttendancesSync = () => getCachedDataSync(LS_KEYS.ATTENDANCES);
20
+ export const getCachedAttendances = ({ params, }) => getCachedData({
21
+ config: ATTENDANCE_CACHE_CONFIG,
22
+ params,
23
+ headers: {
24
+ "Content-Type": "application/json",
25
+ "x-api-token": process.env.NEXT_PUBLIC_API_KEY,
26
+ },
27
+ });
28
+ export const getCachedAttendanceById = (attendanceId) => getCachedItemById(LS_KEYS.ATTENDANCES, attendanceId);
29
+ export const invalidateAttendancesCache = () => invalidateCache(LS_KEYS.ATTENDANCES);
30
+ export const preloadAttendances = () => preloadCache(ATTENDANCE_CACHE_CONFIG);
31
+ export const isAttendancesCacheStale = () => isCacheStale(LS_KEYS.ATTENDANCES);
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Attendance Constants
3
+ *
4
+ * Organization:
5
+ * - Page Configuration
6
+ * - API Routes
7
+ * - Status Options
8
+ */
9
+ import { ATTENDANCE_STATUS } from "../../type";
10
+ export declare const pageLimit: number;
11
+ export declare const ATTENDANCE_API_ROUTES: {
12
+ readonly UNIT: "/api/v1/attendance";
13
+ };
14
+ export declare const ATTENDANCE_STATUS_OPTIONS: {
15
+ label: string;
16
+ value: ATTENDANCE_STATUS;
17
+ }[];
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Attendance Constants
3
+ *
4
+ * Organization:
5
+ * - Page Configuration
6
+ * - API Routes
7
+ * - Status Options
8
+ */
9
+ import { ATTENDANCE_STATUS } from "../../type";
10
+ // ============================================================================
11
+ // PAGE CONFIGURATION
12
+ // ============================================================================
13
+ export const pageLimit = Number(process.env.NEXT_PUBLIC_PAGE_LIMIT) || 10;
14
+ // ============================================================================
15
+ // API ROUTES
16
+ // ============================================================================
17
+ export const ATTENDANCE_API_ROUTES = {
18
+ UNIT: "/api/v1/attendance",
19
+ };
20
+ // ============================================================================
21
+ // STATUS OPTIONS
22
+ // ============================================================================
23
+ export const ATTENDANCE_STATUS_OPTIONS = [
24
+ { label: "Present", value: ATTENDANCE_STATUS.PRESENT },
25
+ { label: "Absent", value: ATTENDANCE_STATUS.ABSENT },
26
+ { label: "Late", value: ATTENDANCE_STATUS.LATE },
27
+ { label: "Excused", value: ATTENDANCE_STATUS.EXCUSED },
28
+ { label: "Half Day", value: ATTENDANCE_STATUS.HALF_DAY },
29
+ ];
@@ -0,0 +1,167 @@
1
+ import { RowAction, TableRow } from "@appcorp/shadcn/components/enhanced-table";
2
+ import { AttendanceBE, ATTENDANCE_STATUS, SchoolBE, StudentProfileBE } from "../../type";
3
+ export declare const ATTENDANCE_DRAWER: {
4
+ readonly FILTER_DRAWER: string;
5
+ readonly FORM_DRAWER: string;
6
+ readonly MORE_ACTIONS_DRAWER: string;
7
+ readonly VIEW_DRAWER: string;
8
+ };
9
+ export declare const ATTENDANCE_ACTION_TYPES: {
10
+ readonly RESET_FORM: "RESET_FORM";
11
+ readonly SET_CURRENT_PAGE: "SET_CURRENT_PAGE";
12
+ readonly SET_PAGE_LIMIT: "SET_PAGE_LIMIT";
13
+ readonly SET_SEARCH_QUERY: "SET_SEARCH_QUERY";
14
+ readonly SET_DRAWER: "SET_DRAWER";
15
+ readonly SET_ITEMS: "SET_ITEMS";
16
+ readonly SET_FORM_DATA: "SET_FORM_DATA";
17
+ readonly SET_DISABLE_SAVE_BUTTON: "SET_DISABLE_SAVE_BUTTON";
18
+ readonly SET_INPUT_FIELD: "SET_INPUT_FIELD";
19
+ readonly SET_ERRORS: "SET_ERRORS";
20
+ readonly SET_FILTERS: "SET_FILTERS";
21
+ }, attendanceModuleConfig: import("@react-pakistan/util-functions/factory/generic-module-factory").ModuleConfig<{
22
+ items: AttendanceBE[];
23
+ count: number;
24
+ currentPage: number;
25
+ pageLimit: number;
26
+ searchQuery: string;
27
+ disableSaveButton: boolean;
28
+ drawer: string | null;
29
+ date: string;
30
+ enabled: boolean;
31
+ errors: Record<string, string>;
32
+ filterEnabled: boolean | undefined;
33
+ id: string;
34
+ remarks: string;
35
+ schoolId: string;
36
+ status: ATTENDANCE_STATUS;
37
+ studentProfileId: string;
38
+ school: SchoolBE | undefined;
39
+ studentProfile: StudentProfileBE | undefined;
40
+ }>, initialAttendanceState: {
41
+ items: AttendanceBE[];
42
+ count: number;
43
+ currentPage: number;
44
+ pageLimit: number;
45
+ searchQuery: string;
46
+ disableSaveButton: boolean;
47
+ drawer: string | null;
48
+ date: string;
49
+ enabled: boolean;
50
+ errors: Record<string, string>;
51
+ filterEnabled: boolean | undefined;
52
+ id: string;
53
+ remarks: string;
54
+ schoolId: string;
55
+ status: ATTENDANCE_STATUS;
56
+ studentProfileId: string;
57
+ school: SchoolBE | undefined;
58
+ studentProfile: StudentProfileBE | undefined;
59
+ }, AttendanceProvider: import("react").FC<{
60
+ children: React.ReactNode;
61
+ }>, attendanceReducer: (state: {
62
+ items: AttendanceBE[];
63
+ count: number;
64
+ currentPage: number;
65
+ pageLimit: number;
66
+ searchQuery: string;
67
+ disableSaveButton: boolean;
68
+ drawer: string | null;
69
+ date: string;
70
+ enabled: boolean;
71
+ errors: Record<string, string>;
72
+ filterEnabled: boolean | undefined;
73
+ id: string;
74
+ remarks: string;
75
+ schoolId: string;
76
+ status: ATTENDANCE_STATUS;
77
+ studentProfileId: string;
78
+ school: SchoolBE | undefined;
79
+ studentProfile: StudentProfileBE | undefined;
80
+ }, action: any) => {
81
+ items: AttendanceBE[];
82
+ count: number;
83
+ currentPage: number;
84
+ pageLimit: number;
85
+ searchQuery: string;
86
+ disableSaveButton: boolean;
87
+ drawer: string | null;
88
+ date: string;
89
+ enabled: boolean;
90
+ errors: Record<string, string>;
91
+ filterEnabled: boolean | undefined;
92
+ id: string;
93
+ remarks: string;
94
+ schoolId: string;
95
+ status: ATTENDANCE_STATUS;
96
+ studentProfileId: string;
97
+ school: SchoolBE | undefined;
98
+ studentProfile: StudentProfileBE | undefined;
99
+ }, useAttendanceContext: () => import("@react-pakistan/util-functions/factory/generic-module-factory").GenericModuleContext<{
100
+ items: AttendanceBE[];
101
+ count: number;
102
+ currentPage: number;
103
+ pageLimit: number;
104
+ searchQuery: string;
105
+ disableSaveButton: boolean;
106
+ drawer: string | null;
107
+ date: string;
108
+ enabled: boolean;
109
+ errors: Record<string, string>;
110
+ filterEnabled: boolean | undefined;
111
+ id: string;
112
+ remarks: string;
113
+ schoolId: string;
114
+ status: ATTENDANCE_STATUS;
115
+ studentProfileId: string;
116
+ school: SchoolBE | undefined;
117
+ studentProfile: StudentProfileBE | undefined;
118
+ }>;
119
+ export declare const useAttendanceModule: () => {
120
+ applyFilters: () => void;
121
+ byIdLoading: boolean;
122
+ clearFilters: () => void;
123
+ deleteLoading: boolean;
124
+ handleChange: (field: string, value: string | number | boolean | undefined) => void;
125
+ handleCloseDrawer: () => void;
126
+ handleCreate: () => void;
127
+ handleDelete: (row?: TableRow) => void;
128
+ handleEdit: (row?: TableRow) => void;
129
+ handleFilters: () => void;
130
+ handleMoreActions: () => void;
131
+ handlePageChange: (page: number) => void;
132
+ handlePageLimitChange: (limit: number) => void;
133
+ handleSearch: (query: string) => void;
134
+ handleSubmit: () => void;
135
+ handleView: (row?: TableRow) => void;
136
+ headerActions: {
137
+ enabled: boolean;
138
+ handleOnClick: () => void;
139
+ icon: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
140
+ label: string;
141
+ order: number;
142
+ }[];
143
+ listLoading: boolean;
144
+ rowActions: RowAction[];
145
+ updateLoading: boolean;
146
+ state: {
147
+ items: AttendanceBE[];
148
+ count: number;
149
+ currentPage: number;
150
+ pageLimit: number;
151
+ searchQuery: string;
152
+ disableSaveButton: boolean;
153
+ drawer: string | null;
154
+ date: string;
155
+ enabled: boolean;
156
+ errors: Record<string, string>;
157
+ filterEnabled: boolean | undefined;
158
+ id: string;
159
+ remarks: string;
160
+ schoolId: string;
161
+ status: ATTENDANCE_STATUS;
162
+ studentProfileId: string;
163
+ school: SchoolBE | undefined;
164
+ studentProfile: StudentProfileBE | undefined;
165
+ };
166
+ dispatch: React.Dispatch<any>;
167
+ };
@@ -0,0 +1,412 @@
1
+ "use client";
2
+ /**
3
+ * Attendance Module — business logic + API integration
4
+ *
5
+ * This module wires the generic module state (created by
6
+ * `createGenericModule`) to network actions using `useModuleEntityV2`.
7
+ * It contains the domain-specific handlers (create/view/edit/delete),
8
+ * local validation wiring, and optimistic UI helpers.
9
+ *
10
+ * Key responsibilities:
11
+ * - expose `useAttendanceModule()` which UI components call for actions
12
+ * - keep the module-specific `apiParams` and callbacks in one place
13
+ * - ensure cache invalidation and toast notifications on mutation
14
+ *
15
+ * Exported utilities:
16
+ * - `AttendanceProvider` — provider component used by the page
17
+ * - `useAttendanceModule()` — hook that returns handlers and state
18
+ */
19
+ import { useCallback, useEffect, useMemo } from "react";
20
+ import { isCreatedOrUpdated, validateForm, } from "@react-pakistan/util-functions";
21
+ import { useModuleEntityV2, } from "@react-pakistan/util-functions/hooks/use-module-entity-v2";
22
+ import { useDebounce } from "@react-pakistan/util-functions/hooks/use-debounce";
23
+ import { createGenericModule } from "@react-pakistan/util-functions/factory/generic-module-factory";
24
+ import { DRAWER_TYPES } from "@react-pakistan/util-functions/factory/generic-component-factory";
25
+ import { ATTENDANCE_API_ROUTES, pageLimit } from "./constants";
26
+ import { getCachedAttendances, invalidateAttendancesCache } from "./cache";
27
+ import { attendanceFormValidation } from "./validate";
28
+ import { generateThemeToast, TOAST_VARIANT, } from "@appcorp/shadcn/lib/toast-utils";
29
+ import { Edit, Eye, Filter, MoreHorizontal, Plus } from "lucide-react";
30
+ import { ATTENDANCE_STATUS, } from "../../type";
31
+ import { getCachedWorkspaceSync } from "../workspace/cache";
32
+ // ============================================================================
33
+ // DRAWER TYPES
34
+ // ============================================================================
35
+ export const ATTENDANCE_DRAWER = {
36
+ FILTER_DRAWER: DRAWER_TYPES.FILTER_DRAWER,
37
+ FORM_DRAWER: DRAWER_TYPES.FORM_DRAWER,
38
+ MORE_ACTIONS_DRAWER: "MORE_ACTIONS_DRAWER",
39
+ VIEW_DRAWER: DRAWER_TYPES.VIEW_DRAWER,
40
+ };
41
+ // ============================================================================
42
+ // CONFIGURATION
43
+ // ============================================================================
44
+ const attendanceConfig = {
45
+ name: "Attendance",
46
+ displayName: "Attendance",
47
+ initialState: {
48
+ // List Data
49
+ items: [],
50
+ count: 0,
51
+ // Search & Pagination
52
+ currentPage: 1,
53
+ pageLimit,
54
+ searchQuery: "",
55
+ // UI State
56
+ disableSaveButton: false,
57
+ drawer: null,
58
+ // Form State
59
+ date: new Date().toISOString().split("T")[0],
60
+ enabled: true,
61
+ errors: {},
62
+ filterEnabled: undefined,
63
+ id: "",
64
+ remarks: "",
65
+ schoolId: "",
66
+ status: ATTENDANCE_STATUS.PRESENT,
67
+ studentProfileId: "",
68
+ // Relations (populated from byId fetch)
69
+ school: undefined,
70
+ studentProfile: undefined,
71
+ },
72
+ drawerTypes: DRAWER_TYPES,
73
+ };
74
+ // ============================================================================
75
+ // CREATE ATTENDANCE MODULE
76
+ // ============================================================================
77
+ export const { actionTypes: ATTENDANCE_ACTION_TYPES, config: attendanceModuleConfig, initialState: initialAttendanceState, Provider: AttendanceProvider, reducer: attendanceReducer, useContext: useAttendanceContext, } = createGenericModule(attendanceConfig);
78
+ // ============================================================================
79
+ // ENHANCED ATTENDANCE HOOK WITH API INTEGRATION
80
+ // ============================================================================
81
+ export const useAttendanceModule = () => {
82
+ var _a;
83
+ const context = useAttendanceContext();
84
+ const { state, dispatch } = context;
85
+ const debouncedQuery = useDebounce(state.searchQuery, 800);
86
+ const workspace = getCachedWorkspaceSync();
87
+ const schoolId = ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "";
88
+ // ============================================================================
89
+ // API PARAMETERS
90
+ // ============================================================================
91
+ const listParams = useMemo(() => (Object.assign(Object.assign({ currentPage: state.currentPage, pageLimit: state.pageLimit, schoolId }, (debouncedQuery ? { searchQuery: debouncedQuery } : {})), (state.filterEnabled !== undefined
92
+ ? { filterEnabled: String(state.filterEnabled) }
93
+ : {}))), [
94
+ state.currentPage,
95
+ state.filterEnabled,
96
+ state.pageLimit,
97
+ debouncedQuery,
98
+ schoolId,
99
+ ]);
100
+ const updateParams = useMemo(() => ({
101
+ date: state.date,
102
+ enabled: state.enabled,
103
+ id: state.id,
104
+ remarks: state.remarks,
105
+ schoolId,
106
+ status: state.status,
107
+ studentProfileId: state.studentProfileId,
108
+ }), [state, schoolId]);
109
+ const byIdParams = useMemo(() => ({ id: state.id }), [state.id]);
110
+ const deleteParams = useMemo(() => ({ id: state.id }), [state.id]);
111
+ // ============================================================================
112
+ // TOAST UTILITY
113
+ // ============================================================================
114
+ const showToast = useCallback((message, variant) => {
115
+ generateThemeToast({ description: message, variant });
116
+ }, []);
117
+ const resetFormAndCloseDrawer = useCallback(() => {
118
+ dispatch({
119
+ type: ATTENDANCE_ACTION_TYPES.SET_ERRORS,
120
+ payload: { errors: {} },
121
+ });
122
+ dispatch({
123
+ type: ATTENDANCE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
124
+ payload: { disabled: false },
125
+ });
126
+ dispatch({
127
+ type: ATTENDANCE_ACTION_TYPES.SET_DRAWER,
128
+ payload: { drawer: null },
129
+ });
130
+ }, [dispatch]);
131
+ // ============================================================================
132
+ // API CALLBACKS
133
+ // ============================================================================
134
+ const listCallback = ({ data, error }) => {
135
+ var _a;
136
+ if (error) {
137
+ showToast("Failed to fetch attendance records", TOAST_VARIANT.ERROR);
138
+ return;
139
+ }
140
+ if (data) {
141
+ const response = data;
142
+ const items = (_a = response.items) !== null && _a !== void 0 ? _a : [];
143
+ const count = typeof response.count === "number" ? response.count : 0;
144
+ dispatch({
145
+ type: ATTENDANCE_ACTION_TYPES.SET_ITEMS,
146
+ payload: { items, count },
147
+ });
148
+ }
149
+ };
150
+ const updateCallback = ({ data, error }) => {
151
+ const isCreated = isCreatedOrUpdated(data);
152
+ if (error) {
153
+ showToast(isCreated
154
+ ? "Failed to create attendance record"
155
+ : "Failed to update attendance record", TOAST_VARIANT.ERROR);
156
+ return;
157
+ }
158
+ if (data) {
159
+ showToast("Attendance record saved successfully", TOAST_VARIANT.SUCCESS);
160
+ invalidateAttendancesCache();
161
+ listFetchNow();
162
+ resetFormAndCloseDrawer();
163
+ }
164
+ };
165
+ const byIdCallback = ({ data, error }) => {
166
+ if (error) {
167
+ showToast("Failed to fetch attendance details", TOAST_VARIANT.ERROR);
168
+ return;
169
+ }
170
+ if (data) {
171
+ dispatch({
172
+ type: ATTENDANCE_ACTION_TYPES.SET_FORM_DATA,
173
+ payload: { form: Object.assign(Object.assign({}, data), { filterEnabled: undefined }) },
174
+ });
175
+ }
176
+ };
177
+ const deleteCallback = ({ data, error }) => {
178
+ if (error) {
179
+ showToast("Failed to delete attendance record", TOAST_VARIANT.ERROR);
180
+ return;
181
+ }
182
+ if (data) {
183
+ showToast("Attendance record deleted successfully", TOAST_VARIANT.SUCCESS);
184
+ invalidateAttendancesCache();
185
+ listFetchNow();
186
+ }
187
+ };
188
+ // ============================================================================
189
+ // HANDLERS
190
+ // ============================================================================
191
+ const handleChange = useCallback((field, value) => {
192
+ dispatch({
193
+ type: ATTENDANCE_ACTION_TYPES.SET_ERRORS,
194
+ payload: { errors: {} },
195
+ });
196
+ dispatch({
197
+ type: ATTENDANCE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
198
+ payload: { disabled: false },
199
+ });
200
+ dispatch({
201
+ type: ATTENDANCE_ACTION_TYPES.SET_INPUT_FIELD,
202
+ payload: { key: field, value },
203
+ });
204
+ }, [dispatch]);
205
+ const handlePageChange = useCallback((page) => {
206
+ dispatch({
207
+ type: ATTENDANCE_ACTION_TYPES.SET_CURRENT_PAGE,
208
+ payload: { currentPage: page },
209
+ });
210
+ }, [dispatch]);
211
+ const handlePageLimitChange = useCallback((limit) => {
212
+ dispatch({
213
+ type: ATTENDANCE_ACTION_TYPES.SET_PAGE_LIMIT,
214
+ payload: { pageLimit: limit },
215
+ });
216
+ }, [dispatch]);
217
+ const handleCloseDrawer = useCallback(() => {
218
+ resetFormAndCloseDrawer();
219
+ }, [resetFormAndCloseDrawer]);
220
+ const handleCreate = useCallback(() => {
221
+ dispatch({
222
+ type: ATTENDANCE_ACTION_TYPES.SET_DRAWER,
223
+ payload: { drawer: ATTENDANCE_DRAWER.FORM_DRAWER },
224
+ });
225
+ }, [dispatch]);
226
+ const handleFilters = useCallback(() => {
227
+ dispatch({
228
+ type: ATTENDANCE_ACTION_TYPES.SET_DRAWER,
229
+ payload: { drawer: ATTENDANCE_DRAWER.FILTER_DRAWER },
230
+ });
231
+ }, [dispatch]);
232
+ const handleMoreActions = useCallback(() => {
233
+ dispatch({
234
+ type: ATTENDANCE_ACTION_TYPES.SET_DRAWER,
235
+ payload: { drawer: ATTENDANCE_DRAWER.MORE_ACTIONS_DRAWER },
236
+ });
237
+ }, [dispatch]);
238
+ const handleSearch = useCallback((query) => {
239
+ dispatch({
240
+ type: ATTENDANCE_ACTION_TYPES.SET_SEARCH_QUERY,
241
+ payload: { searchQuery: query },
242
+ });
243
+ }, [dispatch]);
244
+ const clearFilters = useCallback(() => {
245
+ dispatch({
246
+ type: ATTENDANCE_ACTION_TYPES.RESET_FORM,
247
+ });
248
+ }, [dispatch]);
249
+ // ============================================================================
250
+ // API HOOKS
251
+ // ============================================================================
252
+ const { listFetchNow, listLoading, updateFetchNow, updateLoading, byIdFetchNow, deleteFetchNow, deleteLoading, byIdLoading, } = useModuleEntityV2({
253
+ byIdCallback,
254
+ byIdParams,
255
+ deleteCallback,
256
+ deleteParams,
257
+ listCallback,
258
+ listParams,
259
+ listUrl: ATTENDANCE_API_ROUTES.UNIT,
260
+ searchQuery: debouncedQuery,
261
+ unitByIdUrl: ATTENDANCE_API_ROUTES.UNIT,
262
+ unitUrl: ATTENDANCE_API_ROUTES.UNIT,
263
+ updateCallback,
264
+ updateParams,
265
+ headers: {
266
+ "Content-Type": "application/json",
267
+ "x-api-token": process.env.NEXT_PUBLIC_API_KEY,
268
+ },
269
+ });
270
+ // ============================================================================
271
+ // HANDLERS THAT USE API HOOKS (moved after API hooks)
272
+ // ============================================================================
273
+ const handleView = useCallback((row) => {
274
+ byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
275
+ dispatch({
276
+ type: ATTENDANCE_ACTION_TYPES.SET_DRAWER,
277
+ payload: { drawer: ATTENDANCE_DRAWER.VIEW_DRAWER },
278
+ });
279
+ }, [byIdFetchNow, dispatch]);
280
+ const handleEdit = useCallback((row) => {
281
+ byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
282
+ dispatch({
283
+ type: ATTENDANCE_ACTION_TYPES.SET_DRAWER,
284
+ payload: { drawer: ATTENDANCE_DRAWER.FORM_DRAWER },
285
+ });
286
+ }, [byIdFetchNow, dispatch]);
287
+ const handleDelete = useCallback((row) => {
288
+ if (!confirm("Are you sure you want to delete this attendance record?"))
289
+ return;
290
+ deleteFetchNow === null || deleteFetchNow === void 0 ? void 0 : deleteFetchNow(undefined, {
291
+ body: JSON.stringify({ id: row === null || row === void 0 ? void 0 : row.id }),
292
+ });
293
+ }, [deleteFetchNow]);
294
+ const handleSubmit = useCallback(() => {
295
+ dispatch({
296
+ type: ATTENDANCE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
297
+ payload: { disabled: true },
298
+ });
299
+ validateForm({
300
+ params: updateParams,
301
+ schema: attendanceFormValidation,
302
+ successCallback: () => {
303
+ updateFetchNow(undefined, {
304
+ body: JSON.stringify(Object.assign(Object.assign({}, updateParams), { markedBy: "" })),
305
+ });
306
+ },
307
+ errorCallback: (errors) => {
308
+ dispatch({
309
+ type: ATTENDANCE_ACTION_TYPES.SET_ERRORS,
310
+ payload: { errors },
311
+ });
312
+ dispatch({
313
+ type: ATTENDANCE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
314
+ payload: { disabled: false },
315
+ });
316
+ showToast("Please fix the form errors", TOAST_VARIANT.ERROR);
317
+ },
318
+ });
319
+ }, [dispatch, updateParams, updateFetchNow, showToast]);
320
+ // ============================================================================
321
+ // HEADER / ROW ACTIONS
322
+ // ============================================================================
323
+ const headerActions = useMemo(() => [
324
+ {
325
+ enabled: false,
326
+ handleOnClick: handleMoreActions,
327
+ icon: MoreHorizontal,
328
+ label: "More Actions",
329
+ order: 1,
330
+ },
331
+ {
332
+ enabled: true,
333
+ handleOnClick: handleFilters,
334
+ icon: Filter,
335
+ label: "Filters",
336
+ order: 2,
337
+ },
338
+ {
339
+ enabled: true,
340
+ handleOnClick: handleCreate,
341
+ icon: Plus,
342
+ label: "Add Attendance",
343
+ order: 3,
344
+ },
345
+ ], [handleMoreActions, handleFilters, handleCreate]);
346
+ const rowActions = useMemo(() => [
347
+ {
348
+ enabled: true,
349
+ handleOnClick: handleView,
350
+ icon: Eye,
351
+ label: "View",
352
+ order: 1,
353
+ },
354
+ {
355
+ enabled: true,
356
+ handleOnClick: handleEdit,
357
+ icon: Edit,
358
+ label: "Edit",
359
+ order: 2,
360
+ },
361
+ ], [handleView, handleEdit]);
362
+ const applyFilters = useCallback(() => {
363
+ dispatch({
364
+ type: ATTENDANCE_ACTION_TYPES.SET_CURRENT_PAGE,
365
+ payload: { currentPage: 1 },
366
+ });
367
+ listFetchNow();
368
+ handleCloseDrawer();
369
+ }, [dispatch, listFetchNow, handleCloseDrawer]);
370
+ // ============================================================================
371
+ // EFFECTS
372
+ // ============================================================================
373
+ useEffect(() => {
374
+ (async () => {
375
+ try {
376
+ const { count, items } = await getCachedAttendances({
377
+ params: listParams,
378
+ });
379
+ dispatch({
380
+ type: ATTENDANCE_ACTION_TYPES.SET_ITEMS,
381
+ payload: { items: items || [], count: count || 0 },
382
+ });
383
+ }
384
+ catch (_a) {
385
+ showToast("Failed to fetch attendance records", TOAST_VARIANT.ERROR);
386
+ }
387
+ })();
388
+ }, [listParams, dispatch, showToast]);
389
+ // ============================================================================
390
+ // RETURN
391
+ // ============================================================================
392
+ return Object.assign(Object.assign({}, context), { applyFilters,
393
+ byIdLoading,
394
+ clearFilters,
395
+ deleteLoading,
396
+ handleChange,
397
+ handleCloseDrawer,
398
+ handleCreate,
399
+ handleDelete,
400
+ handleEdit,
401
+ handleFilters,
402
+ handleMoreActions,
403
+ handlePageChange,
404
+ handlePageLimitChange,
405
+ handleSearch,
406
+ handleSubmit,
407
+ handleView,
408
+ headerActions,
409
+ listLoading,
410
+ rowActions,
411
+ updateLoading });
412
+ };
@@ -0,0 +1,8 @@
1
+ import { FC } from "react";
2
+ interface AttendanceFilterProps {
3
+ labelAll: string;
4
+ labelEnabled: string;
5
+ labelDisabled: string;
6
+ }
7
+ export declare const AttendanceFilter: FC<AttendanceFilterProps>;
8
+ export {};