@appcorp/fusion-storybook 0.4.39 → 0.4.40
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/bulk-operations/constants.d.ts +12 -0
- package/base-modules/bulk-operations/constants.js +20 -0
- package/base-modules/bulk-operations/context.d.ts +172 -0
- package/base-modules/bulk-operations/context.js +283 -0
- package/base-modules/bulk-operations/filter.d.ts +1 -0
- package/base-modules/bulk-operations/filter.js +31 -0
- package/base-modules/bulk-operations/page.d.ts +33 -0
- package/base-modules/bulk-operations/page.js +144 -0
- package/base-modules/bulk-operations/view.d.ts +1 -0
- package/base-modules/bulk-operations/view.js +35 -0
- package/constants.d.ts +4 -0
- package/constants.js +4 -0
- package/package.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/bulk-operations.d.ts +48 -0
- package/types/bulk-operations.js +8 -0
- package/types/index.d.ts +1 -0
- package/types/index.js +1 -0
- package/utils/resolve-rbac-permissions.js +10 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bulk Operations Constants
|
|
3
|
+
*
|
|
4
|
+
* Organization:
|
|
5
|
+
* - Page Configuration
|
|
6
|
+
* - Status Options
|
|
7
|
+
*/
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// PAGE CONFIGURATION
|
|
10
|
+
// ============================================================================
|
|
11
|
+
export const pageLimit = Number(process.env.NEXT_PUBLIC_PAGE_LIMIT) || 10;
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// STATUS OPTIONS
|
|
14
|
+
// ============================================================================
|
|
15
|
+
export const BULK_JOB_STATUS_OPTIONS = [
|
|
16
|
+
{ label: "queued", value: "queued" },
|
|
17
|
+
{ label: "running", value: "running" },
|
|
18
|
+
{ label: "completed", value: "completed" },
|
|
19
|
+
{ label: "failed", value: "failed" },
|
|
20
|
+
];
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { type HeaderAction, type RowAction, type TableRow } from "@appcorp/shadcn/components/enhanced-table";
|
|
2
|
+
import { BulkJobRecord } from "../../type";
|
|
3
|
+
export declare const BULK_OPERATIONS_DRAWER: {
|
|
4
|
+
readonly FILTER_DRAWER: string;
|
|
5
|
+
readonly VIEW_DRAWER: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const BULK_OPERATIONS_ACTION_TYPES: {
|
|
8
|
+
readonly RESET_FORM: "RESET_FORM";
|
|
9
|
+
readonly SET_CURRENT_PAGE: "SET_CURRENT_PAGE";
|
|
10
|
+
readonly SET_PAGE_LIMIT: "SET_PAGE_LIMIT";
|
|
11
|
+
readonly SET_SEARCH_QUERY: "SET_SEARCH_QUERY";
|
|
12
|
+
readonly SET_DRAWER: "SET_DRAWER";
|
|
13
|
+
readonly SET_ITEMS: "SET_ITEMS";
|
|
14
|
+
readonly SET_FORM_DATA: "SET_FORM_DATA";
|
|
15
|
+
readonly SET_DISABLE_SAVE_BUTTON: "SET_DISABLE_SAVE_BUTTON";
|
|
16
|
+
readonly SET_INPUT_FIELD: "SET_INPUT_FIELD";
|
|
17
|
+
readonly SET_ERRORS: "SET_ERRORS";
|
|
18
|
+
readonly SET_FILTERS: "SET_FILTERS";
|
|
19
|
+
}, bulkOperationsModuleConfig: import("@react-pakistan/util-functions/factory/generic-module-factory").ModuleConfig<{
|
|
20
|
+
items: BulkJobRecord[];
|
|
21
|
+
count: number;
|
|
22
|
+
types: string[];
|
|
23
|
+
currentPage: number;
|
|
24
|
+
pageLimit: number;
|
|
25
|
+
searchQuery: string;
|
|
26
|
+
filterStatus: string;
|
|
27
|
+
filterType: string;
|
|
28
|
+
createdAt: string;
|
|
29
|
+
errors: Record<string, string>;
|
|
30
|
+
jobId: string;
|
|
31
|
+
processed: number;
|
|
32
|
+
results: BulkJobRecord["results"];
|
|
33
|
+
status: string;
|
|
34
|
+
total: number;
|
|
35
|
+
type: string;
|
|
36
|
+
updatedAt: string;
|
|
37
|
+
webhookUrl: string | null;
|
|
38
|
+
disableSaveButton: boolean;
|
|
39
|
+
drawer: string | null;
|
|
40
|
+
}>, initialBulkOperationsState: {
|
|
41
|
+
items: BulkJobRecord[];
|
|
42
|
+
count: number;
|
|
43
|
+
types: string[];
|
|
44
|
+
currentPage: number;
|
|
45
|
+
pageLimit: number;
|
|
46
|
+
searchQuery: string;
|
|
47
|
+
filterStatus: string;
|
|
48
|
+
filterType: string;
|
|
49
|
+
createdAt: string;
|
|
50
|
+
errors: Record<string, string>;
|
|
51
|
+
jobId: string;
|
|
52
|
+
processed: number;
|
|
53
|
+
results: BulkJobRecord["results"];
|
|
54
|
+
status: string;
|
|
55
|
+
total: number;
|
|
56
|
+
type: string;
|
|
57
|
+
updatedAt: string;
|
|
58
|
+
webhookUrl: string | null;
|
|
59
|
+
disableSaveButton: boolean;
|
|
60
|
+
drawer: string | null;
|
|
61
|
+
}, BulkOperationsProvider: import("react").FC<{
|
|
62
|
+
children: React.ReactNode;
|
|
63
|
+
}>, bulkOperationsReducer: (state: {
|
|
64
|
+
items: BulkJobRecord[];
|
|
65
|
+
count: number;
|
|
66
|
+
types: string[];
|
|
67
|
+
currentPage: number;
|
|
68
|
+
pageLimit: number;
|
|
69
|
+
searchQuery: string;
|
|
70
|
+
filterStatus: string;
|
|
71
|
+
filterType: string;
|
|
72
|
+
createdAt: string;
|
|
73
|
+
errors: Record<string, string>;
|
|
74
|
+
jobId: string;
|
|
75
|
+
processed: number;
|
|
76
|
+
results: BulkJobRecord["results"];
|
|
77
|
+
status: string;
|
|
78
|
+
total: number;
|
|
79
|
+
type: string;
|
|
80
|
+
updatedAt: string;
|
|
81
|
+
webhookUrl: string | null;
|
|
82
|
+
disableSaveButton: boolean;
|
|
83
|
+
drawer: string | null;
|
|
84
|
+
}, action: any) => {
|
|
85
|
+
items: BulkJobRecord[];
|
|
86
|
+
count: number;
|
|
87
|
+
types: string[];
|
|
88
|
+
currentPage: number;
|
|
89
|
+
pageLimit: number;
|
|
90
|
+
searchQuery: string;
|
|
91
|
+
filterStatus: string;
|
|
92
|
+
filterType: string;
|
|
93
|
+
createdAt: string;
|
|
94
|
+
errors: Record<string, string>;
|
|
95
|
+
jobId: string;
|
|
96
|
+
processed: number;
|
|
97
|
+
results: BulkJobRecord["results"];
|
|
98
|
+
status: string;
|
|
99
|
+
total: number;
|
|
100
|
+
type: string;
|
|
101
|
+
updatedAt: string;
|
|
102
|
+
webhookUrl: string | null;
|
|
103
|
+
disableSaveButton: boolean;
|
|
104
|
+
drawer: string | null;
|
|
105
|
+
}, useBulkOperationsContext: () => import("@react-pakistan/util-functions/factory/generic-module-factory").GenericModuleContextWithHandlers<{
|
|
106
|
+
items: BulkJobRecord[];
|
|
107
|
+
count: number;
|
|
108
|
+
types: string[];
|
|
109
|
+
currentPage: number;
|
|
110
|
+
pageLimit: number;
|
|
111
|
+
searchQuery: string;
|
|
112
|
+
filterStatus: string;
|
|
113
|
+
filterType: string;
|
|
114
|
+
createdAt: string;
|
|
115
|
+
errors: Record<string, string>;
|
|
116
|
+
jobId: string;
|
|
117
|
+
processed: number;
|
|
118
|
+
results: BulkJobRecord["results"];
|
|
119
|
+
status: string;
|
|
120
|
+
total: number;
|
|
121
|
+
type: string;
|
|
122
|
+
updatedAt: string;
|
|
123
|
+
webhookUrl: string | null;
|
|
124
|
+
disableSaveButton: boolean;
|
|
125
|
+
drawer: string | null;
|
|
126
|
+
}>;
|
|
127
|
+
export declare const BULK_OPERATIONS_STATUS_OPTIONS: {
|
|
128
|
+
label: string;
|
|
129
|
+
value: string;
|
|
130
|
+
}[];
|
|
131
|
+
export declare const useBulkOperationsModule: () => {
|
|
132
|
+
applyFilters: () => void;
|
|
133
|
+
clearFilters: () => void;
|
|
134
|
+
clearSearch: () => void;
|
|
135
|
+
closeDrawer: () => void;
|
|
136
|
+
handleChange: (field: string, value: string | number | boolean | undefined) => void;
|
|
137
|
+
handleFilters: () => void;
|
|
138
|
+
handlePageChange: (pageOrEvent?: unknown) => void;
|
|
139
|
+
handlePageLimitChange: (k: string, value: object) => void;
|
|
140
|
+
handleRefresh: () => void;
|
|
141
|
+
handleSearch: (query: string) => void;
|
|
142
|
+
handleView: (row?: TableRow) => void;
|
|
143
|
+
headerActions: HeaderAction[];
|
|
144
|
+
listFetchNow: (url?: string, config?: import("@react-pakistan/util-functions/hooks/use-fetch").FetchConfig) => void;
|
|
145
|
+
listLoading: boolean;
|
|
146
|
+
rowActions: RowAction[];
|
|
147
|
+
handleCloseDrawer?: () => void;
|
|
148
|
+
handleSubmit?: (data: any) => void;
|
|
149
|
+
state: {
|
|
150
|
+
items: BulkJobRecord[];
|
|
151
|
+
count: number;
|
|
152
|
+
types: string[];
|
|
153
|
+
currentPage: number;
|
|
154
|
+
pageLimit: number;
|
|
155
|
+
searchQuery: string;
|
|
156
|
+
filterStatus: string;
|
|
157
|
+
filterType: string;
|
|
158
|
+
createdAt: string;
|
|
159
|
+
errors: Record<string, string>;
|
|
160
|
+
jobId: string;
|
|
161
|
+
processed: number;
|
|
162
|
+
results: BulkJobRecord["results"];
|
|
163
|
+
status: string;
|
|
164
|
+
total: number;
|
|
165
|
+
type: string;
|
|
166
|
+
updatedAt: string;
|
|
167
|
+
webhookUrl: string | null;
|
|
168
|
+
disableSaveButton: boolean;
|
|
169
|
+
drawer: string | null;
|
|
170
|
+
};
|
|
171
|
+
dispatch: React.Dispatch<any>;
|
|
172
|
+
};
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
/**
|
|
3
|
+
* Bulk Operations Module — business logic + API integration
|
|
4
|
+
*
|
|
5
|
+
* Read-only module that lists all Redis-backed bulk jobs for the current school.
|
|
6
|
+
* Uses the generic module state (`createGenericModule`) wired to `useModuleEntityV2`.
|
|
7
|
+
* No create/edit/delete — only list (search, filter, paginate), a view drawer,
|
|
8
|
+
* and a manual refresh header action.
|
|
9
|
+
*/
|
|
10
|
+
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
11
|
+
import { useTheme } from "next-themes";
|
|
12
|
+
import { useTranslations } from "next-intl";
|
|
13
|
+
import { useDebounce } from "@react-pakistan/util-functions/hooks/use-debounce";
|
|
14
|
+
import { useModuleEntityV2, } from "@react-pakistan/util-functions/hooks/use-module-entity-v2";
|
|
15
|
+
import { createGenericModule } from "@react-pakistan/util-functions/factory/generic-module-factory";
|
|
16
|
+
import { DRAWER_TYPES } from "@react-pakistan/util-functions/factory/generic-component-factory";
|
|
17
|
+
import { generateThemeToast, TOAST_VARIANT, } from "@appcorp/shadcn/lib/toast-utils";
|
|
18
|
+
import { pageLimit } from "./constants";
|
|
19
|
+
import { BULK_OPERATIONS_API_ROUTES } from "../../constants";
|
|
20
|
+
import { getCachedWorkspaceSync } from "../workspace/cache";
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// 1.1 DRAWER TYPES
|
|
23
|
+
// ============================================================================
|
|
24
|
+
export const BULK_OPERATIONS_DRAWER = {
|
|
25
|
+
FILTER_DRAWER: DRAWER_TYPES.FILTER_DRAWER,
|
|
26
|
+
VIEW_DRAWER: DRAWER_TYPES.VIEW_DRAWER,
|
|
27
|
+
};
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// 1.2 MODULE CONFIGURATION
|
|
30
|
+
// ============================================================================
|
|
31
|
+
const BULK_OPERATIONS_CONFIG = {
|
|
32
|
+
name: "Bulk Operations",
|
|
33
|
+
displayName: "Bulk Operations",
|
|
34
|
+
drawerTypes: DRAWER_TYPES,
|
|
35
|
+
initialState: {
|
|
36
|
+
// List Data
|
|
37
|
+
items: [],
|
|
38
|
+
count: 0,
|
|
39
|
+
types: [],
|
|
40
|
+
// Search & Pagination
|
|
41
|
+
currentPage: 1,
|
|
42
|
+
pageLimit,
|
|
43
|
+
searchQuery: "",
|
|
44
|
+
// Filters
|
|
45
|
+
filterStatus: "",
|
|
46
|
+
filterType: "",
|
|
47
|
+
// View Drawer Data (populated via SET_FORM_DATA spread on row View)
|
|
48
|
+
createdAt: "",
|
|
49
|
+
errors: {},
|
|
50
|
+
jobId: "",
|
|
51
|
+
processed: 0,
|
|
52
|
+
results: null,
|
|
53
|
+
status: "",
|
|
54
|
+
total: 0,
|
|
55
|
+
type: "",
|
|
56
|
+
updatedAt: "",
|
|
57
|
+
webhookUrl: null,
|
|
58
|
+
// UI State
|
|
59
|
+
disableSaveButton: false,
|
|
60
|
+
drawer: null,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
export const { actionTypes: BULK_OPERATIONS_ACTION_TYPES, config: bulkOperationsModuleConfig, initialState: initialBulkOperationsState, Provider: BulkOperationsProvider, reducer: bulkOperationsReducer, useContext: useBulkOperationsContext, } = createGenericModule(BULK_OPERATIONS_CONFIG);
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// 1.3 ENHANCED BULK OPERATIONS HOOK WITH API INTEGRATION
|
|
66
|
+
// ============================================================================
|
|
67
|
+
export const BULK_OPERATIONS_STATUS_OPTIONS = [
|
|
68
|
+
{ label: "queued", value: "queued" },
|
|
69
|
+
{ label: "running", value: "running" },
|
|
70
|
+
{ label: "completed", value: "completed" },
|
|
71
|
+
{ label: "failed", value: "failed" },
|
|
72
|
+
];
|
|
73
|
+
export const useBulkOperationsModule = () => {
|
|
74
|
+
var _a;
|
|
75
|
+
const context = useBulkOperationsContext();
|
|
76
|
+
const { dispatch } = context;
|
|
77
|
+
const state = context.state;
|
|
78
|
+
const t = useTranslations("bulkOperations");
|
|
79
|
+
const { theme } = useTheme();
|
|
80
|
+
const workspace = getCachedWorkspaceSync();
|
|
81
|
+
const schoolId = ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "";
|
|
82
|
+
const listFetchNowRef = useRef(null);
|
|
83
|
+
const debouncedQuery = useDebounce(state.searchQuery, 800);
|
|
84
|
+
// ==========================================================================
|
|
85
|
+
// 1.3.1 API PARAMETERS
|
|
86
|
+
// ==========================================================================
|
|
87
|
+
const listParams = useMemo(() => (Object.assign(Object.assign(Object.assign({ currentPage: state.currentPage, pageLimit: state.pageLimit, schoolId }, (state.filterType ? { type: state.filterType } : {})), (state.filterStatus ? { status: state.filterStatus } : {})), (debouncedQuery ? { q: debouncedQuery } : {}))), [
|
|
88
|
+
state.currentPage,
|
|
89
|
+
state.filterStatus,
|
|
90
|
+
state.filterType,
|
|
91
|
+
state.pageLimit,
|
|
92
|
+
debouncedQuery,
|
|
93
|
+
schoolId,
|
|
94
|
+
]);
|
|
95
|
+
const noopParams = useMemo(() => ({}), []);
|
|
96
|
+
const noopCallback = useCallback(() => { }, []);
|
|
97
|
+
// ==========================================================================
|
|
98
|
+
// 1.3.2 UTILITIES
|
|
99
|
+
// ==========================================================================
|
|
100
|
+
const showToast = useCallback((description, variant) => {
|
|
101
|
+
generateThemeToast({
|
|
102
|
+
description,
|
|
103
|
+
theme: theme,
|
|
104
|
+
variant,
|
|
105
|
+
});
|
|
106
|
+
}, [theme]);
|
|
107
|
+
const closeDrawer = useCallback(() => {
|
|
108
|
+
dispatch({ type: BULK_OPERATIONS_ACTION_TYPES.SET_DRAWER, payload: { drawer: null } });
|
|
109
|
+
}, [dispatch]);
|
|
110
|
+
// ==========================================================================
|
|
111
|
+
// 1.3.3 API CALLBACKS
|
|
112
|
+
// ==========================================================================
|
|
113
|
+
const listCallback = useCallback(({ data, error }) => {
|
|
114
|
+
var _a, _b;
|
|
115
|
+
if (error) {
|
|
116
|
+
showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (data) {
|
|
120
|
+
const response = data;
|
|
121
|
+
dispatch({
|
|
122
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_ITEMS,
|
|
123
|
+
payload: {
|
|
124
|
+
items: (_a = response.items) !== null && _a !== void 0 ? _a : [],
|
|
125
|
+
count: typeof response.count === "number" ? response.count : 0,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
dispatch({
|
|
129
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_INPUT_FIELD,
|
|
130
|
+
payload: { key: "types", value: (_b = response.types) !== null && _b !== void 0 ? _b : [] },
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}, [dispatch, showToast, t]);
|
|
134
|
+
// ==========================================================================
|
|
135
|
+
// 1.3.4 API HOOKS
|
|
136
|
+
// ==========================================================================
|
|
137
|
+
const { listFetchNow, listLoading } = useModuleEntityV2({
|
|
138
|
+
byIdCallback: noopCallback,
|
|
139
|
+
byIdParams: noopParams,
|
|
140
|
+
listCallback,
|
|
141
|
+
listParams,
|
|
142
|
+
listUrl: BULK_OPERATIONS_API_ROUTES.LIST,
|
|
143
|
+
searchQuery: debouncedQuery,
|
|
144
|
+
unitByIdUrl: BULK_OPERATIONS_API_ROUTES.LIST,
|
|
145
|
+
unitUrl: BULK_OPERATIONS_API_ROUTES.LIST,
|
|
146
|
+
updateCallback: noopCallback,
|
|
147
|
+
updateParams: noopParams,
|
|
148
|
+
headers: {},
|
|
149
|
+
});
|
|
150
|
+
// ==========================================================================
|
|
151
|
+
// 1.3.5 HANDLERS
|
|
152
|
+
// ==========================================================================
|
|
153
|
+
const handleChange = useCallback((field, value) => {
|
|
154
|
+
dispatch({
|
|
155
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_INPUT_FIELD,
|
|
156
|
+
payload: { key: field, value },
|
|
157
|
+
});
|
|
158
|
+
}, [dispatch]);
|
|
159
|
+
const handlePageChange = useCallback((pageOrEvent) => {
|
|
160
|
+
const page = typeof pageOrEvent === "number" && !isNaN(pageOrEvent)
|
|
161
|
+
? pageOrEvent
|
|
162
|
+
: state.currentPage + 1;
|
|
163
|
+
dispatch({
|
|
164
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_CURRENT_PAGE,
|
|
165
|
+
payload: { currentPage: page },
|
|
166
|
+
});
|
|
167
|
+
}, [dispatch, state.currentPage]);
|
|
168
|
+
const handlePageLimitChange = useCallback((k, value) => {
|
|
169
|
+
const val = Object.assign({}, value);
|
|
170
|
+
dispatch({
|
|
171
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_PAGE_LIMIT,
|
|
172
|
+
payload: { pageLimit: Number(val.option) },
|
|
173
|
+
});
|
|
174
|
+
dispatch({
|
|
175
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_CURRENT_PAGE,
|
|
176
|
+
payload: { currentPage: 1 },
|
|
177
|
+
});
|
|
178
|
+
}, [dispatch]);
|
|
179
|
+
const handleSearch = useCallback((query) => {
|
|
180
|
+
dispatch({
|
|
181
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_SEARCH_QUERY,
|
|
182
|
+
payload: { searchQuery: query },
|
|
183
|
+
});
|
|
184
|
+
}, [dispatch]);
|
|
185
|
+
const clearFilters = useCallback(() => {
|
|
186
|
+
dispatch({
|
|
187
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_FILTERS,
|
|
188
|
+
payload: { filters: { filterType: "", filterStatus: "" } },
|
|
189
|
+
});
|
|
190
|
+
dispatch({
|
|
191
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_CURRENT_PAGE,
|
|
192
|
+
payload: { currentPage: 1 },
|
|
193
|
+
});
|
|
194
|
+
}, [dispatch]);
|
|
195
|
+
const clearSearch = useCallback(() => {
|
|
196
|
+
dispatch({
|
|
197
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_SEARCH_QUERY,
|
|
198
|
+
payload: { searchQuery: "" },
|
|
199
|
+
});
|
|
200
|
+
}, [dispatch]);
|
|
201
|
+
const handleFilters = useCallback(() => {
|
|
202
|
+
dispatch({
|
|
203
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_DRAWER,
|
|
204
|
+
payload: { drawer: BULK_OPERATIONS_DRAWER.FILTER_DRAWER },
|
|
205
|
+
});
|
|
206
|
+
}, [dispatch]);
|
|
207
|
+
const handleRefresh = useCallback(() => {
|
|
208
|
+
var _a;
|
|
209
|
+
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
210
|
+
}, []);
|
|
211
|
+
const handleView = useCallback((row) => {
|
|
212
|
+
if (!row)
|
|
213
|
+
return;
|
|
214
|
+
dispatch({
|
|
215
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_FORM_DATA,
|
|
216
|
+
payload: { form: Object.assign({}, row) },
|
|
217
|
+
});
|
|
218
|
+
dispatch({
|
|
219
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_DRAWER,
|
|
220
|
+
payload: { drawer: BULK_OPERATIONS_DRAWER.VIEW_DRAWER },
|
|
221
|
+
});
|
|
222
|
+
}, [dispatch]);
|
|
223
|
+
const applyFilters = useCallback(() => {
|
|
224
|
+
dispatch({
|
|
225
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_CURRENT_PAGE,
|
|
226
|
+
payload: { currentPage: 1 },
|
|
227
|
+
});
|
|
228
|
+
closeDrawer();
|
|
229
|
+
}, [dispatch, closeDrawer]);
|
|
230
|
+
// ==========================================================================
|
|
231
|
+
// 1.3.6 EFFECTS
|
|
232
|
+
// ==========================================================================
|
|
233
|
+
useEffect(() => {
|
|
234
|
+
listFetchNowRef.current = listFetchNow;
|
|
235
|
+
}, [listFetchNow]);
|
|
236
|
+
useEffect(() => {
|
|
237
|
+
var _a;
|
|
238
|
+
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
239
|
+
}, [listParams]);
|
|
240
|
+
// ==========================================================================
|
|
241
|
+
// 1.3.7 HEADER & ROW ACTIONS
|
|
242
|
+
// ==========================================================================
|
|
243
|
+
const headerActions = useMemo(() => [
|
|
244
|
+
{
|
|
245
|
+
enabled: true,
|
|
246
|
+
handleOnClick: handleRefresh,
|
|
247
|
+
label: t("actionsButtonRefresh"),
|
|
248
|
+
order: 0,
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
enabled: true,
|
|
252
|
+
handleOnClick: handleFilters,
|
|
253
|
+
label: t("actionsButtonFilters"),
|
|
254
|
+
order: 1,
|
|
255
|
+
},
|
|
256
|
+
], [handleFilters, handleRefresh, t]);
|
|
257
|
+
const rowActions = useMemo(() => [
|
|
258
|
+
{
|
|
259
|
+
enabled: true,
|
|
260
|
+
handleOnClick: handleView,
|
|
261
|
+
label: t("actionsButtonView"),
|
|
262
|
+
order: 0,
|
|
263
|
+
},
|
|
264
|
+
], [handleView, t]);
|
|
265
|
+
// ==========================================================================
|
|
266
|
+
// 1.3.8 RETURN
|
|
267
|
+
// ==========================================================================
|
|
268
|
+
return Object.assign(Object.assign({}, context), { applyFilters,
|
|
269
|
+
clearFilters,
|
|
270
|
+
clearSearch,
|
|
271
|
+
closeDrawer,
|
|
272
|
+
handleChange,
|
|
273
|
+
handleFilters,
|
|
274
|
+
handlePageChange,
|
|
275
|
+
handlePageLimitChange,
|
|
276
|
+
handleRefresh,
|
|
277
|
+
handleSearch,
|
|
278
|
+
handleView,
|
|
279
|
+
headerActions,
|
|
280
|
+
listFetchNow,
|
|
281
|
+
listLoading,
|
|
282
|
+
rowActions });
|
|
283
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BulkOperationsFilter: () => import("react").JSX.Element;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* Bulk Operations Filter
|
|
5
|
+
*
|
|
6
|
+
* Filter UI for the bulk-operations list. Supports filterType (select, options
|
|
7
|
+
* populated from the list response `types`) and filterStatus (select).
|
|
8
|
+
*
|
|
9
|
+
* Uses the base generic context directly (state + dispatch) rather than the
|
|
10
|
+
* enhanced module hook, so consuming this component does not create a second
|
|
11
|
+
* useModuleEntityV2 instance / auto-fetch effect.
|
|
12
|
+
*/
|
|
13
|
+
import { useTranslations } from "next-intl";
|
|
14
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@appcorp/shadcn/components/ui/select";
|
|
15
|
+
import { Label } from "@appcorp/shadcn/components/ui/label";
|
|
16
|
+
import { BULK_OPERATIONS_ACTION_TYPES, useBulkOperationsContext } from "./context";
|
|
17
|
+
import { BULK_JOB_STATUS_OPTIONS } from "./constants";
|
|
18
|
+
export const BulkOperationsFilter = () => {
|
|
19
|
+
const t = useTranslations("bulkOperations");
|
|
20
|
+
const { state, dispatch } = useBulkOperationsContext();
|
|
21
|
+
const { filterType, filterStatus, types } = state;
|
|
22
|
+
const handleChange = (field, value) => {
|
|
23
|
+
dispatch({
|
|
24
|
+
type: BULK_OPERATIONS_ACTION_TYPES.SET_INPUT_FIELD,
|
|
25
|
+
payload: { key: field, value },
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
const typeValue = filterType || "__none";
|
|
29
|
+
const statusValue = filterStatus || "__none";
|
|
30
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "filterType", children: t("filterTypeLabel") }), _jsxs(Select, { value: typeValue, onValueChange: (v) => handleChange("filterType", v === "__none" ? "" : v), children: [_jsx(SelectTrigger, { id: "filterType", className: "w-full", children: _jsx(SelectValue, { placeholder: t("filterAllTypes") }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "__none", children: t("filterAllTypes") }), types.map((type) => (_jsx(SelectItem, { value: type, children: type }, type)))] })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "filterStatus", children: t("filterStatusLabel") }), _jsxs(Select, { value: statusValue, onValueChange: (v) => handleChange("filterStatus", v === "__none" ? "" : v), children: [_jsx(SelectTrigger, { id: "filterStatus", className: "w-full", children: _jsx(SelectValue, { placeholder: t("filterAllStatuses") }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "__none", children: t("filterAllStatuses") }), BULK_JOB_STATUS_OPTIONS.map((opt) => (_jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value)))] })] })] })] }));
|
|
31
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bulk Operations Page Component
|
|
3
|
+
*
|
|
4
|
+
* Thin wrapper around GenericModulePage. All handlers, header actions, and row
|
|
5
|
+
* actions live in context.tsx — this file only owns:
|
|
6
|
+
* - tableBodyCols (static, module-level constant)
|
|
7
|
+
* - bulkOperationsConfig (memoised on locale + drawer change only)
|
|
8
|
+
* - permission guard
|
|
9
|
+
*
|
|
10
|
+
* Exported utilities: `BulkOperationsPage`
|
|
11
|
+
*/
|
|
12
|
+
import { FC } from "react";
|
|
13
|
+
import { USER_ROLE } from "../../type";
|
|
14
|
+
interface Props {
|
|
15
|
+
cancelLabel: string;
|
|
16
|
+
drawerFilterDescription: string;
|
|
17
|
+
drawerFilterTitle: string;
|
|
18
|
+
drawerViewDescription: string;
|
|
19
|
+
drawerViewTitle: string;
|
|
20
|
+
labelActions: string;
|
|
21
|
+
labelId: string;
|
|
22
|
+
labelProgress: string;
|
|
23
|
+
labelState: string;
|
|
24
|
+
labelStatus: string;
|
|
25
|
+
labelType: string;
|
|
26
|
+
saveLabel: string;
|
|
27
|
+
searchPlaceholder: string;
|
|
28
|
+
tableDescription: string;
|
|
29
|
+
tableTitle: string;
|
|
30
|
+
userRole: USER_ROLE;
|
|
31
|
+
}
|
|
32
|
+
export declare const BulkOperationsPage: FC<Props>;
|
|
33
|
+
export {};
|