@appcorp/fusion-storybook 0.2.40 → 0.2.42

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 (98) hide show
  1. package/base-modules/admission/constants.d.ts +5 -17
  2. package/base-modules/admission/constants.js +12 -7
  3. package/base-modules/admission/context/use-admission-module.js +11 -48
  4. package/base-modules/admission/filter.js +23 -3
  5. package/base-modules/admission/form.js +49 -19
  6. package/base-modules/attendance/context.js +3 -37
  7. package/base-modules/attendance/form.js +26 -10
  8. package/base-modules/attendance/more-actions.js +34 -25
  9. package/base-modules/campus/context.js +7 -7
  10. package/base-modules/class/cache.js +0 -1
  11. package/base-modules/class/context.js +10 -48
  12. package/base-modules/class/more-actions.js +0 -2
  13. package/base-modules/course/context.js +3 -37
  14. package/base-modules/course/form.js +91 -292
  15. package/base-modules/discount-code/constants.d.ts +5 -0
  16. package/base-modules/discount-code/constants.js +5 -0
  17. package/base-modules/discount-code/context.d.ts +1 -0
  18. package/base-modules/discount-code/context.js +40 -39
  19. package/base-modules/discount-code/form.js +21 -15
  20. package/base-modules/discount-code/more-actions.js +1 -1
  21. package/base-modules/enrollment/context.js +3 -37
  22. package/base-modules/enrollment/form.js +38 -11
  23. package/base-modules/enrollment/more-actions.js +0 -2
  24. package/base-modules/expense/constants.js +1 -1
  25. package/base-modules/expense/context.js +5 -32
  26. package/base-modules/expense/filter.js +50 -3
  27. package/base-modules/expense/form.js +82 -6
  28. package/base-modules/family/context.js +7 -38
  29. package/base-modules/family-member/context.js +7 -39
  30. package/base-modules/fee-structure/context.js +1 -25
  31. package/base-modules/fee-structure/form.js +77 -89
  32. package/base-modules/fee-structure/more-actions.js +0 -2
  33. package/base-modules/rbac/context.d.ts +1 -0
  34. package/base-modules/rbac/context.js +23 -32
  35. package/base-modules/school/context.js +1 -1
  36. package/base-modules/school/form.js +34 -14
  37. package/base-modules/section/context.d.ts +1 -0
  38. package/base-modules/section/context.js +40 -47
  39. package/base-modules/section/form.js +25 -80
  40. package/base-modules/section/more-actions.js +0 -2
  41. package/base-modules/section/view.js +9 -7
  42. package/base-modules/student-fee/context/use-student-fee-module.d.ts +1 -0
  43. package/base-modules/student-fee/context/use-student-fee-module.js +48 -32
  44. package/base-modules/student-fee/context.d.ts +1 -1
  45. package/base-modules/student-fee/context.js +1 -1
  46. package/base-modules/student-fee/filter.js +23 -3
  47. package/base-modules/student-fee/form.js +93 -174
  48. package/base-modules/student-fee/view.d.ts +7 -1
  49. package/base-modules/student-fee/view.js +17 -20
  50. package/base-modules/student-profile/constants.d.ts +0 -6
  51. package/base-modules/student-profile/constants.js +1 -3
  52. package/base-modules/student-profile/context/use-student-profile-module.d.ts +1 -0
  53. package/base-modules/student-profile/context/use-student-profile-module.js +62 -55
  54. package/base-modules/student-profile/context.d.ts +1 -1
  55. package/base-modules/student-profile/context.js +1 -1
  56. package/base-modules/student-profile/filter.js +23 -3
  57. package/base-modules/student-profile/form.js +35 -3
  58. package/base-modules/subject/context.d.ts +1 -0
  59. package/base-modules/subject/context.js +38 -47
  60. package/base-modules/subject/more-actions.js +0 -2
  61. package/base-modules/teacher/constants.d.ts +0 -6
  62. package/base-modules/teacher/constants.js +0 -2
  63. package/base-modules/teacher/context.d.ts +1 -0
  64. package/base-modules/teacher/context.js +58 -39
  65. package/base-modules/teacher/form.js +46 -11
  66. package/base-modules/teacher/more-actions.js +0 -2
  67. package/base-modules/user/context/use-user-module.d.ts +1 -0
  68. package/base-modules/user/context/use-user-module.js +36 -32
  69. package/base-modules/user/context.js +1 -1
  70. package/base-modules/user/filter.js +6 -4
  71. package/base-modules/user/form.js +29 -5
  72. package/base-modules/user/more-actions.js +9 -7
  73. package/base-modules/user/view.js +3 -1
  74. package/base-modules/workspace/form.js +18 -8
  75. package/base-modules/workspace-user/context.d.ts +2 -1
  76. package/base-modules/workspace-user/context.js +31 -29
  77. package/package.json +1 -1
  78. package/tsconfig.build.tsbuildinfo +1 -1
  79. package/base-modules/admission/cache.d.ts +0 -14
  80. package/base-modules/admission/cache.js +0 -31
  81. package/base-modules/attendance/cache.d.ts +0 -14
  82. package/base-modules/attendance/cache.js +0 -31
  83. package/base-modules/course/cache.d.ts +0 -14
  84. package/base-modules/course/cache.js +0 -31
  85. package/base-modules/enrollment/cache.d.ts +0 -14
  86. package/base-modules/enrollment/cache.js +0 -31
  87. package/base-modules/expense/cache.d.ts +0 -14
  88. package/base-modules/expense/cache.js +0 -31
  89. package/base-modules/family/cache.d.ts +0 -14
  90. package/base-modules/family/cache.js +0 -31
  91. package/base-modules/family-member/cache.d.ts +0 -14
  92. package/base-modules/family-member/cache.js +0 -31
  93. package/base-modules/rbac/cache.d.ts +0 -27
  94. package/base-modules/rbac/cache.js +0 -46
  95. package/base-modules/student-fee/cache.d.ts +0 -15
  96. package/base-modules/student-fee/cache.js +0 -21
  97. package/base-modules/workspace-user/cache.d.ts +0 -14
  98. package/base-modules/workspace-user/cache.js +0 -31
