@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,1615 @@
1
+ "use strict";
2
+
3
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
4
+ import { ActivityIndicator, Alert, FlatList, Modal, Pressable, SafeAreaView, ScrollView, 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 { LoadingState } from "../../../shared/loaders/LoadingState.js";
8
+ import { fetchClassTeacherClasses, fetchCoScholasticCategories, fetchCoScholasticEntry, fetchCoScholasticGrades, fetchExamDropdown, fetchMarksClasses, fetchMarksSections, fetchScholasticEntry, fetchStudentRemarks, fetchTeacherSubjectsForExam, submitCoScholasticMarks, submitExamMarks, submitExamRemark } from "../services/marksService.js";
9
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
+ const REMARK_OPTIONS = ['Good in studies. Needs to put in a little more effort in oral work.', 'Needs to work hard for better marks. Needs practice in both writing and oral work', 'Has shown considerable improvement b needs to pay more attention to conversation skills.', 'Needs systematic and regular follow up at home with regard to studies.', 'Can do better with some help at home. Oral work needs brushing up', 'promising child who needs to put in a little more effort', 'Has the potential to do very well but needs more focused attention.', 'Good in studies. Can be excellent with a little extra care.', 'Has shown good improvement. Has the potential to do even better.', 'Extra care can bring improvement in performance. All round improvement required.', 'Has not yet become familiar with the school atmosphere. No amount of coaxing can make him write.', 'Has performed below ability. Needs special care, time and encouragement to do better.', 'Has not yet become familiar with the school atmosphere. No amount of coaxing can make him write.', 'Needs to be more patient with written work. More practice in conversation is also required.', 'Has shown no improvement. Parents are requested to give special care at home.', 'Finishes the given work but is very talkative and disturbing in class.', 'Handwriting needs to improve. Proper guidance at home can bring good results.', 'Weak in studies. Does not respond in class. Needs to work much harder in order to get promotion.', 'An average child who can improve with a little more care and attention at home.', 'Inattentive in class. Does not follow class room instructions. Needs to pay attention to his studies.', 'Others'];
11
+ function normalizeList(result) {
12
+ if (Array.isArray(result)) {
13
+ return result;
14
+ }
15
+ if (Array.isArray(result?.data)) {
16
+ return result.data;
17
+ }
18
+ if (Array.isArray(result?.data?.data)) {
19
+ return result.data.data;
20
+ }
21
+ return [];
22
+ }
23
+ function normalizeOptions(result) {
24
+ const list = normalizeList(result);
25
+ return list.map((item, index) => ({
26
+ label: String(item?.label ?? item?.type ?? item?.title ?? item?.skill ?? item?.name ?? `Option ${index + 1}`),
27
+ value: item?.value ?? item?.id ?? item?.mark_to ?? index + 1,
28
+ parent: item?.parent,
29
+ raw: item
30
+ }));
31
+ }
32
+ function normalizeGradeOptions(list) {
33
+ return list.map((item, index) => ({
34
+ label: String(item?.label ?? item?.title ?? item?.mark_to ?? item?.value ?? `Grade ${index + 1}`),
35
+ value: String(item?.value ?? item?.mark_to ?? item?.id ?? ''),
36
+ raw: item
37
+ }));
38
+ }
39
+ function matchesValue(a, b) {
40
+ return String(a ?? '') === String(b ?? '');
41
+ }
42
+ function findOption(options, value) {
43
+ return options.find(item => matchesValue(item.value, value)) ?? null;
44
+ }
45
+ function hasOverLimit(value, fullMarks) {
46
+ const parsed = Number(value ?? '');
47
+ const max = Number(fullMarks ?? '');
48
+ if (!Number.isFinite(parsed) || !Number.isFinite(max)) {
49
+ return false;
50
+ }
51
+ return parsed > max;
52
+ }
53
+ function buildRemarkForm(student) {
54
+ const existingRemark = String(student?.exam_remarks ?? '');
55
+ const predefined = REMARK_OPTIONS.find(item => item === existingRemark) ?? '';
56
+ return {
57
+ selectedRemark: predefined || (existingRemark ? 'Others' : ''),
58
+ remarks: predefined ? predefined : existingRemark,
59
+ metting_date_1: String(student?.metting_date_1 ?? ''),
60
+ attended_1: String(student?.attended_1 ?? ''),
61
+ metting_date_2: String(student?.metting_date_2 ?? ''),
62
+ attended_2: String(student?.attended_2 ?? ''),
63
+ metting_date_3: String(student?.metting_date_3 ?? ''),
64
+ attended_3: String(student?.attended_3 ?? ''),
65
+ working_days: String(student?.working_days ?? ''),
66
+ days_present: String(student?.days_present ?? '')
67
+ };
68
+ }
69
+ function SelectField({
70
+ label,
71
+ value,
72
+ options,
73
+ placeholder,
74
+ onChange
75
+ }) {
76
+ const [open, setOpen] = useState(false);
77
+ return /*#__PURE__*/_jsxs(View, {
78
+ style: styles.field,
79
+ children: [/*#__PURE__*/_jsx(Text, {
80
+ style: styles.label,
81
+ children: label
82
+ }), /*#__PURE__*/_jsx(Pressable, {
83
+ onPress: () => setOpen(true),
84
+ style: styles.select,
85
+ children: /*#__PURE__*/_jsx(Text, {
86
+ style: styles.selectText,
87
+ children: value?.label ?? placeholder
88
+ })
89
+ }), /*#__PURE__*/_jsx(Modal, {
90
+ visible: open,
91
+ transparent: true,
92
+ animationType: "fade",
93
+ children: /*#__PURE__*/_jsx(Pressable, {
94
+ style: styles.modalOverlay,
95
+ onPress: () => setOpen(false),
96
+ children: /*#__PURE__*/_jsxs(Pressable, {
97
+ style: styles.modalCard,
98
+ onPress: () => {},
99
+ children: [/*#__PURE__*/_jsx(Text, {
100
+ style: styles.modalTitle,
101
+ children: label
102
+ }), /*#__PURE__*/_jsx(FlatList, {
103
+ data: options,
104
+ keyExtractor: (item, index) => `${item.value}-${index}`,
105
+ renderItem: ({
106
+ item
107
+ }) => /*#__PURE__*/_jsx(Pressable, {
108
+ style: styles.optionRow,
109
+ onPress: () => {
110
+ onChange(item);
111
+ setOpen(false);
112
+ },
113
+ children: /*#__PURE__*/_jsx(Text, {
114
+ style: styles.optionText,
115
+ children: item.label
116
+ })
117
+ }),
118
+ ListEmptyComponent: /*#__PURE__*/_jsx(Text, {
119
+ style: styles.optionEmpty,
120
+ children: "No options"
121
+ })
122
+ })]
123
+ })
124
+ })
125
+ })]
126
+ });
127
+ }
128
+ function FlowTab({
129
+ title,
130
+ active,
131
+ onPress
132
+ }) {
133
+ return /*#__PURE__*/_jsx(TouchableOpacity, {
134
+ onPress: onPress,
135
+ style: [styles.tabBtn, active ? styles.tabBtnActive : null],
136
+ children: /*#__PURE__*/_jsx(Text, {
137
+ style: [styles.tabBtnText, active ? styles.tabBtnTextActive : null],
138
+ children: title
139
+ })
140
+ });
141
+ }
142
+ function StatusToggle({
143
+ label,
144
+ value,
145
+ onValueChange
146
+ }) {
147
+ return /*#__PURE__*/_jsxs(View, {
148
+ style: styles.toggleLine,
149
+ children: [/*#__PURE__*/_jsx(Text, {
150
+ style: styles.toggleText,
151
+ children: label
152
+ }), /*#__PURE__*/_jsx(Switch, {
153
+ value: value,
154
+ onValueChange: onValueChange
155
+ })]
156
+ });
157
+ }
158
+ function MarksInput({
159
+ label,
160
+ value,
161
+ fullMarks,
162
+ absent,
163
+ useSelect,
164
+ onTextChange,
165
+ onPick,
166
+ onAbsentChange
167
+ }) {
168
+ const overLimit = hasOverLimit(value, fullMarks);
169
+ return /*#__PURE__*/_jsxs(View, {
170
+ style: styles.markField,
171
+ children: [/*#__PURE__*/_jsxs(View, {
172
+ style: styles.markHeader,
173
+ children: [/*#__PURE__*/_jsx(Text, {
174
+ style: styles.markLabel,
175
+ children: label
176
+ }), /*#__PURE__*/_jsxs(Text, {
177
+ style: styles.markMax,
178
+ children: ["Max: ", String(fullMarks ?? '-')]
179
+ })]
180
+ }), useSelect ? /*#__PURE__*/_jsx(TouchableOpacity, {
181
+ style: [styles.markSelectBtn, absent ? styles.disabledInput : null],
182
+ onPress: onPick,
183
+ disabled: absent,
184
+ children: /*#__PURE__*/_jsx(Text, {
185
+ style: styles.markSelectText,
186
+ children: value || 'Select Grade'
187
+ })
188
+ }) : /*#__PURE__*/_jsx(TextInput, {
189
+ value: value,
190
+ onChangeText: onTextChange,
191
+ placeholder: "Enter marks",
192
+ placeholderTextColor: "#9CA3AF",
193
+ keyboardType: "numeric",
194
+ editable: !absent,
195
+ style: [styles.input, absent ? styles.disabledInput : null, overLimit ? styles.errorBorder : null]
196
+ }), /*#__PURE__*/_jsx(StatusToggle, {
197
+ label: "Absent",
198
+ value: absent,
199
+ onValueChange: onAbsentChange
200
+ }), overLimit ? /*#__PURE__*/_jsx(Text, {
201
+ style: styles.errorText,
202
+ children: "Marks exceed max marks"
203
+ }) : null]
204
+ });
205
+ }
206
+ export function MarksScreen(props) {
207
+ const {
208
+ api
209
+ } = useERP();
210
+ const sessionId = props.sessionId;
211
+ const [flow, setFlow] = useState('scholastic');
212
+ const [entryMode, setEntryMode] = useState('filters');
213
+ const [classes, setClasses] = useState([]);
214
+ const [sections, setSections] = useState([]);
215
+ const [exams, setExams] = useState([]);
216
+ const [subjects, setSubjects] = useState([]);
217
+ const [selectedClass, setSelectedClass] = useState(null);
218
+ const [selectedSection, setSelectedSection] = useState(null);
219
+ const [selectedExam, setSelectedExam] = useState(null);
220
+ const [selectedSubject, setSelectedSubject] = useState(null);
221
+ const [loadingFilters, setLoadingFilters] = useState(true);
222
+ const [busy, setBusy] = useState(false);
223
+ const [gradeModal, setGradeModal] = useState({
224
+ visible: false,
225
+ title: '',
226
+ options: []
227
+ });
228
+ const [scholasticStudents, setScholasticStudents] = useState([]);
229
+ const [scholasticExam, setScholasticExam] = useState(null);
230
+ const [scholasticGrades, setScholasticGrades] = useState([]);
231
+ const [coStudents, setCoStudents] = useState([]);
232
+ const [coAreas, setCoAreas] = useState([]);
233
+ const [coGrades, setCoGrades] = useState([]);
234
+ const [coFormData, setCoFormData] = useState([]);
235
+ const [remarkStudents, setRemarkStudents] = useState([]);
236
+ const [remarkModalVisible, setRemarkModalVisible] = useState(false);
237
+ const [selectedRemarkStudent, setSelectedRemarkStudent] = useState(null);
238
+ const [remarkForm, setRemarkForm] = useState({
239
+ selectedRemark: '',
240
+ remarks: '',
241
+ metting_date_1: '',
242
+ attended_1: '',
243
+ metting_date_2: '',
244
+ attended_2: '',
245
+ metting_date_3: '',
246
+ attended_3: '',
247
+ working_days: '',
248
+ days_present: ''
249
+ });
250
+ const resetFilters = useCallback(() => {
251
+ setSections([]);
252
+ setExams([]);
253
+ setSubjects([]);
254
+ setSelectedClass(null);
255
+ setSelectedSection(null);
256
+ setSelectedExam(null);
257
+ setSelectedSubject(null);
258
+ setEntryMode('filters');
259
+ setScholasticStudents([]);
260
+ setScholasticExam(null);
261
+ setScholasticGrades([]);
262
+ setCoStudents([]);
263
+ setCoAreas([]);
264
+ setCoGrades([]);
265
+ setCoFormData([]);
266
+ setRemarkStudents([]);
267
+ }, []);
268
+ useEffect(() => {
269
+ resetFilters();
270
+ setLoadingFilters(true);
271
+ const load = async () => {
272
+ try {
273
+ const res = flow === 'remarks' ? await fetchClassTeacherClasses(api) : await fetchMarksClasses(api);
274
+ setClasses(normalizeOptions(res));
275
+ } catch (error) {
276
+ Alert.alert('Error', String(error?.message ?? 'Could not load classes'));
277
+ } finally {
278
+ setLoadingFilters(false);
279
+ }
280
+ };
281
+ load().catch(() => {});
282
+ }, [api, flow, resetFilters]);
283
+ useEffect(() => {
284
+ if (!selectedClass?.value) {
285
+ setSections([]);
286
+ setExams([]);
287
+ setSubjects([]);
288
+ setSelectedSection(null);
289
+ setSelectedExam(null);
290
+ setSelectedSubject(null);
291
+ return;
292
+ }
293
+ fetchMarksSections(api, {
294
+ classId: selectedClass.value
295
+ }).then(res => {
296
+ setSections(normalizeOptions(res));
297
+ }).catch(error => {
298
+ Alert.alert('Error', String(error?.message ?? 'Could not load sections'));
299
+ });
300
+ if (sessionId === undefined) {
301
+ setExams([]);
302
+ return;
303
+ }
304
+ fetchExamDropdown(api, {
305
+ sessionId,
306
+ classId: selectedClass.value
307
+ }).then(res => {
308
+ setExams(normalizeOptions(res));
309
+ }).catch(error => {
310
+ Alert.alert('Error', String(error?.message ?? 'Could not load exams'));
311
+ });
312
+ }, [api, selectedClass?.value, sessionId]);
313
+ useEffect(() => {
314
+ setSubjects([]);
315
+ setSelectedSubject(null);
316
+ if (!selectedClass?.value || !selectedExam?.value || sessionId === undefined) {
317
+ return;
318
+ }
319
+ if (flow === 'scholastic') {
320
+ if (!selectedSection?.value) {
321
+ return;
322
+ }
323
+ const args = {
324
+ sessionId,
325
+ classId: selectedClass.value,
326
+ sectionId: selectedSection.value,
327
+ examId: selectedExam.value
328
+ };
329
+ fetchTeacherSubjectsForExam(api, args).then(res => {
330
+ const normalized = normalizeOptions(res);
331
+ const list = normalized.flatMap(item => {
332
+ const raw = item.raw;
333
+ if (Array.isArray(raw?.options)) {
334
+ return raw.options.map((opt, index) => ({
335
+ label: String(opt?.label ?? `Subject ${index + 1}`),
336
+ value: opt?.value ?? opt?.id ?? index + 1,
337
+ raw: opt
338
+ }));
339
+ }
340
+ return [item];
341
+ });
342
+ setSubjects(list);
343
+ }).catch(error => {
344
+ Alert.alert('Error', String(error?.message ?? 'Could not load subjects'));
345
+ });
346
+ return;
347
+ }
348
+ if (flow === 'coscholastic') {
349
+ fetchCoScholasticCategories(api, {
350
+ sessionId,
351
+ classId: selectedClass.value,
352
+ examId: selectedExam.value
353
+ }).then(res => {
354
+ setSubjects(normalizeOptions(res));
355
+ }).catch(error => {
356
+ Alert.alert('Error', String(error?.message ?? 'Could not load categories'));
357
+ });
358
+ }
359
+ }, [api, flow, selectedClass?.value, selectedExam?.value, selectedSection?.value, sessionId]);
360
+ const openGradePicker = useCallback((title, options, onSelect) => {
361
+ setGradeModal({
362
+ visible: true,
363
+ title,
364
+ options,
365
+ onSelect
366
+ });
367
+ }, []);
368
+ const closeGradePicker = useCallback(() => {
369
+ setGradeModal({
370
+ visible: false,
371
+ title: '',
372
+ options: [],
373
+ onSelect: undefined
374
+ });
375
+ }, []);
376
+ const handleScholasticMarkChange = useCallback((studentId, subject, value, assessmentIndex) => {
377
+ setScholasticStudents(prev => prev.map(student => {
378
+ if (!matchesValue(student.id, studentId)) {
379
+ return student;
380
+ }
381
+ if (subject !== 'assessment') {
382
+ return {
383
+ ...student,
384
+ [subject]: value
385
+ };
386
+ }
387
+ const currentMarks = [...(student.assement_marks ?? [])];
388
+ const assessmentId = scholasticExam?.assesment_type?.[assessmentIndex ?? 0]?.id;
389
+ const existingIndex = currentMarks.findIndex(mark => matchesValue(mark?.assement_id, assessmentId));
390
+ if (existingIndex >= 0) {
391
+ currentMarks[existingIndex] = {
392
+ ...currentMarks[existingIndex],
393
+ marks: value
394
+ };
395
+ } else {
396
+ currentMarks.push({
397
+ assement_id: assessmentId,
398
+ marks: value,
399
+ is_absent: false
400
+ });
401
+ }
402
+ return {
403
+ ...student,
404
+ assement_marks: currentMarks
405
+ };
406
+ }));
407
+ }, [scholasticExam?.assesment_type]);
408
+ const handleScholasticAbsentChange = useCallback((studentId, type, isAbsent, index) => {
409
+ setScholasticStudents(prev => prev.map(student => {
410
+ if (!matchesValue(student.id, studentId)) {
411
+ return student;
412
+ }
413
+ if (type === 'theory') {
414
+ return {
415
+ ...student,
416
+ theory_absent: isAbsent
417
+ };
418
+ }
419
+ if (type === 'practical') {
420
+ return {
421
+ ...student,
422
+ practical_absent: isAbsent
423
+ };
424
+ }
425
+ const currentMarks = [...(student.assement_marks ?? [])];
426
+ const assessmentId = scholasticExam?.assesment_type?.[index ?? 0]?.id;
427
+ const existingIndex = currentMarks.findIndex(mark => matchesValue(mark?.assement_id, assessmentId));
428
+ if (existingIndex >= 0) {
429
+ currentMarks[existingIndex] = {
430
+ ...currentMarks[existingIndex],
431
+ is_absent: isAbsent
432
+ };
433
+ } else {
434
+ currentMarks.push({
435
+ assement_id: assessmentId,
436
+ marks: '',
437
+ is_absent: isAbsent
438
+ });
439
+ }
440
+ return {
441
+ ...student,
442
+ assement_marks: currentMarks
443
+ };
444
+ }));
445
+ }, [scholasticExam?.assesment_type]);
446
+ const loadScholasticEntry = useCallback(async () => {
447
+ if (!selectedClass?.value || !selectedSection?.value || !selectedExam?.value || !selectedSubject?.value) {
448
+ Alert.alert('Error', 'Please provide class, section, exam, and subject');
449
+ return;
450
+ }
451
+ setBusy(true);
452
+ try {
453
+ const res = await fetchScholasticEntry(api, {
454
+ classId: selectedClass.value,
455
+ sectionId: selectedSection.value,
456
+ examId: selectedExam.value,
457
+ subjectId: selectedSubject.value
458
+ });
459
+ const response = res;
460
+ if (response?.Status && response.Status !== 'Success') {
461
+ Alert.alert('Failed', String(response?.msg ?? response?.Message ?? 'Could not load marks'));
462
+ return;
463
+ }
464
+ const exam = response?.exam_details?.[0] ?? response?.data?.exam_details?.[0] ?? null;
465
+ const rawStudents = normalizeList(response?.data ?? response);
466
+ const initialized = rawStudents.map(student => ({
467
+ ...student,
468
+ theory_absent: student?.main_subject_marks === 'AB' || student?.main_subject_marks === '-1',
469
+ practical_absent: student?.practical_subject_marks === 'AB' || student?.practical_subject_marks === '-1',
470
+ assement_marks: (student?.assement_marks ?? []).map(mark => ({
471
+ ...mark,
472
+ is_absent: String(mark?.status ?? '').toLowerCase() === 'absent' || mark?.marks === 'AB' || mark?.marks === '-1'
473
+ }))
474
+ }));
475
+ setScholasticStudents(initialized);
476
+ setScholasticExam(exam);
477
+ setScholasticGrades(normalizeGradeOptions(response?.exam_grade ?? []));
478
+ setEntryMode('scholastic');
479
+ } catch (error) {
480
+ Alert.alert('Error', String(error?.message ?? 'Could not load marks entry'));
481
+ } finally {
482
+ setBusy(false);
483
+ }
484
+ }, [api, selectedClass?.value, selectedExam?.value, selectedSection?.value, selectedSubject?.value]);
485
+ const loadCoScholasticEntry = useCallback(async () => {
486
+ if (!selectedClass?.value || !selectedSection?.value || !selectedExam?.value || !selectedSubject?.value) {
487
+ Alert.alert('Error', 'Please provide class, section, exam, and category');
488
+ return;
489
+ }
490
+ setBusy(true);
491
+ try {
492
+ const [gradesRes, entryRes] = await Promise.all([fetchCoScholasticGrades(api), fetchCoScholasticEntry(api, {
493
+ classId: selectedClass.value,
494
+ sectionId: selectedSection.value,
495
+ examId: selectedExam.value,
496
+ categoryId: selectedSubject.value
497
+ })]);
498
+ const entryResponse = entryRes;
499
+ if (entryResponse?.Status && entryResponse.Status !== 'Success') {
500
+ Alert.alert('Failed', String(entryResponse?.msg ?? entryResponse?.Message ?? 'Could not load co-scholastic entry'));
501
+ return;
502
+ }
503
+ const students = normalizeList(entryResponse?.data ?? entryResponse);
504
+ const areas = entryResponse?.exam_details ?? entryResponse?.data?.exam_details ?? [];
505
+ const formData = students.map(student => {
506
+ const row = {
507
+ studentid: student.id
508
+ };
509
+ areas.forEach(area => {
510
+ const existing = (student.marks_data ?? []).find(mark => matchesValue(mark?.fk_co_scholasticarea_id, area.id));
511
+ row[String(area.id ?? '')] = existing && !matchesValue(existing.marks_grade_id, '0') ? String(existing.marks_grade_id) : '0';
512
+ });
513
+ return row;
514
+ });
515
+ setCoGrades(normalizeOptions(gradesRes));
516
+ setCoStudents(students);
517
+ setCoAreas(areas);
518
+ setCoFormData(formData);
519
+ setEntryMode('coscholastic');
520
+ } catch (error) {
521
+ Alert.alert('Error', String(error?.message ?? 'Could not load co-scholastic entry'));
522
+ } finally {
523
+ setBusy(false);
524
+ }
525
+ }, [api, selectedClass?.value, selectedExam?.value, selectedSection?.value, selectedSubject?.value]);
526
+ const loadRemarksEntry = useCallback(async () => {
527
+ if (!selectedClass?.value || !selectedSection?.value || !selectedExam?.value) {
528
+ Alert.alert('Error', 'Please provide class, section, and exam');
529
+ return;
530
+ }
531
+ setBusy(true);
532
+ try {
533
+ const res = await fetchStudentRemarks(api, {
534
+ classId: selectedClass.value,
535
+ sectionId: selectedSection.value,
536
+ examId: selectedExam.value
537
+ });
538
+ const response = res;
539
+ if (response?.Status && response.Status !== 'Success') {
540
+ Alert.alert('Failed', String(response?.msg ?? response?.Message ?? 'Could not load remarks'));
541
+ return;
542
+ }
543
+ setRemarkStudents(normalizeList(response));
544
+ setEntryMode('remarks');
545
+ } catch (error) {
546
+ Alert.alert('Error', String(error?.message ?? 'Could not load remarks entry'));
547
+ } finally {
548
+ setBusy(false);
549
+ }
550
+ }, [api, selectedClass?.value, selectedExam?.value, selectedSection?.value]);
551
+ const startEntry = useCallback(() => {
552
+ if (sessionId === undefined) {
553
+ Alert.alert('Error', 'Pass sessionId to MarksScreen');
554
+ return;
555
+ }
556
+ if (flow === 'scholastic') {
557
+ loadScholasticEntry().catch(() => {});
558
+ return;
559
+ }
560
+ if (flow === 'coscholastic') {
561
+ loadCoScholasticEntry().catch(() => {});
562
+ return;
563
+ }
564
+ loadRemarksEntry().catch(() => {});
565
+ }, [flow, loadCoScholasticEntry, loadRemarksEntry, loadScholasticEntry, sessionId]);
566
+ const submitScholastic = useCallback(async () => {
567
+ if (!selectedClass?.value || !selectedSection?.value || !selectedExam?.value || !selectedSubject?.value || !scholasticExam) {
568
+ Alert.alert('Error', 'Missing scholastic filters');
569
+ return;
570
+ }
571
+ setBusy(true);
572
+ try {
573
+ const data = scholasticStudents.map(student => {
574
+ const row = {
575
+ student_id: student.id,
576
+ attendance_status: scholasticExam?.is_theory === 'yes' && student?.theory_absent ? 'Absent' : 'Present'
577
+ };
578
+ if (scholasticExam?.is_theory === 'yes') {
579
+ row.main_marks = student?.theory_absent ? 'AB' : student.main_subject_marks || '0';
580
+ }
581
+ if (scholasticExam?.is_practical === 'yes') {
582
+ row.practical_marks = student?.practical_absent ? 'AB' : student.practical_subject_marks || '0';
583
+ }
584
+ if (Array.isArray(scholasticExam?.assesment_type) && scholasticExam.assesment_type.length) {
585
+ row.assesment_coloum = scholasticExam.assesment_type.map((assessment, index) => {
586
+ const currentMark = (student.assement_marks ?? []).find(mark => matchesValue(mark?.assement_id, assessment.id));
587
+ if (currentMark?.is_absent) {
588
+ return {
589
+ assement_id: assessment.id ?? index,
590
+ marks: 'AB',
591
+ status: 'Absent'
592
+ };
593
+ }
594
+ return {
595
+ assement_id: assessment.id ?? index,
596
+ marks: currentMark?.marks || '0',
597
+ status: 'Present'
598
+ };
599
+ });
600
+ }
601
+ return row;
602
+ });
603
+ const payload = {
604
+ exam_id: selectedExam.value,
605
+ subject_id: selectedSubject.value,
606
+ class_id: selectedClass.value,
607
+ section_id: selectedSection.value,
608
+ exam_schedule_id: scholasticExam?.id,
609
+ Isassessment: scholasticExam?.Isassessment,
610
+ assesment_type_id: scholasticExam?.template_details?.assessment_type === 'Exam_wise' ? scholasticExam?.assesment_type?.[0]?.fk_assesment_id : scholasticExam?.assesment_type?.[0]?.assesment_type_id,
611
+ assessment_type: scholasticExam?.template_details?.assessment_type,
612
+ isFinalExam: false,
613
+ data
614
+ };
615
+ const res = await submitExamMarks(api, payload);
616
+ const response = res;
617
+ if (response?.Status && response.Status !== 'Success') {
618
+ Alert.alert('Failed', String(response?.msg ?? response?.Message ?? 'Marks submission failed'));
619
+ return;
620
+ }
621
+ Alert.alert('Success', 'Marks submitted successfully');
622
+ } catch (error) {
623
+ Alert.alert('Error', String(error?.message ?? 'Failed to submit marks'));
624
+ } finally {
625
+ setBusy(false);
626
+ }
627
+ }, [api, scholasticExam, scholasticStudents, selectedClass?.value, selectedExam?.value, selectedSection?.value, selectedSubject?.value]);
628
+ const submitCoScholastic = useCallback(async () => {
629
+ if (!selectedClass?.value || !selectedSection?.value || !selectedExam?.value || !selectedSubject?.value) {
630
+ Alert.alert('Error', 'Missing co-scholastic filters');
631
+ return;
632
+ }
633
+ setBusy(true);
634
+ try {
635
+ const res = await submitCoScholasticMarks(api, {
636
+ formData: coFormData,
637
+ examdetails: {
638
+ class_id: selectedClass.value,
639
+ section_id: selectedSection.value,
640
+ exam_id: selectedExam.value,
641
+ subject_id: selectedSubject.value,
642
+ parentVal: selectedExam?.parent
643
+ }
644
+ });
645
+ const response = res;
646
+ if (response?.Status && response.Status !== 'Success') {
647
+ Alert.alert('Failed', String(response?.msg ?? response?.Message ?? 'Marks submission failed'));
648
+ return;
649
+ }
650
+ Alert.alert('Success', 'Marks submitted successfully');
651
+ } catch (error) {
652
+ Alert.alert('Error', String(error?.message ?? 'Failed to submit co-scholastic marks'));
653
+ } finally {
654
+ setBusy(false);
655
+ }
656
+ }, [api, coFormData, selectedClass?.value, selectedExam?.parent, selectedExam?.value, selectedSection?.value, selectedSubject?.value]);
657
+ const openRemarksEditor = useCallback(student => {
658
+ setSelectedRemarkStudent(student);
659
+ setRemarkForm(buildRemarkForm(student));
660
+ setRemarkModalVisible(true);
661
+ }, []);
662
+ const saveRemarks = useCallback(async () => {
663
+ if (!selectedRemarkStudent?.student_id && !selectedRemarkStudent?.id) {
664
+ Alert.alert('Error', 'Student is missing');
665
+ return;
666
+ }
667
+ if (!selectedExam?.value) {
668
+ Alert.alert('Error', 'Exam is missing');
669
+ return;
670
+ }
671
+ const payload = {
672
+ studentId: selectedRemarkStudent.student_id ?? selectedRemarkStudent.id,
673
+ examId: selectedExam.value,
674
+ exam_remarks: remarkForm.remarks,
675
+ metting_date_1: remarkForm.metting_date_1,
676
+ attended_1: remarkForm.attended_1,
677
+ metting_date_2: remarkForm.metting_date_2,
678
+ attended_2: remarkForm.attended_2,
679
+ metting_date_3: remarkForm.metting_date_3,
680
+ attended_3: remarkForm.attended_3,
681
+ working_days: remarkForm.working_days,
682
+ days_present: remarkForm.days_present
683
+ };
684
+ setBusy(true);
685
+ try {
686
+ const res = await submitExamRemark(api, payload);
687
+ const response = res;
688
+ if (response?.Status && response.Status !== 'Success') {
689
+ Alert.alert('Failed', String(response?.msg ?? response?.Message ?? 'Could not save remarks'));
690
+ return;
691
+ }
692
+ Alert.alert('Success', 'Remarks saved successfully');
693
+ setRemarkModalVisible(false);
694
+ setSelectedRemarkStudent(null);
695
+ await loadRemarksEntry();
696
+ } catch (error) {
697
+ Alert.alert('Error', String(error?.message ?? 'Could not save remarks'));
698
+ } finally {
699
+ setBusy(false);
700
+ }
701
+ }, [api, loadRemarksEntry, remarkForm, selectedExam?.value, selectedRemarkStudent]);
702
+ const selectedFlowLabel = useMemo(() => {
703
+ if (flow === 'scholastic') return 'Marks';
704
+ if (flow === 'coscholastic') return 'Co-Scholastic';
705
+ return 'Exam Remarks';
706
+ }, [flow]);
707
+ if (loadingFilters) {
708
+ return /*#__PURE__*/_jsx(LoadingState, {});
709
+ }
710
+ const renderFilters = () => {
711
+ return /*#__PURE__*/_jsx(ScrollView, {
712
+ contentContainerStyle: styles.content,
713
+ children: /*#__PURE__*/_jsxs(View, {
714
+ style: styles.card,
715
+ children: [/*#__PURE__*/_jsx(Text, {
716
+ style: styles.cardTitle,
717
+ children: selectedFlowLabel
718
+ }), /*#__PURE__*/_jsxs(View, {
719
+ style: styles.tabRow,
720
+ children: [/*#__PURE__*/_jsx(FlowTab, {
721
+ title: "Marks",
722
+ active: flow === 'scholastic',
723
+ onPress: () => setFlow('scholastic')
724
+ }), /*#__PURE__*/_jsx(FlowTab, {
725
+ title: "Co-Scholastic",
726
+ active: flow === 'coscholastic',
727
+ onPress: () => setFlow('coscholastic')
728
+ }), /*#__PURE__*/_jsx(FlowTab, {
729
+ title: "Exam Remarks",
730
+ active: flow === 'remarks',
731
+ onPress: () => setFlow('remarks')
732
+ })]
733
+ }), /*#__PURE__*/_jsx(SelectField, {
734
+ label: "Class",
735
+ value: selectedClass,
736
+ options: classes,
737
+ placeholder: "Select class",
738
+ onChange: next => {
739
+ setSelectedClass(next);
740
+ setSelectedSection(null);
741
+ setSelectedExam(null);
742
+ setSelectedSubject(null);
743
+ setSections([]);
744
+ setExams([]);
745
+ setSubjects([]);
746
+ }
747
+ }), /*#__PURE__*/_jsx(SelectField, {
748
+ label: "Section",
749
+ value: selectedSection,
750
+ options: sections,
751
+ placeholder: "Select section",
752
+ onChange: next => {
753
+ setSelectedSection(next);
754
+ setSelectedSubject(null);
755
+ }
756
+ }), /*#__PURE__*/_jsx(SelectField, {
757
+ label: "Exam",
758
+ value: selectedExam,
759
+ options: exams,
760
+ placeholder: "Select exam",
761
+ onChange: next => {
762
+ setSelectedExam(next);
763
+ setSelectedSubject(null);
764
+ }
765
+ }), flow !== 'remarks' ? /*#__PURE__*/_jsx(SelectField, {
766
+ label: flow === 'scholastic' ? 'Subject' : 'Category',
767
+ value: selectedSubject,
768
+ options: subjects,
769
+ placeholder: flow === 'scholastic' ? 'Select subject' : 'Select category',
770
+ onChange: setSelectedSubject
771
+ }) : null, sessionId === undefined ? /*#__PURE__*/_jsx(Text, {
772
+ style: styles.helperText,
773
+ children: "Pass `sessionId` to `MarksScreen` to load exams and marks entry."
774
+ }) : null, /*#__PURE__*/_jsx(TouchableOpacity, {
775
+ onPress: startEntry,
776
+ style: styles.primaryBtn,
777
+ disabled: busy,
778
+ children: busy ? /*#__PURE__*/_jsx(ActivityIndicator, {
779
+ color: "#FFFFFF"
780
+ }) : /*#__PURE__*/_jsx(Text, {
781
+ style: styles.primaryBtnText,
782
+ children: flow === 'remarks' ? 'Open Remarks' : 'Open Entry'
783
+ })
784
+ })]
785
+ })
786
+ });
787
+ };
788
+ const renderScholasticEntry = () => {
789
+ if (!scholasticExam) {
790
+ return /*#__PURE__*/_jsx(EmptyState, {
791
+ title: "No Data Found"
792
+ });
793
+ }
794
+ const isAdditional = scholasticExam?.subject_type === 'Additional';
795
+ const isMinorMarks = scholasticExam?.template_details?.minor_sub_marks_type === 'MARKS';
796
+ const useGradeForSubject = isAdditional && !isMinorMarks;
797
+ const useGradeForAssessment = scholasticExam?.assessment_type === 'only_assessment';
798
+ return /*#__PURE__*/_jsx(FlatList, {
799
+ data: scholasticStudents,
800
+ keyExtractor: (item, index) => String(item?.id ?? index),
801
+ contentContainerStyle: styles.content,
802
+ ListHeaderComponent: /*#__PURE__*/_jsxs(View, {
803
+ style: styles.card,
804
+ children: [/*#__PURE__*/_jsx(Text, {
805
+ style: styles.cardTitle,
806
+ children: "Scholastic Entry"
807
+ }), /*#__PURE__*/_jsxs(View, {
808
+ style: styles.infoRow,
809
+ children: [/*#__PURE__*/_jsxs(Text, {
810
+ style: styles.infoText,
811
+ children: ["Class: ", selectedClass?.label]
812
+ }), /*#__PURE__*/_jsxs(Text, {
813
+ style: styles.infoText,
814
+ children: ["Section: ", selectedSection?.label]
815
+ })]
816
+ }), /*#__PURE__*/_jsxs(View, {
817
+ style: styles.infoRow,
818
+ children: [/*#__PURE__*/_jsxs(Text, {
819
+ style: styles.infoText,
820
+ children: ["Exam: ", selectedExam?.label]
821
+ }), /*#__PURE__*/_jsxs(Text, {
822
+ style: styles.infoText,
823
+ children: ["Subject: ", selectedSubject?.label]
824
+ })]
825
+ }), /*#__PURE__*/_jsxs(View, {
826
+ style: styles.actionRow,
827
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
828
+ onPress: () => setEntryMode('filters'),
829
+ style: styles.secondaryBtn,
830
+ children: /*#__PURE__*/_jsx(Text, {
831
+ style: styles.secondaryBtnText,
832
+ children: "Back"
833
+ })
834
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
835
+ onPress: submitScholastic,
836
+ style: styles.primaryBtnCompact,
837
+ children: busy ? /*#__PURE__*/_jsx(ActivityIndicator, {
838
+ color: "#FFFFFF"
839
+ }) : /*#__PURE__*/_jsx(Text, {
840
+ style: styles.primaryBtnText,
841
+ children: "Submit Marks"
842
+ })
843
+ })]
844
+ })]
845
+ }),
846
+ renderItem: ({
847
+ item
848
+ }) => /*#__PURE__*/_jsxs(View, {
849
+ style: styles.studentCard,
850
+ children: [/*#__PURE__*/_jsxs(View, {
851
+ style: styles.studentHeader,
852
+ children: [/*#__PURE__*/_jsxs(Text, {
853
+ style: styles.studentName,
854
+ children: [String(item?.firstname ?? ''), " ", String(item?.lastname ?? '')]
855
+ }), /*#__PURE__*/_jsxs(Text, {
856
+ style: styles.rollText,
857
+ children: ["Roll No: ", String(item?.roll_no ?? '-')]
858
+ })]
859
+ }), scholasticExam?.is_theory === 'yes' && scholasticExam?.assessment_type !== 'only_assessment' ? /*#__PURE__*/_jsx(MarksInput, {
860
+ label: "Theory",
861
+ value: String(item?.main_subject_marks ?? ''),
862
+ fullMarks: scholasticExam?.full_marks,
863
+ absent: Boolean(item?.theory_absent),
864
+ useSelect: useGradeForSubject,
865
+ onTextChange: value => handleScholasticMarkChange(item.id, 'main_subject_marks', value),
866
+ onPick: () => openGradePicker('Select Theory Grade', scholasticGrades, value => handleScholasticMarkChange(item.id, 'main_subject_marks', value)),
867
+ onAbsentChange: value => handleScholasticAbsentChange(item.id, 'theory', value)
868
+ }) : null, scholasticExam?.is_practical === 'yes' ? /*#__PURE__*/_jsx(MarksInput, {
869
+ label: "Practical",
870
+ value: String(item?.practical_subject_marks ?? ''),
871
+ fullMarks: scholasticExam?.practical_full_marks,
872
+ absent: Boolean(item?.practical_absent),
873
+ useSelect: useGradeForSubject,
874
+ onTextChange: value => handleScholasticMarkChange(item.id, 'practical_subject_marks', value),
875
+ onPick: () => openGradePicker('Select Practical Grade', scholasticGrades, value => handleScholasticMarkChange(item.id, 'practical_subject_marks', value)),
876
+ onAbsentChange: value => handleScholasticAbsentChange(item.id, 'practical', value)
877
+ }) : null, scholasticExam?.subject_type !== 'Additional' ? scholasticExam?.assesment_type?.map((assessment, index) => {
878
+ const currentMark = (item.assement_marks ?? []).find(mark => matchesValue(mark?.assement_id, assessment.id));
879
+ return /*#__PURE__*/_jsx(MarksInput, {
880
+ label: String(assessment?.title ?? `Assessment ${index + 1}`),
881
+ value: String(currentMark?.marks ?? ''),
882
+ fullMarks: assessment?.max_marks,
883
+ absent: Boolean(currentMark?.is_absent),
884
+ useSelect: useGradeForAssessment,
885
+ onTextChange: value => handleScholasticMarkChange(item.id, 'assessment', value, index),
886
+ onPick: () => openGradePicker(`Select ${String(assessment?.title ?? 'Assessment')} Grade`, scholasticGrades, value => handleScholasticMarkChange(item.id, 'assessment', value, index)),
887
+ onAbsentChange: value => handleScholasticAbsentChange(item.id, 'assessment', value, index)
888
+ }, `${item.id}-${assessment.id ?? index}`);
889
+ }) : null]
890
+ }),
891
+ ListEmptyComponent: /*#__PURE__*/_jsx(EmptyState, {
892
+ title: "No students found"
893
+ })
894
+ });
895
+ };
896
+ const renderCoScholasticEntry = () => {
897
+ return /*#__PURE__*/_jsx(FlatList, {
898
+ data: coStudents,
899
+ keyExtractor: (item, index) => String(item?.id ?? index),
900
+ contentContainerStyle: styles.content,
901
+ ListHeaderComponent: /*#__PURE__*/_jsxs(View, {
902
+ style: styles.card,
903
+ children: [/*#__PURE__*/_jsx(Text, {
904
+ style: styles.cardTitle,
905
+ children: "Co-Scholastic Entry"
906
+ }), /*#__PURE__*/_jsxs(View, {
907
+ style: styles.infoRow,
908
+ children: [/*#__PURE__*/_jsxs(Text, {
909
+ style: styles.infoText,
910
+ children: ["Class: ", selectedClass?.label]
911
+ }), /*#__PURE__*/_jsxs(Text, {
912
+ style: styles.infoText,
913
+ children: ["Section: ", selectedSection?.label]
914
+ })]
915
+ }), /*#__PURE__*/_jsxs(View, {
916
+ style: styles.infoRow,
917
+ children: [/*#__PURE__*/_jsxs(Text, {
918
+ style: styles.infoText,
919
+ children: ["Exam: ", selectedExam?.label]
920
+ }), /*#__PURE__*/_jsxs(Text, {
921
+ style: styles.infoText,
922
+ children: ["Category: ", selectedSubject?.label]
923
+ })]
924
+ }), /*#__PURE__*/_jsxs(View, {
925
+ style: styles.actionRow,
926
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
927
+ onPress: () => setEntryMode('filters'),
928
+ style: styles.secondaryBtn,
929
+ children: /*#__PURE__*/_jsx(Text, {
930
+ style: styles.secondaryBtnText,
931
+ children: "Back"
932
+ })
933
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
934
+ onPress: submitCoScholastic,
935
+ style: styles.primaryBtnCompact,
936
+ children: busy ? /*#__PURE__*/_jsx(ActivityIndicator, {
937
+ color: "#FFFFFF"
938
+ }) : /*#__PURE__*/_jsx(Text, {
939
+ style: styles.primaryBtnText,
940
+ children: "Submit Marks"
941
+ })
942
+ })]
943
+ })]
944
+ }),
945
+ renderItem: ({
946
+ item
947
+ }) => {
948
+ return /*#__PURE__*/_jsxs(View, {
949
+ style: styles.studentCard,
950
+ children: [/*#__PURE__*/_jsxs(View, {
951
+ style: styles.studentHeader,
952
+ children: [/*#__PURE__*/_jsxs(Text, {
953
+ style: styles.studentName,
954
+ children: [String(item?.firstname ?? ''), " ", String(item?.lastname ?? '')]
955
+ }), /*#__PURE__*/_jsxs(Text, {
956
+ style: styles.rollText,
957
+ children: ["Roll No: ", String(item?.roll_no ?? '-')]
958
+ })]
959
+ }), Array.from({
960
+ length: Math.ceil(coAreas.length / 3)
961
+ }, (_, rowIndex) => {
962
+ const rowItems = coAreas.slice(rowIndex * 3, rowIndex * 3 + 3);
963
+ return /*#__PURE__*/_jsx(View, {
964
+ style: styles.criteriaRow,
965
+ children: rowItems.map(area => {
966
+ const row = coFormData.find(form => matchesValue(form.studentid, item.id));
967
+ const currentValue = String(row?.[String(area.id ?? '')] ?? '0');
968
+ const currentGrade = findOption(coGrades, currentValue)?.label ?? 'Select Grade';
969
+ return /*#__PURE__*/_jsxs(View, {
970
+ style: styles.criteriaCol,
971
+ children: [/*#__PURE__*/_jsx(Text, {
972
+ style: styles.criteriaLabel,
973
+ children: String(area?.skill ?? '-')
974
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
975
+ style: styles.markSelectBtn,
976
+ onPress: () => openGradePicker(`Select Grade for ${String(area?.skill ?? '')}`, coGrades, value => setCoFormData(prev => prev.map(form => matchesValue(form.studentid, item.id) ? {
977
+ ...form,
978
+ [String(area.id ?? '')]: value
979
+ } : form))),
980
+ children: /*#__PURE__*/_jsx(Text, {
981
+ style: styles.markSelectText,
982
+ children: currentGrade
983
+ })
984
+ })]
985
+ }, String(area.id ?? ''));
986
+ })
987
+ }, rowIndex);
988
+ })]
989
+ });
990
+ },
991
+ ListEmptyComponent: /*#__PURE__*/_jsx(EmptyState, {
992
+ title: "No students found"
993
+ })
994
+ });
995
+ };
996
+ const renderRemarksEntry = () => {
997
+ return /*#__PURE__*/_jsx(FlatList, {
998
+ data: remarkStudents,
999
+ keyExtractor: (item, index) => String(item?.student_id ?? item?.id ?? index),
1000
+ contentContainerStyle: styles.content,
1001
+ ListHeaderComponent: /*#__PURE__*/_jsxs(View, {
1002
+ style: styles.card,
1003
+ children: [/*#__PURE__*/_jsx(Text, {
1004
+ style: styles.cardTitle,
1005
+ children: "Exam Remarks"
1006
+ }), /*#__PURE__*/_jsxs(View, {
1007
+ style: styles.infoRow,
1008
+ children: [/*#__PURE__*/_jsxs(Text, {
1009
+ style: styles.infoText,
1010
+ children: ["Class: ", selectedClass?.label]
1011
+ }), /*#__PURE__*/_jsxs(Text, {
1012
+ style: styles.infoText,
1013
+ children: ["Section: ", selectedSection?.label]
1014
+ })]
1015
+ }), /*#__PURE__*/_jsx(View, {
1016
+ style: styles.infoRow,
1017
+ children: /*#__PURE__*/_jsxs(Text, {
1018
+ style: styles.infoText,
1019
+ children: ["Exam: ", selectedExam?.label]
1020
+ })
1021
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
1022
+ onPress: () => setEntryMode('filters'),
1023
+ style: styles.secondaryBtn,
1024
+ children: /*#__PURE__*/_jsx(Text, {
1025
+ style: styles.secondaryBtnText,
1026
+ children: "Back"
1027
+ })
1028
+ })]
1029
+ }),
1030
+ renderItem: ({
1031
+ item
1032
+ }) => {
1033
+ const hasRemarks = String(item?.exam_remarks ?? '').trim().length > 0;
1034
+ return /*#__PURE__*/_jsx(View, {
1035
+ style: [styles.studentCard, hasRemarks ? styles.successBorder : styles.errorBorderLeft],
1036
+ children: /*#__PURE__*/_jsxs(View, {
1037
+ style: styles.remarkTopRow,
1038
+ children: [/*#__PURE__*/_jsxs(View, {
1039
+ style: {
1040
+ flex: 1
1041
+ },
1042
+ children: [/*#__PURE__*/_jsxs(Text, {
1043
+ style: styles.studentName,
1044
+ children: [String(item?.firstname ?? ''), " ", String(item?.lastname ?? '')]
1045
+ }), /*#__PURE__*/_jsxs(Text, {
1046
+ style: styles.rollText,
1047
+ children: ["Roll No: ", String(item?.roll_no ?? '-')]
1048
+ }), hasRemarks ? /*#__PURE__*/_jsxs(Text, {
1049
+ style: styles.remarkText,
1050
+ children: ["Remarks: ", String(item?.exam_remarks ?? '')]
1051
+ }) : null]
1052
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
1053
+ style: styles.primaryBtnSmall,
1054
+ onPress: () => openRemarksEditor(item),
1055
+ children: /*#__PURE__*/_jsx(Text, {
1056
+ style: styles.primaryBtnSmallText,
1057
+ children: "Add Remarks"
1058
+ })
1059
+ })]
1060
+ })
1061
+ });
1062
+ },
1063
+ ListEmptyComponent: /*#__PURE__*/_jsx(EmptyState, {
1064
+ title: "No students found"
1065
+ })
1066
+ });
1067
+ };
1068
+ return /*#__PURE__*/_jsxs(SafeAreaView, {
1069
+ style: styles.root,
1070
+ children: [/*#__PURE__*/_jsx(View, {
1071
+ style: styles.screenHeader,
1072
+ children: /*#__PURE__*/_jsx(Text, {
1073
+ style: styles.screenTitle,
1074
+ children: "Marks"
1075
+ })
1076
+ }), entryMode === 'filters' ? renderFilters() : null, entryMode === 'scholastic' ? renderScholasticEntry() : null, entryMode === 'coscholastic' ? renderCoScholasticEntry() : null, entryMode === 'remarks' ? renderRemarksEntry() : null, /*#__PURE__*/_jsx(Modal, {
1077
+ visible: gradeModal.visible,
1078
+ transparent: true,
1079
+ animationType: "fade",
1080
+ children: /*#__PURE__*/_jsx(Pressable, {
1081
+ style: styles.modalOverlay,
1082
+ onPress: closeGradePicker,
1083
+ children: /*#__PURE__*/_jsxs(Pressable, {
1084
+ style: styles.modalCard,
1085
+ onPress: () => {},
1086
+ children: [/*#__PURE__*/_jsx(Text, {
1087
+ style: styles.modalTitle,
1088
+ children: gradeModal.title
1089
+ }), /*#__PURE__*/_jsx(FlatList, {
1090
+ data: gradeModal.options,
1091
+ keyExtractor: (item, index) => `${item.value}-${index}`,
1092
+ renderItem: ({
1093
+ item
1094
+ }) => /*#__PURE__*/_jsx(Pressable, {
1095
+ style: styles.optionRow,
1096
+ onPress: () => {
1097
+ gradeModal.onSelect?.(String(item.value));
1098
+ closeGradePicker();
1099
+ },
1100
+ children: /*#__PURE__*/_jsx(Text, {
1101
+ style: styles.optionText,
1102
+ children: item.label
1103
+ })
1104
+ })
1105
+ })]
1106
+ })
1107
+ })
1108
+ }), /*#__PURE__*/_jsx(Modal, {
1109
+ visible: remarkModalVisible,
1110
+ transparent: true,
1111
+ animationType: "slide",
1112
+ children: /*#__PURE__*/_jsx(View, {
1113
+ style: styles.modalOverlay,
1114
+ children: /*#__PURE__*/_jsxs(View, {
1115
+ style: styles.remarkModalCard,
1116
+ children: [/*#__PURE__*/_jsxs(View, {
1117
+ style: styles.remarkHeader,
1118
+ children: [/*#__PURE__*/_jsx(Text, {
1119
+ style: styles.modalTitle,
1120
+ children: "Remarks and Others"
1121
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
1122
+ onPress: () => {
1123
+ setRemarkModalVisible(false);
1124
+ setSelectedRemarkStudent(null);
1125
+ },
1126
+ style: styles.secondaryBtn,
1127
+ children: /*#__PURE__*/_jsx(Text, {
1128
+ style: styles.secondaryBtnText,
1129
+ children: "Close"
1130
+ })
1131
+ })]
1132
+ }), /*#__PURE__*/_jsxs(ScrollView, {
1133
+ showsVerticalScrollIndicator: false,
1134
+ children: [selectedRemarkStudent ? /*#__PURE__*/_jsxs(View, {
1135
+ style: styles.field,
1136
+ children: [/*#__PURE__*/_jsxs(Text, {
1137
+ style: styles.studentName,
1138
+ children: [String(selectedRemarkStudent?.firstname ?? ''), ' ', String(selectedRemarkStudent?.lastname ?? '')]
1139
+ }), /*#__PURE__*/_jsxs(Text, {
1140
+ style: styles.rollText,
1141
+ children: ["Roll No: ", String(selectedRemarkStudent?.roll_no ?? '-')]
1142
+ })]
1143
+ }) : null, /*#__PURE__*/_jsx(SelectField, {
1144
+ label: "Remark",
1145
+ value: remarkForm.selectedRemark ? {
1146
+ label: remarkForm.selectedRemark,
1147
+ value: remarkForm.selectedRemark
1148
+ } : null,
1149
+ options: REMARK_OPTIONS.map(item => ({
1150
+ label: item,
1151
+ value: item
1152
+ })),
1153
+ placeholder: "Select a remark",
1154
+ onChange: next => {
1155
+ const selected = String(next.value);
1156
+ setRemarkForm(prev => ({
1157
+ ...prev,
1158
+ selectedRemark: selected,
1159
+ remarks: selected === 'Others' ? '' : selected
1160
+ }));
1161
+ }
1162
+ }), remarkForm.selectedRemark === 'Others' ? /*#__PURE__*/_jsxs(View, {
1163
+ style: styles.field,
1164
+ children: [/*#__PURE__*/_jsx(Text, {
1165
+ style: styles.label,
1166
+ children: "Custom Remark"
1167
+ }), /*#__PURE__*/_jsx(TextInput, {
1168
+ value: remarkForm.remarks,
1169
+ onChangeText: value => setRemarkForm(prev => ({
1170
+ ...prev,
1171
+ remarks: value
1172
+ })),
1173
+ placeholder: "Enter custom remark",
1174
+ placeholderTextColor: "#9CA3AF",
1175
+ multiline: true,
1176
+ style: [styles.input, styles.textarea]
1177
+ })]
1178
+ }) : null, /*#__PURE__*/_jsx(Text, {
1179
+ style: styles.sectionTitle,
1180
+ children: "Meeting Dates"
1181
+ }), [['metting_date_1', 'attended_1'], ['metting_date_2', 'attended_2'], ['metting_date_3', 'attended_3']].map((pair, index) => {
1182
+ const dateKey = pair[0];
1183
+ const attendedKey = pair[1];
1184
+ return /*#__PURE__*/_jsxs(View, {
1185
+ style: styles.doubleRow,
1186
+ children: [/*#__PURE__*/_jsxs(View, {
1187
+ style: styles.doubleCol,
1188
+ children: [/*#__PURE__*/_jsxs(Text, {
1189
+ style: styles.label,
1190
+ children: ["Date ", index + 1]
1191
+ }), /*#__PURE__*/_jsx(TextInput, {
1192
+ value: remarkForm[dateKey],
1193
+ onChangeText: value => setRemarkForm(prev => ({
1194
+ ...prev,
1195
+ [dateKey]: value
1196
+ })),
1197
+ placeholder: "Date",
1198
+ placeholderTextColor: "#9CA3AF",
1199
+ style: styles.input
1200
+ })]
1201
+ }), /*#__PURE__*/_jsxs(View, {
1202
+ style: styles.doubleCol,
1203
+ children: [/*#__PURE__*/_jsxs(Text, {
1204
+ style: styles.label,
1205
+ children: ["Attended ", index + 1]
1206
+ }), /*#__PURE__*/_jsx(TextInput, {
1207
+ value: remarkForm[attendedKey],
1208
+ onChangeText: value => setRemarkForm(prev => ({
1209
+ ...prev,
1210
+ [attendedKey]: value
1211
+ })),
1212
+ placeholder: "Attended",
1213
+ placeholderTextColor: "#9CA3AF",
1214
+ style: styles.input
1215
+ })]
1216
+ })]
1217
+ }, String(dateKey));
1218
+ }), /*#__PURE__*/_jsx(Text, {
1219
+ style: styles.sectionTitle,
1220
+ children: "Attendance Detailed"
1221
+ }), /*#__PURE__*/_jsxs(View, {
1222
+ style: styles.doubleRow,
1223
+ children: [/*#__PURE__*/_jsxs(View, {
1224
+ style: styles.doubleCol,
1225
+ children: [/*#__PURE__*/_jsx(Text, {
1226
+ style: styles.label,
1227
+ children: "Total Working Days"
1228
+ }), /*#__PURE__*/_jsx(TextInput, {
1229
+ value: remarkForm.working_days,
1230
+ onChangeText: value => setRemarkForm(prev => ({
1231
+ ...prev,
1232
+ working_days: value
1233
+ })),
1234
+ placeholder: "Total working days",
1235
+ placeholderTextColor: "#9CA3AF",
1236
+ keyboardType: "numeric",
1237
+ style: styles.input
1238
+ })]
1239
+ }), /*#__PURE__*/_jsxs(View, {
1240
+ style: styles.doubleCol,
1241
+ children: [/*#__PURE__*/_jsx(Text, {
1242
+ style: styles.label,
1243
+ children: "Days Present"
1244
+ }), /*#__PURE__*/_jsx(TextInput, {
1245
+ value: remarkForm.days_present,
1246
+ onChangeText: value => setRemarkForm(prev => ({
1247
+ ...prev,
1248
+ days_present: value
1249
+ })),
1250
+ placeholder: "Number of days present",
1251
+ placeholderTextColor: "#9CA3AF",
1252
+ keyboardType: "numeric",
1253
+ style: styles.input
1254
+ })]
1255
+ })]
1256
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
1257
+ onPress: saveRemarks,
1258
+ style: styles.primaryBtn,
1259
+ children: busy ? /*#__PURE__*/_jsx(ActivityIndicator, {
1260
+ color: "#FFFFFF"
1261
+ }) : /*#__PURE__*/_jsx(Text, {
1262
+ style: styles.primaryBtnText,
1263
+ children: "Save"
1264
+ })
1265
+ })]
1266
+ })]
1267
+ })
1268
+ })
1269
+ })]
1270
+ });
1271
+ }
1272
+ const styles = StyleSheet.create({
1273
+ root: {
1274
+ flex: 1,
1275
+ backgroundColor: '#F8FAFC'
1276
+ },
1277
+ screenHeader: {
1278
+ paddingHorizontal: 16,
1279
+ paddingVertical: 14,
1280
+ borderBottomWidth: 1,
1281
+ borderBottomColor: '#E5E7EB',
1282
+ backgroundColor: '#FFFFFF'
1283
+ },
1284
+ screenTitle: {
1285
+ fontSize: 18,
1286
+ fontWeight: '700',
1287
+ color: '#111827'
1288
+ },
1289
+ content: {
1290
+ padding: 16,
1291
+ gap: 12
1292
+ },
1293
+ card: {
1294
+ backgroundColor: '#FFFFFF',
1295
+ borderWidth: 1,
1296
+ borderColor: '#E5E7EB',
1297
+ borderRadius: 16,
1298
+ padding: 16
1299
+ },
1300
+ cardTitle: {
1301
+ fontSize: 17,
1302
+ fontWeight: '700',
1303
+ color: '#111827',
1304
+ marginBottom: 12
1305
+ },
1306
+ field: {
1307
+ marginTop: 10,
1308
+ gap: 6
1309
+ },
1310
+ label: {
1311
+ fontSize: 12,
1312
+ fontWeight: '600',
1313
+ color: '#6B7280'
1314
+ },
1315
+ select: {
1316
+ borderWidth: 1,
1317
+ borderColor: '#E5E7EB',
1318
+ borderRadius: 12,
1319
+ paddingHorizontal: 12,
1320
+ paddingVertical: 12,
1321
+ backgroundColor: '#FFFFFF'
1322
+ },
1323
+ selectText: {
1324
+ fontSize: 14,
1325
+ color: '#111827'
1326
+ },
1327
+ helperText: {
1328
+ marginTop: 10,
1329
+ fontSize: 12,
1330
+ color: '#6B7280'
1331
+ },
1332
+ tabRow: {
1333
+ flexDirection: 'row',
1334
+ gap: 8,
1335
+ flexWrap: 'wrap',
1336
+ marginBottom: 8
1337
+ },
1338
+ tabBtn: {
1339
+ flexGrow: 1,
1340
+ minWidth: '30%',
1341
+ borderWidth: 1,
1342
+ borderColor: '#CBD5E1',
1343
+ borderRadius: 999,
1344
+ paddingVertical: 10,
1345
+ paddingHorizontal: 12,
1346
+ alignItems: 'center',
1347
+ backgroundColor: '#FFFFFF'
1348
+ },
1349
+ tabBtnActive: {
1350
+ backgroundColor: '#2563EB',
1351
+ borderColor: '#2563EB'
1352
+ },
1353
+ tabBtnText: {
1354
+ fontSize: 12,
1355
+ fontWeight: '700',
1356
+ color: '#111827'
1357
+ },
1358
+ tabBtnTextActive: {
1359
+ color: '#FFFFFF'
1360
+ },
1361
+ primaryBtn: {
1362
+ marginTop: 16,
1363
+ backgroundColor: '#2563EB',
1364
+ borderRadius: 12,
1365
+ paddingVertical: 14,
1366
+ alignItems: 'center',
1367
+ justifyContent: 'center'
1368
+ },
1369
+ primaryBtnCompact: {
1370
+ flex: 1,
1371
+ backgroundColor: '#2563EB',
1372
+ borderRadius: 12,
1373
+ paddingVertical: 14,
1374
+ alignItems: 'center',
1375
+ justifyContent: 'center'
1376
+ },
1377
+ primaryBtnText: {
1378
+ color: '#FFFFFF',
1379
+ fontSize: 14,
1380
+ fontWeight: '700'
1381
+ },
1382
+ secondaryBtn: {
1383
+ minWidth: 88,
1384
+ paddingVertical: 12,
1385
+ paddingHorizontal: 16,
1386
+ borderRadius: 12,
1387
+ backgroundColor: '#E5E7EB',
1388
+ alignItems: 'center',
1389
+ justifyContent: 'center'
1390
+ },
1391
+ secondaryBtnText: {
1392
+ color: '#111827',
1393
+ fontSize: 14,
1394
+ fontWeight: '700'
1395
+ },
1396
+ actionRow: {
1397
+ marginTop: 12,
1398
+ flexDirection: 'row',
1399
+ gap: 10
1400
+ },
1401
+ infoRow: {
1402
+ flexDirection: 'row',
1403
+ justifyContent: 'space-between',
1404
+ gap: 8,
1405
+ marginTop: 6
1406
+ },
1407
+ infoText: {
1408
+ fontSize: 12,
1409
+ color: '#4B5563',
1410
+ flex: 1
1411
+ },
1412
+ studentCard: {
1413
+ backgroundColor: '#FFFFFF',
1414
+ borderWidth: 1,
1415
+ borderColor: '#E5E7EB',
1416
+ borderRadius: 16,
1417
+ padding: 16,
1418
+ marginBottom: 12
1419
+ },
1420
+ studentHeader: {
1421
+ paddingBottom: 12,
1422
+ marginBottom: 12,
1423
+ borderBottomWidth: 1,
1424
+ borderBottomColor: '#E5E7EB'
1425
+ },
1426
+ studentName: {
1427
+ fontSize: 16,
1428
+ fontWeight: '700',
1429
+ color: '#111827'
1430
+ },
1431
+ rollText: {
1432
+ marginTop: 4,
1433
+ fontSize: 13,
1434
+ color: '#6B7280'
1435
+ },
1436
+ markField: {
1437
+ marginTop: 10,
1438
+ padding: 12,
1439
+ borderWidth: 1,
1440
+ borderColor: '#E5E7EB',
1441
+ borderRadius: 12,
1442
+ backgroundColor: '#F9FAFB'
1443
+ },
1444
+ markHeader: {
1445
+ flexDirection: 'row',
1446
+ justifyContent: 'space-between',
1447
+ marginBottom: 8,
1448
+ gap: 8
1449
+ },
1450
+ markLabel: {
1451
+ fontSize: 13,
1452
+ fontWeight: '700',
1453
+ color: '#111827',
1454
+ flex: 1
1455
+ },
1456
+ markMax: {
1457
+ fontSize: 12,
1458
+ color: '#6B7280'
1459
+ },
1460
+ input: {
1461
+ borderWidth: 1,
1462
+ borderColor: '#D1D5DB',
1463
+ borderRadius: 10,
1464
+ paddingHorizontal: 12,
1465
+ paddingVertical: 10,
1466
+ backgroundColor: '#FFFFFF',
1467
+ color: '#111827'
1468
+ },
1469
+ textarea: {
1470
+ minHeight: 90,
1471
+ textAlignVertical: 'top'
1472
+ },
1473
+ markSelectBtn: {
1474
+ borderWidth: 1,
1475
+ borderColor: '#D1D5DB',
1476
+ borderRadius: 10,
1477
+ paddingHorizontal: 12,
1478
+ paddingVertical: 12,
1479
+ backgroundColor: '#FFFFFF'
1480
+ },
1481
+ markSelectText: {
1482
+ fontSize: 14,
1483
+ color: '#111827'
1484
+ },
1485
+ disabledInput: {
1486
+ opacity: 0.55
1487
+ },
1488
+ toggleLine: {
1489
+ marginTop: 10,
1490
+ flexDirection: 'row',
1491
+ alignItems: 'center',
1492
+ justifyContent: 'space-between'
1493
+ },
1494
+ toggleText: {
1495
+ fontSize: 12,
1496
+ color: '#4B5563',
1497
+ fontWeight: '600'
1498
+ },
1499
+ errorText: {
1500
+ marginTop: 6,
1501
+ fontSize: 12,
1502
+ color: '#DC2626'
1503
+ },
1504
+ errorBorder: {
1505
+ borderColor: '#DC2626'
1506
+ },
1507
+ criteriaRow: {
1508
+ flexDirection: 'row',
1509
+ gap: 8,
1510
+ marginTop: 10
1511
+ },
1512
+ criteriaCol: {
1513
+ flex: 1
1514
+ },
1515
+ criteriaLabel: {
1516
+ minHeight: 36,
1517
+ fontSize: 12,
1518
+ fontWeight: '700',
1519
+ color: '#2563EB',
1520
+ textAlign: 'center',
1521
+ marginBottom: 6
1522
+ },
1523
+ primaryBtnSmall: {
1524
+ paddingHorizontal: 12,
1525
+ paddingVertical: 10,
1526
+ borderRadius: 10,
1527
+ backgroundColor: '#2563EB',
1528
+ alignItems: 'center',
1529
+ justifyContent: 'center'
1530
+ },
1531
+ primaryBtnSmallText: {
1532
+ color: '#FFFFFF',
1533
+ fontSize: 12,
1534
+ fontWeight: '700'
1535
+ },
1536
+ remarkTopRow: {
1537
+ flexDirection: 'row',
1538
+ alignItems: 'center',
1539
+ gap: 12
1540
+ },
1541
+ remarkText: {
1542
+ marginTop: 8,
1543
+ fontSize: 12,
1544
+ color: '#16A34A'
1545
+ },
1546
+ successBorder: {
1547
+ borderLeftWidth: 4,
1548
+ borderLeftColor: '#16A34A'
1549
+ },
1550
+ errorBorderLeft: {
1551
+ borderLeftWidth: 4,
1552
+ borderLeftColor: '#DC2626'
1553
+ },
1554
+ modalOverlay: {
1555
+ flex: 1,
1556
+ backgroundColor: 'rgba(0,0,0,0.45)',
1557
+ justifyContent: 'center',
1558
+ padding: 16
1559
+ },
1560
+ modalCard: {
1561
+ backgroundColor: '#FFFFFF',
1562
+ borderRadius: 16,
1563
+ maxHeight: '80%',
1564
+ overflow: 'hidden'
1565
+ },
1566
+ modalTitle: {
1567
+ paddingHorizontal: 16,
1568
+ paddingTop: 16,
1569
+ paddingBottom: 8,
1570
+ fontSize: 16,
1571
+ fontWeight: '700',
1572
+ color: '#111827'
1573
+ },
1574
+ optionRow: {
1575
+ paddingHorizontal: 16,
1576
+ paddingVertical: 12,
1577
+ borderTopWidth: 1,
1578
+ borderTopColor: '#F3F4F6'
1579
+ },
1580
+ optionText: {
1581
+ fontSize: 14,
1582
+ color: '#111827'
1583
+ },
1584
+ optionEmpty: {
1585
+ paddingHorizontal: 16,
1586
+ paddingVertical: 12,
1587
+ color: '#6B7280'
1588
+ },
1589
+ remarkModalCard: {
1590
+ backgroundColor: '#FFFFFF',
1591
+ borderRadius: 16,
1592
+ maxHeight: '88%',
1593
+ padding: 16
1594
+ },
1595
+ remarkHeader: {
1596
+ flexDirection: 'row',
1597
+ justifyContent: 'space-between',
1598
+ alignItems: 'center',
1599
+ marginBottom: 8
1600
+ },
1601
+ sectionTitle: {
1602
+ marginTop: 16,
1603
+ fontSize: 15,
1604
+ fontWeight: '700',
1605
+ color: '#111827'
1606
+ },
1607
+ doubleRow: {
1608
+ flexDirection: 'row',
1609
+ gap: 10,
1610
+ marginTop: 10
1611
+ },
1612
+ doubleCol: {
1613
+ flex: 1
1614
+ }
1615
+ });