@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,54 @@
1
+ "use strict";
2
+
3
+ import { endpoints } from "../../../core/api/endpoints.js";
4
+ export async function fetchNotesList(api, params) {
5
+ const page = params.page ?? 1;
6
+ const perPage = params.perPage ?? 10;
7
+ const res = await api.get(endpoints.notes.listByClassSection({
8
+ page,
9
+ perPage,
10
+ classId: params.classId,
11
+ sectionId: params.sectionId,
12
+ subjectId: params.subjectId
13
+ }));
14
+ return res.data;
15
+ }
16
+ export async function fetchNotesClasses(api) {
17
+ const res = await api.get(endpoints.notes.classDropdown);
18
+ return res.data;
19
+ }
20
+ export async function fetchNotesSections(api, args) {
21
+ const res = await api.get(endpoints.notes.sectionDropdown(args));
22
+ return res.data;
23
+ }
24
+ export async function fetchNotesSubjects(api, args) {
25
+ const res = await api.get(endpoints.notes.teacherSubjectsByClass(args));
26
+ return res.data;
27
+ }
28
+ export async function fetchNoteDetails(api, args) {
29
+ const res = await api.get(endpoints.notes.details(args));
30
+ return res.data;
31
+ }
32
+ export async function uploadNoteFile(api, file) {
33
+ const formData = new FormData();
34
+ formData.append('file', {
35
+ uri: file.uri,
36
+ name: file.name,
37
+ type: file.type
38
+ });
39
+ formData.append('filepath', 'uploads/student/note/');
40
+ const res = await api.post(endpoints.notes.upload, formData, {
41
+ headers: {
42
+ 'Content-Type': 'multipart/form-data'
43
+ }
44
+ });
45
+ return res.data;
46
+ }
47
+ export async function createNote(api, payload) {
48
+ const res = await api.post(endpoints.notes.add, payload);
49
+ return res.data;
50
+ }
51
+ export async function updateNote(api, payload) {
52
+ const res = await api.post(endpoints.notes.update, payload);
53
+ return res.data;
54
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ import { useApiQuery } from "../../../core/hooks/useApiQuery.js";
4
+ import { fetchNoticeboardList } from "../services/noticeboardService.js";
5
+ export function useNoticeboardList(params) {
6
+ const page = params.page ?? 1;
7
+ const perPage = params.perPage ?? 10;
8
+ return useApiQuery({
9
+ queryKey: ['noticeboard', 'list', page, perPage],
10
+ queryFn: api => fetchNoticeboardList(api, params)
11
+ });
12
+ }
@@ -0,0 +1,375 @@
1
+ "use strict";
2
+
3
+ import React, { useCallback, useEffect, useState } from 'react';
4
+ import { ActivityIndicator, FlatList, Modal, SafeAreaView, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
5
+ import { useERP } from "../../../core/provider/useERP.js";
6
+ import { fetchNoticeboardList } from "../services/noticeboardService.js";
7
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
+ function getNoticeMessage(item) {
9
+ return String(item?.message ?? item?.description ?? '');
10
+ }
11
+ function getNoticeDate(item) {
12
+ return String(item?.date ?? item?.created_at ?? '');
13
+ }
14
+ function getNoticeTitle(item) {
15
+ return String(item?.title ?? 'Notice');
16
+ }
17
+ function getNoticePreview(item) {
18
+ const message = getNoticeMessage(item);
19
+ if (!message) {
20
+ return '.....';
21
+ }
22
+ let preview = '';
23
+ for (let index = 0; index < 40 && index < message.length; index += 1) {
24
+ preview += message[index];
25
+ }
26
+ return `${preview}.....`;
27
+ }
28
+ export function NoticeBoardScreen(props) {
29
+ const {
30
+ api
31
+ } = useERP();
32
+ const initialPage = props.page ?? 1;
33
+ const perPage = props.perPage ?? 10;
34
+ const [notices, setNotices] = useState([]);
35
+ const [selectedNotice, setSelectedNotice] = useState(null);
36
+ const [currentPage, setCurrentPage] = useState(initialPage);
37
+ const [homeworkAvailability, setHomeworkAvailability] = useState(true);
38
+ const [totalPage, setTotalPage] = useState(1);
39
+ const [loaded, setLoaded] = useState(false);
40
+ const getNotices = useCallback(async (pageToLoad, reset = false) => {
41
+ try {
42
+ const res = await fetchNoticeboardList(api, {
43
+ page: pageToLoad,
44
+ perPage
45
+ });
46
+ const list = Array.isArray(res?.data) ? res.data : [];
47
+ const pages = Number(res?.pagination?.total_pages ?? 1) || 1;
48
+ if (list.length > 0) {
49
+ setNotices(prev => reset ? list : [...prev, ...list]);
50
+ setTotalPage(pages);
51
+ setLoaded(true);
52
+ return;
53
+ }
54
+ setLoaded(true);
55
+ setTotalPage(pages);
56
+ if (reset) {
57
+ setNotices([]);
58
+ }
59
+ } catch (e) {
60
+ console.log('noticeboard_error', e?.message ?? e);
61
+ setLoaded(true);
62
+ if (reset) {
63
+ setNotices([]);
64
+ }
65
+ }
66
+ }, [api, perPage]);
67
+ useEffect(() => {
68
+ setNotices([]);
69
+ setCurrentPage(initialPage);
70
+ setHomeworkAvailability(true);
71
+ setTotalPage(1);
72
+ setLoaded(false);
73
+ }, [initialPage, perPage]);
74
+ useEffect(() => {
75
+ if (homeworkAvailability) {
76
+ getNotices(currentPage, currentPage === initialPage).catch(() => {});
77
+ }
78
+ }, [currentPage, getNotices, homeworkAvailability, initialPage]);
79
+ const renderItem = ({
80
+ item
81
+ }) => {
82
+ return /*#__PURE__*/_jsxs(TouchableOpacity, {
83
+ style: styles.card,
84
+ activeOpacity: 0.85,
85
+ onPress: () => setSelectedNotice(item),
86
+ children: [/*#__PURE__*/_jsx(View, {
87
+ style: styles.cardHeader,
88
+ children: /*#__PURE__*/_jsx(Text, {
89
+ style: styles.cardTitle,
90
+ children: getNoticeTitle(item)
91
+ })
92
+ }), /*#__PURE__*/_jsx(Text, {
93
+ style: styles.cardDesc,
94
+ children: getNoticePreview(item)
95
+ }), /*#__PURE__*/_jsx(View, {
96
+ style: styles.dateRow,
97
+ children: /*#__PURE__*/_jsx(Text, {
98
+ style: styles.cardDate,
99
+ children: getNoticeDate(item)
100
+ })
101
+ })]
102
+ });
103
+ };
104
+ const renderFooter = () => {
105
+ if (!homeworkAvailability) {
106
+ return null;
107
+ }
108
+ return /*#__PURE__*/_jsx(View, {
109
+ style: styles.footer,
110
+ children: /*#__PURE__*/_jsx(ActivityIndicator, {
111
+ color: "#1D4ED8",
112
+ size: "large"
113
+ })
114
+ });
115
+ };
116
+ return /*#__PURE__*/_jsxs(SafeAreaView, {
117
+ style: styles.root,
118
+ children: [!loaded ? /*#__PURE__*/_jsxs(View, {
119
+ style: styles.centerState,
120
+ children: [/*#__PURE__*/_jsx(ActivityIndicator, {
121
+ size: "large",
122
+ color: "#1D4ED8"
123
+ }), /*#__PURE__*/_jsx(Text, {
124
+ style: styles.loadingText,
125
+ children: "Loading"
126
+ })]
127
+ }) : notices.length === 0 ? /*#__PURE__*/_jsx(View, {
128
+ style: styles.centerState,
129
+ children: /*#__PURE__*/_jsx(Text, {
130
+ style: styles.emptyText,
131
+ children: "No Data Found"
132
+ })
133
+ }) : /*#__PURE__*/_jsx(FlatList, {
134
+ data: notices,
135
+ keyExtractor: (item, index) => String(item?.id ?? `${index}-${getNoticeDate(item) || 'row'}`),
136
+ renderItem: renderItem,
137
+ ListFooterComponent: renderFooter,
138
+ onEndReached: () => {
139
+ if (totalPage !== currentPage) {
140
+ setCurrentPage(prevPage => prevPage + 1);
141
+ setHomeworkAvailability(true);
142
+ } else {
143
+ setHomeworkAvailability(false);
144
+ }
145
+ },
146
+ onEndReachedThreshold: 0.2,
147
+ style: styles.list
148
+ }), /*#__PURE__*/_jsx(Modal, {
149
+ visible: selectedNotice !== null,
150
+ animationType: "slide",
151
+ onRequestClose: () => setSelectedNotice(null),
152
+ children: /*#__PURE__*/_jsxs(SafeAreaView, {
153
+ style: styles.detailRoot,
154
+ children: [/*#__PURE__*/_jsxs(View, {
155
+ style: styles.detailHeader,
156
+ children: [/*#__PURE__*/_jsx(Text, {
157
+ style: styles.detailHeaderTitle,
158
+ children: "Notice Details"
159
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
160
+ style: styles.closeBtn,
161
+ onPress: () => setSelectedNotice(null),
162
+ children: /*#__PURE__*/_jsx(Text, {
163
+ style: styles.closeBtnText,
164
+ children: "Close"
165
+ })
166
+ })]
167
+ }), selectedNotice ? /*#__PURE__*/_jsx(ScrollView, {
168
+ style: styles.detailScroll,
169
+ contentContainerStyle: styles.detailScreenContent,
170
+ showsVerticalScrollIndicator: false,
171
+ children: /*#__PURE__*/_jsxs(View, {
172
+ style: styles.detailContainer,
173
+ children: [/*#__PURE__*/_jsxs(View, {
174
+ style: styles.detailMetaRow,
175
+ children: [/*#__PURE__*/_jsx(View, {
176
+ style: styles.noticeBadge,
177
+ children: /*#__PURE__*/_jsx(Text, {
178
+ style: styles.noticeBadgeText,
179
+ children: "NOTICE"
180
+ })
181
+ }), /*#__PURE__*/_jsx(Text, {
182
+ style: styles.detailTopDate,
183
+ children: getNoticeDate(selectedNotice)
184
+ })]
185
+ }), /*#__PURE__*/_jsx(Text, {
186
+ style: styles.detailTitle,
187
+ children: getNoticeTitle(selectedNotice)
188
+ }), /*#__PURE__*/_jsxs(View, {
189
+ style: styles.messageCard,
190
+ children: [/*#__PURE__*/_jsx(Text, {
191
+ style: styles.messageLabel,
192
+ children: "Message"
193
+ }), /*#__PURE__*/_jsx(Text, {
194
+ style: styles.detailDesc,
195
+ children: getNoticeMessage(selectedNotice) || '-'
196
+ })]
197
+ })]
198
+ })
199
+ }) : null]
200
+ })
201
+ })]
202
+ });
203
+ }
204
+ const styles = StyleSheet.create({
205
+ root: {
206
+ flex: 1,
207
+ backgroundColor: '#F3F4F6'
208
+ },
209
+ centerState: {
210
+ flex: 1,
211
+ alignItems: 'center',
212
+ justifyContent: 'center',
213
+ gap: 10
214
+ },
215
+ loadingText: {
216
+ fontSize: 16,
217
+ fontWeight: '600',
218
+ color: '#1D4ED8'
219
+ },
220
+ list: {
221
+ marginBottom: 90
222
+ },
223
+ card: {
224
+ backgroundColor: '#FFFFFF',
225
+ width: '90%',
226
+ alignSelf: 'center',
227
+ marginVertical: 8,
228
+ borderRadius: 5,
229
+ padding: 20,
230
+ elevation: 1,
231
+ shadowColor: '#000000',
232
+ shadowOpacity: 0.06,
233
+ shadowRadius: 4,
234
+ shadowOffset: {
235
+ width: 0,
236
+ height: 2
237
+ }
238
+ },
239
+ cardHeader: {
240
+ flexDirection: 'row',
241
+ alignItems: 'center',
242
+ justifyContent: 'space-between',
243
+ marginBottom: 10
244
+ },
245
+ cardTitle: {
246
+ flex: 1,
247
+ fontSize: 18,
248
+ fontWeight: '700',
249
+ color: '#1D4ED8'
250
+ },
251
+ cardDesc: {
252
+ fontSize: 16,
253
+ lineHeight: 22,
254
+ color: '#111827'
255
+ },
256
+ dateRow: {
257
+ flexDirection: 'row',
258
+ justifyContent: 'flex-end',
259
+ marginTop: 8
260
+ },
261
+ cardDate: {
262
+ fontSize: 16,
263
+ color: '#1D4ED8'
264
+ },
265
+ emptyText: {
266
+ fontSize: 20,
267
+ color: '#1D4ED8',
268
+ fontWeight: '700',
269
+ textAlign: 'center'
270
+ },
271
+ footer: {
272
+ paddingVertical: 16
273
+ },
274
+ detailRoot: {
275
+ flex: 1,
276
+ backgroundColor: '#F8FAFC'
277
+ },
278
+ detailHeader: {
279
+ minHeight: 58,
280
+ paddingHorizontal: 16,
281
+ paddingVertical: 10,
282
+ borderBottomWidth: 1,
283
+ borderBottomColor: '#E5E7EB',
284
+ flexDirection: 'row',
285
+ alignItems: 'center',
286
+ justifyContent: 'space-between'
287
+ },
288
+ detailHeaderTitle: {
289
+ fontSize: 18,
290
+ fontWeight: '700',
291
+ color: '#111827'
292
+ },
293
+ detailContainer: {
294
+ width: '92%',
295
+ alignSelf: 'center',
296
+ marginTop: 16
297
+ },
298
+ closeBtn: {
299
+ borderWidth: 1,
300
+ borderColor: '#BFDBFE',
301
+ backgroundColor: '#EFF6FF',
302
+ borderRadius: 10,
303
+ paddingHorizontal: 14,
304
+ paddingVertical: 8
305
+ },
306
+ closeBtnText: {
307
+ fontSize: 14,
308
+ fontWeight: '700',
309
+ color: '#1D4ED8'
310
+ },
311
+ detailScreenContent: {
312
+ paddingBottom: 32
313
+ },
314
+ detailMetaRow: {
315
+ flexDirection: 'row',
316
+ alignItems: 'center',
317
+ justifyContent: 'space-between',
318
+ marginBottom: 16
319
+ },
320
+ noticeBadge: {
321
+ borderRadius: 999,
322
+ backgroundColor: '#DBEAFE',
323
+ paddingHorizontal: 12,
324
+ paddingVertical: 6
325
+ },
326
+ noticeBadgeText: {
327
+ fontSize: 12,
328
+ fontWeight: '700',
329
+ color: '#1D4ED8',
330
+ letterSpacing: 0.8
331
+ },
332
+ detailTopDate: {
333
+ color: '#1D4ED8',
334
+ fontSize: 14,
335
+ fontWeight: '600'
336
+ },
337
+ detailTitle: {
338
+ fontSize: 28,
339
+ fontWeight: '700',
340
+ color: '#111827',
341
+ lineHeight: 36,
342
+ marginBottom: 18
343
+ },
344
+ detailScroll: {
345
+ flex: 1
346
+ },
347
+ messageCard: {
348
+ backgroundColor: '#FFFFFF',
349
+ borderRadius: 18,
350
+ paddingHorizontal: 18,
351
+ paddingVertical: 18,
352
+ borderWidth: 1,
353
+ borderColor: '#E5E7EB',
354
+ shadowColor: '#0F172A',
355
+ shadowOpacity: 0.06,
356
+ shadowRadius: 10,
357
+ shadowOffset: {
358
+ width: 0,
359
+ height: 4
360
+ },
361
+ elevation: 2
362
+ },
363
+ messageLabel: {
364
+ fontSize: 13,
365
+ fontWeight: '700',
366
+ color: '#64748B',
367
+ marginBottom: 10,
368
+ textTransform: 'uppercase'
369
+ },
370
+ detailDesc: {
371
+ fontSize: 21,
372
+ lineHeight: 32,
373
+ color: '#0F172A'
374
+ }
375
+ });
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ import { endpoints } from "../../../core/api/endpoints.js";
4
+ export async function fetchNoticeboardList(api, params) {
5
+ const page = params.page ?? 1;
6
+ const perPage = params.perPage ?? 10;
7
+ const res = await api.get(endpoints.noticeboard.list({
8
+ page,
9
+ perPage
10
+ }));
11
+ return res.data;
12
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ import { useApiQuery } from "../../../core/hooks/useApiQuery.js";
4
+ import { fetchNotificationList } from "../services/notificationService.js";
5
+ export function useNotifications(params) {
6
+ const page = params.page ?? 1;
7
+ const perPage = params.perPage ?? 10;
8
+ return useApiQuery({
9
+ queryKey: ['notification', 'list', page, perPage],
10
+ queryFn: api => fetchNotificationList(api, params)
11
+ });
12
+ }
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+
3
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
4
+ import { ActivityIndicator, FlatList, RefreshControl, SafeAreaView, StyleSheet, Text, View } from 'react-native';
5
+ import { useERP } from "../../../core/provider/useERP.js";
6
+ import { ErrorState } from "../../../shared/empty-states/ErrorState.js";
7
+ import { fetchNotificationList } from "../services/notificationService.js";
8
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
+ export function NotificationScreen(props) {
10
+ const {
11
+ api
12
+ } = useERP();
13
+ const perPage = props.perPage ?? 10;
14
+ const initialPage = props.page ?? 1;
15
+ const [items, setItems] = useState([]);
16
+ const [page, setPage] = useState(initialPage);
17
+ const [totalPages, setTotalPages] = useState(1);
18
+ const [loading, setLoading] = useState(true);
19
+ const [refreshing, setRefreshing] = useState(false);
20
+ const [loadingMore, setLoadingMore] = useState(false);
21
+ const [error, setError] = useState(null);
22
+ const hasMore = useMemo(() => page < totalPages, [page, totalPages]);
23
+ const loadPage = useCallback(async (nextPage, reset = false) => {
24
+ try {
25
+ if (reset) {
26
+ setRefreshing(true);
27
+ setError(null);
28
+ } else if (nextPage === initialPage && !items.length) {
29
+ setLoading(true);
30
+ setError(null);
31
+ } else {
32
+ setLoadingMore(true);
33
+ }
34
+ const res = await fetchNotificationList(api, {
35
+ page: nextPage,
36
+ perPage
37
+ });
38
+ const list = Array.isArray(res?.data) ? res.data : [];
39
+ const pages = Number(res?.pagination?.total_pages ?? 1);
40
+ setTotalPages(pages > 0 ? pages : 1);
41
+ setPage(nextPage);
42
+ setItems(prev => reset ? list : [...prev, ...list]);
43
+ } catch (e) {
44
+ setError(String(e?.message ?? 'Could not load notifications'));
45
+ } finally {
46
+ setLoading(false);
47
+ setRefreshing(false);
48
+ setLoadingMore(false);
49
+ }
50
+ }, [api, initialPage, items.length, perPage]);
51
+ useEffect(() => {
52
+ setItems([]);
53
+ setPage(initialPage);
54
+ setTotalPages(1);
55
+ loadPage(initialPage, true).catch(() => {});
56
+ }, [initialPage, loadPage, perPage]);
57
+ if (error && !items.length) {
58
+ return /*#__PURE__*/_jsx(ErrorState, {
59
+ message: error
60
+ });
61
+ }
62
+ const renderItem = ({
63
+ item
64
+ }) => {
65
+ return /*#__PURE__*/_jsxs(View, {
66
+ style: styles.card,
67
+ children: [/*#__PURE__*/_jsx(Text, {
68
+ style: styles.cardTitle,
69
+ children: String(item?.title ?? 'Notification')
70
+ }), /*#__PURE__*/_jsx(Text, {
71
+ style: styles.cardMessage,
72
+ children: String(item?.message ?? '-')
73
+ }), /*#__PURE__*/_jsx(Text, {
74
+ style: styles.cardDate,
75
+ children: String(item?.created_at ?? '')
76
+ })]
77
+ });
78
+ };
79
+ return /*#__PURE__*/_jsx(SafeAreaView, {
80
+ style: styles.root,
81
+ children: loading ? /*#__PURE__*/_jsx(View, {
82
+ style: styles.loaderWrap,
83
+ children: /*#__PURE__*/_jsx(ActivityIndicator, {
84
+ size: "large",
85
+ color: "#1D4ED8"
86
+ })
87
+ }) : /*#__PURE__*/_jsx(FlatList, {
88
+ data: items,
89
+ keyExtractor: (item, index) => String(item?.id ?? `${index}-${item?.created_at ?? 'row'}`),
90
+ renderItem: renderItem,
91
+ contentContainerStyle: items.length ? styles.content : styles.emptyWrap,
92
+ refreshControl: /*#__PURE__*/_jsx(RefreshControl, {
93
+ refreshing: refreshing,
94
+ onRefresh: () => {
95
+ loadPage(initialPage, true).catch(() => {});
96
+ },
97
+ tintColor: "#1D4ED8"
98
+ }),
99
+ onEndReached: () => {
100
+ if (!loadingMore && hasMore) {
101
+ loadPage(page + 1).catch(() => {});
102
+ }
103
+ },
104
+ onEndReachedThreshold: 0.4,
105
+ ListHeaderComponent: /*#__PURE__*/_jsx(Text, {
106
+ style: styles.title,
107
+ children: "Notifications"
108
+ }),
109
+ ListEmptyComponent: /*#__PURE__*/_jsx(Text, {
110
+ style: styles.emptyText,
111
+ children: "No Data Found"
112
+ }),
113
+ ListFooterComponent: loadingMore ? /*#__PURE__*/_jsx(View, {
114
+ style: styles.footer,
115
+ children: /*#__PURE__*/_jsx(ActivityIndicator, {
116
+ color: "#1D4ED8"
117
+ })
118
+ }) : null
119
+ })
120
+ });
121
+ }
122
+ const styles = StyleSheet.create({
123
+ root: {
124
+ flex: 1,
125
+ backgroundColor: '#F9FAFB'
126
+ },
127
+ content: {
128
+ padding: 16,
129
+ paddingBottom: 32
130
+ },
131
+ emptyWrap: {
132
+ flexGrow: 1,
133
+ padding: 16,
134
+ justifyContent: 'center'
135
+ },
136
+ loaderWrap: {
137
+ flex: 1,
138
+ alignItems: 'center',
139
+ justifyContent: 'center'
140
+ },
141
+ title: {
142
+ fontSize: 20,
143
+ fontWeight: '700',
144
+ color: '#111827',
145
+ marginBottom: 12
146
+ },
147
+ card: {
148
+ backgroundColor: '#FFFFFF',
149
+ borderRadius: 12,
150
+ padding: 14,
151
+ marginBottom: 12,
152
+ borderWidth: 1,
153
+ borderColor: '#E5E7EB'
154
+ },
155
+ cardTitle: {
156
+ fontSize: 16,
157
+ fontWeight: '700',
158
+ color: '#1D4ED8',
159
+ marginBottom: 6
160
+ },
161
+ cardMessage: {
162
+ fontSize: 14,
163
+ lineHeight: 20,
164
+ color: '#111827'
165
+ },
166
+ cardDate: {
167
+ fontSize: 12,
168
+ color: '#2563EB',
169
+ textAlign: 'right',
170
+ marginTop: 8
171
+ },
172
+ emptyText: {
173
+ fontSize: 16,
174
+ color: '#6B7280',
175
+ textAlign: 'center'
176
+ },
177
+ footer: {
178
+ paddingVertical: 16
179
+ }
180
+ });
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ import { endpoints } from "../../../core/api/endpoints.js";
4
+ export async function fetchNotificationList(api, params) {
5
+ const page = params.page ?? 1;
6
+ const perPage = params.perPage ?? 10;
7
+ const res = await api.get(endpoints.notification.list({
8
+ page,
9
+ perPage
10
+ }));
11
+ return res.data;
12
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ import { useApiQuery } from "../../../core/hooks/useApiQuery.js";
4
+ import { fetchPromoteStudentSearch } from "../services/promoteStudentService.js";
5
+ export function usePromoteStudentSearch(params) {
6
+ const enabled = !!params && !!params.classId && !!params.sectionId;
7
+ return useApiQuery({
8
+ queryKey: ['promoteStudent', 'search', params?.classId ?? null, params?.sectionId ?? null],
9
+ enabled,
10
+ queryFn: api => fetchPromoteStudentSearch(api, params)
11
+ });
12
+ }