@@ -8,301 +8,100 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  */
9
9
  import { EnhancedInput } from "@appcorp/shadcn/components/enhanced-input";
10
10
  import { EnhancedCheckbox } from "@appcorp/shadcn/components/enhanced-checkbox";
11
- import { EnhancedCombobox } from "@appcorp/shadcn/components/enhanced-combobox";
12
- import { useDebounce } from "@react-pakistan/util-functions/hooks/use-debounce";
13
- import { useEffect, useMemo, useState } from "react";
11
+ import { useEnhancedCombobox } from "@appcorp/shadcn/hooks/use-enhanced-combobox";
14
12
  import { useCourseModule } from "./context";
15
- import { getCachedSectionsSync } from "../section/cache";
16
- import { getCachedTeachersSync, getCachedTeachers } from "../teacher/cache";
17
- import { getCachedSubjectsSync } from "../subject/cache";
18
- import { getCachedSections } from "../section/cache";
19
- import { getCachedSubjects } from "../subject/cache";
20
- import { getCachedWorkspaceSync } from "../workspace/cache";
13
+ import { COURSE_API_ROUTES } from "./constants";
21
14
  import { useTranslations } from "next-intl";
15
+ import { useFetch } from "@react-pakistan/util-functions/hooks/use-fetch";
16
+ import { API_METHODS } from "@react-pakistan/util-functions";
17
+ import { getCachedWorkspaceSync } from "../workspace/cache";
22
18
  export const CourseForm = () => {
23
- var _a;
19
+ const workspace = getCachedWorkspaceSync();
24
20
  const t = useTranslations("course");
25
21
  const { state, handleChange } = useCourseModule();
26
- const workspace = getCachedWorkspaceSync();
27
- const schoolId = ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "";
28
- const { code, enabled, errors, sectionId, sectionLabel, subjectId, subjectLabel, teacherId, teacherLabel, } = state;
29
- const cachedSections = getCachedSectionsSync();
30
- const cachedSubjects = getCachedSubjectsSync();
31
- const cachedTeachers = getCachedTeachersSync();
32
- const [sectionSearchQuery, setSectionSearchQuery] = useState("");
33
- const [subjectSearchQuery, setSubjectSearchQuery] = useState("");
34
- const [teacherSearchQuery, setTeacherSearchQuery] = useState("");
35
- const [remoteSectionOptions, setRemoteSectionOptions] = useState(cachedSections.items.map((section) => {
36
- var _a;
37
- return ({
38
- label: ((_a = section.class) === null || _a === void 0 ? void 0 : _a.code)
39
- ? `${section.class.code}-${section.name}`
40
- : section.name,
41
- value: section.id,
42
- });
43
- }));
44
- const [remoteSubjectOptions, setRemoteSubjectOptions] = useState(cachedSubjects.items.map((subject) => ({
45
- label: subject.name,
46
- value: subject.id,
47
- })));
48
- const [remoteTeacherOptions, setRemoteTeacherOptions] = useState(cachedTeachers.items.map((teacher) => ({
49
- label: `${teacher.firstName || ""} ${teacher.lastName || ""}`.trim() ||
50
- teacher.teacherCode ||
51
- teacher.id,
52
- value: teacher.id,
53
- })));
54
- const [sectionOptionsLoading, setSectionOptionsLoading] = useState(false);
55
- const [subjectOptionsLoading, setSubjectOptionsLoading] = useState(false);
56
- const [teacherOptionsLoading, setTeacherOptionsLoading] = useState(false);
57
- const debouncedSectionSearchQuery = useDebounce(sectionSearchQuery, 300);
58
- const debouncedSubjectSearchQuery = useDebounce(subjectSearchQuery, 300);
59
- const debouncedTeacherSearchQuery = useDebounce(teacherSearchQuery, 300);
60
- const trimmedSectionSearchQuery = debouncedSectionSearchQuery.trim();
61
- const trimmedSubjectSearchQuery = debouncedSubjectSearchQuery.trim();
62
- const trimmedTeacherSearchQuery = debouncedTeacherSearchQuery.trim();
63
- const sectionOptions = useMemo(() => cachedSections.items.map((section) => {
64
- var _a;
65
- return ({
66
- label: ((_a = section.class) === null || _a === void 0 ? void 0 : _a.code)
67
- ? `${section.class.code}-${section.name}`
68
- : section.name,
69
- value: section.id,
70
- });
71
- }), [cachedSections.items]);
72
- const subjectOptions = useMemo(() => cachedSubjects.items.map((subject) => ({
73
- label: subject.name,
74
- value: subject.id,
75
- })), [cachedSubjects.items]);
76
- const teacherOptions = useMemo(() => cachedTeachers.items.map((teacher) => ({
77
- label: `${teacher.firstName || ""} ${teacher.lastName || ""}`.trim() ||
78
- teacher.teacherCode ||
79
- teacher.id,
80
- value: teacher.id,
81
- })), [cachedTeachers.items]);
82
- const selectedSectionOption = useMemo(() => {
83
- var _a;
84
- const selectedSection = cachedSections.items.find((section) => section.id === sectionId);
85
- return selectedSection
86
- ? [
87
- {
88
- label: ((_a = selectedSection.class) === null || _a === void 0 ? void 0 : _a.code)
89
- ? `${selectedSection.class.code}-${selectedSection.name}`
90
- : selectedSection.name,
91
- value: selectedSection.id,
92
- },
93
- ]
94
- : sectionId && sectionLabel
95
- ? [
96
- {
97
- label: sectionLabel,
98
- value: sectionId,
99
- },
100
- ]
101
- : [];
102
- }, [cachedSections.items, sectionId, sectionLabel]);
103
- const selectedSubjectOption = useMemo(() => {
104
- const selectedSubject = cachedSubjects.items.find((subject) => subject.id === subjectId);
105
- return selectedSubject
106
- ? [
107
- {
108
- label: selectedSubject.name,
109
- value: selectedSubject.id,
110
- },
111
- ]
112
- : subjectId && subjectLabel
113
- ? [
114
- {
115
- label: subjectLabel,
116
- value: subjectId,
117
- },
118
- ]
119
- : [];
120
- }, [cachedSubjects.items, subjectId, subjectLabel]);
121
- const selectedTeacherOption = useMemo(() => {
122
- const selectedTeacher = cachedTeachers.items.find((teacher) => teacher.id === teacherId);
123
- return selectedTeacher
124
- ? [
125
- {
126
- label: `${selectedTeacher.firstName || ""} ${selectedTeacher.lastName || ""}`.trim() ||
127
- selectedTeacher.teacherCode ||
128
- selectedTeacher.id,
129
- value: selectedTeacher.id,
130
- },
131
- ]
132
- : teacherId && teacherLabel
133
- ? [
134
- {
135
- label: teacherLabel,
136
- value: teacherId,
137
- },
138
- ]
139
- : [];
140
- }, [cachedTeachers.items, teacherId, teacherLabel]);
141
- const displayedSectionOptions = useMemo(() => {
142
- const sourceOptions = trimmedSectionSearchQuery
143
- ? remoteSectionOptions
144
- : sectionOptions;
145
- const mergedOptions = [...selectedSectionOption, ...sourceOptions];
146
- const uniqueOptions = new Map(mergedOptions.map((option) => [option.value, option]));
147
- return [...uniqueOptions.values()];
148
- }, [
149
- remoteSectionOptions,
150
- sectionOptions,
151
- selectedSectionOption,
152
- trimmedSectionSearchQuery,
153
- ]);
154
- const displayedSubjectOptions = useMemo(() => {
155
- const sourceOptions = trimmedSubjectSearchQuery
156
- ? remoteSubjectOptions
157
- : subjectOptions;
158
- const mergedOptions = [...selectedSubjectOption, ...sourceOptions];
159
- const uniqueOptions = new Map(mergedOptions.map((option) => [option.value, option]));
160
- return [...uniqueOptions.values()];
161
- }, [
162
- remoteSubjectOptions,
163
- selectedSubjectOption,
164
- subjectOptions,
165
- trimmedSubjectSearchQuery,
166
- ]);
167
- const displayedTeacherOptions = useMemo(() => {
168
- const sourceOptions = trimmedTeacherSearchQuery
169
- ? remoteTeacherOptions
170
- : teacherOptions;
171
- const mergedOptions = [...selectedTeacherOption, ...sourceOptions];
172
- const uniqueOptions = new Map(mergedOptions.map((option) => [option.value, option]));
173
- return [...uniqueOptions.values()];
174
- }, [
175
- remoteTeacherOptions,
176
- selectedTeacherOption,
177
- teacherOptions,
178
- trimmedTeacherSearchQuery,
179
- ]);
180
- useEffect(() => {
181
- if (!trimmedSectionSearchQuery || !schoolId)
182
- return;
183
- let isActive = true;
184
- const fetchSections = async () => {
185
- setSectionOptionsLoading(true);
186
- try {
187
- const { items } = await getCachedSections({
188
- params: {
189
- schoolId,
190
- searchQuery: trimmedSectionSearchQuery,
191
- },
192
- });
193
- if (!isActive)
194
- return;
195
- setRemoteSectionOptions((items || []).map((section) => {
196
- var _a;
197
- return ({
198
- label: ((_a = section.class) === null || _a === void 0 ? void 0 : _a.code)
199
- ? `${section.class.code}-${section.name}`
200
- : section.name,
201
- value: section.id,
202
- });
203
- }));
204
- }
205
- catch (_a) {
206
- if (!isActive)
207
- return;
208
- setRemoteSectionOptions([]);
209
- }
210
- finally {
211
- if (isActive) {
212
- setSectionOptionsLoading(false);
213
- }
214
- }
215
- };
216
- void fetchSections();
217
- return () => {
218
- isActive = false;
219
- };
220
- }, [schoolId, trimmedSectionSearchQuery]);
221
- useEffect(() => {
222
- if (!trimmedSubjectSearchQuery || !schoolId)
223
- return;
224
- let isActive = true;
225
- const fetchSubjects = async () => {
226
- setSubjectOptionsLoading(true);
227
- try {
228
- const { items } = await getCachedSubjects({
229
- params: {
230
- schoolId,
231
- searchQuery: trimmedSubjectSearchQuery,
232
- },
233
- });
234
- if (!isActive)
235
- return;
236
- setRemoteSubjectOptions((items || []).map((subject) => ({
237
- label: subject.name,
238
- value: subject.id,
239
- })));
240
- }
241
- catch (_a) {
242
- if (!isActive)
243
- return;
244
- setRemoteSubjectOptions([]);
245
- }
246
- finally {
247
- if (isActive) {
248
- setSubjectOptionsLoading(false);
249
- }
250
- }
251
- };
252
- void fetchSubjects();
253
- return () => {
254
- isActive = false;
255
- };
256
- }, [schoolId, trimmedSubjectSearchQuery]);
257
- useEffect(() => {
258
- if (!trimmedTeacherSearchQuery || !schoolId)
259
- return;
260
- let isActive = true;
261
- const fetchTeachers = async () => {
262
- setTeacherOptionsLoading(true);
263
- try {
264
- const { items } = await getCachedTeachers({
265
- params: {
266
- schoolId,
267
- searchQuery: trimmedTeacherSearchQuery,
268
- },
269
- });
270
- if (!isActive)
271
- return;
272
- setRemoteTeacherOptions((items || []).map((teacher) => ({
273
- label: `${teacher.firstName || ""} ${teacher.lastName || ""}`.trim() ||
274
- teacher.teacherCode ||
275
- teacher.id,
276
- value: teacher.id,
277
- })));
278
- }
279
- catch (_a) {
280
- if (!isActive)
281
- return;
282
- setRemoteTeacherOptions([]);
283
- }
284
- finally {
285
- if (isActive) {
286
- setTeacherOptionsLoading(false);
287
- }
288
- }
289
- };
290
- void fetchTeachers();
291
- return () => {
292
- isActive = false;
293
- };
294
- }, [schoolId, trimmedTeacherSearchQuery]);
295
- return (_jsxs("div", { className: "space-y-4", children: [_jsx(EnhancedInput, { error: errors.code, id: "code", info: t("formCourseCodeInfo"), label: t("formCourseCodeLabel"), onChange: (e) => handleChange("code", e.target.value), placeholder: t("formCourseCodePlaceholder"), required: true, value: code }), _jsx(EnhancedCombobox, { emptyText: t("formNoSectionEmpty"), error: errors.sectionId, id: "sectionId", info: t("sectionInfo"), label: t("section"), loading: sectionOptionsLoading && Boolean(trimmedSectionSearchQuery), onValueChange: (value) => {
296
- var _a;
297
- handleChange("sectionId", value);
298
- handleChange("sectionLabel", ((_a = displayedSectionOptions.find((option) => option.value === value)) === null || _a === void 0 ? void 0 : _a.label) || "");
299
- }, onSearchChange: setSectionSearchQuery, options: displayedSectionOptions, placeholder: t("sectionPlaceholder"), required: true, searchPlaceholder: t("formSearchSectionsPlaceholder"), value: sectionId }), _jsx(EnhancedCombobox, { emptyText: t("formNoSubjectEmpty"), error: errors.subjectId, id: "subjectId", info: t("formSubjectInfo"), label: t("formSubjectLabel"), loading: subjectOptionsLoading && Boolean(trimmedSubjectSearchQuery), onValueChange: (value) => {
300
- var _a;
301
- handleChange("subjectId", value);
302
- handleChange("subjectLabel", ((_a = displayedSubjectOptions.find((option) => option.value === value)) === null || _a === void 0 ? void 0 : _a.label) || "");
303
- }, onSearchChange: setSubjectSearchQuery, options: displayedSubjectOptions, placeholder: t("formSubjectPlaceholder"), required: true, searchPlaceholder: t("formSearchSubjectsPlaceholder"), value: subjectId }), _jsx(EnhancedCombobox, { emptyText: t("formNoTeacherEmpty"), error: errors.teacherId, id: "teacherId", info: t("formTeacherInfo"), label: t("formTeacherLabel"), loading: teacherOptionsLoading && Boolean(trimmedTeacherSearchQuery), onValueChange: (value) => {
304
- var _a;
305
- handleChange("teacherId", value);
306
- handleChange("teacherLabel", ((_a = displayedTeacherOptions.find((option) => option.value === value)) === null || _a === void 0 ? void 0 : _a.label) || "");
307
- }, onSearchChange: setTeacherSearchQuery, options: displayedTeacherOptions, placeholder: t("formTeacherPlaceholder"), required: true, searchPlaceholder: t("formSearchTeachersPlaceholder"), value: teacherId }), _jsx(EnhancedCheckbox, { label: t("formActiveCourseLabel"), defaultChecked: enabled, onCheckedChange: (checked) => handleChange("enabled", checked), info: t("actionToggleEnableOrDisableCourse") })] }));
22
+ const { code, enabled, errors, sectionId, subjectId, teacherId } = state;
23
+ const { data: sections } = useFetch("/api/v1/sections", {
24
+ method: API_METHODS.GET,
25
+ params: { workspaceId: workspace === null || workspace === void 0 ? void 0 : workspace.id },
26
+ });
27
+ const { data: subjects } = useFetch("/api/v1/subjects", {
28
+ method: API_METHODS.GET,
29
+ params: { workspaceId: workspace === null || workspace === void 0 ? void 0 : workspace.id },
30
+ });
31
+ const { data: teachers } = useFetch("/api/v1/teachers", {
32
+ method: API_METHODS.GET,
33
+ params: { workspaceId: workspace === null || workspace === void 0 ? void 0 : workspace.id },
34
+ });
35
+ const { enhancedComboboxElement: sectionIdCombo } = useEnhancedCombobox({
36
+ emptyText: t("formNoSectionEmpty"),
37
+ id: "sectionId",
38
+ info: t("sectionInfo"),
39
+ label: t("section"),
40
+ onValueChange: (value) => {
41
+ var _a;
42
+ handleChange("sectionId", value);
43
+ handleChange("sectionLabel", ((_a = sections.find((s) => s.id === value)) === null || _a === void 0 ? void 0 : _a.name) || "");
44
+ },
45
+ options: sections === null || sections === void 0 ? void 0 : sections.map((section) => {
46
+ var _a;
47
+ return ({
48
+ id: section.id,
49
+ name: ((_a = section.class) === null || _a === void 0 ? void 0 : _a.code)
50
+ ? `${section.class.code}-${section.name}`
51
+ : section.name,
52
+ });
53
+ }),
54
+ placeholder: t("sectionPlaceholder"),
55
+ required: true,
56
+ searchEndpoint: COURSE_API_ROUTES.UNIT,
57
+ searchPlaceholder: t("formSearchSectionsPlaceholder"),
58
+ value: sectionId,
59
+ });
60
+ const { enhancedComboboxElement: subjectIdCombo } = useEnhancedCombobox({
61
+ emptyText: t("formNoSubjectEmpty"),
62
+ id: "subjectId",
63
+ info: t("formSubjectInfo"),
64
+ label: t("formSubjectLabel"),
65
+ onValueChange: (value) => {
66
+ var _a;
67
+ handleChange("subjectId", value);
68
+ handleChange("subjectLabel", ((_a = subjects === null || subjects === void 0 ? void 0 : subjects.find((s) => s.id === value)) === null || _a === void 0 ? void 0 : _a.name) || "");
69
+ },
70
+ options: subjects === null || subjects === void 0 ? void 0 : subjects.map((subject) => ({
71
+ id: subject.id,
72
+ name: subject.name,
73
+ })),
74
+ placeholder: t("formSubjectPlaceholder"),
75
+ required: true,
76
+ searchEndpoint: COURSE_API_ROUTES.UNIT,
77
+ searchPlaceholder: t("formSearchSubjectsPlaceholder"),
78
+ value: subjectId,
79
+ });
80
+ const { enhancedComboboxElement: teacherIdCombo } = useEnhancedCombobox({
81
+ emptyText: t("formNoTeacherEmpty"),
82
+ id: "teacherId",
83
+ info: t("formTeacherInfo"),
84
+ label: t("formTeacherLabel"),
85
+ onValueChange: (value) => {
86
+ handleChange("teacherId", value);
87
+ const teacher = teachers === null || teachers === void 0 ? void 0 : teachers.find((t) => t.id === value);
88
+ handleChange("teacherLabel", teacher
89
+ ? `${teacher.firstName || ""} ${teacher.lastName || ""}`.trim() ||
90
+ teacher.teacherCode ||
91
+ teacher.id
92
+ : "");
93
+ },
94
+ options: teachers === null || teachers === void 0 ? void 0 : teachers.map((teacher) => ({
95
+ id: teacher.id,
96
+ name: `${teacher.firstName || ""} ${teacher.lastName || ""}`.trim() ||
97
+ teacher.teacherCode ||
98
+ teacher.id,
99
+ })),
100
+ placeholder: t("formTeacherPlaceholder"),
101
+ required: true,
102
+ searchEndpoint: COURSE_API_ROUTES.UNIT,
103
+ searchPlaceholder: t("formSearchTeachersPlaceholder"),
104
+ value: teacherId,
105
+ });
106
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(EnhancedInput, { error: errors.code, id: "code", info: t("formCourseCodeInfo"), label: t("formCourseCodeLabel"), onChange: (e) => handleChange("code", e.target.value), placeholder: t("formCourseCodePlaceholder"), required: true, value: code }), sectionIdCombo, subjectIdCombo, teacherIdCombo, _jsx(EnhancedCheckbox, { label: t("formActiveCourseLabel"), defaultChecked: enabled, onCheckedChange: (checked) => handleChange("enabled", checked), info: t("actionToggleEnableOrDisableCourse") })] }));
308
107
  };
