icleafreportui 0.2.6 → 0.2.8

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.
@@ -0,0 +1,213 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Autocomplete, FormControl, Button, Grid, Box, Typography, Paper, Snackbar, Alert, CircularProgress, TextField } from '@mui/material';
3
+ import { useTenant } from '../../context/TenantProvider';
4
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
+ function CourseReportContent() {
6
+ const {
7
+ apiClient
8
+ } = useTenant();
9
+ const [subjects, setSubjects] = useState([]);
10
+ const [courses, setCourses] = useState([]);
11
+ const [selectedSubject, setSelectedSubject] = useState(null);
12
+ const [selectedCourse, setSelectedCourse] = useState(null);
13
+ const [reportTypes] = useState(['Summary', 'Daywise']);
14
+ const [selectedReportType, setSelectedReportType] = useState(null);
15
+ const [alertMessage, setAlertMessage] = useState('');
16
+ const [loading, setLoading] = useState(false);
17
+ const [alertOpen, setAlertOpen] = useState(false);
18
+ useEffect(() => {
19
+ fetchAllSubjects();
20
+ }, []);
21
+ const fetchAllSubjects = async () => {
22
+ try {
23
+ const data = await apiClient.get('/api/showAllSubjects');
24
+ setSubjects(data);
25
+ } catch (error) {
26
+ console.error('Error fetching subjects:', error);
27
+ }
28
+ };
29
+ const fetchCourses = async subjectId => {
30
+ try {
31
+ const data = await apiClient.get(`/api/getCoursesBySubject?subjectId=${subjectId}`);
32
+ setCourses(data);
33
+ } catch (error) {
34
+ console.error('Error fetching courses:', error);
35
+ }
36
+ };
37
+ const handleSubjectChange = (event, newValue) => {
38
+ setSelectedSubject(newValue);
39
+ setSelectedCourse(null);
40
+ setCourses([]);
41
+ if (newValue) {
42
+ fetchCourses(newValue.subjectId);
43
+ }
44
+ };
45
+ const handleCourseChange = (event, newValue) => {
46
+ setSelectedCourse(newValue);
47
+ };
48
+ const handleReportTypeChange = (event, newValue) => {
49
+ setSelectedReportType(newValue);
50
+ };
51
+ const handleDownload = async () => {
52
+ setLoading(true);
53
+ try {
54
+ let url;
55
+ if (selectedReportType === 'Summary') {
56
+ url = '/api/downloadUserCorpCourseExcel';
57
+ } else if (selectedReportType === 'Daywise') {
58
+ url = '/api/downloadUserCorpCourseExcelDayWise';
59
+ }
60
+ const fullUrl = `${url}?corpCourseId=${selectedCourse.id}`;
61
+ const response = await fetch(`${apiClient.baseURL}${fullUrl}`, {
62
+ headers: {
63
+ 'X-Tenant-Token': apiClient.tenantToken
64
+ }
65
+ });
66
+ const blob = await response.blob();
67
+ const text = await blob.text();
68
+ if (text.includes('Course not configured')) {
69
+ setAlertMessage('Course not configured.');
70
+ setAlertOpen(true);
71
+ } else {
72
+ const downloadBlob = new Blob([blob], {
73
+ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
74
+ });
75
+ const blobUrl = URL.createObjectURL(downloadBlob);
76
+ const link = document.createElement('a');
77
+ link.href = blobUrl;
78
+ link.setAttribute('download', 'course_report.xlsx');
79
+ document.body.appendChild(link);
80
+ link.click();
81
+ link.parentNode.removeChild(link);
82
+ URL.revokeObjectURL(blobUrl);
83
+ }
84
+ } catch (error) {
85
+ console.error('Error downloading course report:', error);
86
+ } finally {
87
+ setLoading(false);
88
+ }
89
+ };
90
+ return /*#__PURE__*/_jsxs(Box, {
91
+ sx: {
92
+ maxWidth: 800,
93
+ mx: 'auto',
94
+ my: 4,
95
+ p: 3,
96
+ backgroundColor: '#f5f5f5',
97
+ borderRadius: 2
98
+ },
99
+ children: [/*#__PURE__*/_jsxs(Paper, {
100
+ elevation: 6,
101
+ sx: {
102
+ p: 5,
103
+ textAlign: 'center',
104
+ backgroundColor: '#fff'
105
+ },
106
+ children: [/*#__PURE__*/_jsx(Typography, {
107
+ variant: "h4",
108
+ component: "h1",
109
+ gutterBottom: true,
110
+ sx: {
111
+ color: '#3f51b5',
112
+ marginBottom: "20px"
113
+ },
114
+ children: "Course Report"
115
+ }), /*#__PURE__*/_jsxs(Grid, {
116
+ container: true,
117
+ spacing: 2,
118
+ justifyContent: "center",
119
+ children: [/*#__PURE__*/_jsx(Grid, {
120
+ item: true,
121
+ xs: 12,
122
+ sm: 4,
123
+ children: /*#__PURE__*/_jsx(FormControl, {
124
+ fullWidth: true,
125
+ children: /*#__PURE__*/_jsx(Autocomplete, {
126
+ options: subjects,
127
+ getOptionLabel: option => option.subjectName,
128
+ value: selectedSubject,
129
+ onChange: handleSubjectChange,
130
+ renderInput: params => /*#__PURE__*/_jsx(TextField, {
131
+ ...params,
132
+ label: "Subject"
133
+ })
134
+ })
135
+ })
136
+ }), /*#__PURE__*/_jsx(Grid, {
137
+ item: true,
138
+ xs: 12,
139
+ sm: 4,
140
+ children: /*#__PURE__*/_jsx(FormControl, {
141
+ fullWidth: true,
142
+ children: /*#__PURE__*/_jsx(Autocomplete, {
143
+ options: courses,
144
+ getOptionLabel: option => option.courseName,
145
+ value: selectedCourse,
146
+ onChange: handleCourseChange,
147
+ renderInput: params => /*#__PURE__*/_jsx(TextField, {
148
+ ...params,
149
+ label: "Course"
150
+ })
151
+ })
152
+ })
153
+ }), /*#__PURE__*/_jsx(Grid, {
154
+ item: true,
155
+ xs: 12,
156
+ sm: 4,
157
+ children: /*#__PURE__*/_jsx(FormControl, {
158
+ fullWidth: true,
159
+ children: /*#__PURE__*/_jsx(Autocomplete, {
160
+ options: reportTypes,
161
+ getOptionLabel: option => option,
162
+ value: selectedReportType,
163
+ onChange: handleReportTypeChange,
164
+ renderInput: params => /*#__PURE__*/_jsx(TextField, {
165
+ ...params,
166
+ label: "Report Type"
167
+ })
168
+ })
169
+ })
170
+ })]
171
+ }), /*#__PURE__*/_jsxs(Box, {
172
+ sx: {
173
+ mt: 3,
174
+ position: 'relative'
175
+ },
176
+ children: [/*#__PURE__*/_jsx(Button, {
177
+ variant: "contained",
178
+ color: "primary",
179
+ onClick: handleDownload,
180
+ disabled: !selectedSubject || !selectedCourse || !selectedReportType || loading,
181
+ sx: {
182
+ width: 'auto',
183
+ backgroundColor: '#3f51b5'
184
+ },
185
+ children: loading ? 'Downloading...' : 'Download Report'
186
+ }), loading && /*#__PURE__*/_jsx(CircularProgress, {
187
+ size: 24,
188
+ sx: {
189
+ position: 'absolute',
190
+ top: '50%',
191
+ left: '50%',
192
+ marginTop: '-12px',
193
+ marginLeft: '-12px'
194
+ }
195
+ })]
196
+ })]
197
+ }), /*#__PURE__*/_jsx(Snackbar, {
198
+ open: alertOpen,
199
+ autoHideDuration: 6000,
200
+ onClose: () => setAlertOpen(false),
201
+ anchorOrigin: {
202
+ vertical: 'top',
203
+ horizontal: 'center'
204
+ },
205
+ children: /*#__PURE__*/_jsx(Alert, {
206
+ onClose: () => setAlertOpen(false),
207
+ severity: "info",
208
+ children: alertMessage
209
+ })
210
+ })]
211
+ });
212
+ }
213
+ export default CourseReportContent;
@@ -0,0 +1,522 @@
1
+ import React, { useState, useEffect, useRef } from 'react';
2
+ import { Autocomplete, FormControl, Button, Grid, Box, Typography, Paper, Snackbar, Alert, CircularProgress, TextField, InputAdornment } from '@mui/material';
3
+ import { DataGrid } from '@mui/x-data-grid';
4
+ import FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined';
5
+ import SearchOutlinedIcon from '@mui/icons-material/SearchOutlined';
6
+ import Backdrop from '@mui/material/Backdrop';
7
+ import { useTenant } from '../../context/TenantProvider';
8
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
9
+ function ExamPackReportContent() {
10
+ const {
11
+ apiClient
12
+ } = useTenant();
13
+ const [subjects, setSubjects] = useState([]);
14
+ const [courses, setCourses] = useState([]);
15
+ const [selectedSubject, setSelectedSubject] = useState(null);
16
+ const [selectedCourse, setSelectedCourse] = useState(null);
17
+ const [alertMessage, setAlertMessage] = useState('');
18
+ const [loading, setLoading] = useState(false);
19
+ const [alertOpen, setAlertOpen] = useState(false);
20
+ const reportType = [{
21
+ value: "Batch Wise",
22
+ label: "Batch Wise"
23
+ }, {
24
+ value: "User Wise",
25
+ label: "User Wise"
26
+ }];
27
+ const [selectedReportType, setSelectedReportType] = useState(null);
28
+ const [columns, setColumns] = useState(null);
29
+ const [rows, setRows] = useState([]);
30
+ const [tableShow, setTableShow] = useState(false);
31
+ const [multiLoading, setMultiLoading] = useState(false);
32
+ const [userSelect, setUserSelect] = useState(false);
33
+ const [selectedUserList, setSelectedUserList] = useState([]);
34
+ const [tableKey, setTableKey] = useState(0);
35
+ const [searchQuery, setSearchQuery] = useState("");
36
+ const baseURL = apiClient?.baseURL || process.env.REACT_APP_BASE_URL;
37
+ const filteredRows = userSelect ? rows.filter(row => {
38
+ const searchTerms = searchQuery.split(',').map(term => term.trim().toLowerCase()).filter(term => term.length > 0);
39
+ if (searchTerms.length === 0) return true;
40
+ const email = row.userName?.toLowerCase() || '';
41
+ const localPart = email.split('@')[0];
42
+ return searchTerms.some(term => {
43
+ if (term.includes('@')) {
44
+ return email === term;
45
+ } else {
46
+ return localPart.includes(term);
47
+ }
48
+ });
49
+ }) : rows;
50
+ const batchListColumns = [{
51
+ field: 'sno',
52
+ headerName: 'S.No',
53
+ width: 60,
54
+ sortable: false,
55
+ renderCell: params => params.api.getAllRowIds().indexOf(params.id) + 1
56
+ }, {
57
+ field: 'batchName',
58
+ headerName: 'Batch Name',
59
+ width: 230
60
+ }, {
61
+ field: 'batchStatus',
62
+ headerName: 'Status',
63
+ width: 170,
64
+ renderCell: params => /*#__PURE__*/_jsx("span", {
65
+ style: {
66
+ color: params.value ? 'green' : 'red',
67
+ fontWeight: 'bold'
68
+ },
69
+ children: params.value ? 'Active' : 'Inactive'
70
+ })
71
+ }, {
72
+ field: 'dailyProgressMail',
73
+ headerName: 'Daily Progress Mail',
74
+ width: 130,
75
+ renderCell: params => /*#__PURE__*/_jsx("span", {
76
+ style: {
77
+ color: params.value ? 'green' : 'red',
78
+ fontWeight: 'bold'
79
+ },
80
+ children: params.value ? 'Active' : 'Inactive'
81
+ })
82
+ }, {
83
+ field: "report",
84
+ headerName: "Report",
85
+ sortable: false,
86
+ width: 70,
87
+ renderCell: params => /*#__PURE__*/_jsx(FileDownloadOutlinedIcon, {
88
+ onClick: () => handleDownloadBatchReport(params.row),
89
+ fontSize: "small",
90
+ style: {
91
+ cursor: "pointer"
92
+ }
93
+ })
94
+ }];
95
+ const userListColumns = [{
96
+ field: 'sno',
97
+ headerName: 'S.No',
98
+ width: 60,
99
+ sortable: false,
100
+ renderCell: params => params.api.getAllRowIds().indexOf(params.id) + 1
101
+ }, {
102
+ field: 'userName',
103
+ headerName: 'User Name',
104
+ width: 280
105
+ }, {
106
+ field: 'userRoleType',
107
+ headerName: 'Role Type',
108
+ width: 200,
109
+ renderCell: params => /*#__PURE__*/_jsx("span", {
110
+ style: {
111
+ color: params.value ? 'green' : 'red',
112
+ fontWeight: 'bold'
113
+ },
114
+ children: params.value ? 'User' : ''
115
+ })
116
+ }, {
117
+ field: "report",
118
+ headerName: "Report",
119
+ sortable: false,
120
+ width: 70,
121
+ renderCell: params => /*#__PURE__*/_jsx(FileDownloadOutlinedIcon, {
122
+ onClick: () => handleDownloadSingleUserReport(params.row),
123
+ fontSize: "small",
124
+ style: {
125
+ cursor: "pointer"
126
+ }
127
+ })
128
+ }];
129
+ useEffect(() => {
130
+ fetchAllSubjects();
131
+ }, []);
132
+ const fetchAllSubjects = async () => {
133
+ try {
134
+ const data = await apiClient.get('/api/showAllSubjects');
135
+ setSubjects(data);
136
+ } catch (error) {
137
+ console.error('Error fetching subjects:', error);
138
+ }
139
+ };
140
+ const fetchCourses = async subjectId => {
141
+ try {
142
+ const data = await apiClient.get(`/api/getCoursesBySubject?subjectId=${subjectId}`);
143
+ setCourses(data);
144
+ } catch (error) {
145
+ console.error('Error fetching courses:', error);
146
+ }
147
+ };
148
+ const handleSubjectChange = (event, newValue) => {
149
+ setSelectedSubject(newValue);
150
+ setSelectedCourse(null);
151
+ setCourses([]);
152
+ setSelectedReportType(null);
153
+ setTableShow(false);
154
+ setRows([]);
155
+ setColumns([]);
156
+ if (newValue?.subjectId) {
157
+ fetchCourses(newValue.subjectId);
158
+ }
159
+ };
160
+ const handleCourseChange = (event, newValue) => {
161
+ setSelectedCourse(newValue);
162
+ setTableKey(prevKey => prevKey + 1);
163
+ fetchReportData(newValue?.id, selectedReportType?.value);
164
+ };
165
+ const handleReportTypeChange = (event, newValue) => {
166
+ setSelectedReportType(newValue);
167
+ setTableKey(prevKey => prevKey + 1);
168
+ fetchReportData(selectedCourse?.id, newValue?.value);
169
+ };
170
+ const fetchReportData = (courseId, reportTypeValue) => {
171
+ if (!selectedSubject?.subjectId || !courseId) return;
172
+ const apiMap = {
173
+ "Batch Wise": getBatchWiseList,
174
+ "User Wise": getUserWiseList
175
+ };
176
+ apiMap[reportTypeValue]?.(courseId);
177
+ };
178
+ const getBatchWiseList = async () => {
179
+ setLoading(true);
180
+ try {
181
+ const data = await apiClient.get(`/api/getCorpCourseBatches?subjectId=${selectedSubject.subjectId}&corpCourseId=${selectedCourse.id}`);
182
+ if (data) {
183
+ setUserSelect(false);
184
+ setRows(data.corpCourseBatches || []);
185
+ setColumns(batchListColumns);
186
+ setTableShow(true);
187
+ }
188
+ } catch (error) {
189
+ setAlertOpen(true);
190
+ setAlertMessage(error.response?.data?.error || 'Error fetching batch data');
191
+ setTableShow(false);
192
+ setRows([]);
193
+ setColumns([]);
194
+ console.error("Error fetching batch-wise data:", error);
195
+ } finally {
196
+ setLoading(false);
197
+ }
198
+ };
199
+ const getUserWiseList = async () => {
200
+ setLoading(true);
201
+ try {
202
+ const data = await apiClient.get(`/api/getCorpCourseUsers?subjectId=${selectedSubject.subjectId}&corpCourseId=${selectedCourse.id}`);
203
+ if (data) {
204
+ setRows(data.users || []);
205
+ setColumns(userListColumns);
206
+ setTableShow(true);
207
+ setUserSelect(true);
208
+ }
209
+ } catch (error) {
210
+ setAlertOpen(true);
211
+ setAlertMessage(error.response?.data?.error || 'Error fetching user data');
212
+ setTableShow(false);
213
+ setRows([]);
214
+ setColumns([]);
215
+ console.error("Error fetching user-wise data:", error);
216
+ } finally {
217
+ setLoading(false);
218
+ }
219
+ };
220
+ const handleRowSelection = newSelection => {
221
+ setSelectedUserList(newSelection);
222
+ };
223
+ const handleDownloadBatchReport = async item => {
224
+ setLoading(true);
225
+ try {
226
+ const blob = await apiClient.download(`/api/downloadCourseAndBatchWiseReport`, {
227
+ subjectId: selectedSubject.subjectId,
228
+ corpCourseId: selectedCourse.id,
229
+ batchId: item.id
230
+ });
231
+ const text = await blob.text();
232
+ if (text.includes('Course not configured')) {
233
+ setAlertMessage('Course not configured.');
234
+ setAlertOpen(true);
235
+ } else {
236
+ const filename = `${item.batchName}_Batch_Report.xlsx`;
237
+ const blobUrl = URL.createObjectURL(blob);
238
+ const link = document.createElement('a');
239
+ link.href = blobUrl;
240
+ link.setAttribute('download', filename);
241
+ document.body.appendChild(link);
242
+ link.click();
243
+ link.parentNode.removeChild(link);
244
+ URL.revokeObjectURL(blobUrl);
245
+ }
246
+ } catch (error) {
247
+ setAlertOpen(true);
248
+ setAlertMessage(error.response?.data?.error || 'Error downloading report');
249
+ console.error('Error downloading batch report:', error);
250
+ } finally {
251
+ setLoading(false);
252
+ }
253
+ };
254
+ const handleDownloadSingleUserReport = async item => {
255
+ setLoading(true);
256
+ try {
257
+ const blob = await apiClient.download(`/api/downloadExamPackReportByCourse`, {
258
+ userId: item.id,
259
+ corpCourseId: selectedCourse.id,
260
+ subjectId: selectedSubject.subjectId
261
+ });
262
+ const text = await blob.text();
263
+ if (text.includes('Course not configured')) {
264
+ setAlertMessage('Course not configured.');
265
+ setAlertOpen(true);
266
+ } else {
267
+ const filename = `${item.userName}_Pack_Report.xlsx`;
268
+ const blobUrl = URL.createObjectURL(blob);
269
+ const link = document.createElement('a');
270
+ link.href = blobUrl;
271
+ link.setAttribute('download', filename);
272
+ document.body.appendChild(link);
273
+ link.click();
274
+ link.parentNode.removeChild(link);
275
+ URL.revokeObjectURL(blobUrl);
276
+ }
277
+ } catch (error) {
278
+ setAlertOpen(true);
279
+ setAlertMessage(error.response?.data?.error || 'Error downloading report');
280
+ console.error('Error downloading user report:', error);
281
+ } finally {
282
+ setLoading(false);
283
+ }
284
+ };
285
+ const handleSummaryDownload = async () => {
286
+ setMultiLoading(true);
287
+ const selectedRowIds = rows.filter(row => selectedUserList.includes(row.id)).map(row => row.id);
288
+ try {
289
+ const response = await fetch(`${baseURL}/api/downloadExamPacksAndUserIdsReport?subjectId=${selectedSubject.subjectId}&corpCourseId=${selectedCourse.id}`, {
290
+ method: 'POST',
291
+ headers: {
292
+ 'Content-Type': 'application/json',
293
+ 'X-Tenant-Token': apiClient.tenantToken
294
+ },
295
+ body: JSON.stringify({
296
+ userIds: selectedRowIds
297
+ })
298
+ });
299
+ const blob = await response.blob();
300
+ const text = await blob.text();
301
+ if (text.includes('Course not configured')) {
302
+ setAlertMessage('Course not configured.');
303
+ setAlertOpen(true);
304
+ } else {
305
+ const filename = 'User_Exam_Pack_Report.xlsx';
306
+ const blobUrl = URL.createObjectURL(blob);
307
+ const link = document.createElement('a');
308
+ link.href = blobUrl;
309
+ link.setAttribute('download', filename);
310
+ document.body.appendChild(link);
311
+ link.click();
312
+ link.parentNode.removeChild(link);
313
+ URL.revokeObjectURL(blobUrl);
314
+ }
315
+ } catch (error) {
316
+ setAlertOpen(true);
317
+ setAlertMessage(error.response?.data?.error || 'Error downloading report');
318
+ console.error('Error downloading summary report:', error);
319
+ } finally {
320
+ setMultiLoading(false);
321
+ }
322
+ };
323
+
324
+ // Add download method to apiClient if not exists
325
+ const download = async function (endpoint) {
326
+ let params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
327
+ const query = new URLSearchParams(params).toString();
328
+ const url = `${endpoint}?${query}`;
329
+ const response = await fetch(`${baseURL}/${url}`, {
330
+ headers: {
331
+ 'X-Tenant-Token': apiClient.tenantToken
332
+ }
333
+ });
334
+ return response.blob();
335
+ };
336
+
337
+ // Add download method to apiClient
338
+ if (apiClient && !apiClient.download) {
339
+ apiClient.download = download;
340
+ }
341
+ const paginationModel = {
342
+ page: 0,
343
+ pageSize: 5
344
+ };
345
+ return /*#__PURE__*/_jsxs(Box, {
346
+ sx: {
347
+ maxWidth: 1000,
348
+ mx: 'auto',
349
+ my: 4,
350
+ p: 3,
351
+ backgroundColor: '#f5f5f5',
352
+ borderRadius: 2
353
+ },
354
+ children: [/*#__PURE__*/_jsxs(Paper, {
355
+ elevation: 6,
356
+ sx: {
357
+ p: 5,
358
+ textAlign: 'center',
359
+ backgroundColor: '#fff'
360
+ },
361
+ children: [/*#__PURE__*/_jsx(Typography, {
362
+ variant: "h4",
363
+ component: "h1",
364
+ gutterBottom: true,
365
+ sx: {
366
+ color: '#3f51b5',
367
+ marginBottom: "20px"
368
+ },
369
+ children: "Exam Pack Report"
370
+ }), /*#__PURE__*/_jsxs(Grid, {
371
+ container: true,
372
+ spacing: 2,
373
+ justifyContent: "center",
374
+ children: [/*#__PURE__*/_jsx(Grid, {
375
+ item: true,
376
+ xs: 12,
377
+ sm: 4,
378
+ children: /*#__PURE__*/_jsx(FormControl, {
379
+ fullWidth: true,
380
+ children: /*#__PURE__*/_jsx(Autocomplete, {
381
+ options: subjects,
382
+ getOptionLabel: option => option.subjectName,
383
+ value: selectedSubject,
384
+ onChange: handleSubjectChange,
385
+ renderInput: params => /*#__PURE__*/_jsx(TextField, {
386
+ ...params,
387
+ label: "Subject"
388
+ })
389
+ })
390
+ })
391
+ }), /*#__PURE__*/_jsx(Grid, {
392
+ item: true,
393
+ xs: 12,
394
+ sm: 4,
395
+ children: /*#__PURE__*/_jsx(FormControl, {
396
+ fullWidth: true,
397
+ children: /*#__PURE__*/_jsx(Autocomplete, {
398
+ options: courses,
399
+ getOptionLabel: option => option.courseName,
400
+ value: selectedCourse,
401
+ onChange: handleCourseChange,
402
+ renderInput: params => /*#__PURE__*/_jsx(TextField, {
403
+ ...params,
404
+ label: "Course"
405
+ })
406
+ })
407
+ })
408
+ }), /*#__PURE__*/_jsx(Grid, {
409
+ item: true,
410
+ xs: 12,
411
+ sm: 4,
412
+ children: /*#__PURE__*/_jsx(FormControl, {
413
+ fullWidth: true,
414
+ children: /*#__PURE__*/_jsx(Autocomplete, {
415
+ options: reportType,
416
+ getOptionLabel: option => option.label,
417
+ value: selectedReportType,
418
+ onChange: handleReportTypeChange,
419
+ renderInput: params => /*#__PURE__*/_jsx(TextField, {
420
+ ...params,
421
+ label: "Report Type"
422
+ })
423
+ })
424
+ })
425
+ })]
426
+ }), tableShow && /*#__PURE__*/_jsxs(_Fragment, {
427
+ children: [/*#__PURE__*/_jsx(Box, {
428
+ sx: {
429
+ display: "flex",
430
+ justifyContent: "flex-end",
431
+ width: "100%",
432
+ margin: "20px 0px"
433
+ },
434
+ children: userSelect && /*#__PURE__*/_jsx(Button, {
435
+ variant: "contained",
436
+ color: "primary",
437
+ onClick: handleSummaryDownload,
438
+ disabled: selectedUserList.length <= 1,
439
+ sx: {
440
+ width: 'auto',
441
+ backgroundColor: '#3f51b5'
442
+ },
443
+ children: multiLoading ? 'Downloading...' : 'Download Report'
444
+ })
445
+ }), /*#__PURE__*/_jsxs(Paper, {
446
+ sx: {
447
+ width: '100%'
448
+ },
449
+ children: [/*#__PURE__*/_jsx("div", {
450
+ style: {
451
+ display: "flex",
452
+ justifyContent: "end",
453
+ alignItems: "center",
454
+ height: "100%",
455
+ padding: "10px 5px"
456
+ },
457
+ children: userSelect && /*#__PURE__*/_jsx(TextField, {
458
+ label: "Search",
459
+ variant: "outlined",
460
+ size: "small",
461
+ sx: {
462
+ mb: 2
463
+ },
464
+ value: searchQuery,
465
+ onChange: e => setSearchQuery(e.target.value),
466
+ InputProps: {
467
+ endAdornment: /*#__PURE__*/_jsx(InputAdornment, {
468
+ position: "start",
469
+ children: /*#__PURE__*/_jsx(SearchOutlinedIcon, {})
470
+ })
471
+ }
472
+ })
473
+ }), /*#__PURE__*/_jsx(DataGrid, {
474
+ rows: userSelect ? filteredRows : rows,
475
+ columns: columns,
476
+ initialState: {
477
+ pagination: {
478
+ paginationModel
479
+ }
480
+ },
481
+ pageSizeOptions: [5, 10, 50, 100],
482
+ checkboxSelection: userSelect,
483
+ disableRowSelectionOnClick: true,
484
+ onRowSelectionModelChange: handleRowSelection,
485
+ sx: {
486
+ border: 0,
487
+ "& .MuiTablePagination-selectLabel": {
488
+ margin: "unset"
489
+ },
490
+ "& .MuiTablePagination-displayedRows": {
491
+ margin: "unset"
492
+ }
493
+ }
494
+ }, tableKey)]
495
+ })]
496
+ })]
497
+ }), /*#__PURE__*/_jsx(Snackbar, {
498
+ open: alertOpen,
499
+ autoHideDuration: 6000,
500
+ onClose: () => setAlertOpen(false),
501
+ anchorOrigin: {
502
+ vertical: 'top',
503
+ horizontal: 'center'
504
+ },
505
+ children: /*#__PURE__*/_jsx(Alert, {
506
+ onClose: () => setAlertOpen(false),
507
+ severity: "info",
508
+ children: alertMessage
509
+ })
510
+ }), /*#__PURE__*/_jsx(Backdrop, {
511
+ sx: theme => ({
512
+ color: '#fff',
513
+ zIndex: theme.zIndex.drawer + 1
514
+ }),
515
+ open: loading || multiLoading,
516
+ children: /*#__PURE__*/_jsx(CircularProgress, {
517
+ color: "inherit"
518
+ })
519
+ })]
520
+ });
521
+ }
522
+ export default ExamPackReportContent;
@@ -0,0 +1,206 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Autocomplete, FormControl, Button, Grid, Box, Typography, Paper, Snackbar, Alert, CircularProgress, TextField } from '@mui/material';
3
+ import { useTenant } from '../../context/TenantProvider';
4
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
+ function ExamReportContent() {
6
+ const {
7
+ apiClient
8
+ } = useTenant();
9
+ const [subjects, setSubjects] = useState([]);
10
+ const [examPacks, setExamPacks] = useState([]);
11
+ const [exams, setExams] = useState([]);
12
+ const [selectedSubject, setSelectedSubject] = useState(null);
13
+ const [selectedExamPack, setSelectedExamPack] = useState(null);
14
+ const [selectedExam, setSelectedExam] = useState(null);
15
+ const [alertMessage, setAlertMessage] = useState('');
16
+ const [openAlert, setOpenAlert] = useState(false);
17
+ const [loading, setLoading] = useState(false);
18
+ useEffect(() => {
19
+ fetchAllSubjects();
20
+ }, []);
21
+ const fetchAllSubjects = async () => {
22
+ try {
23
+ const data = await apiClient.get('/api/showAllSubjects');
24
+ setSubjects(data);
25
+ } catch (error) {
26
+ console.error('Error fetching subjects:', error);
27
+ }
28
+ };
29
+ const fetchExamPacks = async subjectId => {
30
+ try {
31
+ const data = await apiClient.get(`/api/getAllExamPacks?subjectId=${subjectId}`);
32
+ setExamPacks(data);
33
+ } catch (error) {
34
+ console.error('Error fetching exam packs:', error);
35
+ }
36
+ };
37
+ const fetchExams = async examPackId => {
38
+ try {
39
+ const data = await apiClient.get(`/api/getAllExams?examPackId=${examPackId}`);
40
+ setExams(data);
41
+ } catch (error) {
42
+ console.error('Error fetching exams:', error);
43
+ }
44
+ };
45
+ const handleSubjectChange = (event, newValue) => {
46
+ setSelectedSubject(newValue);
47
+ setSelectedExamPack(null);
48
+ setSelectedExam(null);
49
+ setExamPacks([]);
50
+ setExams([]);
51
+ if (newValue) {
52
+ fetchExamPacks(newValue.subjectId);
53
+ }
54
+ };
55
+ const handleExamPackChange = (event, newValue) => {
56
+ setSelectedExamPack(newValue);
57
+ setSelectedExam(null);
58
+ setExams([]);
59
+ if (newValue) {
60
+ fetchExams(newValue.id);
61
+ }
62
+ };
63
+ const handleExamChange = (event, newValue) => {
64
+ setSelectedExam(newValue);
65
+ };
66
+ const handleDownload = async () => {
67
+ setLoading(true);
68
+ try {
69
+ const response = await fetch(`${apiClient.baseURL}/api/generateReportForExam?subjectId=${selectedSubject.subjectId}&examPackId=${selectedExamPack.id}&examId=${selectedExam.id}`, {
70
+ headers: {
71
+ 'X-Tenant-Token': apiClient.tenantToken
72
+ }
73
+ });
74
+ const blob = await response.blob();
75
+ const blobUrl = URL.createObjectURL(blob);
76
+ const link = document.createElement('a');
77
+ link.href = blobUrl;
78
+ link.setAttribute('download', 'QuestionewiseExamReport.xlsx');
79
+ document.body.appendChild(link);
80
+ link.click();
81
+ link.parentNode.removeChild(link);
82
+ URL.revokeObjectURL(blobUrl);
83
+ } catch (error) {
84
+ console.error('Error downloading report:', error);
85
+ } finally {
86
+ setLoading(false);
87
+ }
88
+ };
89
+ return /*#__PURE__*/_jsxs(Box, {
90
+ sx: {
91
+ maxWidth: 800,
92
+ mx: 'auto',
93
+ my: 4,
94
+ p: 3,
95
+ backgroundColor: '#f5f5f5',
96
+ borderRadius: 2
97
+ },
98
+ children: [/*#__PURE__*/_jsxs(Paper, {
99
+ elevation: 6,
100
+ sx: {
101
+ p: 5,
102
+ textAlign: 'center',
103
+ backgroundColor: '#fff'
104
+ },
105
+ children: [/*#__PURE__*/_jsx(Typography, {
106
+ variant: "h4",
107
+ component: "h1",
108
+ gutterBottom: true,
109
+ sx: {
110
+ color: '#3f51b5',
111
+ marginBottom: "20px"
112
+ },
113
+ children: "Exam Questions Report"
114
+ }), /*#__PURE__*/_jsxs(Grid, {
115
+ container: true,
116
+ spacing: 2,
117
+ justifyContent: "center",
118
+ children: [/*#__PURE__*/_jsx(Grid, {
119
+ item: true,
120
+ xs: 12,
121
+ sm: 6,
122
+ children: /*#__PURE__*/_jsx(FormControl, {
123
+ fullWidth: true,
124
+ children: /*#__PURE__*/_jsx(Autocomplete, {
125
+ options: subjects,
126
+ getOptionLabel: option => option.subjectName,
127
+ value: selectedSubject,
128
+ onChange: handleSubjectChange,
129
+ renderInput: params => /*#__PURE__*/_jsx(TextField, {
130
+ ...params,
131
+ label: "Subject"
132
+ })
133
+ })
134
+ })
135
+ }), /*#__PURE__*/_jsx(Grid, {
136
+ item: true,
137
+ xs: 12,
138
+ sm: 6,
139
+ children: /*#__PURE__*/_jsx(FormControl, {
140
+ fullWidth: true,
141
+ children: /*#__PURE__*/_jsx(Autocomplete, {
142
+ options: examPacks,
143
+ getOptionLabel: option => option.name,
144
+ value: selectedExamPack,
145
+ onChange: handleExamPackChange,
146
+ renderInput: params => /*#__PURE__*/_jsx(TextField, {
147
+ ...params,
148
+ label: "Exam Pack"
149
+ })
150
+ })
151
+ })
152
+ }), /*#__PURE__*/_jsx(Grid, {
153
+ item: true,
154
+ xs: 12,
155
+ sm: 6,
156
+ children: /*#__PURE__*/_jsx(FormControl, {
157
+ fullWidth: true,
158
+ children: /*#__PURE__*/_jsx(Autocomplete, {
159
+ options: exams,
160
+ getOptionLabel: option => option.examName,
161
+ value: selectedExam,
162
+ onChange: handleExamChange,
163
+ renderInput: params => /*#__PURE__*/_jsx(TextField, {
164
+ ...params,
165
+ label: "Exam"
166
+ })
167
+ })
168
+ })
169
+ })]
170
+ }), /*#__PURE__*/_jsxs(Box, {
171
+ sx: {
172
+ mt: 3,
173
+ position: 'relative'
174
+ },
175
+ children: [/*#__PURE__*/_jsx(Button, {
176
+ variant: "contained",
177
+ color: "primary",
178
+ onClick: handleDownload,
179
+ disabled: !selectedSubject || !selectedExamPack || !selectedExam || loading,
180
+ sx: {
181
+ width: 'auto',
182
+ backgroundColor: '#3f51b5'
183
+ },
184
+ children: loading ? 'Downloading...' : 'Download Report'
185
+ }), loading && /*#__PURE__*/_jsx(CircularProgress, {
186
+ size: 24,
187
+ sx: {
188
+ position: 'absolute',
189
+ top: '50%',
190
+ left: '50%'
191
+ }
192
+ })]
193
+ })]
194
+ }), /*#__PURE__*/_jsx(Snackbar, {
195
+ open: openAlert,
196
+ autoHideDuration: 6000,
197
+ onClose: () => setOpenAlert(false),
198
+ children: /*#__PURE__*/_jsx(Alert, {
199
+ onClose: () => setOpenAlert(false),
200
+ severity: "info",
201
+ children: alertMessage
202
+ })
203
+ })]
204
+ });
205
+ }
206
+ export default ExamReportContent;
@@ -1,6 +1,6 @@
1
1
  import React, { useState, useEffect } from 'react';
