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