@@ -5,6 +5,7 @@
5
5
  * environment-driven (via `NEXT_PUBLIC_*`) where appropriate so CI/infra
6
6
  * can override them without code changes.
7
7
  */
8
+ import { DISCOUNT_TYPE } from "../../types";
8
9
  /**
9
10
  * Default page limit for the discount codes list. Controlled by
10
11
  * `NEXT_PUBLIC_PAGE_LIMIT` with a safe fallback to `10`.
@@ -17,3 +18,7 @@ export declare const pageLimit: number;
17
18
  export declare const DISCOUNT_CODE_API_ROUTES: {
18
19
  UNIT: string;
19
20
  };
21
+ export declare const DISCOUNT_TYPE_OPTIONS: {
22
+ label: string;
23
+ value: DISCOUNT_TYPE;
24
+ }[];
@@ -6,6 +6,7 @@
6
6
  * can override them without code changes.
7
7
  */
8
8
  "use client";
9
+ import { DISCOUNT_TYPE } from "../../types";
9
10
  // ============================================================================
10
11
  // PAGE CONFIGURATION
11
12
  // ============================================================================
@@ -24,3 +25,7 @@ export const pageLimit = Number(process.env.NEXT_PUBLIC_PAGE_LIMIT) || 10;
24
25
  export const DISCOUNT_CODE_API_ROUTES = {
25
26
  UNIT: "/api/v1/discount-code",
26
27
  };
