@appcorp/fusion-storybook 0.2.40 → 0.2.44
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/admission/constants.d.ts +5 -17
- package/base-modules/admission/constants.js +12 -7
- package/base-modules/admission/context/use-admission-module.js +11 -48
- package/base-modules/admission/filter.js +23 -3
- package/base-modules/admission/form.js +49 -19
- package/base-modules/attendance/context.js +3 -37
- package/base-modules/attendance/filter.js +3 -1
- package/base-modules/attendance/form.js +26 -10
- package/base-modules/attendance/more-actions.js +34 -25
- package/base-modules/campus/context.js +7 -7
- package/base-modules/class/cache.js +0 -1
- package/base-modules/class/context.js +10 -48
- package/base-modules/class/more-actions.js +47 -24
- package/base-modules/course/context.js +3 -37
- package/base-modules/course/form.js +91 -292
- package/base-modules/discount-code/constants.d.ts +5 -0
- package/base-modules/discount-code/constants.js +5 -0
- package/base-modules/discount-code/context.d.ts +1 -0
- package/base-modules/discount-code/context.js +40 -39
- package/base-modules/discount-code/form.js +21 -15
- package/base-modules/discount-code/more-actions.js +1 -1
- package/base-modules/enrollment/context.js +3 -37
- package/base-modules/enrollment/form.js +38 -11
- package/base-modules/enrollment/more-actions.js +48 -25
- package/base-modules/expense/constants.js +1 -1
- package/base-modules/expense/context.js +5 -32
- package/base-modules/expense/filter.js +50 -3
- package/base-modules/expense/form.js +82 -6
- package/base-modules/family/context.js +7 -38
- package/base-modules/family-member/context.js +7 -39
- package/base-modules/fee-structure/context.js +1 -25
- package/base-modules/fee-structure/form.js +77 -89
- package/base-modules/fee-structure/more-actions.js +45 -22
- package/base-modules/rbac/context.d.ts +1 -0
- package/base-modules/rbac/context.js +24 -33
- package/base-modules/rbac/form.js +3 -1
- package/base-modules/school/context.js +1 -1
- package/base-modules/school/form.js +34 -14
- package/base-modules/section/context.d.ts +1 -0
- package/base-modules/section/context.js +40 -47
- package/base-modules/section/form.js +25 -80
- package/base-modules/section/more-actions.js +47 -24
- package/base-modules/section/view.js +9 -7
- package/base-modules/student-fee/context/use-student-fee-module.d.ts +1 -0
- package/base-modules/student-fee/context/use-student-fee-module.js +48 -32
- package/base-modules/student-fee/context.d.ts +1 -1
- package/base-modules/student-fee/context.js +1 -1
- package/base-modules/student-fee/filter.js +23 -3
- package/base-modules/student-fee/form.js +93 -174
- package/base-modules/student-fee/view.d.ts +7 -1
- package/base-modules/student-fee/view.js +17 -20
- package/base-modules/student-profile/constants.d.ts +0 -6
- package/base-modules/student-profile/constants.js +1 -3
- package/base-modules/student-profile/context/use-student-profile-module.d.ts +1 -0
- package/base-modules/student-profile/context/use-student-profile-module.js +62 -55
- package/base-modules/student-profile/context.d.ts +1 -1
- package/base-modules/student-profile/context.js +1 -1
- package/base-modules/student-profile/filter.js +24 -4
- package/base-modules/student-profile/form.js +35 -3
- package/base-modules/subject/context.d.ts +1 -0
- package/base-modules/subject/context.js +38 -47
- package/base-modules/subject/more-actions.js +47 -24
- package/base-modules/teacher/constants.d.ts +0 -6
- package/base-modules/teacher/constants.js +0 -2
- package/base-modules/teacher/context.d.ts +1 -0
- package/base-modules/teacher/context.js +58 -39
- package/base-modules/teacher/form.js +46 -11
- package/base-modules/teacher/more-actions.js +45 -22
- package/base-modules/user/context/use-user-module.d.ts +1 -0
- package/base-modules/user/context/use-user-module.js +36 -32
- package/base-modules/user/context.js +1 -1
- package/base-modules/user/filter.js +6 -4
- package/base-modules/user/form.js +29 -5
- package/base-modules/user/more-actions.js +9 -7
- package/base-modules/user/view.js +3 -1
- package/base-modules/workspace/form.js +18 -8
- package/base-modules/workspace-user/context.d.ts +2 -1
- package/base-modules/workspace-user/context.js +31 -29
- package/package.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/base-modules/admission/cache.d.ts +0 -14
- package/base-modules/admission/cache.js +0 -31
- package/base-modules/attendance/cache.d.ts +0 -14
- package/base-modules/attendance/cache.js +0 -31
- package/base-modules/course/cache.d.ts +0 -14
- package/base-modules/course/cache.js +0 -31
- package/base-modules/enrollment/cache.d.ts +0 -14
- package/base-modules/enrollment/cache.js +0 -31
- package/base-modules/expense/cache.d.ts +0 -14
- package/base-modules/expense/cache.js +0 -31
- package/base-modules/family/cache.d.ts +0 -14
- package/base-modules/family/cache.js +0 -31
- package/base-modules/family-member/cache.d.ts +0 -14
- package/base-modules/family-member/cache.js +0 -31
- package/base-modules/rbac/cache.d.ts +0 -27
- package/base-modules/rbac/cache.js +0 -46
- package/base-modules/student-fee/cache.d.ts +0 -15
- package/base-modules/student-fee/cache.js +0 -21
- package/base-modules/workspace-user/cache.d.ts +0 -14
- package/base-modules/workspace-user/cache.js +0 -31
|
@@ -8,7 +8,6 @@ import { Timeline } from "../../components/timeline";
|
|
|
8
8
|
import { useTranslations } from "next-intl";
|
|
9
9
|
import { feeStructureFormValidation } from "./validate";
|
|
10
10
|
import { FEE_STRUCTURE_API_ROUTES, pageLimit } from "./constants";
|
|
11
|
-
import { invalidateFeeStructuresCache } from "./cache";
|
|
12
11
|
import { FEE_STRUCTURE_ACTION_TYPES, useFeeStructureContext } from "./context";
|
|
13
12
|
import { useRef, useEffect, useCallback } from "react";
|
|
14
13
|
const workspace = getCachedWorkspaceSync();
|
|
@@ -68,13 +67,15 @@ async function pollBulkJob(jobId, signal, onProgress) {
|
|
|
68
67
|
}
|
|
69
68
|
}
|
|
70
69
|
}
|
|
71
|
-
function formatErrorSummary(errors) {
|
|
70
|
+
function formatErrorSummary(t, errors) {
|
|
72
71
|
if (!(errors === null || errors === void 0 ? void 0 : errors.length))
|
|
73
72
|
return "";
|
|
74
|
-
const lines = errors
|
|
73
|
+
const lines = errors
|
|
74
|
+
.slice(0, 5)
|
|
75
|
+
.map((e) => t("messagesBulkRowError", { row: e.row, error: e.error }));
|
|
75
76
|
const remaining = errors.length - 5;
|
|
76
77
|
if (remaining > 0)
|
|
77
|
-
lines.push(
|
|
78
|
+
lines.push(t("messagesBulkMoreRows", { count: remaining }));
|
|
78
79
|
return lines.join("\n");
|
|
79
80
|
}
|
|
80
81
|
export const FeeStructureMoreActions = () => {
|
|
@@ -104,7 +105,7 @@ export const FeeStructureMoreActions = () => {
|
|
|
104
105
|
const text = await file.text();
|
|
105
106
|
const records = converter.csv2json(text);
|
|
106
107
|
if (!Array.isArray(records) || records.length === 0) {
|
|
107
|
-
showErrorToast("
|
|
108
|
+
showErrorToast(t("messagesBulkCsvEmpty"));
|
|
108
109
|
return;
|
|
109
110
|
}
|
|
110
111
|
const validationErrors = [];
|
|
@@ -119,7 +120,7 @@ export const FeeStructureMoreActions = () => {
|
|
|
119
120
|
}
|
|
120
121
|
else {
|
|
121
122
|
if (!((_b = row.id) === null || _b === void 0 ? void 0 : _b.trim()))
|
|
122
|
-
msgs.push("
|
|
123
|
+
msgs.push(t("validationRequiredIdForUpdate"));
|
|
123
124
|
}
|
|
124
125
|
if (msgs.length > 0) {
|
|
125
126
|
validationErrors.push({ row: i + 1, messages: msgs });
|
|
@@ -128,40 +129,59 @@ export const FeeStructureMoreActions = () => {
|
|
|
128
129
|
if (validationErrors.length > 0) {
|
|
129
130
|
const summary = validationErrors
|
|
130
131
|
.slice(0, 5)
|
|
131
|
-
.map((e) =>
|
|
132
|
+
.map((e) => t("messagesBulkRowError", {
|
|
133
|
+
row: e.row,
|
|
134
|
+
error: e.messages.join("; "),
|
|
135
|
+
}))
|
|
132
136
|
.join("\n");
|
|
133
|
-
|
|
134
|
-
|
|
137
|
+
showErrorToast(t("messagesBulkValidationFailed", {
|
|
138
|
+
count: validationErrors.length,
|
|
139
|
+
errors: summary,
|
|
140
|
+
}));
|
|
135
141
|
return;
|
|
136
142
|
}
|
|
137
143
|
try {
|
|
138
|
-
showInfoToast(
|
|
144
|
+
showInfoToast(t("messagesBulkJobQueued", { action: label, count: records.length }));
|
|
139
145
|
let jobId;
|
|
140
146
|
try {
|
|
141
147
|
jobId = await submitBulkJob(text, method, signal);
|
|
142
148
|
}
|
|
143
149
|
catch (submitError) {
|
|
144
|
-
showErrorToast(
|
|
150
|
+
showErrorToast(t("messagesBulkJobSubmitFailed", {
|
|
151
|
+
action: label,
|
|
152
|
+
error: submitError instanceof Error
|
|
153
|
+
? submitError.message
|
|
154
|
+
: t("unknownError"),
|
|
155
|
+
}));
|
|
145
156
|
return;
|
|
146
157
|
}
|
|
147
158
|
const status = await pollBulkJob(jobId, signal, (processed, total) => {
|
|
148
|
-
showInfoToast(
|
|
159
|
+
showInfoToast(t("messagesBulkProgress", { processed, total }));
|
|
149
160
|
});
|
|
150
161
|
if (signal.aborted)
|
|
151
162
|
return;
|
|
152
163
|
if (status.status === "completed") {
|
|
153
164
|
const r = status.results;
|
|
154
165
|
if (r && ((_c = r.errors) === null || _c === void 0 ? void 0 : _c.length) > 0) {
|
|
155
|
-
const summary = formatErrorSummary(r.errors);
|
|
156
|
-
showSuccessToast(
|
|
166
|
+
const summary = formatErrorSummary(t, r.errors);
|
|
167
|
+
showSuccessToast(t("messagesBulkResults", {
|
|
168
|
+
created: r.created,
|
|
169
|
+
updated: r.updated,
|
|
170
|
+
skipped: r.skipped,
|
|
171
|
+
}) +
|
|
172
|
+
"\n" +
|
|
173
|
+
summary);
|
|
157
174
|
}
|
|
158
175
|
else if (r) {
|
|
159
|
-
showSuccessToast(
|
|
176
|
+
showSuccessToast(t("messagesBulkResults", {
|
|
177
|
+
created: r.created,
|
|
178
|
+
updated: r.updated,
|
|
179
|
+
skipped: r.skipped,
|
|
180
|
+
}));
|
|
160
181
|
}
|
|
161
182
|
else {
|
|
162
|
-
showSuccessToast("
|
|
183
|
+
showSuccessToast(t("messagesBulkSuccess"));
|
|
163
184
|
}
|
|
164
|
-
invalidateFeeStructuresCache();
|
|
165
185
|
const schoolId = ((_d = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _d === void 0 ? void 0 : _d.id) || "";
|
|
166
186
|
fetch(`${FEE_STRUCTURE_API_ROUTES.LIST}?currentPage=1&pageLimit=${pageLimit}&schoolId=${schoolId}`, {
|
|
167
187
|
headers: {
|
|
@@ -187,17 +207,20 @@ export const FeeStructureMoreActions = () => {
|
|
|
187
207
|
else {
|
|
188
208
|
const r = status.results;
|
|
189
209
|
const detail = ((_e = r === null || r === void 0 ? void 0 : r.errors) === null || _e === void 0 ? void 0 : _e.length)
|
|
190
|
-
? formatErrorSummary(r.errors)
|
|
191
|
-
: "
|
|
192
|
-
showErrorToast(
|
|
210
|
+
? formatErrorSummary(t, r.errors)
|
|
211
|
+
: t("unknownError");
|
|
212
|
+
showErrorToast(t("messagesBulkFailed", { action: label }) + "\n" + detail);
|
|
193
213
|
}
|
|
194
214
|
}
|
|
195
215
|
catch (error) {
|
|
196
216
|
if (error.message === "Polling cancelled")
|
|
197
217
|
return;
|
|
198
|
-
showErrorToast(
|
|
218
|
+
showErrorToast(t("messagesBulkFailedDetail", {
|
|
219
|
+
action: label,
|
|
220
|
+
error: error instanceof Error ? error.message : t("unknownError"),
|
|
221
|
+
}));
|
|
199
222
|
}
|
|
200
|
-
}, [dispatch]);
|
|
223
|
+
}, [dispatch, t]);
|
|
201
224
|
const handleBulkCreate = useCallback((files) => handleBulkFlow(files, "POST"), [handleBulkFlow]);
|
|
202
225
|
const handleBulkUpdate = useCallback((files) => handleBulkFlow(files, "PUT"), [handleBulkFlow]);
|
|
203
226
|
const create = [
|
|
@@ -120,6 +120,7 @@ export declare const useRbacModule: () => {
|
|
|
120
120
|
closeDrawer: () => void;
|
|
121
121
|
deleteLoading: boolean;
|
|
122
122
|
handleChange: (key: string, value: string | number | boolean | undefined) => void;
|
|
123
|
+
resetRecordFormState: () => void;
|
|
123
124
|
handleCreate: () => void;
|
|
124
125
|
handleDelete: (row?: TableRow) => void;
|
|
125
126
|
handleEdit: (row?: TableRow) => Promise<void>;
|
|
@@ -27,9 +27,7 @@ import { useDebounce } from "@react-pakistan/util-functions/hooks/use-debounce";
|
|
|
27
27
|
import { createGenericModule } from "@react-pakistan/util-functions/factory/generic-module-factory";
|
|
28
28
|
import { DRAWER_TYPES } from "@react-pakistan/util-functions/factory/generic-component-factory";
|
|
29
29
|
import { generateThemeToast, TOAST_VARIANT, } from "@appcorp/shadcn/lib/toast-utils";
|
|
30
|
-
import { USER_ROLE } from "../../type";
|
|
31
30
|
import { RBAC_API_ROUTES, pageLimit } from "./constants";
|
|
32
|
-
import { getCachedRoles, invalidateRolesCache } from "./cache";
|
|
33
31
|
import { roleFormValidation } from "./validate";
|
|
34
32
|
// ============================================================================
|
|
35
33
|
// 1.1 DRAWER TYPES
|
|
@@ -105,7 +103,6 @@ export const useRbacModule = () => {
|
|
|
105
103
|
}), [state.id, state.name, state.description]);
|
|
106
104
|
const byIdParams = useMemo(() => ({ id: state.id }), [state.id]);
|
|
107
105
|
const deleteParams = useMemo(() => ({ id: state.id }), [state.id]);
|
|
108
|
-
const isDefaultListState = state.currentPage === 1 && state.pageLimit === pageLimit && !debouncedQuery;
|
|
109
106
|
// ============================================================================
|
|
110
107
|
// 1.4.3 UTILITIES
|
|
111
108
|
// ============================================================================
|
|
@@ -154,7 +151,6 @@ export const useRbacModule = () => {
|
|
|
154
151
|
}
|
|
155
152
|
if (data) {
|
|
156
153
|
const isCreated = isCreatedOrUpdated(data);
|
|
157
|
-
invalidateRolesCache();
|
|
158
154
|
showToast(isCreated ? t("messagesRoleCreated") : t("messagesRoleUpdated"), TOAST_VARIANT.SUCCESS);
|
|
159
155
|
resetFormAndCloseDrawer();
|
|
160
156
|
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
@@ -179,7 +175,6 @@ export const useRbacModule = () => {
|
|
|
179
175
|
return;
|
|
180
176
|
}
|
|
181
177
|
if (data) {
|
|
182
|
-
invalidateRolesCache();
|
|
183
178
|
showToast(t("messagesRoleDeleted"), TOAST_VARIANT.SUCCESS);
|
|
184
179
|
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
185
180
|
}
|
|
@@ -255,15 +250,31 @@ export const useRbacModule = () => {
|
|
|
255
250
|
payload: { currentPage: 1 },
|
|
256
251
|
});
|
|
257
252
|
}, [dispatch]);
|
|
253
|
+
const resetRecordFormState = useCallback(() => {
|
|
254
|
+
dispatch({
|
|
255
|
+
type: RBAC_ACTION_TYPES.SET_INPUT_FIELD,
|
|
256
|
+
payload: { key: "description", value: "" },
|
|
257
|
+
});
|
|
258
|
+
dispatch({
|
|
259
|
+
type: RBAC_ACTION_TYPES.SET_INPUT_FIELD,
|
|
260
|
+
payload: { key: "enabled", value: true },
|
|
261
|
+
});
|
|
262
|
+
dispatch({
|
|
263
|
+
type: RBAC_ACTION_TYPES.SET_INPUT_FIELD,
|
|
264
|
+
payload: { key: "name", value: "" },
|
|
265
|
+
});
|
|
266
|
+
}, [dispatch]);
|
|
258
267
|
// row actions
|
|
259
268
|
const handleView = useCallback((row) => {
|
|
269
|
+
resetRecordFormState();
|
|
260
270
|
byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
|
|
261
271
|
dispatch({
|
|
262
272
|
type: RBAC_ACTION_TYPES.SET_DRAWER,
|
|
263
273
|
payload: { drawer: RBAC_DRAWER.VIEW_DRAWER },
|
|
264
274
|
});
|
|
265
|
-
}, [byIdFetchNow, dispatch]);
|
|
275
|
+
}, [byIdFetchNow, dispatch, resetRecordFormState]);
|
|
266
276
|
const handleEdit = useCallback(async (row) => {
|
|
277
|
+
resetRecordFormState();
|
|
267
278
|
byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
|
|
268
279
|
// loadAvailablePermissions is declared below in 1.4.7
|
|
269
280
|
// await loadAvailablePermissions();
|
|
@@ -271,7 +282,7 @@ export const useRbacModule = () => {
|
|
|
271
282
|
type: RBAC_ACTION_TYPES.SET_DRAWER,
|
|
272
283
|
payload: { drawer: RBAC_DRAWER.FORM_DRAWER },
|
|
273
284
|
});
|
|
274
|
-
}, [byIdFetchNow, dispatch]);
|
|
285
|
+
}, [byIdFetchNow, dispatch, resetRecordFormState]);
|
|
275
286
|
const handleDelete = useCallback((row) => {
|
|
276
287
|
if (!confirm(t("messagesDeleteConfirmation")))
|
|
277
288
|
return;
|
|
@@ -410,7 +421,6 @@ export const useRbacModule = () => {
|
|
|
410
421
|
}
|
|
411
422
|
// Refetch the role so rolePermissions in state reflects the change
|
|
412
423
|
await (byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: state.id } }));
|
|
413
|
-
invalidateRolesCache();
|
|
414
424
|
}
|
|
415
425
|
catch (_a) {
|
|
416
426
|
showToast(t("messagesFetchFailed"), TOAST_VARIANT.ERROR);
|
|
@@ -468,35 +478,15 @@ export const useRbacModule = () => {
|
|
|
468
478
|
// ============================================================================
|
|
469
479
|
// 1.4.9 EFFECTS
|
|
470
480
|
// ============================================================================
|
|
471
|
-
// Initial load + re-fetch on page/search change via cache
|
|
472
|
-
useEffect(() => {
|
|
473
|
-
var _a;
|
|
474
|
-
if (isDefaultListState) {
|
|
475
|
-
(async () => {
|
|
476
|
-
try {
|
|
477
|
-
const { count, items } = await getCachedRoles({
|
|
478
|
-
params: listParams,
|
|
479
|
-
});
|
|
480
|
-
dispatch({
|
|
481
|
-
type: RBAC_ACTION_TYPES.SET_ITEMS,
|
|
482
|
-
payload: {
|
|
483
|
-
items: items.filter((item) => item.userRole !== USER_ROLE.SUPER_ADMIN) || [],
|
|
484
|
-
count: count || 0,
|
|
485
|
-
},
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
catch (_a) {
|
|
489
|
-
showToast(t("messagesFetchFailed"), TOAST_VARIANT.ERROR);
|
|
490
|
-
}
|
|
491
|
-
})();
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
|
-
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
495
|
-
}, [dispatch, isDefaultListState, listParams, showToast, t]);
|
|
496
481
|
// Sync listFetchNow into ref so callbacks can trigger re-fetch
|
|
497
482
|
useEffect(() => {
|
|
498
483
|
listFetchNowRef.current = listFetchNow;
|
|
499
484
|
}, [listFetchNow]);
|
|
485
|
+
// Fetch list on mount and on page/search change
|
|
486
|
+
useEffect(() => {
|
|
487
|
+
var _a;
|
|
488
|
+
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
489
|
+
}, [dispatch, listParams, showToast, t]);
|
|
500
490
|
// ============================================================================
|
|
501
491
|
// 1.4.10 RETURN
|
|
502
492
|
// ============================================================================
|
|
@@ -507,6 +497,7 @@ export const useRbacModule = () => {
|
|
|
507
497
|
closeDrawer,
|
|
508
498
|
deleteLoading,
|
|
509
499
|
handleChange,
|
|
500
|
+
resetRecordFormState,
|
|
510
501
|
handleCreate,
|
|
511
502
|
handleDelete,
|
|
512
503
|
handleEdit,
|
|
@@ -9,7 +9,9 @@ import { EnhancedInput } from "@appcorp/shadcn/components/enhanced-input";
|
|
|
9
9
|
import { Separator } from "@appcorp/shadcn/components/ui/separator";
|
|
10
10
|
import { useRbacModule } from "./context";
|
|
11
11
|
import { AssignPermissions } from "./assign-permissions";
|
|
12
|
+
import { useTranslations } from "next-intl";
|
|
12
13
|
export const RbacForm = () => {
|
|
14
|
+
const t = useTranslations("rbac");
|
|
13
15
|
const { state, handleChange } = useRbacModule();
|
|
14
|
-
return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid grid-cols-1 gap-4", children: [_jsx(EnhancedInput, { id: "name", label: "
|
|
16
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid grid-cols-1 gap-4", children: [_jsx(EnhancedInput, { id: "name", label: t("formNameLabel"), required: true, type: "text", value: state.name || "", onChange: (e) => handleChange("name", e.target.value), error: state.errors.name, placeholder: t("formNamePlaceholder"), info: t("formNameInfo") }), _jsx(EnhancedInput, { id: "description", label: t("formDescriptionLabel"), type: "text", value: state.description || "", onChange: (e) => handleChange("description", e.target.value || undefined), error: state.errors.description, placeholder: t("formDescriptionPlaceholder"), info: t("formDescriptionInfo") })] }), state.id && (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm font-medium", children: t("viewSectionPermissions") }), _jsx(AssignPermissions, {})] })] }))] }));
|
|
15
17
|
};
|
|
@@ -7,24 +7,44 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
7
7
|
*/
|
|
8
8
|
import { EnhancedInput } from "@appcorp/shadcn/components/enhanced-input";
|
|
9
9
|
import { EnhancedCheckbox } from "@appcorp/shadcn/components/enhanced-checkbox";
|
|
10
|
-
import {
|
|
10
|
+
import { useEnhancedCombobox } from "@appcorp/shadcn/hooks/use-enhanced-combobox";
|
|
11
11
|
import { useSchoolModule } from "./context";
|
|
12
|
-
import { getCachedTeachersSync } from "../teacher/cache";
|
|
13
12
|
import { CURRENCY } from "../../type";
|
|
13
|
+
import { SCHOOL_API_ROUTES } from "./constants";
|
|
14
14
|
import { useTranslations } from "next-intl";
|
|
15
15
|
export const SchoolForm = () => {
|
|
16
16
|
const t = useTranslations("school");
|
|
17
17
|
const { state, handleChange } = useSchoolModule();
|
|
18
|
-
const { address, city, code, country, currency, email, enabled, errors, logo, name, phone, postalCode,
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
const { address, city, code, country, currency, email, enabled, errors, logo, name, phone, postalCode,
|
|
19
|
+
// principalId,
|
|
20
|
+
state: stateField, website, } = state;
|
|
21
|
+
const { enhancedComboboxElement: currencyCombo } = useEnhancedCombobox({
|
|
22
|
+
emptyText: t("formCurrencyEmptyText"),
|
|
23
|
+
id: "currency",
|
|
24
|
+
info: t("formCurrencyInfo"),
|
|
25
|
+
label: t("formCurrencyLabel"),
|
|
26
|
+
onValueChange: (value) => handleChange("currency", value),
|
|
27
|
+
options: Object.values(CURRENCY).map((c) => ({ id: c, name: c })),
|
|
28
|
+
placeholder: t("formCurrencyPlaceholder"),
|
|
29
|
+
required: true,
|
|
30
|
+
searchEndpoint: SCHOOL_API_ROUTES.UNIT,
|
|
31
|
+
searchPlaceholder: t("formCurrencySearchPlaceholder"),
|
|
32
|
+
value: currency,
|
|
33
|
+
});
|
|
34
|
+
// const { enhancedComboboxElement: principalIdCombo } = useEnhancedCombobox({
|
|
35
|
+
// emptyText: t("formPrincipalEmptyText"),
|
|
36
|
+
// id: "principalId",
|
|
37
|
+
// info: t("formPrincipalInfo"),
|
|
38
|
+
// label: t("formPrincipalLabel"),
|
|
39
|
+
// onValueChange: (value) => handleChange("principalId", value),
|
|
40
|
+
// options: getCachedTeachersSync().items.map((teacher) => ({
|
|
41
|
+
// id: teacher.id as string,
|
|
42
|
+
// name: `${teacher.firstName || ""} ${teacher.lastName || ""}`.trim() || teacher.teacherCode || teacher.id,
|
|
43
|
+
// })),
|
|
44
|
+
// placeholder: t("formPrincipalPlaceholder"),
|
|
45
|
+
// searchEndpoint: SCHOOL_API_ROUTES.UNIT,
|
|
46
|
+
// searchPlaceholder: t("formPrincipalSearchPlaceholder"),
|
|
47
|
+
// value: principalId || "",
|
|
48
|
+
// });
|
|
49
|
+
return (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "grid grid-cols-1 gap-4", children: [_jsx(EnhancedInput, { id: "name", label: t("formNameLabel"), value: name, onChange: (e) => handleChange("name", e.target.value), error: errors.name, placeholder: t("formNamePlaceholder"), required: true }), _jsx(EnhancedInput, { id: "code", label: t("formCodeLabel"), value: code, onChange: (e) => handleChange("code", e.target.value), error: errors.code, placeholder: t("formCodePlaceholder"), required: true, info: t("formCodeInfo") }), currencyCombo, _jsx(EnhancedInput, { id: "address", label: t("formAddressLabel"), value: address || "", onChange: (e) => handleChange("address", e.target.value), error: errors.address, placeholder: t("formAddressPlaceholder") }), _jsx(EnhancedInput, { id: "city", label: t("formCityLabel"), value: city || "", onChange: (e) => handleChange("city", e.target.value), error: errors.city, placeholder: t("formCityPlaceholder") }), _jsx(EnhancedInput, { id: "state", label: t("formStateLabel"), value: stateField || "", onChange: (e) => handleChange("state", e.target.value), error: errors.state, placeholder: t("formStatePlaceholder") }), _jsx(EnhancedInput, { id: "country", label: t("formCountryLabel"), value: country || "", onChange: (e) => handleChange("country", e.target.value), error: errors.country, placeholder: t("formCountryPlaceholder") }), _jsx(EnhancedInput, { id: "postalCode", label: t("formPostalCodeLabel"), value: postalCode || "", onChange: (e) => handleChange("postalCode", e.target.value), error: errors.postalCode, placeholder: t("formPostalCodePlaceholder") }), _jsx(EnhancedInput, { id: "phone", label: t("formPhoneLabel"), value: phone || "", onChange: (e) => handleChange("phone", e.target.value), error: errors.phone, placeholder: t("formPhonePlaceholder"), type: "tel" }), _jsx(EnhancedInput, { id: "email", label: t("formEmailLabel"), value: email || "", onChange: (e) => handleChange("email", e.target.value), error: errors.email, placeholder: t("formEmailPlaceholder"), type: "email" })] }), _jsx(EnhancedInput, { id: "website", label: t("formWebsiteLabel"), value: website || "", onChange: (e) => handleChange("website", e.target.value), error: errors.website, placeholder: t("formWebsitePlaceholder"), type: "url" }), _jsx(EnhancedInput, { id: "logo", label: t("formLogoLabel"), value: logo || "", onChange: (e) => handleChange("logo", e.target.value), error: errors.logo, placeholder: t("formLogoPlaceholder"), type: "url" }), _jsx(EnhancedCheckbox, { id: "enabled", label: t("formEnabledLabel"), checked: enabled, error: errors.enabled, onCheckedChange: (checked) => handleChange("enabled", checked), info: t("formEnabledInfo") })] }));
|
|
30
50
|
};
|
|
@@ -128,6 +128,7 @@ export declare const useSectionModule: () => {
|
|
|
128
128
|
}[];
|
|
129
129
|
listFetchNow: (url?: string, config?: import("@react-pakistan/util-functions/hooks/use-fetch").FetchConfig) => void;
|
|
130
130
|
listLoading: boolean;
|
|
131
|
+
resetRecordFormState: () => void;
|
|
131
132
|
rowActions: RowAction[];
|
|
132
133
|
toggleStatus: (row?: TableRow) => void;
|
|
133
134
|
updateLoading: boolean;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Key responsibilities:
|
|
10
10
|
* - Expose `useSectionModule()` which UI components call for actions
|
|
11
11
|
* - Keep module-specific `apiParams` and callbacks in one place
|
|
12
|
-
* - Ensure
|
|
12
|
+
* - Ensure toast notifications on mutation
|
|
13
13
|
*
|
|
14
14
|
* Exported utilities:
|
|
15
15
|
* - `SectionProvider` — provider component used by the page
|
|
@@ -28,7 +28,6 @@ import { DRAWER_TYPES } from "@react-pakistan/util-functions/factory/generic-com
|
|
|
28
28
|
import { generateThemeToast, TOAST_VARIANT, } from "@appcorp/shadcn/lib/toast-utils";
|
|
29
29
|
import { SECTION_API_ROUTES, pageLimit } from "./constants";
|
|
30
30
|
import { sectionFormValidation } from "./validate";
|
|
31
|
-
import { getCachedSections, invalidateSectionsCache } from "./cache";
|
|
32
31
|
import { getCachedWorkspaceSync } from "../workspace/cache";
|
|
33
32
|
// ============================================================================
|
|
34
33
|
// 1.1 DRAWER TYPES
|
|
@@ -136,6 +135,30 @@ export const useSectionModule = () => {
|
|
|
136
135
|
payload: { drawer: null },
|
|
137
136
|
});
|
|
138
137
|
}, [dispatch]);
|
|
138
|
+
const resetRecordFormState = useCallback(() => {
|
|
139
|
+
dispatch({
|
|
140
|
+
type: SECTION_ACTION_TYPES.SET_ERRORS,
|
|
141
|
+
payload: { errors: {} },
|
|
142
|
+
});
|
|
143
|
+
dispatch({
|
|
144
|
+
type: SECTION_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
|
|
145
|
+
payload: { disabled: false },
|
|
146
|
+
});
|
|
147
|
+
dispatch({
|
|
148
|
+
type: SECTION_ACTION_TYPES.SET_FORM_DATA,
|
|
149
|
+
payload: {
|
|
150
|
+
form: {
|
|
151
|
+
capacity: null,
|
|
152
|
+
classId: "",
|
|
153
|
+
enabled: true,
|
|
154
|
+
filterEnabled: undefined,
|
|
155
|
+
id: "",
|
|
156
|
+
name: "",
|
|
157
|
+
schoolId,
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
}, [dispatch, schoolId]);
|
|
139
162
|
// ============================================================================
|
|
140
163
|
// 1.4.4 API CALLBACKS
|
|
141
164
|
// ============================================================================
|
|
@@ -161,7 +184,6 @@ export const useSectionModule = () => {
|
|
|
161
184
|
}
|
|
162
185
|
if (data) {
|
|
163
186
|
const isCreated = isCreatedOrUpdated(data);
|
|
164
|
-
invalidateSectionsCache();
|
|
165
187
|
showToast(isCreated ? t("messagesCreateSuccess") : t("messagesSaveSuccess"), TOAST_VARIANT.SUCCESS);
|
|
166
188
|
resetFormAndCloseDrawer();
|
|
167
189
|
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
@@ -186,7 +208,6 @@ export const useSectionModule = () => {
|
|
|
186
208
|
return;
|
|
187
209
|
}
|
|
188
210
|
if (data) {
|
|
189
|
-
invalidateSectionsCache();
|
|
190
211
|
showToast(t("messagesDeleteSuccess"), TOAST_VARIANT.SUCCESS);
|
|
191
212
|
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
192
213
|
}
|
|
@@ -239,19 +260,21 @@ export const useSectionModule = () => {
|
|
|
239
260
|
});
|
|
240
261
|
}, [dispatch]);
|
|
241
262
|
const handleView = useCallback((row) => {
|
|
263
|
+
resetRecordFormState();
|
|
242
264
|
byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
|
|
243
265
|
dispatch({
|
|
244
266
|
type: SECTION_ACTION_TYPES.SET_DRAWER,
|
|
245
267
|
payload: { drawer: SECTION_DRAWER.VIEW_DRAWER },
|
|
246
268
|
});
|
|
247
|
-
}, [byIdFetchNow, dispatch]);
|
|
269
|
+
}, [byIdFetchNow, dispatch, resetRecordFormState]);
|
|
248
270
|
const handleEdit = useCallback((row) => {
|
|
271
|
+
resetRecordFormState();
|
|
249
272
|
byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
|
|
250
273
|
dispatch({
|
|
251
274
|
type: SECTION_ACTION_TYPES.SET_DRAWER,
|
|
252
275
|
payload: { drawer: SECTION_DRAWER.FORM_DRAWER },
|
|
253
276
|
});
|
|
254
|
-
}, [byIdFetchNow, dispatch]);
|
|
277
|
+
}, [byIdFetchNow, dispatch, resetRecordFormState]);
|
|
255
278
|
const handleDelete = useCallback((row) => {
|
|
256
279
|
if (!confirm(t("messagesDeleteConfirmation")))
|
|
257
280
|
return;
|
|
@@ -372,19 +395,19 @@ export const useSectionModule = () => {
|
|
|
372
395
|
{
|
|
373
396
|
enabled: true,
|
|
374
397
|
handleOnClick: handleMoreActions,
|
|
375
|
-
label: t("
|
|
398
|
+
label: t("actionsButtonMoreActions"),
|
|
376
399
|
order: 0,
|
|
377
400
|
},
|
|
378
401
|
{
|
|
379
402
|
enabled: true,
|
|
380
403
|
handleOnClick: handleFilters,
|
|
381
|
-
label: t("
|
|
404
|
+
label: t("actionsButtonFilters"),
|
|
382
405
|
order: 1,
|
|
383
406
|
},
|
|
384
407
|
{
|
|
385
408
|
enabled: true,
|
|
386
409
|
handleOnClick: handleCreate,
|
|
387
|
-
label: t("
|
|
410
|
+
label: t("actionsButtonAdd"),
|
|
388
411
|
order: 2,
|
|
389
412
|
},
|
|
390
413
|
], [handleCreate, handleFilters, handleMoreActions, t]);
|
|
@@ -392,70 +415,39 @@ export const useSectionModule = () => {
|
|
|
392
415
|
{
|
|
393
416
|
enabled: true,
|
|
394
417
|
handleOnClick: handleView,
|
|
395
|
-
label: t("
|
|
418
|
+
label: t("actionsButtonView"),
|
|
396
419
|
order: 1,
|
|
397
420
|
},
|
|
398
421
|
{
|
|
399
422
|
enabled: (row) => (row === null || row === void 0 ? void 0 : row.enabled) === true,
|
|
400
423
|
handleOnClick: handleEdit,
|
|
401
|
-
label: t("
|
|
424
|
+
label: t("actionsButtonEdit"),
|
|
402
425
|
order: 2,
|
|
403
426
|
},
|
|
404
427
|
{
|
|
405
428
|
enabled: (row) => (row === null || row === void 0 ? void 0 : row.enabled) === false,
|
|
406
429
|
handleOnClick: handleDelete,
|
|
407
|
-
label: t("
|
|
430
|
+
label: t("actionsButtonDelete"),
|
|
408
431
|
order: 3,
|
|
409
432
|
variant: "destructive",
|
|
410
433
|
},
|
|
411
434
|
{
|
|
412
435
|
enabled: false,
|
|
413
436
|
handleOnClick: toggleStatus,
|
|
414
|
-
label: t("
|
|
437
|
+
label: t("actionsButtonToggleStatus"),
|
|
415
438
|
order: 4,
|
|
416
439
|
},
|
|
417
440
|
], [handleDelete, handleEdit, handleView, t, toggleStatus]);
|
|
418
441
|
// ============================================================================
|
|
419
442
|
// 1.4.9 EFFECTS
|
|
420
443
|
// ============================================================================
|
|
421
|
-
// Keep the latest fetch function in a ref so the fetch effect can call it
|
|
422
|
-
// without depending on listFetchNow's unstable identity.
|
|
423
444
|
useEffect(() => {
|
|
424
445
|
listFetchNowRef.current = listFetchNow;
|
|
425
|
-
});
|
|
426
|
-
// Initial load via cache; re-fetch directly from API on page/pageLimit/filter/search changes.
|
|
446
|
+
}, [listFetchNow]);
|
|
427
447
|
useEffect(() => {
|
|
428
448
|
var _a;
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
const currentPage = Number(listParams.currentPage) || 1;
|
|
432
|
-
const currentPageLimit = Number(listParams.pageLimit) || pageLimit;
|
|
433
|
-
const isDefaultLoad = currentPage === 1 &&
|
|
434
|
-
currentPageLimit === pageLimit &&
|
|
435
|
-
!listParams.searchQuery &&
|
|
436
|
-
listParams.filterEnabled === undefined;
|
|
437
|
-
if (isDefaultLoad) {
|
|
438
|
-
(async () => {
|
|
439
|
-
try {
|
|
440
|
-
const { count, items } = await getCachedSections({
|
|
441
|
-
params: listParams,
|
|
442
|
-
});
|
|
443
|
-
dispatch({
|
|
444
|
-
type: SECTION_ACTION_TYPES.SET_ITEMS,
|
|
445
|
-
payload: { items: items || [], count: count || 0 },
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
catch (_a) {
|
|
449
|
-
showToast(t("messagesFetchFailed"), TOAST_VARIANT.ERROR);
|
|
450
|
-
}
|
|
451
|
-
})();
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
// Bypass cache for pagination, pageLimit, filter and search changes.
|
|
455
|
-
// Use ref to avoid the infinite-loop caused by listFetchNow's unstable identity.
|
|
456
|
-
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
457
|
-
}
|
|
458
|
-
}, [dispatch, listParams, schoolId, showToast, t]);
|
|
449
|
+
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
450
|
+
}, [listParams]);
|
|
459
451
|
// ============================================================================
|
|
460
452
|
// 1.4.10 RETURN
|
|
461
453
|
// ============================================================================
|
|
@@ -480,6 +472,7 @@ export const useSectionModule = () => {
|
|
|
480
472
|
headerActions,
|
|
481
473
|
listFetchNow,
|
|
482
474
|
listLoading,
|
|
475
|
+
resetRecordFormState,
|
|
483
476
|
rowActions,
|
|
484
477
|
toggleStatus,
|
|
485
478
|
updateLoading });
|