@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,985 @@
1
+ "use strict";
2
+
3
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
4
+ import { ActivityIndicator, Alert, FlatList, Modal, Pressable, SafeAreaView, ScrollView, StyleSheet, 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 { applyLeave, fetchLeaveRequests, fetchLeaveTypes, uploadLeaveFile } from "../services/leaveRequestService.js";
8
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
+ function normalizeLeaveItems(result) {
10
+ if (Array.isArray(result)) {
11
+ return result;
12
+ }
13
+ if (Array.isArray(result?.data)) {
14
+ return result.data;
15
+ }
16
+ if (Array.isArray(result?.data?.data)) {
17
+ return result.data.data;
18
+ }
19
+ return [];
20
+ }
21
+ function normalizeLeaveTypes(result) {
22
+ const list = Array.isArray(result?.data) ? result.data : Array.isArray(result) ? result : [];
23
+ return list.map((item, index) => ({
24
+ label: String(item?.type ?? item?.label ?? `Type ${index + 1}`),
25
+ value: item?.id ?? item?.value ?? index + 1
26
+ }));
27
+ }
28
+ function tryGetCalendar() {
29
+ try {
30
+ const mod = require('react-native-calendars');
31
+ return mod?.Calendar ?? mod?.default ?? mod;
32
+ } catch {
33
+ return null;
34
+ }
35
+ }
36
+ function todayYmd() {
37
+ const d = new Date();
38
+ const y = d.getFullYear();
39
+ const m = String(d.getMonth() + 1).padStart(2, '0');
40
+ const day = String(d.getDate()).padStart(2, '0');
41
+ return `${y}-${m}-${day}`;
42
+ }
43
+ function addDays(d, days) {
44
+ const next = new Date(d);
45
+ next.setDate(next.getDate() + days);
46
+ return next;
47
+ }
48
+ function toYmd(d) {
49
+ const y = d.getFullYear();
50
+ const m = String(d.getMonth() + 1).padStart(2, '0');
51
+ const day = String(d.getDate()).padStart(2, '0');
52
+ return `${y}-${m}-${day}`;
53
+ }
54
+ function rangeMarkedDates(start, end) {
55
+ if (!start || !end) {
56
+ return {};
57
+ }
58
+ const s = new Date(start);
59
+ const e = new Date(end);
60
+ if (Number.isNaN(s.getTime()) || Number.isNaN(e.getTime())) {
61
+ return {};
62
+ }
63
+ const from = s <= e ? s : e;
64
+ const to = s <= e ? e : s;
65
+ const out = {};
66
+ let cur = new Date(from);
67
+ while (cur <= to) {
68
+ out[toYmd(cur)] = {
69
+ color: '#2563EB',
70
+ textColor: 'white'
71
+ };
72
+ cur = addDays(cur, 1);
73
+ }
74
+ out[toYmd(from)] = {
75
+ startingDay: true,
76
+ color: '#2563EB',
77
+ textColor: 'white'
78
+ };
79
+ out[toYmd(to)] = {
80
+ endingDay: true,
81
+ color: '#2563EB',
82
+ textColor: 'white'
83
+ };
84
+ return out;
85
+ }
86
+ function formatDate(dateString) {
87
+ if (!dateString) {
88
+ return '-';
89
+ }
90
+ const date = new Date(dateString);
91
+ if (Number.isNaN(date.getTime())) {
92
+ return dateString;
93
+ }
94
+ return date.toLocaleDateString('en-US', {
95
+ weekday: 'short',
96
+ day: '2-digit',
97
+ month: 'short'
98
+ });
99
+ }
100
+ function statusColors(status) {
101
+ const normalized = String(status ?? '').toLowerCase();
102
+ if (normalized === 'approved') {
103
+ return {
104
+ bg: '#E7F6E7',
105
+ text: '#2E7D32'
106
+ };
107
+ }
108
+ if (normalized === 'pending') {
109
+ return {
110
+ bg: '#FFF8E1',
111
+ text: '#F57C00'
112
+ };
113
+ }
114
+ if (normalized === 'declined') {
115
+ return {
116
+ bg: '#FFEBEE',
117
+ text: '#C62828'
118
+ };
119
+ }
120
+ return {
121
+ bg: '#F5F5F5',
122
+ text: '#757575'
123
+ };
124
+ }
125
+ function LeaveRequestCard({
126
+ item
127
+ }) {
128
+ const colors = statusColors(String(item?.status ?? ''));
129
+ return /*#__PURE__*/_jsx(View, {
130
+ style: styles.requestCard,
131
+ children: /*#__PURE__*/_jsxs(View, {
132
+ style: styles.requestTopRow,
133
+ children: [/*#__PURE__*/_jsxs(View, {
134
+ style: {
135
+ flex: 1,
136
+ marginRight: 8
137
+ },
138
+ children: [/*#__PURE__*/_jsx(Text, {
139
+ style: styles.requestTitle,
140
+ children: String(item?.employee_remark ?? 'Leave Request')
141
+ }), /*#__PURE__*/_jsx(Text, {
142
+ style: styles.requestType,
143
+ children: String(item?.type ?? '')
144
+ }), /*#__PURE__*/_jsxs(Text, {
145
+ style: styles.requestDate,
146
+ children: [formatDate(String(item?.leave_from ?? '')), " -", ' ', formatDate(String(item?.leave_to ?? ''))]
147
+ })]
148
+ }), /*#__PURE__*/_jsx(View, {
149
+ style: [styles.statusChip, {
150
+ backgroundColor: colors.bg
151
+ }],
152
+ children: /*#__PURE__*/_jsx(Text, {
153
+ style: [styles.statusChipText, {
154
+ color: colors.text
155
+ }],
156
+ children: String(item?.status ?? '').toLowerCase() || 'unknown'
157
+ })
158
+ })]
159
+ })
160
+ });
161
+ }
162
+ function LeaveRequestSkeleton() {
163
+ return /*#__PURE__*/_jsx(View, {
164
+ style: styles.skeletonWrap,
165
+ children: [1, 2, 3, 4, 5].map(item => /*#__PURE__*/_jsx(View, {
166
+ style: styles.skeletonCard
167
+ }, item))
168
+ });
169
+ }
170
+ function SelectModal({
171
+ label,
172
+ value,
173
+ options,
174
+ placeholder,
175
+ onChange
176
+ }) {
177
+ const [open, setOpen] = useState(false);
178
+ return /*#__PURE__*/_jsxs(View, {
179
+ style: styles.field,
180
+ children: [/*#__PURE__*/_jsx(Text, {
181
+ style: styles.label,
182
+ children: label
183
+ }), /*#__PURE__*/_jsx(Pressable, {
184
+ onPress: () => setOpen(true),
185
+ style: styles.select,
186
+ children: /*#__PURE__*/_jsx(Text, {
187
+ style: styles.selectText,
188
+ children: value?.label ?? placeholder
189
+ })
190
+ }), /*#__PURE__*/_jsx(Modal, {
191
+ visible: open,
192
+ transparent: true,
193
+ animationType: "fade",
194
+ children: /*#__PURE__*/_jsx(Pressable, {
195
+ style: styles.modalOverlay,
196
+ onPress: () => setOpen(false),
197
+ children: /*#__PURE__*/_jsxs(Pressable, {
198
+ style: styles.modalCard,
199
+ onPress: () => {},
200
+ children: [/*#__PURE__*/_jsx(Text, {
201
+ style: styles.modalTitle,
202
+ children: label
203
+ }), /*#__PURE__*/_jsx(FlatList, {
204
+ data: options,
205
+ keyExtractor: (item, index) => `${item.value}-${index}`,
206
+ renderItem: ({
207
+ item
208
+ }) => /*#__PURE__*/_jsx(Pressable, {
209
+ style: styles.optionRow,
210
+ onPress: () => {
211
+ onChange(item);
212
+ setOpen(false);
213
+ },
214
+ children: /*#__PURE__*/_jsx(Text, {
215
+ style: styles.optionText,
216
+ children: item.label
217
+ })
218
+ }),
219
+ ListEmptyComponent: /*#__PURE__*/_jsx(Text, {
220
+ style: styles.optionEmpty,
221
+ children: "No options"
222
+ })
223
+ })]
224
+ })
225
+ })
226
+ })]
227
+ });
228
+ }
229
+ function ApplyLeaveView({
230
+ leaveTypes,
231
+ onCancel,
232
+ onSuccess
233
+ }) {
234
+ const {
235
+ api
236
+ } = useERP();
237
+ const Calendar = useMemo(() => tryGetCalendar(), []);
238
+ const [reason, setReason] = useState('');
239
+ const [leaveType, setLeaveType] = useState(null);
240
+ const [startDate, setStartDate] = useState('');
241
+ const [endDate, setEndDate] = useState('');
242
+ const [dateMode, setDateMode] = useState('start');
243
+ const [calendarOpen, setCalendarOpen] = useState(false);
244
+ const [uploadOpen, setUploadOpen] = useState(false);
245
+ const [busy, setBusy] = useState(false);
246
+ const [markedDates, setMarkedDates] = useState({});
247
+ const [fileName, setFileName] = useState('');
248
+ const [filePath, setFilePath] = useState(undefined);
249
+ useEffect(() => {
250
+ setMarkedDates(rangeMarkedDates(startDate, endDate));
251
+ }, [startDate, endDate]);
252
+ const pickDocument = useCallback(async () => {
253
+ let dp = null;
254
+ try {
255
+ dp = require('react-native-document-picker');
256
+ } catch {}
257
+ if (!dp?.pickSingle) {
258
+ Alert.alert('Error', 'Document picker is not available');
259
+ return;
260
+ }
261
+ const selected = await dp.pickSingle({
262
+ presentationStyle: 'fullScreen',
263
+ type: [dp.types.pdf]
264
+ });
265
+ const file = {
266
+ uri: selected.uri,
267
+ name: selected.name ?? 'document.pdf',
268
+ type: selected.type ?? 'application/pdf'
269
+ };
270
+ setFileName(file.name);
271
+ setBusy(true);
272
+ try {
273
+ const res = await uploadLeaveFile(api, file);
274
+ if (res?.Status === 'Success' && res?.data) {
275
+ setFilePath(res.data);
276
+ } else {
277
+ setFileName('');
278
+ setFilePath(undefined);
279
+ Alert.alert('Error', 'File upload failed');
280
+ }
281
+ } catch (error) {
282
+ setFileName('');
283
+ setFilePath(undefined);
284
+ Alert.alert('Error', String(error?.message ?? 'File upload failed'));
285
+ } finally {
286
+ setBusy(false);
287
+ setUploadOpen(false);
288
+ }
289
+ }, [api]);
290
+ const pickCamera = useCallback(async () => {
291
+ let picker = null;
292
+ try {
293
+ picker = require('react-native-image-picker');
294
+ } catch {}
295
+ if (!picker?.launchCamera) {
296
+ Alert.alert('Error', 'Camera picker is not available');
297
+ return;
298
+ }
299
+ const response = await new Promise(resolve => {
300
+ picker.launchCamera({
301
+ mediaType: 'photo',
302
+ saveToPhotos: true,
303
+ includeBase64: false
304
+ }, res => resolve(res));
305
+ });
306
+ const asset = response?.assets?.[0];
307
+ if (!asset?.uri) {
308
+ setUploadOpen(false);
309
+ return;
310
+ }
311
+ const file = {
312
+ uri: asset.uri,
313
+ name: asset.fileName ?? 'camera.jpg',
314
+ type: asset.type ?? 'image/jpeg'
315
+ };
316
+ setFileName(file.name);
317
+ setBusy(true);
318
+ try {
319
+ const res = await uploadLeaveFile(api, file);
320
+ if (res?.Status === 'Success' && res?.data) {
321
+ setFilePath(res.data);
322
+ } else {
323
+ setFileName('');
324
+ setFilePath(undefined);
325
+ Alert.alert('Error', 'File upload failed');
326
+ }
327
+ } catch (error) {
328
+ setFileName('');
329
+ setFilePath(undefined);
330
+ Alert.alert('Error', String(error?.message ?? 'File upload failed'));
331
+ } finally {
332
+ setBusy(false);
333
+ setUploadOpen(false);
334
+ }
335
+ }, [api]);
336
+ const submit = useCallback(async () => {
337
+ const missing = [];
338
+ if (!reason) missing.push('reason');
339
+ if (!leaveType?.value) missing.push('leave type');
340
+ if (!startDate) missing.push('start date');
341
+ if (!endDate) missing.push('end date');
342
+ if (missing.length) {
343
+ Alert.alert('Missing Fields', `Please fill: ${missing.join(', ')}`);
344
+ return;
345
+ }
346
+ setBusy(true);
347
+ try {
348
+ const res = await applyLeave(api, {
349
+ reason,
350
+ leave_type: leaveType.value,
351
+ from_date: startDate,
352
+ to_date: endDate,
353
+ file: filePath
354
+ });
355
+ const response = res;
356
+ if (response?.Status && response.Status !== 'Success') {
357
+ Alert.alert('Failed', String(response?.msg ?? response?.Message ?? 'Request failed'));
358
+ return;
359
+ }
360
+ Alert.alert('Success', String(response?.msg ?? 'Leave applied successfully'));
361
+ onSuccess();
362
+ } catch (error) {
363
+ Alert.alert('Failed', String(error?.message ?? 'Could not apply leave'));
364
+ } finally {
365
+ setBusy(false);
366
+ }
367
+ }, [api, endDate, filePath, leaveType, onSuccess, reason, startDate]);
368
+ return /*#__PURE__*/_jsxs(SafeAreaView, {
369
+ style: styles.root,
370
+ children: [/*#__PURE__*/_jsxs(View, {
371
+ style: styles.header,
372
+ children: [/*#__PURE__*/_jsx(Text, {
373
+ style: styles.headerTitle,
374
+ children: "Leave Request"
375
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
376
+ onPress: onCancel,
377
+ style: styles.secondaryBtn,
378
+ children: /*#__PURE__*/_jsx(Text, {
379
+ style: styles.secondaryBtnText,
380
+ children: "Back"
381
+ })
382
+ })]
383
+ }), /*#__PURE__*/_jsxs(ScrollView, {
384
+ contentContainerStyle: styles.form,
385
+ children: [/*#__PURE__*/_jsxs(View, {
386
+ style: styles.formCard,
387
+ children: [/*#__PURE__*/_jsxs(View, {
388
+ style: styles.field,
389
+ children: [/*#__PURE__*/_jsx(Text, {
390
+ style: styles.label,
391
+ children: "Leave Reason"
392
+ }), /*#__PURE__*/_jsx(TextInput, {
393
+ value: reason,
394
+ onChangeText: setReason,
395
+ placeholder: "Enter the reason for leave",
396
+ placeholderTextColor: "#9CA3AF",
397
+ style: [styles.input, styles.textarea],
398
+ multiline: true
399
+ })]
400
+ }), /*#__PURE__*/_jsx(SelectModal, {
401
+ label: "Leave Type",
402
+ value: leaveType,
403
+ options: leaveTypes,
404
+ placeholder: "Select leave type",
405
+ onChange: setLeaveType
406
+ }), /*#__PURE__*/_jsxs(View, {
407
+ style: styles.field,
408
+ children: [/*#__PURE__*/_jsx(Text, {
409
+ style: styles.label,
410
+ children: "Select Dates"
411
+ }), /*#__PURE__*/_jsxs(View, {
412
+ style: styles.toggleRow,
413
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
414
+ onPress: () => {
415
+ setDateMode('start');
416
+ setCalendarOpen(true);
417
+ },
418
+ style: [styles.toggleBtn, dateMode === 'start' ? styles.toggleBtnActive : null],
419
+ children: /*#__PURE__*/_jsxs(Text, {
420
+ style: [styles.toggleBtnText, dateMode === 'start' ? styles.toggleBtnTextActive : null],
421
+ children: ["Start: ", startDate || 'Select']
422
+ })
423
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
424
+ onPress: () => {
425
+ setDateMode('end');
426
+ setCalendarOpen(true);
427
+ },
428
+ style: [styles.toggleBtn, dateMode === 'end' ? styles.toggleBtnActive : null],
429
+ children: /*#__PURE__*/_jsxs(Text, {
430
+ style: [styles.toggleBtnText, dateMode === 'end' ? styles.toggleBtnTextActive : null],
431
+ children: ["End: ", endDate || 'Select']
432
+ })
433
+ })]
434
+ })]
435
+ }), /*#__PURE__*/_jsxs(View, {
436
+ style: styles.field,
437
+ children: [/*#__PURE__*/_jsx(Text, {
438
+ style: styles.label,
439
+ children: "Attachment (Optional)"
440
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
441
+ onPress: () => setUploadOpen(true),
442
+ style: styles.uploadBtn,
443
+ disabled: busy,
444
+ children: /*#__PURE__*/_jsx(Text, {
445
+ style: styles.uploadBtnText,
446
+ children: filePath ? 'Change File' : 'Attach Document'
447
+ })
448
+ }), fileName ? /*#__PURE__*/_jsxs(Text, {
449
+ style: styles.fileNameText,
450
+ children: ["File Selected: ", fileName]
451
+ }) : null]
452
+ })]
453
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
454
+ onPress: () => submit().catch(() => {}),
455
+ style: styles.primaryBtn,
456
+ disabled: busy,
457
+ children: busy ? /*#__PURE__*/_jsx(ActivityIndicator, {
458
+ color: "#FFFFFF"
459
+ }) : /*#__PURE__*/_jsx(Text, {
460
+ style: styles.primaryBtnText,
461
+ children: "Apply Leave"
462
+ })
463
+ })]
464
+ }), /*#__PURE__*/_jsx(Modal, {
465
+ visible: calendarOpen,
466
+ transparent: true,
467
+ animationType: "fade",
468
+ children: /*#__PURE__*/_jsx(Pressable, {
469
+ style: styles.modalOverlay,
470
+ onPress: () => setCalendarOpen(false),
471
+ children: /*#__PURE__*/_jsxs(Pressable, {
472
+ style: styles.modalCard,
473
+ onPress: () => {},
474
+ children: [/*#__PURE__*/_jsxs(View, {
475
+ style: styles.sheetHeader,
476
+ children: [/*#__PURE__*/_jsx(Text, {
477
+ style: styles.modalTitle,
478
+ children: dateMode === 'start' ? 'Select Start Date' : 'Select End Date'
479
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
480
+ onPress: () => setCalendarOpen(false),
481
+ style: styles.secondaryBtn,
482
+ children: /*#__PURE__*/_jsx(Text, {
483
+ style: styles.secondaryBtnText,
484
+ children: "Close"
485
+ })
486
+ })]
487
+ }), Calendar ? /*#__PURE__*/_jsx(Calendar, {
488
+ minDate: todayYmd(),
489
+ markingType: "period",
490
+ markedDates: markedDates,
491
+ onDayPress: day => {
492
+ const next = String(day?.dateString ?? '');
493
+ if (!next) {
494
+ return;
495
+ }
496
+ if (dateMode === 'start') {
497
+ if (endDate && new Date(next).getTime() > new Date(endDate).getTime()) {
498
+ Alert.alert('Error', 'Start date must be less than end date');
499
+ return;
500
+ }
501
+ setStartDate(next);
502
+ if (!endDate) {
503
+ setEndDate(next);
504
+ }
505
+ } else {
506
+ if (startDate && new Date(next).getTime() < new Date(startDate).getTime()) {
507
+ Alert.alert('Error', 'Start date must be less than end date');
508
+ return;
509
+ }
510
+ setEndDate(next);
511
+ if (!startDate) {
512
+ setStartDate(next);
513
+ }
514
+ }
515
+ setCalendarOpen(false);
516
+ }
517
+ }) : /*#__PURE__*/_jsx(EmptyState, {
518
+ title: "Calendar missing",
519
+ message: "Install react-native-calendars to enable date picker"
520
+ })]
521
+ })
522
+ })
523
+ }), /*#__PURE__*/_jsx(Modal, {
524
+ visible: uploadOpen,
525
+ transparent: true,
526
+ animationType: "fade",
527
+ children: /*#__PURE__*/_jsx(Pressable, {
528
+ style: styles.modalOverlay,
529
+ onPress: () => setUploadOpen(false),
530
+ children: /*#__PURE__*/_jsxs(Pressable, {
531
+ style: styles.actionSheet,
532
+ onPress: () => {},
533
+ children: [/*#__PURE__*/_jsx(Text, {
534
+ style: styles.actionSheetTitle,
535
+ children: "Select Attachment"
536
+ }), /*#__PURE__*/_jsxs(View, {
537
+ style: styles.actionRow,
538
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
539
+ onPress: () => pickCamera().catch(() => {}),
540
+ style: styles.actionBtn,
541
+ children: /*#__PURE__*/_jsx(Text, {
542
+ style: styles.actionBtnTitle,
543
+ children: "Camera"
544
+ })
545
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
546
+ onPress: () => pickDocument().catch(() => {}),
547
+ style: styles.actionBtn,
548
+ children: /*#__PURE__*/_jsx(Text, {
549
+ style: styles.actionBtnTitle,
550
+ children: "Document"
551
+ })
552
+ })]
553
+ })]
554
+ })
555
+ })
556
+ })]
557
+ });
558
+ }
559
+ export function LeaveRequestScreen(props) {
560
+ const {
561
+ api
562
+ } = useERP();
563
+ const [mode, setMode] = useState('list');
564
+ const [tab, setTab] = useState('approved');
565
+ const [requests, setRequests] = useState([]);
566
+ const [leaveTypes, setLeaveTypes] = useState([]);
567
+ const [page, setPage] = useState(props.page ?? 1);
568
+ const [totalPages, setTotalPages] = useState(1);
569
+ const [loading, setLoading] = useState(true);
570
+ const [loadingMore, setLoadingMore] = useState(false);
571
+ const [refreshing, setRefreshing] = useState(false);
572
+ const perPage = props.perPage ?? 5;
573
+ const loadLeaveTypes = useCallback(async () => {
574
+ try {
575
+ const res = await fetchLeaveTypes(api);
576
+ setLeaveTypes(normalizeLeaveTypes(res));
577
+ } catch {}
578
+ }, [api]);
579
+ const loadPage = useCallback(async (nextPage, replace = false) => {
580
+ if (replace) {
581
+ setRefreshing(true);
582
+ } else if (nextPage === (props.page ?? 1)) {
583
+ setLoading(true);
584
+ } else {
585
+ setLoadingMore(true);
586
+ }
587
+ try {
588
+ const res = await fetchLeaveRequests(api, {
589
+ page: nextPage,
590
+ perPage
591
+ });
592
+ const list = normalizeLeaveItems(res);
593
+ const response = res;
594
+ const nextTotalPages = Number(response?.pagination?.total_pages ?? 1);
595
+ setTotalPages(Number.isFinite(nextTotalPages) && nextTotalPages > 0 ? nextTotalPages : 1);
596
+ setPage(nextPage);
597
+ setRequests(prev => replace || nextPage === (props.page ?? 1) ? list : [...prev, ...list]);
598
+ } catch (error) {
599
+ Alert.alert('Error', String(error?.message ?? 'Could not load leave requests'));
600
+ } finally {
601
+ setLoading(false);
602
+ setLoadingMore(false);
603
+ setRefreshing(false);
604
+ }
605
+ }, [api, perPage, props.page]);
606
+ useEffect(() => {
607
+ loadLeaveTypes().catch(() => {});
608
+ loadPage(props.page ?? 1, true).catch(() => {});
609
+ }, [loadLeaveTypes, loadPage, props.page]);
610
+ const approvedRequests = useMemo(() => requests.filter(item => String(item?.status ?? '').toLowerCase() === 'approved'), [requests]);
611
+ const pendingRequests = useMemo(() => requests.filter(item => String(item?.status ?? '').toLowerCase() !== 'approved'), [requests]);
612
+ const visibleRequests = tab === 'approved' ? approvedRequests : pendingRequests;
613
+ if (mode === 'apply') {
614
+ return /*#__PURE__*/_jsx(ApplyLeaveView, {
615
+ leaveTypes: leaveTypes,
616
+ onCancel: () => setMode('list'),
617
+ onSuccess: () => {
618
+ setMode('list');
619
+ loadPage(props.page ?? 1, true).catch(() => {});
620
+ }
621
+ });
622
+ }
623
+ if (loading) {
624
+ return /*#__PURE__*/_jsxs(SafeAreaView, {
625
+ style: styles.root,
626
+ children: [/*#__PURE__*/_jsx(View, {
627
+ style: styles.header,
628
+ children: /*#__PURE__*/_jsx(Text, {
629
+ style: styles.headerTitle,
630
+ children: "Leaves"
631
+ })
632
+ }), /*#__PURE__*/_jsx(LeaveRequestSkeleton, {})]
633
+ });
634
+ }
635
+ return /*#__PURE__*/_jsxs(SafeAreaView, {
636
+ style: styles.root,
637
+ children: [/*#__PURE__*/_jsxs(View, {
638
+ style: styles.header,
639
+ children: [/*#__PURE__*/_jsx(Text, {
640
+ style: styles.headerTitle,
641
+ children: "Leaves"
642
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
643
+ onPress: () => setMode('apply'),
644
+ style: styles.primaryBtnSmall,
645
+ children: /*#__PURE__*/_jsx(Text, {
646
+ style: styles.primaryBtnSmallText,
647
+ children: "Apply"
648
+ })
649
+ })]
650
+ }), /*#__PURE__*/_jsxs(View, {
651
+ style: styles.tabRow,
652
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
653
+ onPress: () => setTab('approved'),
654
+ style: [styles.tabBtn, tab === 'approved' ? styles.tabBtnActive : null],
655
+ children: /*#__PURE__*/_jsx(Text, {
656
+ style: [styles.tabBtnText, tab === 'approved' ? styles.tabBtnTextActive : null],
657
+ children: "Approved"
658
+ })
659
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
660
+ onPress: () => setTab('pending'),
661
+ style: [styles.tabBtn, tab === 'pending' ? styles.tabBtnActive : null],
662
+ children: /*#__PURE__*/_jsx(Text, {
663
+ style: [styles.tabBtnText, tab === 'pending' ? styles.tabBtnTextActive : null],
664
+ children: "Pending / Declined"
665
+ })
666
+ })]
667
+ }), /*#__PURE__*/_jsx(FlatList, {
668
+ data: visibleRequests,
669
+ keyExtractor: (item, index) => String(item?.id ?? index),
670
+ renderItem: ({
671
+ item
672
+ }) => /*#__PURE__*/_jsx(LeaveRequestCard, {
673
+ item: item
674
+ }),
675
+ contentContainerStyle: styles.listContent,
676
+ onEndReached: () => {
677
+ if (!loadingMore && page < totalPages) {
678
+ loadPage(page + 1).catch(() => {});
679
+ }
680
+ },
681
+ onEndReachedThreshold: 0.4,
682
+ onRefresh: () => {
683
+ loadPage(props.page ?? 1, true).catch(() => {});
684
+ },
685
+ refreshing: refreshing,
686
+ ListFooterComponent: loadingMore ? /*#__PURE__*/_jsx(ActivityIndicator, {
687
+ style: {
688
+ marginVertical: 16
689
+ },
690
+ color: "#2563EB"
691
+ }) : null,
692
+ ListEmptyComponent: /*#__PURE__*/_jsx(EmptyState, {
693
+ title: "No Data Found"
694
+ })
695
+ })]
696
+ });
697
+ }
698
+ const styles = StyleSheet.create({
699
+ root: {
700
+ flex: 1,
701
+ backgroundColor: '#FAFAFA'
702
+ },
703
+ header: {
704
+ paddingHorizontal: 16,
705
+ paddingVertical: 12,
706
+ borderBottomWidth: 1,
707
+ borderBottomColor: '#E5E7EB',
708
+ backgroundColor: '#FFFFFF',
709
+ flexDirection: 'row',
710
+ justifyContent: 'space-between',
711
+ alignItems: 'center'
712
+ },
713
+ headerTitle: {
714
+ fontSize: 18,
715
+ fontWeight: '700',
716
+ color: '#111827'
717
+ },
718
+ primaryBtnSmall: {
719
+ paddingHorizontal: 14,
720
+ paddingVertical: 10,
721
+ borderRadius: 10,
722
+ backgroundColor: '#2563EB'
723
+ },
724
+ primaryBtnSmallText: {
725
+ color: '#FFFFFF',
726
+ fontWeight: '700'
727
+ },
728
+ tabRow: {
729
+ flexDirection: 'row',
730
+ backgroundColor: '#FFFFFF',
731
+ paddingVertical: 12,
732
+ paddingHorizontal: 16,
733
+ gap: 12,
734
+ borderBottomWidth: 1,
735
+ borderBottomColor: '#E5E7EB'
736
+ },
737
+ tabBtn: {
738
+ flex: 1,
739
+ paddingVertical: 10,
740
+ alignItems: 'center',
741
+ backgroundColor: '#F5F5F5',
742
+ borderRadius: 8,
743
+ borderWidth: 1,
744
+ borderColor: '#E0E0E0'
745
+ },
746
+ tabBtnActive: {
747
+ backgroundColor: '#2563EB',
748
+ borderColor: '#2563EB'
749
+ },
750
+ tabBtnText: {
751
+ color: '#757575',
752
+ fontWeight: '600',
753
+ fontSize: 15
754
+ },
755
+ tabBtnTextActive: {
756
+ color: '#FFFFFF'
757
+ },
758
+ listContent: {
759
+ paddingVertical: 8
760
+ },
761
+ requestCard: {
762
+ backgroundColor: '#FFFFFF',
763
+ borderRadius: 12,
764
+ marginVertical: 8,
765
+ marginHorizontal: 16,
766
+ padding: 16,
767
+ borderWidth: 1,
768
+ borderColor: '#F0F0F0'
769
+ },
770
+ requestTopRow: {
771
+ flexDirection: 'row',
772
+ justifyContent: 'space-between',
773
+ alignItems: 'flex-start'
774
+ },
775
+ requestTitle: {
776
+ fontSize: 16,
777
+ fontWeight: '700',
778
+ color: '#333333',
779
+ marginBottom: 4
780
+ },
781
+ requestType: {
782
+ fontSize: 14,
783
+ color: '#2563EB',
784
+ fontWeight: '500',
785
+ marginBottom: 8
786
+ },
787
+ requestDate: {
788
+ fontSize: 14,
789
+ color: '#666666',
790
+ fontWeight: '500'
791
+ },
792
+ statusChip: {
793
+ paddingHorizontal: 12,
794
+ paddingVertical: 6,
795
+ borderRadius: 20
796
+ },
797
+ statusChipText: {
798
+ fontWeight: '600',
799
+ fontSize: 12,
800
+ textTransform: 'capitalize'
801
+ },
802
+ skeletonWrap: {
803
+ padding: 16,
804
+ gap: 12
805
+ },
806
+ skeletonCard: {
807
+ height: 96,
808
+ borderRadius: 12,
809
+ backgroundColor: '#E5E7EB'
810
+ },
811
+ form: {
812
+ padding: 16,
813
+ gap: 14
814
+ },
815
+ formCard: {
816
+ backgroundColor: '#FFFFFF',
817
+ borderRadius: 16,
818
+ padding: 16,
819
+ borderWidth: 1,
820
+ borderColor: '#E5E7EB',
821
+ gap: 12
822
+ },
823
+ field: {
824
+ gap: 6
825
+ },
826
+ label: {
827
+ fontSize: 12,
828
+ color: '#6B7280',
829
+ fontWeight: '600'
830
+ },
831
+ input: {
832
+ borderWidth: 1,
833
+ borderColor: '#E5E7EB',
834
+ borderRadius: 12,
835
+ paddingHorizontal: 12,
836
+ paddingVertical: 10,
837
+ color: '#111827',
838
+ backgroundColor: '#FFFFFF'
839
+ },
840
+ textarea: {
841
+ minHeight: 90,
842
+ textAlignVertical: 'top'
843
+ },
844
+ select: {
845
+ borderWidth: 1,
846
+ borderColor: '#E5E7EB',
847
+ borderRadius: 12,
848
+ paddingHorizontal: 12,
849
+ paddingVertical: 12,
850
+ backgroundColor: '#FFFFFF'
851
+ },
852
+ selectText: {
853
+ fontSize: 14,
854
+ color: '#111827'
855
+ },
856
+ toggleRow: {
857
+ flexDirection: 'row',
858
+ gap: 10
859
+ },
860
+ toggleBtn: {
861
+ flex: 1,
862
+ paddingVertical: 12,
863
+ borderRadius: 12,
864
+ backgroundColor: '#F3F4F6',
865
+ alignItems: 'center'
866
+ },
867
+ toggleBtnActive: {
868
+ backgroundColor: '#2563EB'
869
+ },
870
+ toggleBtnText: {
871
+ fontSize: 13,
872
+ fontWeight: '600',
873
+ color: '#374151'
874
+ },
875
+ toggleBtnTextActive: {
876
+ color: '#FFFFFF'
877
+ },
878
+ uploadBtn: {
879
+ paddingVertical: 12,
880
+ borderRadius: 12,
881
+ backgroundColor: '#EFF6FF',
882
+ borderWidth: 1,
883
+ borderColor: '#93C5FD',
884
+ alignItems: 'center'
885
+ },
886
+ uploadBtnText: {
887
+ color: '#1D4ED8',
888
+ fontWeight: '700'
889
+ },
890
+ fileNameText: {
891
+ fontSize: 12,
892
+ color: '#6B7280'
893
+ },
894
+ primaryBtn: {
895
+ paddingVertical: 14,
896
+ borderRadius: 12,
897
+ backgroundColor: '#2563EB',
898
+ alignItems: 'center',
899
+ justifyContent: 'center'
900
+ },
901
+ primaryBtnText: {
902
+ color: '#FFFFFF',
903
+ fontWeight: '800',
904
+ fontSize: 15
905
+ },
906
+ secondaryBtn: {
907
+ paddingHorizontal: 12,
908
+ paddingVertical: 8,
909
+ borderRadius: 10,
910
+ backgroundColor: '#F3F4F6'
911
+ },
912
+ secondaryBtnText: {
913
+ color: '#111827',
914
+ fontWeight: '700'
915
+ },
916
+ modalOverlay: {
917
+ flex: 1,
918
+ backgroundColor: 'rgba(0,0,0,0.45)',
919
+ justifyContent: 'center',
920
+ padding: 16
921
+ },
922
+ modalCard: {
923
+ backgroundColor: '#FFFFFF',
924
+ borderRadius: 16,
925
+ overflow: 'hidden',
926
+ maxHeight: '80%'
927
+ },
928
+ modalTitle: {
929
+ fontSize: 16,
930
+ fontWeight: '700',
931
+ color: '#111827'
932
+ },
933
+ optionRow: {
934
+ paddingHorizontal: 16,
935
+ paddingVertical: 12
936
+ },
937
+ optionText: {
938
+ fontSize: 14,
939
+ color: '#111827'
940
+ },
941
+ optionEmpty: {
942
+ paddingHorizontal: 16,
943
+ paddingVertical: 12,
944
+ color: '#6B7280'
945
+ },
946
+ sheetHeader: {
947
+ paddingHorizontal: 16,
948
+ paddingVertical: 12,
949
+ borderBottomWidth: 1,
950
+ borderBottomColor: '#E5E7EB',
951
+ flexDirection: 'row',
952
+ justifyContent: 'space-between',
953
+ alignItems: 'center'
954
+ },
955
+ actionSheet: {
956
+ backgroundColor: '#FFFFFF',
957
+ borderRadius: 16,
958
+ padding: 20
959
+ },
960
+ actionSheetTitle: {
961
+ fontSize: 18,
962
+ fontWeight: '700',
963
+ color: '#111827',
964
+ textAlign: 'center',
965
+ marginBottom: 20
966
+ },
967
+ actionRow: {
968
+ flexDirection: 'row',
969
+ gap: 12
970
+ },
971
+ actionBtn: {
972
+ flex: 1,
973
+ borderWidth: 1,
974
+ borderColor: '#DBEAFE',
975
+ backgroundColor: '#EFF6FF',
976
+ borderRadius: 14,
977
+ paddingVertical: 18,
978
+ alignItems: 'center'
979
+ },
980
+ actionBtnTitle: {
981
+ fontSize: 14,
982
+ fontWeight: '700',
983
+ color: '#1D4ED8'
984
+ }
985
+ });