28
+ export const DISCOUNT_TYPE_OPTIONS = [
29
+ { label: "Percentage", value: DISCOUNT_TYPE.PERCENTAGE },
30
+ { label: "Fixed Amount", value: DISCOUNT_TYPE.FIXED },
31
+ ];
@@ -113,6 +113,7 @@ export declare const useDiscountCodeModule: () => {
113
113
  clearSearch: () => void;
114
114
  closeDrawer: () => void;
115
115
  deleteLoading: boolean;
116
+ resetRecordFormState: () => void;
116
117
  handleChange: (key: string, value: string | number | boolean | string[]) => void;
117
118
  handleCreate: () => void;
118
119
  handleDelete: (row?: TableRow) => void;
@@ -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 { DISCOUNT_CODE_API_ROUTES, pageLimit } from "./constants";
30
30
  import { accountDiscountCodeFormValidation } from "./validate";
31
- import { getCachedDiscountCodes, invalidateDiscountCodeCache } from "./cache";
32
31
  import { getCachedWorkspaceSync } from "../workspace/cache";
33
32
  // ============================================================================
34
33
  // 1.1 DRAWER TYPES
@@ -121,10 +120,6 @@ export const useDiscountCodeModule = () => {
121
120
  ]);
122
121
  const byIdParams = useMemo(() => ({ id: state.id }), [state.id]);
