@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.
- package/base-modules/class/cache.d.ts +14 -0
- package/base-modules/class/cache.js +31 -0
- package/base-modules/class/constants.d.ts +9 -0
- package/base-modules/class/constants.js +17 -0
- package/base-modules/class/context.d.ts +155 -0
- package/base-modules/class/context.js +453 -0
- package/base-modules/class/filter.d.ts +1 -0
- package/base-modules/class/filter.js +28 -0
- package/base-modules/class/form.d.ts +1 -0
- package/base-modules/class/form.js +18 -0
- package/base-modules/class/more-actions.d.ts +1 -0
- package/base-modules/class/more-actions.js +55 -0
- package/base-modules/class/page.d.ts +28 -0
- package/base-modules/class/page.js +118 -0
- package/base-modules/class/validate.d.ts +12 -0
- package/base-modules/class/validate.js +27 -0
- package/base-modules/class/view.d.ts +1 -0
- package/base-modules/class/view.js +20 -0
- package/base-modules/section/cache.d.ts +14 -0
- package/base-modules/section/cache.js +31 -0
- package/base-modules/section/constants.d.ts +11 -0
- package/base-modules/section/constants.js +17 -0
- package/base-modules/section/context.d.ts +149 -0
- package/base-modules/section/context.js +436 -0
- package/base-modules/section/filter.d.ts +1 -0
- package/base-modules/section/filter.js +28 -0
- package/base-modules/section/form.d.ts +1 -0
- package/base-modules/section/form.js +28 -0
- package/base-modules/section/more-actions.d.ts +1 -0
- package/base-modules/section/more-actions.js +59 -0
- package/base-modules/section/page.d.ts +29 -0
- package/base-modules/section/page.js +122 -0
- package/base-modules/section/validate.d.ts +12 -0
- package/base-modules/section/validate.js +25 -0
- package/base-modules/section/view.d.ts +1 -0
- package/base-modules/section/view.js +26 -0
- package/base-modules/subject/cache.d.ts +14 -0
- package/base-modules/subject/cache.js +31 -0
- package/base-modules/subject/constants.d.ts +11 -0
- package/base-modules/subject/constants.js +17 -0
- package/base-modules/subject/context.d.ts +149 -0
- package/base-modules/subject/context.js +456 -0
- package/base-modules/subject/filter.d.ts +1 -0
- package/base-modules/subject/filter.js +28 -0
- package/base-modules/subject/form.d.ts +1 -0
- package/base-modules/subject/form.js +18 -0
- package/base-modules/subject/more-actions.d.ts +1 -0
- package/base-modules/subject/more-actions.js +59 -0
- package/base-modules/subject/page.d.ts +29 -0
- package/base-modules/subject/page.js +122 -0
- package/base-modules/subject/validate.d.ts +12 -0
- package/base-modules/subject/validate.js +28 -0
- package/base-modules/subject/view.d.ts +1 -0
- package/base-modules/subject/view.js +20 -0
- package/base-modules/workspace-user/context.js +17 -10
- package/base-modules/workspace-user/page.d.ts +4 -4
- package/base-modules/workspace-user/page.js +10 -10
- package/package.json +1 -1
- 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,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;
|