@appcorp/fusion-storybook 0.1.24 → 0.1.27

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 (59) hide show
  1. package/base-modules/class/cache.d.ts +14 -0
  2. package/base-modules/class/cache.js +31 -0
  3. package/base-modules/class/constants.d.ts +9 -0
  4. package/base-modules/class/constants.js +17 -0
  5. package/base-modules/class/context.d.ts +155 -0
  6. package/base-modules/class/context.js +453 -0
  7. package/base-modules/class/filter.d.ts +1 -0
  8. package/base-modules/class/filter.js +28 -0
  9. package/base-modules/class/form.d.ts +1 -0
  10. package/base-modules/class/form.js +18 -0
  11. package/base-modules/class/more-actions.d.ts +1 -0
  12. package/base-modules/class/more-actions.js +55 -0
  13. package/base-modules/class/page.d.ts +28 -0
  14. package/base-modules/class/page.js +118 -0
  15. package/base-modules/class/validate.d.ts +12 -0
  16. package/base-modules/class/validate.js +27 -0
  17. package/base-modules/class/view.d.ts +1 -0
  18. package/base-modules/class/view.js +20 -0
  19. package/base-modules/section/cache.d.ts +14 -0
  20. package/base-modules/section/cache.js +31 -0
  21. package/base-modules/section/constants.d.ts +11 -0
  22. package/base-modules/section/constants.js +17 -0
  23. package/base-modules/section/context.d.ts +149 -0
  24. package/base-modules/section/context.js +436 -0
  25. package/base-modules/section/filter.d.ts +1 -0
  26. package/base-modules/section/filter.js +28 -0
  27. package/base-modules/section/form.d.ts +1 -0
  28. package/base-modules/section/form.js +28 -0
  29. package/base-modules/section/more-actions.d.ts +1 -0
  30. package/base-modules/section/more-actions.js +59 -0
  31. package/base-modules/section/page.d.ts +29 -0
  32. package/base-modules/section/page.js +122 -0
  33. package/base-modules/section/validate.d.ts +12 -0
  34. package/base-modules/section/validate.js +25 -0
  35. package/base-modules/section/view.d.ts +1 -0
  36. package/base-modules/section/view.js +26 -0
  37. package/base-modules/subject/cache.d.ts +14 -0
  38. package/base-modules/subject/cache.js +31 -0
  39. package/base-modules/subject/constants.d.ts +11 -0
  40. package/base-modules/subject/constants.js +17 -0
  41. package/base-modules/subject/context.d.ts +149 -0
  42. package/base-modules/subject/context.js +456 -0
  43. package/base-modules/subject/filter.d.ts +1 -0
  44. package/base-modules/subject/filter.js +28 -0
  45. package/base-modules/subject/form.d.ts +1 -0
  46. package/base-modules/subject/form.js +18 -0
  47. package/base-modules/subject/more-actions.d.ts +1 -0
  48. package/base-modules/subject/more-actions.js +59 -0
  49. package/base-modules/subject/page.d.ts +29 -0
  50. package/base-modules/subject/page.js +122 -0
  51. package/base-modules/subject/validate.d.ts +12 -0
  52. package/base-modules/subject/validate.js +28 -0
  53. package/base-modules/subject/view.d.ts +1 -0
  54. package/base-modules/subject/view.js +20 -0
  55. package/base-modules/workspace-user/context.js +17 -10
  56. package/base-modules/workspace-user/page.d.ts +4 -4
  57. package/base-modules/workspace-user/page.js +10 -10
  58. package/package.json +1 -1
  59. package/tsconfig.build.tsbuildinfo +1 -1
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Class Module Cache Utilities
3
+ *
4
+ * Provides localStorage-based caching for classes using generic cache system.
5
+ */
6
+ import { ClassBE } from "@/type";
7
+ export declare const getCachedClassesSync: () => import("@react-pakistan/util-functions").ListResponse<ClassBE>;
8
+ export declare const getCachedClasses: ({ params, }: {
9
+ params: Record<string, unknown>;
10
+ }) => Promise<import("@react-pakistan/util-functions").ListResponse<ClassBE>>;
11
+ export declare const getCachedClassById: (classId: string) => ClassBE | null;
12
+ export declare const invalidateClassesCache: () => void;
13
+ export declare const isClassesCacheStale: () => boolean;
14
+ export declare const preloadClasses: () => Promise<import("@react-pakistan/util-functions").ListResponse<ClassBE>>;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Class Module Cache Utilities
3
+ *
4
+ * Provides localStorage-based caching for classes using generic cache system.
5
+ */
6
+ import { LS_KEYS } from "@/constants";
7
+ import { CLASS_API_ROUTES } from "./constants";
8
+ import { getCachedData, getCachedDataSync, getCachedItemById, invalidateCache, isCacheStale, preloadCache, } from "@react-pakistan/util-functions";
9
+ // ============================================================================
10
+ // CACHE CONFIGURATION
11
+ // ============================================================================
12
+ const CLASS_CACHE_CONFIG = {
13
+ apiUrl: CLASS_API_ROUTES.UNIT,
14
+ cacheKey: LS_KEYS.CLASSES,
15
+ };
16
+ // ============================================================================
17
+ // CLASS-SPECIFIC CACHE FUNCTIONS
18
+ // ============================================================================
19
+ export const getCachedClassesSync = () => getCachedDataSync(LS_KEYS.CLASSES);
20
+ export const getCachedClasses = ({ params, }) => getCachedData({
21
+ config: CLASS_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 getCachedClassById = (classId) => getCachedItemById(LS_KEYS.CLASSES, classId);
29
+ export const invalidateClassesCache = () => invalidateCache(LS_KEYS.CLASSES);
30
+ export const isClassesCacheStale = () => isCacheStale(LS_KEYS.CLASSES);
31
+ export const preloadClasses = () => preloadCache(CLASS_CACHE_CONFIG);
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Class Constants
3
+ *
4
+ * Organization:
5
+ * - Page Configuration
6
+ * - API Routes
7
+ */
8
+ export declare const pageLimit: number;
9
+ export declare const CLASS_API_ROUTES: Record<string, string>;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Class Constants
3
+ *
4
+ * Organization:
5
+ * - Page Configuration
6
+ * - API Routes
7
+ */
8
+ // ============================================================================
9
+ // PAGE CONFIGURATION
10
+ // ============================================================================
11
+ export const pageLimit = Number(process.env.NEXT_PUBLIC_PAGE_LIMIT) || 10;
12
+ // ============================================================================
13
+ // API ROUTES
14
+ // ============================================================================
15
+ export const CLASS_API_ROUTES = {
16
+ UNIT: "/api/v1/class",
17
+ };
@@ -0,0 +1,155 @@
1
+ import { ClassBE } from "@/type";
2
+ import { type RowAction, type TableRow } from "@appcorp/shadcn/components/enhanced-table";
3
+ export declare const CLASS_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 CLASS_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
+ }, classModuleConfig: import("@react-pakistan/util-functions/factory/generic-module-factory").ModuleConfig<{
22
+ items: ClassBE[];
23
+ count: number;
24
+ currentPage: number;
25
+ pageLimit: number;
26
+ searchQuery: string;
27
+ disableSaveButton: boolean;
28
+ drawer: string | null;
29
+ isInitialLoading: boolean;
30
+ code: string;
31
+ description: string | null;
32
+ enabled: boolean;
33
+ errors: Record<string, string>;
34
+ filterEnabled: boolean | undefined;
35
+ id: string;
36
+ name: string;
37
+ schoolId: string;
38
+ }>, initialClassState: {
39
+ items: ClassBE[];
40
+ count: number;
41
+ currentPage: number;
42
+ pageLimit: number;
43
+ searchQuery: string;
44
+ disableSaveButton: boolean;
45
+ drawer: string | null;
46
+ isInitialLoading: boolean;
47
+ code: string;
48
+ description: string | null;
49
+ enabled: boolean;
50
+ errors: Record<string, string>;
51
+ filterEnabled: boolean | undefined;
52
+ id: string;
53
+ name: string;
54
+ schoolId: string;
55
+ }, ClassProvider: import("react").FC<{
56
+ children: React.ReactNode;
57
+ }>, classReducer: (state: {
58
+ items: ClassBE[];
59
+ count: number;
60
+ currentPage: number;
61
+ pageLimit: number;
62
+ searchQuery: string;
63
+ disableSaveButton: boolean;
64
+ drawer: string | null;
65
+ isInitialLoading: boolean;
66
+ code: string;
67
+ description: string | null;
68
+ enabled: boolean;
69
+ errors: Record<string, string>;
70
+ filterEnabled: boolean | undefined;
71
+ id: string;
72
+ name: string;
73
+ schoolId: string;
74
+ }, action: any) => {
75
+ items: ClassBE[];
76
+ count: number;
77
+ currentPage: number;
78
+ pageLimit: number;
79
+ searchQuery: string;
80
+ disableSaveButton: boolean;
81
+ drawer: string | null;
82
+ isInitialLoading: boolean;
83
+ code: string;
84
+ description: string | null;
85
+ enabled: boolean;
86
+ errors: Record<string, string>;
87
+ filterEnabled: boolean | undefined;
88
+ id: string;
89
+ name: string;
90
+ schoolId: string;
91
+ }, useClassContext: () => import("@react-pakistan/util-functions/factory/generic-module-factory").GenericModuleContext<{
92
+ items: ClassBE[];
93
+ count: number;
94
+ currentPage: number;
95
+ pageLimit: number;
96
+ searchQuery: string;
97
+ disableSaveButton: boolean;
98
+ drawer: string | null;
99
+ isInitialLoading: boolean;
100
+ code: string;
101
+ description: string | null;
102
+ enabled: boolean;
103
+ errors: Record<string, string>;
104
+ filterEnabled: boolean | undefined;
105
+ id: string;
106
+ name: string;
107
+ schoolId: string;
108
+ }>;
109
+ export declare const useClassModule: () => {
110
+ applyFilters: () => void;
111
+ byIdLoading: boolean;
112
+ clearFilters: () => void;
113
+ deleteLoading: boolean;
114
+ handleChange: (field: string, value: string | number | boolean | undefined) => void;
115
+ handleCloseDrawer: () => void;
116
+ handleCreate: () => void;
117
+ handleDelete: (row?: TableRow) => void;
118
+ handleEdit: (row?: TableRow) => void;
119
+ handleFilters: () => void;
120
+ handleMoreActions: () => void;
121
+ handlePageChange: (page: number) => void;
122
+ handlePageLimitChange: (limit: number) => void;
123
+ handleSearch: (query: string) => void;
124
+ handleSubmit: () => void;
125
+ handleView: (row?: TableRow) => void;
126
+ headerActions: {
127
+ enabled: boolean;
128
+ handleOnClick: () => void;
129
+ icon: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
130
+ label: string;
131
+ order: number;
132
+ }[];
133
+ listLoading: boolean;
134
+ rowActions: RowAction[];
135
+ updateLoading: boolean;
136
+ state: {
137
+ items: ClassBE[];
138
+ count: number;
139
+ currentPage: number;
140
+ pageLimit: number;
141
+ searchQuery: string;
142
+ disableSaveButton: boolean;
143
+ drawer: string | null;
144
+ isInitialLoading: boolean;
145
+ code: string;
146
+ description: string | null;
147
+ enabled: boolean;
148
+ errors: Record<string, string>;
149
+ filterEnabled: boolean | undefined;
150
+ id: string;
151
+ name: string;
152
+ schoolId: string;
153
+ };
154
+ dispatch: React.Dispatch<any>;
155
+ };
@@ -0,0 +1,453 @@
1
+ "use client";
2
+ /**
3
+ * Class Module — business logic + API integration
4
+ *
5
+ * Wires the generic module state (created by `createGenericModule`) to network
6
+ * actions using `useModuleEntityV2`. Contains domain-specific handlers for
7
+ * create/view/edit/delete and bulk actions.
8
+ *
9
+ * Key responsibilities:
10
+ * - expose `useClassModule()` which UI components call for actions
11
+ * - keep module-specific `apiParams` and callbacks in one place
12
+ * - ensure cache invalidation and toast notifications on mutation
13
+ *
14
+ * Exported utilities:
15
+ * - `ClassProvider` — provider component used by the page
16
+ * - `CLASS_ACTION_TYPES` — action type constants (from factory)
17
+ * - `CLASS_DRAWER` — drawer type constants
18
+ * - `useClassModule()` — hook that returns state, dispatch, and handlers
19
+ */
20
+ import { useCallback, useEffect, useMemo } from "react";
21
+ import { isCreatedOrUpdated, validateForm, } from "@react-pakistan/util-functions";
22
+ import { useModuleEntityV2, } from "@react-pakistan/util-functions/hooks/use-module-entity-v2";
23
+ import { useDebounce } from "@react-pakistan/util-functions/hooks/use-debounce";
24
+ import { createGenericModule } from "@react-pakistan/util-functions/factory/generic-module-factory";
25
+ import { DRAWER_TYPES } from "@react-pakistan/util-functions/factory/generic-component-factory";
26
+ import { generateThemeToast, TOAST_VARIANT, } from "@appcorp/shadcn/lib/toast-utils";
27
+ import { useTranslations } from "next-intl";
28
+ import { CLASS_API_ROUTES, pageLimit } from "./constants";
29
+ import { classFormValidation } from "./validate";
30
+ import { getCachedClasses, getCachedClassesSync, invalidateClassesCache, isClassesCacheStale, } from "./cache";
31
+ import { getCachedWorkspaceSync } from "../workspace/cache";
32
+ import { Edit, Eye, Filter, MoreHorizontal, Plus, Trash2 } from "lucide-react";
33
+ // ============================================================================
34
+ // DRAWER TYPES
35
+ // ============================================================================
36
+ export const CLASS_DRAWER = {
37
+ FILTER_DRAWER: DRAWER_TYPES.FILTER_DRAWER,
38
+ FORM_DRAWER: DRAWER_TYPES.FORM_DRAWER,
39
+ MORE_ACTIONS_DRAWER: "MORE_ACTIONS_DRAWER",
40
+ VIEW_DRAWER: DRAWER_TYPES.VIEW_DRAWER,
41
+ };
42
+ // ============================================================================
43
+ // CONFIGURATION
44
+ // ============================================================================
45
+ const classConfig = {
46
+ name: "Class",
47
+ displayName: "Class",
48
+ initialState: {
49
+ // List Data
50
+ items: [],
51
+ count: 0,
52
+ // Search & Pagination
53
+ currentPage: 1,
54
+ pageLimit,
55
+ searchQuery: "",
56
+ // UI State
57
+ disableSaveButton: false,
58
+ drawer: null,
59
+ isInitialLoading: true,
60
+ // Form State
61
+ code: "",
62
+ description: null,
63
+ enabled: true,
64
+ errors: {},
65
+ filterEnabled: undefined,
66
+ id: "",
67
+ name: "",
68
+ schoolId: "",
69
+ },
70
+ drawerTypes: DRAWER_TYPES,
71
+ };
72
+ // ============================================================================
73
+ // CREATE CLASS MODULE
74
+ // ============================================================================
75
+ export const { actionTypes: CLASS_ACTION_TYPES, config: classModuleConfig, initialState: initialClassState, Provider: ClassProvider, reducer: classReducer, useContext: useClassContext, } = createGenericModule(classConfig);
76
+ // ============================================================================
77
+ // ENHANCED CLASS HOOK WITH API INTEGRATION
78
+ // ============================================================================
79
+ export const useClassModule = () => {
80
+ var _a;
81
+ const context = useClassContext();
82
+ const { dispatch } = context;
83
+ const t = useTranslations("class");
84
+ const debouncedQuery = useDebounce(context.state.searchQuery, 800);
85
+ const workspace = getCachedWorkspaceSync();
86
+ const schoolId = ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "";
87
+ // ============================================================================
88
+ // API PARAMETERS
89
+ // ============================================================================
90
+ const listParams = useMemo(() => (Object.assign(Object.assign({ currentPage: context.state.currentPage, pageLimit: context.state.pageLimit, schoolId }, (debouncedQuery ? { searchQuery: debouncedQuery } : {})), (context.state.filterEnabled !== undefined
91
+ ? { filterEnabled: String(context.state.filterEnabled) }
92
+ : {}))), [
93
+ context.state.currentPage,
94
+ context.state.filterEnabled,
95
+ context.state.pageLimit,
96
+ schoolId,
97
+ debouncedQuery,
98
+ ]);
99
+ const updateParams = useMemo(() => ({
100
+ code: context.state.code,
101
+ description: context.state.description,
102
+ enabled: context.state.enabled,
103
+ id: context.state.id,
104
+ name: context.state.name,
105
+ schoolId: context.state.schoolId || schoolId,
106
+ }), [context.state, schoolId]);
107
+ const byIdParams = useMemo(() => ({ id: context.state.id }), [context.state.id]);
108
+ const deleteParams = useMemo(() => ({ id: context.state.id }), [context.state.id]);
109
+ // ============================================================================
110
+ // UTILITIES
111
+ // ============================================================================
112
+ const showToast = useCallback((message, variant) => {
113
+ generateThemeToast({ description: message, variant });
114
+ }, []);
115
+ const setField = useCallback((key, value) => {
116
+ let formatted = value === null
117
+ ? undefined
118
+ : value;
119
+ // Format code to uppercase
120
+ if (key === "code" && typeof value === "string") {
121
+ formatted = value.toUpperCase();
122
+ }
123
+ dispatch({
124
+ type: CLASS_ACTION_TYPES.SET_ERRORS,
125
+ payload: { errors: {} },
126
+ });
127
+ dispatch({
128
+ type: CLASS_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
129
+ payload: { disabled: false },
130
+ });
131
+ dispatch({
132
+ type: CLASS_ACTION_TYPES.SET_INPUT_FIELD,
133
+ payload: { key, value: formatted || value },
134
+ });
135
+ }, [dispatch]);
136
+ const resetFormAndCloseDrawer = useCallback(() => {
137
+ dispatch({
138
+ type: CLASS_ACTION_TYPES.SET_ERRORS,
139
+ payload: { errors: {} },
140
+ });
141
+ dispatch({
142
+ type: CLASS_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
143
+ payload: { disabled: false },
144
+ });
145
+ dispatch({
146
+ type: CLASS_ACTION_TYPES.SET_DRAWER,
147
+ payload: { drawer: null },
148
+ });
149
+ }, [dispatch]);
150
+ // ============================================================================
151
+ // API CALLBACKS
152
+ // ============================================================================
153
+ const listCallback = ({ data, error }) => {
154
+ var _a;
155
+ if (error) {
156
+ showToast(t("messagesFetchFailed"), TOAST_VARIANT.ERROR);
157
+ return;
158
+ }
159
+ if (data) {
160
+ const response = data;
161
+ const items = (_a = response.items) !== null && _a !== void 0 ? _a : [];
162
+ const count = typeof response.count === "number" ? response.count : 0;
163
+ dispatch({
164
+ type: CLASS_ACTION_TYPES.SET_ITEMS,
165
+ payload: { items, count },
166
+ });
167
+ }
168
+ };
169
+ const updateCallback = ({ data, error }) => {
170
+ const isCreated = isCreatedOrUpdated(data);
171
+ if (error) {
172
+ showToast(isCreated ? t("messagesCreateFailed") : t("messagesUpdateFailed"), TOAST_VARIANT.ERROR);
173
+ return;
174
+ }
175
+ if (data) {
176
+ showToast(t("messagesSaveSuccess"), TOAST_VARIANT.SUCCESS);
177
+ invalidateClassesCache();
178
+ listFetchNow();
179
+ resetFormAndCloseDrawer();
180
+ }
181
+ };
182
+ const byIdCallback = ({ data, error }) => {
183
+ if (error) {
184
+ showToast(t("messagesDetailsFetchFailed"), TOAST_VARIANT.ERROR);
185
+ return;
186
+ }
187
+ if (data) {
188
+ dispatch({
189
+ type: CLASS_ACTION_TYPES.SET_FORM_DATA,
190
+ payload: { form: Object.assign(Object.assign({}, data), { filterEnabled: undefined }) },
191
+ });
192
+ }
193
+ };
194
+ const deleteCallback = ({ data, error }) => {
195
+ if (error) {
196
+ showToast(t("messagesDeleteFailed"), TOAST_VARIANT.ERROR);
197
+ return;
198
+ }
199
+ if (data) {
200
+ showToast(t("messagesDeleteSuccess"), TOAST_VARIANT.SUCCESS);
201
+ invalidateClassesCache();
202
+ listFetchNow();
203
+ }
204
+ };
205
+ // ============================================================================
206
+ // API HOOKS
207
+ // ============================================================================
208
+ const { listFetchNow, listLoading, updateFetchNow, updateLoading, byIdFetchNow, deleteFetchNow, deleteLoading, byIdLoading, } = useModuleEntityV2({
209
+ byIdCallback,
210
+ byIdParams,
211
+ deleteCallback,
212
+ deleteParams,
213
+ listCallback,
214
+ listParams,
215
+ listUrl: CLASS_API_ROUTES.UNIT,
216
+ searchQuery: debouncedQuery,
217
+ unitByIdUrl: CLASS_API_ROUTES.UNIT,
218
+ unitUrl: CLASS_API_ROUTES.UNIT,
219
+ updateCallback,
220
+ updateParams,
221
+ headers: {
222
+ "Content-Type": "application/json",
223
+ "x-api-token": process.env.NEXT_PUBLIC_API_KEY,
224
+ },
225
+ });
226
+ // ============================================================================
227
+ // HANDLERS
228
+ // ============================================================================
229
+ const handleChange = useCallback((field, value) => {
230
+ setField(field, value);
231
+ }, [setField]);
232
+ const handlePageChange = useCallback((page) => {
233
+ dispatch({
234
+ type: CLASS_ACTION_TYPES.SET_CURRENT_PAGE,
235
+ payload: { currentPage: page },
236
+ });
237
+ }, [dispatch]);
238
+ const handlePageLimitChange = useCallback((limit) => {
239
+ dispatch({
240
+ type: CLASS_ACTION_TYPES.SET_PAGE_LIMIT,
241
+ payload: { pageLimit: limit },
242
+ });
243
+ }, [dispatch]);
244
+ const handleCloseDrawer = useCallback(() => {
245
+ dispatch({
246
+ type: CLASS_ACTION_TYPES.SET_DRAWER,
247
+ payload: { drawer: null },
248
+ });
249
+ dispatch({ type: CLASS_ACTION_TYPES.RESET_FORM });
250
+ dispatch({
251
+ type: CLASS_ACTION_TYPES.SET_ERRORS,
252
+ payload: { errors: {} },
253
+ });
254
+ }, [dispatch]);
255
+ const handleCreate = useCallback(() => {
256
+ dispatch({
257
+ type: CLASS_ACTION_TYPES.SET_DRAWER,
258
+ payload: { drawer: CLASS_DRAWER.FORM_DRAWER },
259
+ });
260
+ }, [dispatch]);
261
+ const handleView = useCallback((row) => {
262
+ byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
263
+ dispatch({
264
+ type: CLASS_ACTION_TYPES.SET_DRAWER,
265
+ payload: { drawer: CLASS_DRAWER.VIEW_DRAWER },
266
+ });
267
+ }, [dispatch, byIdFetchNow]);
268
+ const handleEdit = useCallback((row) => {
269
+ byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
270
+ dispatch({
271
+ type: CLASS_ACTION_TYPES.SET_DRAWER,
272
+ payload: { drawer: CLASS_DRAWER.FORM_DRAWER },
273
+ });
274
+ }, [dispatch, byIdFetchNow]);
275
+ const handleDelete = useCallback((row) => {
276
+ if (!confirm(t("areYouSureYouWantToDeleteThisClass")))
277
+ return;
278
+ deleteFetchNow === null || deleteFetchNow === void 0 ? void 0 : deleteFetchNow(undefined, {
279
+ body: JSON.stringify({ id: row === null || row === void 0 ? void 0 : row.id }),
280
+ });
281
+ }, [t, deleteFetchNow]);
282
+ const handleFilters = useCallback(() => {
283
+ dispatch({
284
+ type: CLASS_ACTION_TYPES.SET_DRAWER,
285
+ payload: { drawer: CLASS_DRAWER.FILTER_DRAWER },
286
+ });
287
+ }, [dispatch]);
288
+ const handleMoreActions = useCallback(() => {
289
+ dispatch({
290
+ type: CLASS_ACTION_TYPES.SET_DRAWER,
291
+ payload: { drawer: CLASS_DRAWER.MORE_ACTIONS_DRAWER },
292
+ });
293
+ }, [dispatch]);
294
+ const handleSearch = useCallback((query) => {
295
+ dispatch({
296
+ type: CLASS_ACTION_TYPES.SET_SEARCH_QUERY,
297
+ payload: { searchQuery: query },
298
+ });
299
+ }, [dispatch]);
300
+ const clearFilters = useCallback(() => {
301
+ dispatch({
302
+ type: CLASS_ACTION_TYPES.SET_FILTERS,
303
+ payload: { filters: { filterEnabled: undefined } },
304
+ });
305
+ dispatch({
306
+ type: CLASS_ACTION_TYPES.SET_CURRENT_PAGE,
307
+ payload: { currentPage: 1 },
308
+ });
309
+ }, [dispatch]);
310
+ // ============================================================================
311
+ // NETWORK ACTIONS
312
+ // ============================================================================
313
+ const handleSubmit = useCallback(() => {
314
+ dispatch({
315
+ type: CLASS_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
316
+ payload: { disabled: true },
317
+ });
318
+ validateForm({
319
+ params: updateParams,
320
+ schema: classFormValidation,
321
+ successCallback: () => {
322
+ updateFetchNow(undefined, {
323
+ body: JSON.stringify(updateParams),
324
+ });
325
+ },
326
+ errorCallback: (errors) => {
327
+ dispatch({
328
+ type: CLASS_ACTION_TYPES.SET_ERRORS,
329
+ payload: { errors },
330
+ });
331
+ dispatch({
332
+ type: CLASS_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
333
+ payload: { disabled: false },
334
+ });
335
+ showToast(t("messagesFormErrors"), TOAST_VARIANT.ERROR);
336
+ },
337
+ });
338
+ }, [dispatch, updateParams, t, showToast, updateFetchNow]);
339
+ // ============================================================================
340
+ // HEADER & ROW ACTIONS
341
+ // ============================================================================
342
+ const headerActions = useMemo(() => [
343
+ {
344
+ enabled: false,
345
+ handleOnClick: handleMoreActions,
346
+ icon: MoreHorizontal,
347
+ label: t("headerActionsMoreActions"),
348
+ order: 1,
349
+ },
350
+ {
351
+ enabled: true,
352
+ handleOnClick: handleFilters,
353
+ icon: Filter,
354
+ label: t("headerActionsFilters"),
355
+ order: 2,
356
+ },
357
+ {
358
+ enabled: true,
359
+ handleOnClick: handleCreate,
360
+ icon: Plus,
361
+ label: t("headerActionsAdd"),
362
+ order: 3,
363
+ },
364
+ ], [handleFilters, handleMoreActions, handleCreate, t]);
365
+ const rowActions = useMemo(() => [
366
+ {
367
+ enabled: true,
368
+ handleOnClick: handleView,
369
+ icon: Eye,
370
+ label: t("rowActionsView"),
371
+ order: 1,
372
+ },
373
+ {
374
+ enabled: (row) => (row === null || row === void 0 ? void 0 : row.enabled) === true,
375
+ handleOnClick: handleEdit,
376
+ icon: Edit,
377
+ label: t("rowActionsEdit"),
378
+ order: 2,
379
+ },
380
+ {
381
+ enabled: (row) => (row === null || row === void 0 ? void 0 : row.enabled) === false,
382
+ handleOnClick: handleDelete,
383
+ icon: Trash2,
384
+ label: t("rowActionsDelete"),
385
+ order: 3,
386
+ },
387
+ ], [handleView, handleEdit, handleDelete, t]);
388
+ const applyFilters = useCallback(() => {
389
+ dispatch({
390
+ type: CLASS_ACTION_TYPES.SET_CURRENT_PAGE,
391
+ payload: { currentPage: 1 },
392
+ });
393
+ listFetchNow();
394
+ handleCloseDrawer();
395
+ }, [dispatch, listFetchNow, handleCloseDrawer]);
396
+ // ============================================================================
397
+ // EFFECTS
398
+ // ============================================================================
399
+ useEffect(() => {
400
+ if (!schoolId)
401
+ return;
402
+ // Use sync cache for initial load to prevent UI hanging
403
+ const cachedData = getCachedClassesSync();
404
+ if (cachedData && !isClassesCacheStale()) {
405
+ // Cache is fresh, use it immediately
406
+ const { count, items } = cachedData;
407
+ dispatch({
408
+ type: CLASS_ACTION_TYPES.SET_ITEMS,
409
+ payload: { items: items || [], count: count || 0 },
410
+ });
411
+ }
412
+ else {
413
+ // Cache is stale or empty, fetch async
414
+ (async () => {
415
+ try {
416
+ const { count, items } = await getCachedClasses({
417
+ params: listParams,
418
+ });
419
+ dispatch({
420
+ type: CLASS_ACTION_TYPES.SET_ITEMS,
421
+ payload: { items: items || [], count: count || 0 },
422
+ });
423
+ }
424
+ catch (_a) {
425
+ showToast(t("messagesFetchFailed"), TOAST_VARIANT.ERROR);
426
+ }
427
+ })();
428
+ }
429
+ }, [listParams, schoolId, showToast, t, dispatch]);
430
+ // ============================================================================
431
+ // RETURN
432
+ // ============================================================================
433
+ return Object.assign(Object.assign({}, context), { applyFilters,
434
+ byIdLoading,
435
+ clearFilters,
436
+ deleteLoading,
437
+ handleChange,
438
+ handleCloseDrawer,
439
+ handleCreate,
440
+ handleDelete,
441
+ handleEdit,
442
+ handleFilters,
443
+ handleMoreActions,
444
+ handlePageChange,
445
+ handlePageLimitChange,
446
+ handleSearch,
447
+ handleSubmit,
448
+ handleView,
449
+ headerActions,
450
+ listLoading,
451
+ rowActions,
452
+ updateLoading });
453
+ };
@@ -0,0 +1 @@
1
+ export declare const ClassFilter: () => import("react/jsx-runtime").JSX.Element;