@ubkinfotech/tecaher-erp 0.1.0

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 (146) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +413 -0
  3. package/lib/commonjs/core/api/apiClient.js +38 -0
  4. package/lib/commonjs/core/api/endpoints.js +139 -0
  5. package/lib/commonjs/core/api/interceptor.js +64 -0
  6. package/lib/commonjs/core/auth/authContext.js +30 -0
  7. package/lib/commonjs/core/auth/authService.js +12 -0
  8. package/lib/commonjs/core/hooks/useApiQuery.js +26 -0
  9. package/lib/commonjs/core/provider/ERPProvider.js +63 -0
  10. package/lib/commonjs/core/provider/types.js +5 -0
  11. package/lib/commonjs/core/provider/useERP.js +17 -0
  12. package/lib/commonjs/core/types/api.js +1 -0
  13. package/lib/commonjs/index.js +110 -0
  14. package/lib/commonjs/modules/assignment/hooks/useAssignmentList.js +16 -0
  15. package/lib/commonjs/modules/assignment/hooks/useHomeworkDetails.js +16 -0
  16. package/lib/commonjs/modules/assignment/hooks/useHomeworkSubmissions.js +16 -0
  17. package/lib/commonjs/modules/assignment/screens/AssignmentScreen.js +2615 -0
  18. package/lib/commonjs/modules/assignment/services/assignmentService.js +75 -0
  19. package/lib/commonjs/modules/attendance/hooks/useAttendance.js +16 -0
  20. package/lib/commonjs/modules/attendance/screens/AttendanceScreen.js +866 -0
  21. package/lib/commonjs/modules/attendance/services/attendanceService.js +31 -0
  22. package/lib/commonjs/modules/leaveRequest/hooks/useLeaveRequests.js +16 -0
  23. package/lib/commonjs/modules/leaveRequest/screens/LeaveRequestScreen.js +991 -0
  24. package/lib/commonjs/modules/leaveRequest/services/leaveRequestService.js +42 -0
  25. package/lib/commonjs/modules/marks/hooks/useMarks.js +14 -0
  26. package/lib/commonjs/modules/marks/screens/MarksScreen.js +1621 -0
  27. package/lib/commonjs/modules/marks/services/marksService.js +71 -0
  28. package/lib/commonjs/modules/myAttendance/hooks/useMyAttendance.js +16 -0
  29. package/lib/commonjs/modules/myAttendance/screens/MyAttendanceScreen.js +357 -0
  30. package/lib/commonjs/modules/myAttendance/services/myAttendanceService.js +11 -0
  31. package/lib/commonjs/modules/notes/hooks/useNotes.js +16 -0
  32. package/lib/commonjs/modules/notes/screens/NotesScreen.js +1287 -0
  33. package/lib/commonjs/modules/notes/services/notesService.js +65 -0
  34. package/lib/commonjs/modules/noticeboard/hooks/useNoticeboard.js +16 -0
  35. package/lib/commonjs/modules/noticeboard/screens/NoticeBoardScreen.js +381 -0
  36. package/lib/commonjs/modules/noticeboard/services/noticeboardService.js +16 -0
  37. package/lib/commonjs/modules/notification/hooks/useNotifications.js +16 -0
  38. package/lib/commonjs/modules/notification/screens/NotificationScreen.js +186 -0
  39. package/lib/commonjs/modules/notification/services/notificationService.js +16 -0
  40. package/lib/commonjs/modules/promoteStudent/hooks/usePromoteStudent.js +16 -0
  41. package/lib/commonjs/modules/promoteStudent/screens/PromoteStudentScreen.js +644 -0
  42. package/lib/commonjs/modules/promoteStudent/services/promoteStudentService.js +36 -0
  43. package/lib/commonjs/modules/timetable/hooks/useTimeTable.js +14 -0
  44. package/lib/commonjs/modules/timetable/screens/TimeTableScreen.js +258 -0
  45. package/lib/commonjs/modules/timetable/services/timetableService.js +16 -0
  46. package/lib/commonjs/package.json +1 -0
  47. package/lib/commonjs/shared/empty-states/EmptyState.js +45 -0
  48. package/lib/commonjs/shared/empty-states/ErrorState.js +45 -0
  49. package/lib/commonjs/shared/loaders/LoadingState.js +25 -0
  50. package/lib/commonjs/shared/theme/theme.js +22 -0
  51. package/lib/module/core/api/apiClient.js +32 -0
  52. package/lib/module/core/api/endpoints.js +135 -0
  53. package/lib/module/core/api/interceptor.js +60 -0
  54. package/lib/module/core/auth/authContext.js +23 -0
  55. package/lib/module/core/auth/authService.js +8 -0
  56. package/lib/module/core/hooks/useApiQuery.js +21 -0
  57. package/lib/module/core/provider/ERPProvider.js +56 -0
  58. package/lib/module/core/provider/types.js +3 -0
  59. package/lib/module/core/provider/useERP.js +12 -0
  60. package/lib/module/core/types/api.js +1 -0
  61. package/lib/module/index.js +17 -0
  62. package/lib/module/modules/assignment/hooks/useAssignmentList.js +12 -0
  63. package/lib/module/modules/assignment/hooks/useHomeworkDetails.js +12 -0
  64. package/lib/module/modules/assignment/hooks/useHomeworkSubmissions.js +12 -0
  65. package/lib/module/modules/assignment/screens/AssignmentScreen.js +2609 -0
  66. package/lib/module/modules/assignment/services/assignmentService.js +62 -0
  67. package/lib/module/modules/attendance/hooks/useAttendance.js +12 -0
  68. package/lib/module/modules/attendance/screens/AttendanceScreen.js +860 -0
  69. package/lib/module/modules/attendance/services/attendanceService.js +23 -0
  70. package/lib/module/modules/leaveRequest/hooks/useLeaveRequests.js +12 -0
  71. package/lib/module/modules/leaveRequest/screens/LeaveRequestScreen.js +985 -0
  72. package/lib/module/modules/leaveRequest/services/leaveRequestService.js +35 -0
  73. package/lib/module/modules/marks/hooks/useMarks.js +10 -0
  74. package/lib/module/modules/marks/screens/MarksScreen.js +1615 -0
  75. package/lib/module/modules/marks/services/marksService.js +55 -0
  76. package/lib/module/modules/myAttendance/hooks/useMyAttendance.js +12 -0
  77. package/lib/module/modules/myAttendance/screens/MyAttendanceScreen.js +351 -0
  78. package/lib/module/modules/myAttendance/services/myAttendanceService.js +7 -0
  79. package/lib/module/modules/notes/hooks/useNotes.js +12 -0
  80. package/lib/module/modules/notes/screens/NotesScreen.js +1281 -0
  81. package/lib/module/modules/notes/services/notesService.js +54 -0
  82. package/lib/module/modules/noticeboard/hooks/useNoticeboard.js +12 -0
  83. package/lib/module/modules/noticeboard/screens/NoticeBoardScreen.js +375 -0
  84. package/lib/module/modules/noticeboard/services/noticeboardService.js +12 -0
  85. package/lib/module/modules/notification/hooks/useNotifications.js +12 -0
  86. package/lib/module/modules/notification/screens/NotificationScreen.js +180 -0
  87. package/lib/module/modules/notification/services/notificationService.js +12 -0
  88. package/lib/module/modules/promoteStudent/hooks/usePromoteStudent.js +12 -0
  89. package/lib/module/modules/promoteStudent/screens/PromoteStudentScreen.js +638 -0
  90. package/lib/module/modules/promoteStudent/services/promoteStudentService.js +27 -0
  91. package/lib/module/modules/timetable/hooks/useTimeTable.js +10 -0
  92. package/lib/module/modules/timetable/screens/TimeTableScreen.js +252 -0
  93. package/lib/module/modules/timetable/services/timetableService.js +11 -0
  94. package/lib/module/package.json +1 -0
  95. package/lib/module/shared/empty-states/EmptyState.js +40 -0
  96. package/lib/module/shared/empty-states/ErrorState.js +40 -0
  97. package/lib/module/shared/loaders/LoadingState.js +20 -0
  98. package/lib/module/shared/theme/theme.js +18 -0
  99. package/lib/typescript/core/api/apiClient.d.ts +14 -0
  100. package/lib/typescript/core/api/endpoints.d.ts +164 -0
  101. package/lib/typescript/core/api/interceptor.d.ts +4 -0
  102. package/lib/typescript/core/auth/authContext.d.ts +11 -0
  103. package/lib/typescript/core/auth/authService.d.ts +9 -0
  104. package/lib/typescript/core/hooks/useApiQuery.d.ts +7 -0
  105. package/lib/typescript/core/provider/ERPProvider.d.ts +14 -0
  106. package/lib/typescript/core/provider/types.d.ts +34 -0
  107. package/lib/typescript/core/provider/useERP.d.ts +3 -0
  108. package/lib/typescript/core/types/api.d.ts +11 -0
  109. package/lib/typescript/index.d.ts +18 -0
  110. package/lib/typescript/modules/assignment/hooks/useAssignmentList.d.ts +3 -0
  111. package/lib/typescript/modules/assignment/hooks/useHomeworkDetails.d.ts +4 -0
  112. package/lib/typescript/modules/assignment/hooks/useHomeworkSubmissions.d.ts +4 -0
  113. package/lib/typescript/modules/assignment/screens/AssignmentScreen.d.ts +9 -0
  114. package/lib/typescript/modules/assignment/services/assignmentService.d.ts +89 -0
  115. package/lib/typescript/modules/attendance/hooks/useAttendance.d.ts +3 -0
  116. package/lib/typescript/modules/attendance/screens/AttendanceScreen.d.ts +5 -0
  117. package/lib/typescript/modules/attendance/services/attendanceService.d.ts +33 -0
  118. package/lib/typescript/modules/leaveRequest/hooks/useLeaveRequests.d.ts +3 -0
  119. package/lib/typescript/modules/leaveRequest/screens/LeaveRequestScreen.d.ts +5 -0
  120. package/lib/typescript/modules/leaveRequest/services/leaveRequestService.d.ts +39 -0
  121. package/lib/typescript/modules/marks/hooks/useMarks.d.ts +2 -0
  122. package/lib/typescript/modules/marks/screens/MarksScreen.d.ts +6 -0
  123. package/lib/typescript/modules/marks/services/marksService.d.ts +150 -0
  124. package/lib/typescript/modules/myAttendance/hooks/useMyAttendance.d.ts +3 -0
  125. package/lib/typescript/modules/myAttendance/screens/MyAttendanceScreen.d.ts +5 -0
  126. package/lib/typescript/modules/myAttendance/services/myAttendanceService.d.ts +10 -0
  127. package/lib/typescript/modules/notes/hooks/useNotes.d.ts +3 -0
  128. package/lib/typescript/modules/notes/screens/NotesScreen.d.ts +8 -0
  129. package/lib/typescript/modules/notes/services/notesService.d.ts +58 -0
  130. package/lib/typescript/modules/noticeboard/hooks/useNoticeboard.d.ts +3 -0
  131. package/lib/typescript/modules/noticeboard/screens/NoticeBoardScreen.d.ts +5 -0
  132. package/lib/typescript/modules/noticeboard/services/noticeboardService.d.ts +17 -0
  133. package/lib/typescript/modules/notification/hooks/useNotifications.d.ts +3 -0
  134. package/lib/typescript/modules/notification/screens/NotificationScreen.d.ts +5 -0
  135. package/lib/typescript/modules/notification/services/notificationService.d.ts +8 -0
  136. package/lib/typescript/modules/promoteStudent/hooks/usePromoteStudent.d.ts +3 -0
  137. package/lib/typescript/modules/promoteStudent/screens/PromoteStudentScreen.d.ts +5 -0
  138. package/lib/typescript/modules/promoteStudent/services/promoteStudentService.d.ts +40 -0
  139. package/lib/typescript/modules/timetable/hooks/useTimeTable.d.ts +3 -0
  140. package/lib/typescript/modules/timetable/screens/TimeTableScreen.d.ts +5 -0
  141. package/lib/typescript/modules/timetable/services/timetableService.d.ts +14 -0
  142. package/lib/typescript/shared/empty-states/EmptyState.d.ts +6 -0
  143. package/lib/typescript/shared/empty-states/ErrorState.d.ts +6 -0
  144. package/lib/typescript/shared/loaders/LoadingState.d.ts +3 -0
  145. package/lib/typescript/shared/theme/theme.d.ts +17 -0
  146. package/package.json +89 -0
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.usePromoteStudentSearch = usePromoteStudentSearch;
7
+ var _useApiQuery = require("../../../core/hooks/useApiQuery");
8
+ var _promoteStudentService = require("../services/promoteStudentService");
9
+ function usePromoteStudentSearch(params) {
10
+ const enabled = !!params && !!params.classId && !!params.sectionId;
11
+ return (0, _useApiQuery.useApiQuery)({
12
+ queryKey: ['promoteStudent', 'search', params?.classId ?? null, params?.sectionId ?? null],
13
+ enabled,
14
+ queryFn: api => (0, _promoteStudentService.fetchPromoteStudentSearch)(api, params)
15
+ });
16
+ }
@@ -0,0 +1,644 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.PromoteStudentScreen = PromoteStudentScreen;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _useERP = require("../../../core/provider/useERP");
10
+ var _EmptyState = require("../../../shared/empty-states/EmptyState");
11
+ var _ErrorState = require("../../../shared/empty-states/ErrorState");
12
+ var _promoteStudentService = require("../services/promoteStudentService");
13
+ var _jsxRuntime = require("react/jsx-runtime");
14
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
15
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
16
+ function normalizeList(result) {
17
+ if (Array.isArray(result)) return result;
18
+ if (Array.isArray(result?.data)) return result.data;
19
+ return [];
20
+ }
21
+ function normalizeOptions(result) {
22
+ return normalizeList(result).map((item, index) => ({
23
+ label: String(item?.label ?? item?.name ?? item?.title ?? `Option ${index + 1}`),
24
+ value: item?.value ?? item?.id ?? index + 1,
25
+ raw: item
26
+ }));
27
+ }
28
+ function SelectField({
29
+ label,
30
+ value,
31
+ options,
32
+ placeholder,
33
+ onChange
34
+ }) {
35
+ const [open, setOpen] = (0, _react.useState)(false);
36
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
37
+ style: styles.field,
38
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
39
+ style: styles.label,
40
+ children: label
41
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
42
+ style: styles.select,
43
+ onPress: () => setOpen(true),
44
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
45
+ style: styles.selectText,
46
+ children: value?.label ?? placeholder
47
+ })
48
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Modal, {
49
+ visible: open,
50
+ transparent: true,
51
+ animationType: "fade",
52
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
53
+ style: styles.modalOverlay,
54
+ onPress: () => setOpen(false),
55
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
56
+ style: styles.modalCard,
57
+ onPress: () => {},
58
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
59
+ style: styles.modalTitle,
60
+ children: label
61
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
62
+ data: options,
63
+ keyExtractor: (item, index) => `${item.value}-${index}`,
64
+ renderItem: ({
65
+ item
66
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
67
+ style: styles.optionRow,
68
+ onPress: () => {
69
+ onChange(item);
70
+ setOpen(false);
71
+ },
72
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
73
+ style: styles.optionText,
74
+ children: item.label
75
+ })
76
+ }),
77
+ ListEmptyComponent: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
78
+ style: styles.optionEmpty,
79
+ children: "No options"
80
+ })
81
+ })]
82
+ })
83
+ })
84
+ })]
85
+ });
86
+ }
87
+ function PromoteStudentScreen(props) {
88
+ const {
89
+ api
90
+ } = (0, _useERP.useERP)();
91
+ const [classes, setClasses] = (0, _react.useState)([]);
92
+ const [sourceSections, setSourceSections] = (0, _react.useState)([]);
93
+ const [destinationSections, setDestinationSections] = (0, _react.useState)([]);
94
+ const [sessions, setSessions] = (0, _react.useState)([]);
95
+ const [sourceClass, setSourceClass] = (0, _react.useState)(null);
96
+ const [sourceSection, setSourceSection] = (0, _react.useState)(null);
97
+ const [destinationClass, setDestinationClass] = (0, _react.useState)(null);
98
+ const [destinationSession, setDestinationSession] = (0, _react.useState)(null);
99
+ const [students, setStudents] = (0, _react.useState)([]);
100
+ const [loading, setLoading] = (0, _react.useState)(true);
101
+ const [searching, setSearching] = (0, _react.useState)(false);
102
+ const [submitting, setSubmitting] = (0, _react.useState)(false);
103
+ const [error, setError] = (0, _react.useState)(null);
104
+ const [sectionModalStudentId, setSectionModalStudentId] = (0, _react.useState)(null);
105
+ const sectionModalStudent = (0, _react.useMemo)(() => {
106
+ return students.find(it => String(it.id) === String(sectionModalStudentId ?? '')) ?? null;
107
+ }, [sectionModalStudentId, students]);
108
+ (0, _react.useEffect)(() => {
109
+ const load = async () => {
110
+ try {
111
+ setLoading(true);
112
+ const [classRes, sessionRes] = await Promise.all([(0, _promoteStudentService.fetchPromoteClasses)(api), (0, _promoteStudentService.fetchPromoteSessions)(api)]);
113
+ const classOptions = normalizeOptions(classRes);
114
+ setClasses(classOptions);
115
+ setSessions(normalizeOptions(sessionRes?.data ?? sessionRes));
116
+ if (props.classId !== undefined) {
117
+ const found = classOptions.find(it => String(it.value) === String(props.classId)) ?? null;
118
+ setSourceClass(found);
119
+ }
120
+ } catch (e) {
121
+ setError(String(e?.message ?? 'Could not load dropdowns'));
122
+ } finally {
123
+ setLoading(false);
124
+ }
125
+ };
126
+ load().catch(() => {});
127
+ }, [api, props.classId]);
128
+ (0, _react.useEffect)(() => {
129
+ if (!sourceClass?.value) {
130
+ setSourceSections([]);
131
+ setSourceSection(null);
132
+ return;
133
+ }
134
+ (0, _promoteStudentService.fetchPromoteSections)(api, {
135
+ classId: sourceClass.value
136
+ }).then(res => {
137
+ const options = normalizeOptions(res);
138
+ setSourceSections(options);
139
+ if (props.sectionId !== undefined) {
140
+ const found = options.find(it => String(it.value) === String(props.sectionId)) ?? null;
141
+ setSourceSection(found);
142
+ }
143
+ }).catch(e => setError(String(e?.message ?? 'Could not load sections')));
144
+ }, [api, props.sectionId, sourceClass?.value]);
145
+ (0, _react.useEffect)(() => {
146
+ if (!destinationClass?.value) {
147
+ setDestinationSections([]);
148
+ return;
149
+ }
150
+ (0, _promoteStudentService.fetchPromoteAllSections)(api, {
151
+ classId: destinationClass.value
152
+ }).then(res => setDestinationSections(normalizeOptions(res))).catch(e => setError(String(e?.message ?? 'Could not load destination sections')));
153
+ }, [api, destinationClass?.value]);
154
+ const searchStudents = (0, _react.useCallback)(async () => {
155
+ if (!sourceClass?.value || !sourceSection?.value) {
156
+ _reactNative.Alert.alert('Error', 'Please select source class and section');
157
+ return;
158
+ }
159
+ try {
160
+ setSearching(true);
161
+ const res = await (0, _promoteStudentService.fetchPromoteStudentSearch)(api, {
162
+ classId: sourceClass.value,
163
+ sectionId: sourceSection.value
164
+ });
165
+ const list = normalizeList(res?.data ?? res);
166
+ setStudents(list.map(item => ({
167
+ ...item,
168
+ selected: false,
169
+ currentResult: 'Pass',
170
+ nextSessionStatus: 'Continue',
171
+ targetSection: '',
172
+ targetSectionId: undefined
173
+ })));
174
+ } catch (e) {
175
+ _reactNative.Alert.alert('Error', String(e?.message ?? 'Could not load students'));
176
+ } finally {
177
+ setSearching(false);
178
+ }
179
+ }, [api, sourceClass?.value, sourceSection?.value]);
180
+ const setRow = (0, _react.useCallback)((id, patch) => {
181
+ setStudents(prev => prev.map(item => String(item.id) === String(id) ? {
182
+ ...item,
183
+ ...patch
184
+ } : item));
185
+ }, []);
186
+ const submit = (0, _react.useCallback)(async () => {
187
+ if (!destinationSession?.value || !destinationClass?.value) {
188
+ _reactNative.Alert.alert('Error', 'Please select destination session and class');
189
+ return;
190
+ }
191
+ const selectedStudents = students.filter(it => it.selected);
192
+ if (!selectedStudents.length) {
193
+ _reactNative.Alert.alert('Error', 'Please select at least one student');
194
+ return;
195
+ }
196
+ for (const student of selectedStudents) {
197
+ const isLeave = student.nextSessionStatus === 'Leave';
198
+ const rollMissing = !isLeave && !String(student.roll_no ?? '').trim();
199
+ const sectionMissing = !isLeave && !String(student.targetSectionId ?? '').trim();
200
+ if (rollMissing || sectionMissing) {
201
+ _reactNative.Alert.alert('Error', 'Roll No and Section are required for continuing students');
202
+ return;
203
+ }
204
+ }
205
+ try {
206
+ setSubmitting(true);
207
+ const payload = {
208
+ session_id: destinationSession.value,
209
+ class_id: destinationClass.value,
210
+ students: selectedStudents.map(student => {
211
+ const base = {
212
+ student_id: student.id,
213
+ current_result: student.currentResult,
214
+ next_session_status: student.nextSessionStatus
215
+ };
216
+ if (student.nextSessionStatus !== 'Leave') {
217
+ base.roll_no = student.roll_no;
218
+ base.section_id = student.targetSectionId;
219
+ }
220
+ return base;
221
+ })
222
+ };
223
+ const res = await (0, _promoteStudentService.submitPromotions)(api, payload);
224
+ const response = res;
225
+ if (response?.Status && response.Status !== 'Success') {
226
+ _reactNative.Alert.alert('Error', String(response?.msg ?? 'Failed to promote students'));
227
+ return;
228
+ }
229
+ _reactNative.Alert.alert('Success', String(response?.msg ?? 'Students promoted successfully'));
230
+ searchStudents().catch(() => {});
231
+ } catch (e) {
232
+ _reactNative.Alert.alert('Error', String(e?.message ?? 'Failed to promote students'));
233
+ } finally {
234
+ setSubmitting(false);
235
+ }
236
+ }, [api, destinationClass?.value, destinationSession?.value, searchStudents, students]);
237
+ if (loading) {
238
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.SafeAreaView, {
239
+ style: styles.root,
240
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
241
+ style: styles.loaderWrap,
242
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
243
+ size: "large",
244
+ color: "#1D4ED8"
245
+ })
246
+ })
247
+ });
248
+ }
249
+ if (error && !classes.length) {
250
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ErrorState.ErrorState, {
251
+ message: error
252
+ });
253
+ }
254
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.SafeAreaView, {
255
+ style: styles.root,
256
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
257
+ data: students,
258
+ keyExtractor: (item, index) => String(item?.id ?? index),
259
+ contentContainerStyle: styles.content,
260
+ ListHeaderComponent: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
261
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
262
+ style: styles.title,
263
+ children: "Promote Student"
264
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
265
+ style: styles.card,
266
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
267
+ style: styles.sectionTitle,
268
+ children: "Source"
269
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(SelectField, {
270
+ label: "Class",
271
+ value: sourceClass,
272
+ options: classes,
273
+ placeholder: "Select class",
274
+ onChange: next => {
275
+ setSourceClass(next);
276
+ setSourceSection(null);
277
+ setStudents([]);
278
+ }
279
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(SelectField, {
280
+ label: "Section",
281
+ value: sourceSection,
282
+ options: sourceSections,
283
+ placeholder: "Select section",
284
+ onChange: next => {
285
+ setSourceSection(next);
286
+ setStudents([]);
287
+ }
288
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
289
+ style: styles.primaryBtn,
290
+ onPress: () => searchStudents().catch(() => {}),
291
+ children: searching ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
292
+ color: "#FFFFFF"
293
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
294
+ style: styles.primaryBtnText,
295
+ children: "Search Students"
296
+ })
297
+ })]
298
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
299
+ style: styles.card,
300
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
301
+ style: styles.sectionTitle,
302
+ children: "Destination"
303
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(SelectField, {
304
+ label: "Session",
305
+ value: destinationSession,
306
+ options: sessions,
307
+ placeholder: "Select session",
308
+ onChange: setDestinationSession
309
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(SelectField, {
310
+ label: "Class",
311
+ value: destinationClass,
312
+ options: classes,
313
+ placeholder: "Select destination class",
314
+ onChange: next => {
315
+ setDestinationClass(next);
316
+ setStudents(prev => prev.map(student => ({
317
+ ...student,
318
+ targetSection: '',
319
+ targetSectionId: undefined
320
+ })));
321
+ }
322
+ })]
323
+ })]
324
+ }),
325
+ renderItem: ({
326
+ item
327
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
328
+ style: styles.studentCard,
329
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
330
+ style: styles.studentHeader,
331
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
332
+ style: {
333
+ flex: 1
334
+ },
335
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
336
+ style: styles.studentName,
337
+ children: [String(item.firstname ?? ''), " ", String(item.lastname ?? '')]
338
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
339
+ style: styles.rollLabel,
340
+ children: ["Current Roll: ", String(item.roll_no ?? '-')]
341
+ })]
342
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Switch, {
343
+ value: item.selected,
344
+ onValueChange: next => setRow(item.id, {
345
+ selected: next
346
+ })
347
+ })]
348
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
349
+ style: styles.segmentRow,
350
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
351
+ style: [styles.segmentBtn, item.currentResult === 'Pass' ? styles.segmentActive : null],
352
+ onPress: () => item.selected && setRow(item.id, {
353
+ currentResult: 'Pass'
354
+ }),
355
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
356
+ style: [styles.segmentText, item.currentResult === 'Pass' ? styles.segmentTextActive : null],
357
+ children: "Pass"
358
+ })
359
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
360
+ style: [styles.segmentBtn, item.currentResult === 'Fail' ? styles.segmentActive : styles.segmentDanger],
361
+ onPress: () => item.selected && setRow(item.id, {
362
+ currentResult: 'Fail'
363
+ }),
364
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
365
+ style: [styles.segmentText, item.currentResult === 'Fail' ? styles.segmentTextActive : styles.segmentDangerText],
366
+ children: "Fail"
367
+ })
368
+ })]
369
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
370
+ style: styles.segmentRow,
371
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
372
+ style: [styles.segmentBtn, item.nextSessionStatus === 'Continue' ? styles.segmentActive : null],
373
+ onPress: () => item.selected && setRow(item.id, {
374
+ nextSessionStatus: 'Continue'
375
+ }),
376
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
377
+ style: [styles.segmentText, item.nextSessionStatus === 'Continue' ? styles.segmentTextActive : null],
378
+ children: "Continue"
379
+ })
380
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
381
+ style: [styles.segmentBtn, item.nextSessionStatus === 'Leave' ? styles.segmentActive : styles.segmentDanger],
382
+ onPress: () => item.selected && setRow(item.id, {
383
+ nextSessionStatus: 'Leave'
384
+ }),
385
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
386
+ style: [styles.segmentText, item.nextSessionStatus === 'Leave' ? styles.segmentTextActive : styles.segmentDangerText],
387
+ children: "Leave"
388
+ })
389
+ })]
390
+ }), item.nextSessionStatus !== 'Leave' ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
391
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
392
+ value: String(item.roll_no ?? ''),
393
+ onChangeText: text => setRow(item.id, {
394
+ roll_no: text.replace(/[^0-9]/g, '')
395
+ }),
396
+ placeholder: "Enter next roll no",
397
+ placeholderTextColor: "#9CA3AF",
398
+ style: styles.input
399
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
400
+ style: styles.select,
401
+ onPress: () => setSectionModalStudentId(item.id),
402
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
403
+ style: styles.selectText,
404
+ children: item.targetSection || 'Select destination section'
405
+ })
406
+ })]
407
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
408
+ style: styles.leaveInfo,
409
+ children: "Section and roll are not required for leave status."
410
+ })]
411
+ }),
412
+ ListEmptyComponent: /*#__PURE__*/(0, _jsxRuntime.jsx)(_EmptyState.EmptyState, {
413
+ title: "No Students",
414
+ message: "Search by source class and section to load students."
415
+ }),
416
+ ListFooterComponent: students.length ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
417
+ style: styles.primaryBtn,
418
+ onPress: () => submit().catch(() => {}),
419
+ disabled: submitting,
420
+ children: submitting ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
421
+ color: "#FFFFFF"
422
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
423
+ style: styles.primaryBtnText,
424
+ children: "Promote Students"
425
+ })
426
+ }) : null
427
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Modal, {
428
+ visible: sectionModalStudent !== null,
429
+ transparent: true,
430
+ animationType: "fade",
431
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
432
+ style: styles.modalOverlay,
433
+ onPress: () => setSectionModalStudentId(null),
434
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
435
+ style: styles.modalCard,
436
+ onPress: () => {},
437
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
438
+ style: styles.modalTitle,
439
+ children: "Select Section"
440
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
441
+ data: destinationSections,
442
+ keyExtractor: (item, index) => `${item.value}-${index}`,
443
+ renderItem: ({
444
+ item
445
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
446
+ style: styles.optionRow,
447
+ onPress: () => {
448
+ if (sectionModalStudent) {
449
+ setRow(sectionModalStudent.id, {
450
+ targetSection: item.label,
451
+ targetSectionId: item.value
452
+ });
453
+ }
454
+ setSectionModalStudentId(null);
455
+ },
456
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
457
+ style: styles.optionText,
458
+ children: item.label
459
+ })
460
+ }),
461
+ ListEmptyComponent: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
462
+ style: styles.optionEmpty,
463
+ children: "No sections"
464
+ })
465
+ })]
466
+ })
467
+ })
468
+ })]
469
+ });
470
+ }
471
+ const styles = _reactNative.StyleSheet.create({
472
+ root: {
473
+ flex: 1,
474
+ backgroundColor: '#F9FAFB'
475
+ },
476
+ loaderWrap: {
477
+ flex: 1,
478
+ alignItems: 'center',
479
+ justifyContent: 'center'
480
+ },
481
+ content: {
482
+ padding: 16,
483
+ paddingBottom: 32
484
+ },
485
+ title: {
486
+ fontSize: 20,
487
+ fontWeight: '700',
488
+ color: '#111827',
489
+ marginBottom: 12
490
+ },
491
+ card: {
492
+ backgroundColor: '#FFFFFF',
493
+ borderRadius: 14,
494
+ borderWidth: 1,
495
+ borderColor: '#E5E7EB',
496
+ padding: 14,
497
+ marginBottom: 12
498
+ },
499
+ sectionTitle: {
500
+ fontSize: 16,
501
+ fontWeight: '700',
502
+ color: '#111827',
503
+ marginBottom: 10
504
+ },
505
+ field: {
506
+ marginBottom: 12
507
+ },
508
+ label: {
509
+ fontSize: 13,
510
+ fontWeight: '600',
511
+ color: '#1F2937',
512
+ marginBottom: 6
513
+ },
514
+ select: {
515
+ borderWidth: 1,
516
+ borderColor: '#D1D5DB',
517
+ borderRadius: 10,
518
+ backgroundColor: '#FFFFFF',
519
+ paddingHorizontal: 12,
520
+ paddingVertical: 12
521
+ },
522
+ selectText: {
523
+ fontSize: 14,
524
+ color: '#111827'
525
+ },
526
+ primaryBtn: {
527
+ backgroundColor: '#1D4ED8',
528
+ borderRadius: 12,
529
+ paddingVertical: 14,
530
+ alignItems: 'center',
531
+ justifyContent: 'center',
532
+ marginTop: 8
533
+ },
534
+ primaryBtnText: {
535
+ color: '#FFFFFF',
536
+ fontSize: 15,
537
+ fontWeight: '700'
538
+ },
539
+ studentCard: {
540
+ backgroundColor: '#FFFFFF',
541
+ borderRadius: 14,
542
+ borderWidth: 1,
543
+ borderColor: '#E5E7EB',
544
+ padding: 14,
545
+ marginBottom: 12
546
+ },
547
+ studentHeader: {
548
+ flexDirection: 'row',
549
+ alignItems: 'center',
550
+ marginBottom: 12,
551
+ gap: 10
552
+ },
553
+ studentName: {
554
+ fontSize: 16,
555
+ fontWeight: '700',
556
+ color: '#111827'
557
+ },
558
+ rollLabel: {
559
+ fontSize: 13,
560
+ color: '#6B7280',
561
+ marginTop: 3
562
+ },
563
+ segmentRow: {
564
+ flexDirection: 'row',
565
+ gap: 8,
566
+ marginBottom: 10
567
+ },
568
+ segmentBtn: {
569
+ flex: 1,
570
+ borderWidth: 1,
571
+ borderColor: '#93C5FD',
572
+ backgroundColor: '#EFF6FF',
573
+ paddingVertical: 10,
574
+ borderRadius: 10,
575
+ alignItems: 'center'
576
+ },
577
+ segmentActive: {
578
+ backgroundColor: '#1D4ED8',
579
+ borderColor: '#1D4ED8'
580
+ },
581
+ segmentDanger: {
582
+ borderColor: '#FCA5A5',
583
+ backgroundColor: '#FEF2F2'
584
+ },
585
+ segmentText: {
586
+ fontSize: 14,
587
+ fontWeight: '700',
588
+ color: '#1D4ED8'
589
+ },
590
+ segmentTextActive: {
591
+ color: '#FFFFFF'
592
+ },
593
+ segmentDangerText: {
594
+ color: '#B91C1C'
595
+ },
596
+ input: {
597
+ borderWidth: 1,
598
+ borderColor: '#D1D5DB',
599
+ borderRadius: 10,
600
+ backgroundColor: '#FFFFFF',
601
+ paddingHorizontal: 12,
602
+ paddingVertical: 12,
603
+ fontSize: 14,
604
+ color: '#111827',
605
+ marginBottom: 10
606
+ },
607
+ leaveInfo: {
608
+ fontSize: 13,
609
+ color: '#6B7280'
610
+ },
611
+ modalOverlay: {
612
+ flex: 1,
613
+ backgroundColor: 'rgba(0,0,0,0.35)',
614
+ justifyContent: 'center',
615
+ padding: 16
616
+ },
617
+ modalCard: {
618
+ backgroundColor: '#FFFFFF',
619
+ borderRadius: 14,
620
+ maxHeight: '75%',
621
+ padding: 16
622
+ },
623
+ modalTitle: {
624
+ fontSize: 16,
625
+ fontWeight: '700',
626
+ color: '#111827',
627
+ marginBottom: 12
628
+ },
629
+ optionRow: {
630
+ paddingVertical: 12,
631
+ borderBottomWidth: 1,
632
+ borderBottomColor: '#F3F4F6'
633
+ },
634
+ optionText: {
635
+ fontSize: 14,
636
+ color: '#111827'
637
+ },
638
+ optionEmpty: {
639
+ fontSize: 14,
640
+ color: '#6B7280',
641
+ textAlign: 'center',
642
+ paddingVertical: 16
643
+ }
644
+ });
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.fetchPromoteAllSections = fetchPromoteAllSections;
7
+ exports.fetchPromoteClasses = fetchPromoteClasses;
8
+ exports.fetchPromoteSections = fetchPromoteSections;
9
+ exports.fetchPromoteSessions = fetchPromoteSessions;
10
+ exports.fetchPromoteStudentSearch = fetchPromoteStudentSearch;
11
+ exports.submitPromotions = submitPromotions;
12
+ var _endpoints = require("../../../core/api/endpoints");
13
+ async function fetchPromoteStudentSearch(api, params) {
14
+ const res = await api.get(_endpoints.endpoints.promoteStudent.searchByClassSection(params));
15
+ return res.data;
16
+ }
17
+ async function fetchPromoteClasses(api) {
18
+ const res = await api.get(_endpoints.endpoints.promoteStudent.classDropdown);
19
+ return res.data;
20
+ }
21
+ async function fetchPromoteSections(api, args) {
22
+ const res = await api.get(_endpoints.endpoints.promoteStudent.sectionDropdown(args));
23
+ return res.data;
24
+ }
25
+ async function fetchPromoteAllSections(api, args) {
26
+ const res = await api.get(_endpoints.endpoints.promoteStudent.allSectionDropdown(args));
27
+ return res.data;
28
+ }
29
+ async function fetchPromoteSessions(api) {
30
+ const res = await api.get(_endpoints.endpoints.promoteStudent.sessionDropdown);
31
+ return res.data;
32
+ }
33
+ async function submitPromotions(api, payload) {
34
+ const res = await api.post(_endpoints.endpoints.promoteStudent.submit, payload);
35
+ return res.data;
36
+ }