123
122
  const deleteParams = useMemo(() => ({ id: state.id }), [state.id]);
124
- const isDefaultListState = state.currentPage === 1 &&
125
- state.pageLimit === pageLimit &&
126
- !debouncedQuery &&
127
- state.filterEnabled === undefined;
128
123
  // ============================================================================
129
124
  // 1.4.3 UTILITIES
130
125
  // ============================================================================
@@ -169,7 +164,6 @@ export const useDiscountCodeModule = () => {
169
164
  }
170
165
  if (data) {
171
166
  const isCreated = isCreatedOrUpdated(data);
172
- invalidateDiscountCodeCache();
173
167
  showToast(isCreated
174
168
  ? t("messagesDiscountCodeCreated")
175
169
  : t("messagesDiscountCodeUpdated"), TOAST_VARIANT.SUCCESS);
@@ -196,7 +190,6 @@ export const useDiscountCodeModule = () => {
196
190
  return;
197
191
  }
198
192
  if (data) {
199
- invalidateDiscountCodeCache();
200
193
  showToast(t("messagesDiscountCodeDeleted"), TOAST_VARIANT.SUCCESS);
201
194
  (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
202
195
  }
@@ -272,22 +265,46 @@ export const useDiscountCodeModule = () => {
272
265
  payload: { currentPage: 1 },
273
266
  });
274
267
  }, [dispatch]);
