@appcorp/fusion-storybook 0.1.21 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/base-modules/teacher/cache.d.ts +14 -0
  2. package/base-modules/teacher/cache.js +31 -0
  3. package/base-modules/teacher/constants.d.ts +23 -0
  4. package/base-modules/teacher/constants.js +27 -0
  5. package/base-modules/teacher/context.d.ts +245 -0
  6. package/base-modules/teacher/context.js +461 -0
  7. package/base-modules/teacher/filter.d.ts +1 -0
  8. package/base-modules/teacher/filter.js +29 -0
  9. package/base-modules/teacher/form.d.ts +1 -0
  10. package/base-modules/teacher/form.js +30 -0
  11. package/base-modules/teacher/more-actions.d.ts +1 -0
  12. package/base-modules/teacher/more-actions.js +50 -0
  13. package/base-modules/teacher/page.d.ts +32 -0
  14. package/base-modules/teacher/page.js +141 -0
  15. package/base-modules/teacher/validate.d.ts +26 -0
  16. package/base-modules/teacher/validate.js +37 -0
  17. package/base-modules/teacher/view.d.ts +1 -0
  18. package/base-modules/teacher/view.js +27 -0
  19. package/base-modules/user/cache.d.ts +14 -0
  20. package/base-modules/user/cache.js +31 -0
  21. package/base-modules/user/constants.d.ts +9 -0
  22. package/base-modules/user/constants.js +19 -0
  23. package/base-modules/user/context.d.ts +218 -0
  24. package/base-modules/user/context.js +585 -0
  25. package/base-modules/user/drawer.d.ts +1 -0
  26. package/base-modules/user/drawer.js +25 -0
  27. package/base-modules/user/filter.d.ts +1 -0
  28. package/base-modules/user/filter.js +21 -0
  29. package/base-modules/user/form.d.ts +1 -0
  30. package/base-modules/user/form.js +28 -0
  31. package/base-modules/user/more-actions.d.ts +1 -0
  32. package/base-modules/user/more-actions.js +48 -0
  33. package/base-modules/user/page.d.ts +30 -0
  34. package/base-modules/user/page.js +120 -0
  35. package/base-modules/user/validate.d.ts +16 -0
  36. package/base-modules/user/validate.js +29 -0
  37. package/base-modules/user/view.d.ts +1 -0
  38. package/base-modules/user/view.js +24 -0
  39. package/base-modules/workspace-user/cache.d.ts +14 -0
  40. package/base-modules/workspace-user/cache.js +31 -0
  41. package/base-modules/workspace-user/constants.d.ts +21 -0
  42. package/base-modules/workspace-user/constants.js +27 -0
  43. package/base-modules/workspace-user/context.d.ts +155 -0
  44. package/base-modules/workspace-user/context.js +382 -0
  45. package/base-modules/workspace-user/filter.d.ts +1 -0
  46. package/base-modules/workspace-user/filter.js +23 -0
  47. package/base-modules/workspace-user/form.d.ts +1 -0
  48. package/base-modules/workspace-user/form.js +12 -0
  49. package/base-modules/workspace-user/more-actions.d.ts +1 -0
  50. package/base-modules/workspace-user/more-actions.js +51 -0
  51. package/base-modules/workspace-user/page.d.ts +28 -0
  52. package/base-modules/workspace-user/page.js +106 -0
  53. package/base-modules/workspace-user/validate.d.ts +12 -0
  54. package/base-modules/workspace-user/validate.js +15 -0
  55. package/base-modules/workspace-user/view.d.ts +1 -0
  56. package/base-modules/workspace-user/view.js +20 -0
  57. package/components/timeline.d.ts +11 -0
  58. package/components/timeline.js +4 -0
  59. package/package.json +4 -2
  60. package/tsconfig.build.tsbuildinfo +1 -1
  61. package/utils/toast-network-error.d.ts +1 -0
  62. package/utils/toast-network-error.js +7 -0