2
2
  import { Autocomplete, FormControl, Button, Grid, Box, Typography, Paper, Snackbar, Alert, CircularProgress, TextField, Checkbox, FormControlLabel } from '@mui/material';
3
- import { useTenant } from '../context/TenantProvider';
3
+ import { useTenant } from '../../context/TenantProvider';
4
4
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
5
  function ReportContent() {
6
6
  const {
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import Header from '../../components/Header';
3
+ import Sidebar from '../../components/sidebar';
4
+ import ExamReportContent from './ExamReportContent';
5
+ import CourseReportContent from './CourseReportContent';
6
+ import ExamPackReportContent from './ExamPackReportContent';
7
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
+ function ReportViewer(_ref) {
9
+ let {
10
+ type = 'exam',
11
+ embedded = false
12
+ } = _ref;
13
+ const renderContent = () => {
14
+ switch (type) {
15
+ case 'exam':
16
+ return /*#__PURE__*/_jsx(ExamReportContent, {});
17
+ case 'course':
18
+ return /*#__PURE__*/_jsx(CourseReportContent, {});
19
+ case 'exampack':
20
+ return /*#__PURE__*/_jsx(ExamPackReportContent, {});
21
+ default:
22
+ return /*#__PURE__*/_jsx(ExamReportContent, {});
23
+ }
24
+ };
25
+
26
+ // If embedded mode, just return the content (no Header/Sidebar)
27
+ if (embedded) {
28
+ return renderContent();
29
+ }
30
+
31
+ // Full layout with Header and Sidebar
32
+ return /*#__PURE__*/_jsxs("div", {
33
+ children: [/*#__PURE__*/_jsx(Header, {}), /*#__PURE__*/_jsx(Sidebar, {}), /*#__PURE__*/_jsx("div", {
34
+ style: {
35
+ padding: "100px 0px 0px 100px",
36
+ marginLeft: "140px"
37
+ },
38
+ children: renderContent()
39
+ })]
40
+ });
41
+ }
42
+ export default ReportViewer;
package/dist/package.js CHANGED
@@ -13,7 +13,10 @@ export { default as ExamReport } from './Reports/ExamReport';
13
13
  export { default as ExamPackReport } from './Reports/ExamPackReport';
14
14
 
15
15
  //no header and sidebar
16
- export { default as ReportContent } from './Reports/ReportContent';
16
+ export { default as ReportContent } from './Reports/ImportContent/ReportContent';
17
+
18
+ // src/package.js
19
+ export { default as ReportViewer } from './Reports/ImportContent/ReportViewer';
17
20
 
18
21
  // Context
19
22
  export { TenantProvider, useTenant } from './context/TenantProvider';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icleafreportui",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "private": false,
5
5
  "main": "dist/package.js",
6
6
  "files": [