268
+ const resetRecordFormState = useCallback(() => {
269
+ dispatch({
270
+ type: DISCOUNT_CODE_ACTION_TYPES.SET_INPUT_FIELD,
271
+ payload: { key: "code", value: "" },
272
+ });
273
+ dispatch({
274
+ type: DISCOUNT_CODE_ACTION_TYPES.SET_INPUT_FIELD,
275
+ payload: { key: "description", value: "" },
276
+ });
277
+ dispatch({
278
+ type: DISCOUNT_CODE_ACTION_TYPES.SET_INPUT_FIELD,
279
+ payload: { key: "discountType", value: "" },
280
+ });
281
+ dispatch({
282
+ type: DISCOUNT_CODE_ACTION_TYPES.SET_INPUT_FIELD,
283
+ payload: { key: "discountValue", value: 0 },
284
+ });
285
+ dispatch({
286
+ type: DISCOUNT_CODE_ACTION_TYPES.SET_INPUT_FIELD,
287
+ payload: { key: "enabled", value: true },
288
+ });
289
+ }, [dispatch]);
275
290
  const handleView = useCallback((row) => {
291
+ resetRecordFormState();
276
292
  byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
277
293
  dispatch({
278
294
  type: DISCOUNT_CODE_ACTION_TYPES.SET_DRAWER,
279
295
  payload: { drawer: DISCOUNT_CODE_DRAWER.VIEW_DRAWER },
280
296
  });
281
- }, [byIdFetchNow, dispatch]);
297
+ }, [byIdFetchNow, dispatch, resetRecordFormState]);
282
298
  const handleEdit = useCallback((row) => {
299
+ resetRecordFormState();
283
300
  byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
284
301
  dispatch({
285
302
  type: DISCOUNT_CODE_ACTION_TYPES.SET_DRAWER,
286
303
  payload: { drawer: DISCOUNT_CODE_DRAWER.FORM_DRAWER },
287
304
  });
288
- }, [byIdFetchNow, dispatch]);
305
+ }, [byIdFetchNow, dispatch, resetRecordFormState]);
289
306
  const handleDelete = useCallback((row) => {
290
- if (confirm(t("actionDeleteConfirmation"))) {
307
+ if (confirm(t("messagesDeleteConfirmation"))) {
291
308
  deleteFetchNow === null || deleteFetchNow === void 0 ? void 0 : deleteFetchNow(undefined, {
292
309
  body: JSON.stringify({ id: row === null || row === void 0 ? void 0 : row.id }),
293
310
  });
@@ -376,19 +393,19 @@ export const useDiscountCodeModule = () => {
376
393
  {
377
394
  enabled: true,
378
395
  handleOnClick: handleMoreActions,
379
- label: t("actionHeaderMoreActions"),
396
+ label: t("actionsButtonMoreActions"),
380
397
  order: 0,
381
398
  },
382
399
  {
383
400
  enabled: true,
384
401
  handleOnClick: handleFilters,
385
- label: t("actionHeaderFilters"),
402
+ label: t("actionsButtonFilters"),
386
403
  order: 1,
387
404
  },
388
405
  {
389
406
  enabled: true,
390
407
  handleOnClick: handleCreate,
391
- label: t("actionHeaderAdd"),
408
+ label: t("actionsButtonAdd"),
392
409
  order: 2,
393
410
  },
394
411
  ], [handleCreate, handleFilters, handleMoreActions, t]);
@@ -396,53 +413,36 @@ export const useDiscountCodeModule = () => {
396
413
  {
397
414
  enabled: true,
398
415
  handleOnClick: handleView,
399
- label: t("actionRowView"),
416
+ label: t("actionsButtonView"),
400
417
  order: 1,
401
418
  },
402
419
  {
403
420
  enabled: true,
404
421
  handleOnClick: handleEdit,
405
- label: t("actionRowEdit"),
422
+ label: t("actionsButtonEdit"),
406
423
  order: 2,
407
424
  },
408
425
  {
409
426
  enabled: true,
410
427
  handleOnClick: handleDelete,
411
- label: t("actionRowDelete"),
428
+ label: t("actionsButtonDelete"),
412
429
  order: 3,
413
430
  },
414
431
  ], [handleDelete, handleEdit, handleView, t]);
415
432
  // ============================================================================
416
433
  // 1.4.9 EFFECTS
417
434
  // ============================================================================
418
- // Initial load + re-fetch on page/search/filter change via cache
435
+ // Keep ref in sync with latest listFetchNow (avoids stale closure in callbacks)
436
+ useEffect(() => {
437
+ listFetchNowRef.current = listFetchNow;
438
+ }, [listFetchNow]);
439
+ // Fetch list on mount and on page/search/filter change
419
440
  useEffect(() => {
420
441
  var _a;
421
442
  if (!(workspace === null || workspace === void 0 ? void 0 : workspace.id))
422
443
  return;
423
- if (isDefaultListState) {
424
- (async () => {
425
- try {
426
- const { count, items } = await getCachedDiscountCodes({
427
- params: listParams,
428
- });
429
- dispatch({
430
- type: DISCOUNT_CODE_ACTION_TYPES.SET_ITEMS,
431
- payload: { items: items || [], count: count || 0 },
432
- });
433
- }
434
- catch (_a) {
435
- showToast(t("messagesNetworkError"), TOAST_VARIANT.ERROR);
436
- }
437
- })();
438
- return;
439
- }
440
444
  (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
441
- }, [dispatch, isDefaultListState, listParams, showToast, t, workspace === null || workspace === void 0 ? void 0 : workspace.id]);
442
- // Keep ref in sync with latest listFetchNow (avoids stale closure in callbacks)
443
- useEffect(() => {
444
- listFetchNowRef.current = listFetchNow;
445
- }, [listFetchNow]);
445
+ }, [dispatch, listParams, showToast, t, workspace === null || workspace === void 0 ? void 0 : workspace.id]);
446
446
  // ============================================================================
447
447
  // 1.4.10 RETURN
448
448
  // ============================================================================
@@ -452,6 +452,7 @@ export const useDiscountCodeModule = () => {
452
452
  clearSearch,
453
453
  closeDrawer,
454
454
  deleteLoading,
455
+ resetRecordFormState,
455
456
  handleChange,
456
457
  handleCreate,
457
458
  handleDelete,