@@ -0,0 +1,461 @@
1
+ "use client";
2
+ /**
3
+ * Teacher 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 `useTeacherModule()` 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
+ * - `TeacherProvider` — provider component used by the page
16
+ * - `TEACHER_ACTION_TYPES` — action type constants (from factory)
17
+ * - `TEACHER_DRAWER` — drawer type constants
18
+ * - `useTeacherModule()` — 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 { GENDER } from "../../type";
28
+ import { useTranslations } from "next-intl";
29
+ import { TEACHER_API_ROUTES, pageLimit } from "./constants";
30
+ import { teacherFormValidation } from "./validate";
31
+ import { getCachedTeachers, invalidateTeachersCache } from "./cache";
32
+ import { getCachedWorkspaceSync } from "../workspace/cache";
33
+ import { Edit, Eye, Filter, MoreHorizontal, Plus, Trash2 } from "lucide-react";
34
+ // ============================================================================
35
+ // DRAWER TYPES
36
+ // ============================================================================
37
+ export const TEACHER_DRAWER = {
38
+ FILTER_DRAWER: DRAWER_TYPES.FILTER_DRAWER,
39
+ FORM_DRAWER: DRAWER_TYPES.FORM_DRAWER,
40
+ MORE_ACTIONS_DRAWER: "MORE_ACTIONS_DRAWER",
41
+ VIEW_DRAWER: DRAWER_TYPES.VIEW_DRAWER,
42
+ };
43
+ // ============================================================================
44
+ // CONFIGURATION
45
+ // ============================================================================
46
+ const teacherConfig = {
47
+ name: "Teacher",
48
+ displayName: "Teacher",
49
+ initialState: {
50
+ // List Data
51
+ items: [],
52
+ count: 0,
53
+ // Search & Pagination
54
+ currentPage: 1,
55
+ pageLimit,
56
+ searchQuery: "",
57
+ // UI State
58
+ disableSaveButton: false,
59
+ drawer: null,
60
+ // Form State
61
+ address: null,
62
+ avatar: null,
63
+ bio: null,
64
+ city: null,
65
+ country: null,
66
+ dateOfBirth: null,
67
+ emergencyPhone: null,
68
+ enabled: true,
69
+ errors: {},
70
+ experience: null,
71
+ filterEnabled: undefined,
72
+ firstName: "",
73
+ gender: GENDER.MALE,
74
+ id: "",
75
+ joiningDate: new Date().toISOString().split("T")[0],
76
+ lastName: "",
77
+ phone: null,
78
+ postalCode: null,
79
+ qualification: null,
80
+ schoolId: "",
81
+ specialization: null,
82
+ state: null,
83
+ teacherCode: "",
84
+ userId: "",
85
+ },
86
+ drawerTypes: DRAWER_TYPES,
87
+ };
88
+ // ============================================================================
89
+ // CREATE TEACHER MODULE
90
+ // ============================================================================
91
+ export const { actionTypes: TEACHER_ACTION_TYPES, config: teacherModuleConfig, initialState: initialTeacherState, Provider: TeacherProvider, reducer: teacherReducer, useContext: useTeacherContext, } = createGenericModule(teacherConfig);
92
+ // ============================================================================
93
+ // ENHANCED TEACHER HOOK WITH API INTEGRATION
94
+ // ============================================================================
95
+ export const useTeacherModule = () => {
96
+ var _a;
97
+ const context = useTeacherContext();
98
+ const { state, dispatch } = context;
99
+ const t = useTranslations("teacher");
100
+ const debouncedQuery = useDebounce(state.searchQuery, 800);
101
+ const workspace = getCachedWorkspaceSync();
102
+ const schoolId = ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "";
103
+ // ============================================================================
104
+ // API PARAMETERS
105
+ // ============================================================================
106
+ const listParams = useMemo(() => (Object.assign(Object.assign({ currentPage: state.currentPage, pageLimit: state.pageLimit, schoolId }, (debouncedQuery ? { searchQuery: debouncedQuery } : {})), (state.filterEnabled !== undefined
107
+ ? { filterEnabled: String(state.filterEnabled) }
108
+ : {}))), [
109
+ state.currentPage,
110
+ state.filterEnabled,
111
+ state.pageLimit,
112
+ debouncedQuery,
113
+ schoolId,
114
+ ]);
115
+ const updateParams = useMemo(() => ({
116
+ address: state.address,
117
+ avatar: state.avatar,
118
+ bio: state.bio,
119
+ city: state.city,
120
+ country: state.country,
121
+ dateOfBirth: state.dateOfBirth,
122
+ emergencyPhone: state.emergencyPhone,
123
+ enabled: state.enabled,
124
+ experience: state.experience,
125
+ firstName: state.firstName,
126
+ gender: state.gender,
127
+ id: state.id,
128
+ joiningDate: state.joiningDate,
129
+ lastName: state.lastName,
130
+ phone: state.phone,
131
+ postalCode: state.postalCode,
132
+ qualification: state.qualification,
133
+ schoolId,
134
+ specialization: state.specialization,
135
+ state: state.state,
136
+ teacherCode: state.teacherCode,
137
+ userId: state.userId,
138
+ }), [state, schoolId]);
139
+ const byIdParams = useMemo(() => ({ id: state.id }), [state.id]);
140
+ const deleteParams = useMemo(() => ({ id: state.id }), [state.id]);
141
+ // ============================================================================
142
+ // UTILITIES
143
+ // ============================================================================
144
+ const showToast = useCallback((message, variant) => {
145
+ generateThemeToast({ description: message, variant });
146
+ }, []);
147
+ const resetFormAndCloseDrawer = useCallback(() => {
148
+ dispatch({
149
+ type: TEACHER_ACTION_TYPES.SET_ERRORS,
150
+ payload: { errors: {} },
151
+ });
152
+ dispatch({
153
+ type: TEACHER_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
154
+ payload: { disabled: false },
155
+ });
156
+ dispatch({
157
+ type: TEACHER_ACTION_TYPES.SET_DRAWER,
158
+ payload: { drawer: null },
159
+ });
160
+ }, [dispatch]);
161
+ // ============================================================================
162
+ // API CALLBACKS
163
+ // ============================================================================
164
+ const listCallback = ({ data, error }) => {
165
+ var _a;
166
+ if (error) {
167
+ showToast(t("messagesFetchFailed"), TOAST_VARIANT.ERROR);
168
+ return;
169
+ }
170
+ if (data) {
171
+ const response = data;
172
+ const items = (_a = response.items) !== null && _a !== void 0 ? _a : [];
173
+ const count = typeof response.count === "number" ? response.count : 0;
174
+ dispatch({
175
+ type: TEACHER_ACTION_TYPES.SET_ITEMS,
176
+ payload: { items, count },
177
+ });
178
+ }
179
+ };
180
+ const updateCallback = ({ data, error }) => {
181
+ const isCreated = isCreatedOrUpdated(data);
182
+ if (error) {
183
+ showToast(isCreated ? t("messagesCreateFailed") : t("messagesUpdateFailed"), TOAST_VARIANT.ERROR);
184
+ return;
185
+ }
186
+ if (data) {
187
+ showToast(t("messagesSaveSuccess"), TOAST_VARIANT.SUCCESS);
188
+ invalidateTeachersCache();
189
+ listFetchNow();
190
+ resetFormAndCloseDrawer();
191
+ }
192
+ };
193
+ const byIdCallback = ({ data, error }) => {
194
+ if (error) {
195
+ showToast(t("messagesDetailsFetchFailed"), TOAST_VARIANT.ERROR);
196
+ return;
197
+ }
198
+ if (data) {
199
+ dispatch({
200
+ type: TEACHER_ACTION_TYPES.SET_FORM_DATA,
201
+ payload: { form: Object.assign(Object.assign({}, data), { filterEnabled: undefined }) },
202
+ });
203
+ }
204
+ };
205
+ const deleteCallback = ({ data, error }) => {
206
+ if (error) {
207
+ showToast(t("messagesDeleteFailed"), TOAST_VARIANT.ERROR);
208
+ return;
209
+ }
210
+ if (data) {
211
+ showToast(t("messagesDeleteSuccess"), TOAST_VARIANT.SUCCESS);
212
+ invalidateTeachersCache();
213
+ listFetchNow();
214
+ }
215
+ };
216
+ // ============================================================================
217
+ // HANDLERS
218
+ // ============================================================================
219
+ const handleChange = useCallback((field, value) => {
220
+ dispatch({
221
+ type: TEACHER_ACTION_TYPES.SET_ERRORS,
222
+ payload: { errors: {} },
223
+ });
224
+ dispatch({
225
+ type: TEACHER_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
226
+ payload: { disabled: false },
227
+ });
228
+ dispatch({
229
+ type: TEACHER_ACTION_TYPES.SET_INPUT_FIELD,
230
+ payload: { key: field, value },
231
+ });
232
+ }, [dispatch]);
233
+ const handlePageChange = useCallback((page) => {
234
+ dispatch({
235
+ type: TEACHER_ACTION_TYPES.SET_CURRENT_PAGE,
236
+ payload: { currentPage: page },
237
+ });
238
+ }, [dispatch]);
239
+ const handlePageLimitChange = useCallback((limit) => {
240
+ dispatch({
241
+ type: TEACHER_ACTION_TYPES.SET_PAGE_LIMIT,
242
+ payload: { pageLimit: limit },
243
+ });
244
+ }, [dispatch]);
245
+ const handleCloseDrawer = useCallback(() => {
246
+ dispatch({
247
+ type: TEACHER_ACTION_TYPES.SET_DRAWER,
248
+ payload: { drawer: null },
249
+ });
250
+ dispatch({ type: TEACHER_ACTION_TYPES.RESET_FORM });
251
+ dispatch({
252
+ type: TEACHER_ACTION_TYPES.SET_ERRORS,
253
+ payload: { errors: {} },
254
+ });
255
+ }, [dispatch]);
256
+ const handleCreate = useCallback(() => {
257
+ dispatch({
258
+ type: TEACHER_ACTION_TYPES.SET_DRAWER,
259
+ payload: { drawer: TEACHER_DRAWER.FORM_DRAWER },
260
+ });
261
+ }, [dispatch]);
262
+ const handleFilters = useCallback(() => {
263
+ dispatch({
264
+ type: TEACHER_ACTION_TYPES.SET_DRAWER,
265
+ payload: { drawer: TEACHER_DRAWER.FILTER_DRAWER },
266
+ });
267
+ }, [dispatch]);
268
+ const handleMoreActions = useCallback(() => {
269
+ dispatch({
270
+ type: TEACHER_ACTION_TYPES.SET_DRAWER,
271
+ payload: { drawer: TEACHER_DRAWER.MORE_ACTIONS_DRAWER },
272
+ });
273
+ }, [dispatch]);
274
+ const handleSearch = useCallback((query) => {
275
+ dispatch({
276
+ type: TEACHER_ACTION_TYPES.SET_SEARCH_QUERY,
277
+ payload: { searchQuery: query },
278
+ });
279
+ }, [dispatch]);
280
+ const clearFilters = useCallback(() => {
281
+ dispatch({
282
+ type: TEACHER_ACTION_TYPES.SET_FILTERS,
283
+ payload: { filters: { filterEnabled: undefined } },
284
+ });
285
+ dispatch({
286
+ type: TEACHER_ACTION_TYPES.SET_CURRENT_PAGE,
287
+ payload: { currentPage: 1 },
288
+ });
289
+ }, [dispatch]);
290
+ // ============================================================================
291
+ // HEADER & ROW ACTIONS
292
+ // ============================================================================
293
+ const headerActions = useMemo(() => [
294
+ {
295
+ enabled: false,
296
+ handleOnClick: handleMoreActions,
297
+ icon: MoreHorizontal,
298
+ label: t("headerActionsMoreActions"),
299
+ order: 1,
300
+ },
301
+ {
302
+ enabled: true,
303
+ handleOnClick: handleFilters,
304
+ icon: Filter,
305
+ label: t("headerActionsFilters"),
306
+ order: 2,
307
+ },
308
+ {
309
+ enabled: true,
310
+ handleOnClick: handleCreate,
311
+ icon: Plus,
312
+ label: t("headerActionsAddTeacher"),
313
+ order: 3,
314
+ },
315
+ ], [handleFilters, handleMoreActions, handleCreate, t]);
316
+ // ============================================================================
317
+ // NETWORK ACTIONS
318
+ // ============================================================================
319
+ // HEADER & ROW ACTIONS
320
+ // ============================================================================
321
+ const { listFetchNow, listLoading, updateFetchNow, updateLoading, byIdFetchNow, deleteFetchNow, deleteLoading, byIdLoading, } = useModuleEntityV2({
322
+ byIdCallback,
323
+ byIdParams,
324
+ deleteCallback,
325
+ deleteParams,
326
+ listCallback,
327
+ listParams,
328
+ listUrl: TEACHER_API_ROUTES.LIST,
329
+ searchQuery: debouncedQuery,
330
+ unitByIdUrl: TEACHER_API_ROUTES.UNIT,
331
+ unitUrl: TEACHER_API_ROUTES.UNIT,
332
+ updateCallback,
333
+ updateParams,
334
+ headers: {
335
+ "Content-Type": "application/json",
336
+ "x-api-token": process.env.NEXT_PUBLIC_API_KEY,
337
+ },
338
+ });
339
+ const applyFilters = useCallback(() => {
340
+ dispatch({
341
+ type: TEACHER_ACTION_TYPES.SET_CURRENT_PAGE,
342
+ payload: { currentPage: 1 },
343
+ });
344
+ listFetchNow();
345
+ handleCloseDrawer();
346
+ }, [dispatch, listFetchNow, handleCloseDrawer]);
347
+ const handleSubmit = useCallback(() => {
348
+ dispatch({
349
+ type: TEACHER_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
350
+ payload: { disabled: true },
351
+ });
352
+ validateForm({
353
+ params: updateParams,
354
+ schema: teacherFormValidation,
355
+ successCallback: () => {
356
+ updateFetchNow(undefined, {
357
+ body: JSON.stringify(updateParams),
358
+ });
359
+ },
360
+ errorCallback: (errors) => {
361
+ dispatch({
362
+ type: TEACHER_ACTION_TYPES.SET_ERRORS,
363
+ payload: { errors },
364
+ });
365
+ dispatch({
366
+ type: TEACHER_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
367
+ payload: { disabled: false },
368
+ });
369
+ showToast(t("messagesFormErrors"), TOAST_VARIANT.ERROR);
370
+ },
371
+ });
372
+ }, [updateParams, t, showToast, updateFetchNow, dispatch]);
373
+ const handleView = useCallback((row) => {
374
+ byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
375
+ dispatch({
376
+ type: TEACHER_ACTION_TYPES.SET_DRAWER,
377
+ payload: { drawer: TEACHER_DRAWER.VIEW_DRAWER },
378
+ });
379
+ }, [dispatch, byIdFetchNow]);
380
+ const handleEdit = useCallback((row) => {
381
+ byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
382
+ dispatch({
383
+ type: TEACHER_ACTION_TYPES.SET_DRAWER,
384
+ payload: { drawer: TEACHER_DRAWER.FORM_DRAWER },
385
+ });
386
+ }, [dispatch, byIdFetchNow]);
387
+ const handleDelete = useCallback((row) => {
388
+ if (!confirm(t("areYouSureYouWantToDeleteThisTeacher")))
389
+ return;
390
+ deleteFetchNow === null || deleteFetchNow === void 0 ? void 0 : deleteFetchNow(undefined, {
391
+ body: JSON.stringify({ id: row === null || row === void 0 ? void 0 : row.id }),
392
+ });
393
+ }, [t, deleteFetchNow]);
394
+ const rowActions = useMemo(() => [
395
+ {
396
+ enabled: true,
397
+ handleOnClick: handleView,
398
+ icon: Eye,
399
+ label: t("rowActionsView"),
400
+ order: 1,
401
+ },
402
+ {
403
+ enabled: true,
404
+ handleOnClick: handleEdit,
405
+ icon: Edit,
406
+ label: t("rowActionsEdit"),
407
+ order: 2,
408
+ },
409
+ {
410
+ enabled: true,
411
+ handleOnClick: handleDelete,
412
+ icon: Trash2,
413
+ label: t("rowActionsDelete"),
414
+ order: 3,
415
+ },
416
+ ], [handleView, handleEdit, handleDelete, t]);
417
+ // ============================================================================
418
+ // EFFECTS
419
+ // ============================================================================
420
+ useEffect(() => {
421
+ if (!schoolId)
422
+ return;
423
+ (async () => {
424
+ try {
425
+ const { count, items } = await getCachedTeachers({
426
+ params: listParams,
427
+ });
428
+ dispatch({
429
+ type: TEACHER_ACTION_TYPES.SET_ITEMS,
430
+ payload: { items: items || [], count: count || 0 },
431
+ });
432
+ }
433
+ catch (_a) {
434
+ showToast(t("messagesFetchFailed"), TOAST_VARIANT.ERROR);
435
+ }
436
+ })();
437
+ }, [dispatch, listParams, schoolId, showToast, t]);
438
+ // ============================================================================
439
+ // RETURN
440
+ // ============================================================================
441
+ return Object.assign(Object.assign({}, context), { applyFilters,
442
+ byIdLoading,
443
+ clearFilters,
444
+ deleteLoading,
445
+ handleChange,
446
+ handleCloseDrawer,
447
+ handleCreate,
448
+ handleDelete,
449
+ handleEdit,
450
+ handleFilters,
451
+ handleMoreActions,
452
+ handlePageChange,
453
+ handlePageLimitChange,
454
+ handleSearch,
455
+ handleSubmit,
456
+ handleView,
457
+ headerActions,
458
+ listLoading,
459
+ rowActions,
460
+ updateLoading });
461
+ };
@@ -0,0 +1 @@
1
+ export declare const TeacherFilter: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,29 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ /**
4
+ * Teacher Filter Component
5
+ *
6
+ * Filter UI for teacher records. Uses the module state pattern:
7
+ * `const { state, handleChange } = useTeacherModule()`
8
+ */
9
+ import { EnhancedRadio } from "@appcorp/shadcn/components/enhanced-radio";
10
+ import { useTranslations } from "next-intl";
11
+ import { useTeacherModule } from "./context";
12
+ export const TeacherFilter = () => {
13
+ const { state, handleChange } = useTeacherModule();
14
+ const { filterEnabled } = state;
15
+ const t = useTranslations("teacher");
16
+ const filterEnabledValue = filterEnabled === undefined
17
+ ? "undefined"
18
+ : filterEnabled
19
+ ? "true"
20
+ : "false";
21
+ return (_jsx("div", { className: "space-y-4", children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx(EnhancedRadio, { label: t("enabled"), name: "filterEnabled", value: filterEnabledValue, options: [
22
+ { label: t("all"), value: "undefined" },
23
+ { label: t("enabled"), value: "true" },
24
+ { label: t("disabled"), value: "false" },
25
+ ], onValueChange: (next) => {
26
+ const parsed = next === "true" ? true : next === "false" ? false : undefined;
27
+ handleChange("filterEnabled", parsed);
28
+ } }) }) }));
29
+ };
@@ -0,0 +1 @@
1
+ export declare const TeacherForm: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { EnhancedInput } from "@appcorp/shadcn/components/enhanced-input";
4
+ import { EnhancedCheckbox } from "@appcorp/shadcn/components/enhanced-checkbox";
5
+ import { EnhancedDropzone } from "@appcorp/shadcn/components/enhanced-dropzone";
6
+ import { EnhancedCombobox } from "@appcorp/shadcn/components/enhanced-combobox";
7
+ import { EnhancedTextarea } from "@appcorp/shadcn/components/enhanced-textarea";
8
+ import { useTranslations } from "next-intl";
9
+ import { USER_ROLE } from "../../type";
10
+ import { getCachedUsersSync } from "../user/cache";
11
+ import { useTeacherModule } from "./context";
12
+ import { GENDER_OPTIONS } from "./constants";
13
+ export const TeacherForm = () => {
14
+ var _a;
15
+ const t = useTranslations("teacher");
16
+ const context = useTeacherModule();
17
+ const { address, avatar, bio, city, country, dateOfBirth, emergencyPhone, enabled, errors, experience, firstName, gender, joiningDate, lastName, phone, postalCode, qualification, specialization, teacherCode, userId, } = context.state;
18
+ const stateValue = context.state.state;
19
+ const { handleChange } = context;
20
+ const users = getCachedUsersSync();
21
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(EnhancedInput, { error: errors.teacherCode, id: "teacherCode", info: t("uniqueTeacherIdentifier"), label: t("teacherCode"), onChange: (e) => handleChange("teacherCode", e.target.value), placeholder: t("teacherCodePlaceholder"), required: true, value: teacherCode }), _jsx(EnhancedInput, { error: errors.firstName, id: "firstName", info: t("teachersFirstName"), label: t("firstName"), onChange: (e) => handleChange("firstName", e.target.value), placeholder: t("firstNamePlaceholder"), required: true, value: firstName }), _jsx(EnhancedInput, { error: errors.lastName, id: "lastName", info: t("teachersLastName"), label: t("lastName"), onChange: (e) => handleChange("lastName", e.target.value), placeholder: t("lastNamePlaceholder"), required: true, value: lastName }), _jsx(EnhancedInput, { error: errors.joiningDate, id: "joiningDate", info: t("dateTeacherJoinedTheSchool"), label: t("joiningDate"), onChange: (e) => handleChange("joiningDate", e.target.value), onClick: (e) => { var _a, _b; return (_b = (_a = e.currentTarget).showPicker) === null || _b === void 0 ? void 0 : _b.call(_a); }, required: true, type: "date", value: joiningDate ? new Date(joiningDate).toISOString().split("T")[0] : "" }), _jsx(EnhancedCombobox, { emptyText: t("noTeacherUsersFound"), error: errors.userId, id: "userId", info: t("linkedSystemUser"), label: t("selectTeacherUser"), onValueChange: (value) => handleChange("userId", value || null), options: (_a = users.items) === null || _a === void 0 ? void 0 : _a.filter(({ workspaces }) => workspaces === null || workspaces === void 0 ? void 0 : workspaces.filter(({ role }) => (role === null || role === void 0 ? void 0 : role.userRole) === USER_ROLE.TEACHER).length).map((u) => ({
22
+ label: (u === null || u === void 0 ? void 0 : u.name) || (u === null || u === void 0 ? void 0 : u.email) || u.id,
23
+ value: u.id,
24
+ })), placeholder: t("selectLinkedUserPlaceholder"), required: true, searchPlaceholder: t("searchUsersPlaceholder"), value: userId || "" }), _jsx(EnhancedCombobox, { error: errors.gender, id: "gender", info: t("selectTeachersGender"), label: t("gender"), onValueChange: (value) => handleChange("gender", value || null), options: GENDER_OPTIONS.slice(1), value: gender || "" }), _jsx(EnhancedInput, { error: errors.dateOfBirth, id: "dateOfBirth", info: t("teachersDateOfBirth"), label: t("dateOfBirth"), onChange: (e) => handleChange("dateOfBirth", e.target.value), onClick: (e) => { var _a, _b; return (_b = (_a = e.currentTarget).showPicker) === null || _b === void 0 ? void 0 : _b.call(_a); }, type: "date", value: dateOfBirth ? new Date(dateOfBirth).toISOString().split("T")[0] : "" }), _jsx(EnhancedInput, { error: errors.phone, id: "phone", info: t("teachersPhoneNumber"), label: t("phone"), onChange: (e) => handleChange("phone", e.target.value), placeholder: t("phonePlaceholder"), type: "tel", value: phone || "" }), _jsx(EnhancedInput, { error: errors.emergencyPhone, id: "emergencyPhone", info: t("emergencyContactNumber"), label: t("emergencyPhone"), onChange: (e) => handleChange("emergencyPhone", e.target.value), placeholder: t("emergencyPhonePlaceholder"), type: "tel", value: emergencyPhone || "" }), _jsx(EnhancedInput, { error: errors.qualification, id: "qualification", info: t("teachersEducationalQualification"), label: t("qualification"), onChange: (e) => handleChange("qualification", e.target.value), placeholder: t("qualificationPlaceholder"), value: qualification || "" }), _jsx(EnhancedInput, { error: errors.specialization, id: "specialization", info: t("teachersAreaOfSpecialization"), label: t("specialization"), onChange: (e) => handleChange("specialization", e.target.value), placeholder: t("specializationPlaceholder"), value: specialization || "" }), _jsx(EnhancedInput, { error: errors.experience, id: "experience", info: t("yearsOfTeachingExperience"), label: t("experience"), onChange: (e) => handleChange("experience", parseInt(e.target.value) || null), placeholder: t("experiencePlaceholder"), type: "number", value: (experience === null || experience === void 0 ? void 0 : experience.toString()) || "" }), _jsx(EnhancedInput, { error: errors.address, id: "address", info: t("streetAddress"), label: t("address"), onChange: (e) => handleChange("address", e.target.value), placeholder: t("addressPlaceholder"), value: address || "" }), _jsx(EnhancedInput, { error: errors.city, id: "city", info: t("cityName"), label: t("city"), onChange: (e) => handleChange("city", e.target.value), placeholder: t("cityPlaceholder"), value: city || "" }), _jsx(EnhancedInput, { error: errors.state, id: "state", info: t("stateOrProvince"), label: t("stateProvince"), onChange: (e) => handleChange("state", e.target.value), placeholder: t("statePlaceholder"), value: stateValue || "" }), _jsx(EnhancedInput, { error: errors.country, id: "country", info: t("countryName"), label: t("country"), onChange: (e) => handleChange("country", e.target.value), placeholder: t("countryPlaceholder"), value: country || "" }), _jsx(EnhancedInput, { error: errors.postalCode, id: "postalCode", info: t("postalOrZipCode"), label: t("postalCode"), onChange: (e) => handleChange("postalCode", e.target.value), placeholder: t("postalCodePlaceholder"), value: postalCode || "" }), _jsx(EnhancedDropzone, { accept: ["image/*"], error: errors.avatar, id: "avatar", info: t("uploadTeachersPhoto"), label: t("avatar"), maxFiles: 1, maxSize: 1 * 1024 * 1024, onChange: (files) => {
25
+ if (files.length > 0) {
26
+ const fileUrl = URL.createObjectURL(files[0]);
27
+ handleChange("avatar", fileUrl);
28
+ }
29
+ }, onRemoveRemote: () => handleChange("avatar", null), value: avatar ? [avatar] : [] }), _jsx(EnhancedTextarea, { error: errors.bio, id: "bio", info: t("briefBiographyOrDescription"), label: t("bio"), onChange: (e) => handleChange("bio", e.target.value), placeholder: t("bioPlaceholder"), rows: 4, value: bio || "" }), _jsx(EnhancedCheckbox, { checked: enabled, info: t("toggleToActivateOrDeactivateTeacher"), label: t("activeTeacher"), onCheckedChange: (checked) => handleChange("enabled", checked) })] }));
30
+ };
@@ -0,0 +1 @@
1
+ export declare const TeacherMoreActions: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,50 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { API_METHODS, downloadFromUrl } from "@react-pakistan/util-functions";
4
+ import { getCachedWorkspaceSync } from "../workspace/cache";
5
+ import converter from "json-2-csv";
6
+ import { Timeline } from "../../components/timeline";
7
+ import { useTranslations } from "next-intl";
8
+ const workspace = getCachedWorkspaceSync();
9
+ const handleGetAllRecords = async (schoolId) => {
10
+ const response = await fetch(`/api/v1/teacher?pageLimit=1000&currentPage=1&schoolId=${schoolId}`, { method: API_METHODS.GET });
11
+ const result = await response.json();
12
+ const csv = await converter.json2csv(result.items || [], {});
13
+ const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
14
+ await downloadFromUrl(blob, "teacher.csv");
15
+ };
16
+ export const TeacherMoreActions = () => {
17
+ const t = useTranslations("teacher");
18
+ const create = [
19
+ {
20
+ id: "1",
21
+ title: t("moreActionsDownloadEmptyCsvTemplate"),
22
+ handleOnClick: async () => {
23
+ await downloadFromUrl("https://nwolvgylwmjuqxsngjxt.supabase.co/storage/v1/object/public/public-blob/common-assets/teacher.csv", "teacher-template.csv");
24
+ },
25
+ },
26
+ { id: "2", title: t("moreActionsAddYourDataToTheCsv") },
27
+ {
28
+ id: "3",
29
+ title: t("moreActionsUploadTheCompletedCsvToTheSystem"),
30
+ handleOnClick: () => console.log("clicked"),
31
+ },
32
+ ];
33
+ const update = [
34
+ {
35
+ id: "1",
36
+ title: t("moreActionsDownloadPopulatedCsvTemplate"),
37
+ handleOnClick: async () => {
38
+ var _a;
39
+ await handleGetAllRecords(((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "");
40
+ },
41
+ },
42
+ { id: "2", title: t("moreActionsUpdateYourDataToTheCsv") },
43
+ {
44
+ id: "3",
45
+ title: t("moreActionsUploadTheCompletedCsvToTheSystem"),
46
+ handleOnClick: () => console.log("clicked"),
47
+ },
48
+ ];
49
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(Timeline, { events: create, heading: t("moreActionsBulkCreate") }), _jsx(Timeline, { events: update, heading: t("moreActionsBulkUpdate") })] }));
50
+ };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Teacher 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
+ * - teacherConfig (memoised on locale change only; size fixed per drawer so
8
+ * the component type produced by createGenericModulePage never changes at
9
+ * runtime, preventing the infinite-remount re-render loop)
10
+ * - permission guard
11
+ */
12
+ import { FC } from "react";
13
+ import { USER_ROLE } from "../../type";
14
+ interface Props {
15
+ cancelLabel: string;
16
+ drawerTitle: string;
17
+ labelActions: string;
18
+ labelEmail: string;
19
+ labelEnabled: string;
20
+ labelId: string;
21
+ labelName: string;
22
+ labelPhone: string;
23
+ labelSpecialization: string;
24
+ labelTeacherCode: string;
25
+ saveLabel: string;
26
+ searchPlaceholder: string;
27
+ tableDescription: string;
28
+ tableTitle: string;
29
+ userRole: USER_ROLE;
30
+ }
31
+ export declare const TeacherPage: FC<Props>;
32
+ export {};