icleafreportui 0.1.0 → 0.1.2

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 (92) hide show
  1. package/dist/App.js +52 -0
  2. package/dist/Login.js +177 -0
  3. package/dist/Reports/CourseReport.js +243 -0
  4. package/dist/Reports/ExamPackReport.js +559 -0
  5. package/dist/Reports/ExamReport.js +290 -0
  6. package/dist/Reports/Report.js +299 -0
  7. package/dist/api/client.js +44 -0
  8. package/dist/components/Header.js +147 -0
  9. package/dist/components/Loader.js +30 -0
  10. package/dist/components/imagePathUrl.js +17 -0
  11. package/dist/components/sidebar.js +78 -0
  12. package/dist/context/TenantProvider.js +34 -0
  13. package/dist/index.js +19 -0
  14. package/dist/package.js +101 -0
  15. package/dist/reportWebVitals.js +27 -0
  16. package/dist/setupTests.js +3 -0
  17. package/package.json +11 -3
  18. package/.env +0 -7
  19. package/public/favicon.ico +0 -0
  20. package/public/images/EResourcesImg.png +0 -0
  21. package/public/images/courseCardImg.png +0 -0
  22. package/public/images/courseInfo.png +0 -0
  23. package/public/images/exam-options.png +0 -0
  24. package/public/images/icleaf-11.png +0 -0
  25. package/public/images/icleaf_logo.png +0 -0
  26. package/public/images/template.png +0 -0
  27. package/public/images/unnamed.png +0 -0
  28. package/public/images/user.jpg +0 -0
  29. package/public/images/young-man-studying-library-using-laptop-1.png +0 -0
  30. package/public/index.html +0 -45
  31. package/public/logo192.png +0 -0
  32. package/public/logo512.png +0 -0
  33. package/public/manifest.json +0 -25
  34. package/public/robots.txt +0 -3
  35. package/src/App.js +0 -37
  36. package/src/Login.js +0 -159
  37. package/src/Reports/CourseReport.js +0 -209
  38. package/src/Reports/ExamPackReport.js +0 -554
  39. package/src/Reports/ExamReport.js +0 -269
  40. package/src/Reports/Report.js +0 -271
  41. package/src/api/client.jsx +0 -42
  42. package/src/components/Header.jsx +0 -192
  43. package/src/components/Loader.jsx +0 -23
  44. package/src/components/imagePathUrl.jsx +0 -11
  45. package/src/components/sidebar.jsx +0 -81
  46. package/src/context/TenantProvider.jsx +0 -22
  47. package/src/index.js +0 -21
  48. package/src/package.js +0 -10
  49. package/src/reportWebVitals.js +0 -13
  50. package/src/setupTests.js +0 -5
  51. /package/{src → dist}/App.css +0 -0
  52. /package/{src → dist}/components/Header.css +0 -0
  53. /package/{src → dist}/components/sidebar.css +0 -0
  54. /package/{src → dist}/fonts/210000.jpg +0 -0
  55. /package/{src → dist}/fonts/210001.jpg +0 -0
  56. /package/{src → dist}/fonts/210003.jpg +0 -0
  57. /package/{src → dist}/fonts/210004.jpg +0 -0
  58. /package/{src → dist}/fonts/210006.jpg +0 -0
  59. /package/{src → dist}/fonts/210018.jpg +0 -0
  60. /package/{src → dist}/fonts/210019.jpg +0 -0
  61. /package/{src → dist}/fonts/210020.jpg +0 -0
  62. /package/{src → dist}/fonts/210279.jpg +0 -0
  63. /package/{src → dist}/fonts/210280.jpg +0 -0
  64. /package/{src → dist}/fonts/Gilroy-Black.ttf +0 -0
  65. /package/{src → dist}/fonts/Gilroy-BlackItalic.ttf +0 -0
  66. /package/{src → dist}/fonts/Gilroy-Bold.ttf +0 -0
  67. /package/{src → dist}/fonts/Gilroy-BoldItalic.ttf +0 -0
  68. /package/{src → dist}/fonts/Gilroy-ExtraBold.ttf +0 -0
  69. /package/{src → dist}/fonts/Gilroy-ExtraBoldItalic.ttf +0 -0
  70. /package/{src → dist}/fonts/Gilroy-Heavy.ttf +0 -0
  71. /package/{src → dist}/fonts/Gilroy-HeavyItalic.ttf +0 -0
  72. /package/{src → dist}/fonts/Gilroy-Light.ttf +0 -0
  73. /package/{src → dist}/fonts/Gilroy-LightItalic.ttf +0 -0
  74. /package/{src → dist}/fonts/Gilroy-Medium.ttf +0 -0
  75. /package/{src → dist}/fonts/Gilroy-MediumItalic.ttf +0 -0
  76. /package/{src → dist}/fonts/Gilroy-Regular.ttf +0 -0
  77. /package/{src → dist}/fonts/Gilroy-RegularItalic.ttf +0 -0
  78. /package/{src → dist}/fonts/Gilroy-SemiBold.ttf +0 -0
  79. /package/{src → dist}/fonts/Gilroy-SemiBoldItalic.ttf +0 -0
  80. /package/{src → dist}/fonts/Gilroy-Thin.ttf +0 -0
  81. /package/{src → dist}/fonts/Gilroy-ThinItalic.ttf +0 -0
  82. /package/{src → dist}/fonts/Gilroy-UltraLight.ttf +0 -0
  83. /package/{src → dist}/fonts/Gilroy-UltraLightItalic.ttf +0 -0
  84. /package/{src → dist}/fonts/Help - Guide Document.pdf +0 -0
  85. /package/{src → dist}/fonts/License.txt +0 -0
  86. /package/{src → dist}/fonts/More Free Fonts on fontshmonts.com.url +0 -0
  87. /package/{src → dist}/fonts/cover.jpg +0 -0
  88. /package/{src → dist}/index.css +0 -0
  89. /package/{src → dist}/login.css +0 -0
  90. /package/{src → dist}/logo.svg +0 -0
  91. /package/{src → dist}/styles.css +0 -0
  92. /package/{src → dist}/theme.css +0 -0
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _axios = _interopRequireDefault(require("axios"));
9
+ var _material = require("@mui/material");
10
+ var _reactRouterDom = require("react-router-dom");
11
+ var _Header = _interopRequireDefault(require("../components/Header"));
12
+ var _sidebar = _interopRequireDefault(require("../components/sidebar"));
13
+ require("../App.css");
14
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
16
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
17
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
18
+ function ExamReport() {
19
+ const [token, setToken] = (0, _react.useState)(localStorage.getItem("token"));
20
+ const navigate = (0, _reactRouterDom.useNavigate)();
21
+ const [subjects, setSubjects] = (0, _react.useState)([]);
22
+ const [examPacks, setExamPacks] = (0, _react.useState)([]);
23
+ const [exams, setExams] = (0, _react.useState)([]);
24
+ const [users, setUsers] = (0, _react.useState)([]);
25
+ const [selectedSubject, setSelectedSubject] = (0, _react.useState)(null);
26
+ const [selectedExamPack, setSelectedExamPack] = (0, _react.useState)(null);
27
+ const [selectedExam, setSelectedExam] = (0, _react.useState)(null);
28
+ const [selectedUser, setSelectedUser] = (0, _react.useState)(null);
29
+ const [alertMessage, setAlertMessage] = (0, _react.useState)('');
30
+ const [openAlert, setOpenAlert] = (0, _react.useState)(false);
31
+ const [loading, setLoading] = (0, _react.useState)(false);
32
+ const baseURL = process.env.REACT_APP_BASE_URL;
33
+ (0, _react.useEffect)(() => {
34
+ if (token == null) {
35
+ navigate("/login");
36
+ } else {
37
+ fetchAllSubjects();
38
+ }
39
+ }, []);
40
+ const fetchAllSubjects = async () => {
41
+ try {
42
+ const response = await (0, _axios.default)({
43
+ method: "get",
44
+ url: `${baseURL}api/showAllSubjects`,
45
+ headers: {
46
+ Authorization: `Bearer ${token}`
47
+ }
48
+ });
49
+ setSubjects(response.data);
50
+ } catch (error) {
51
+ console.error('Error fetching subjects:', error);
52
+ }
53
+ };
54
+ const fetchExamPacks = async subjectId => {
55
+ try {
56
+ const response = await (0, _axios.default)({
57
+ method: "get",
58
+ params: {
59
+ subjectId
60
+ },
61
+ url: `${baseURL}api/getAllExamPacks`,
62
+ headers: {
63
+ Authorization: `Bearer ${token}`
64
+ }
65
+ });
66
+ setExamPacks(response.data);
67
+ } catch (error) {
68
+ console.error('Error fetching exam packs:', error);
69
+ }
70
+ };
71
+ const fetchExams = async examPackId => {
72
+ try {
73
+ const response = await (0, _axios.default)({
74
+ method: "get",
75
+ params: {
76
+ examPackId
77
+ },
78
+ url: `${baseURL}api/getAllExams`,
79
+ headers: {
80
+ Authorization: `Bearer ${token}`
81
+ }
82
+ });
83
+ setExams(response.data);
84
+ } catch (error) {
85
+ console.error('Error fetching exams:', error);
86
+ }
87
+ };
88
+ const fetchUsers = async examId => {
89
+ try {
90
+ const response = await (0, _axios.default)({
91
+ method: "get",
92
+ params: {
93
+ examId
94
+ },
95
+ url: `${baseURL}api/getAllUsers`,
96
+ headers: {
97
+ Authorization: `Bearer ${token}`
98
+ }
99
+ });
100
+ setUsers(response.data);
101
+ } catch (error) {
102
+ console.error('Error fetching users:', error);
103
+ }
104
+ };
105
+ const handleSubjectChange = (event, newValue) => {
106
+ setSelectedSubject(newValue);
107
+ setSelectedExamPack(null);
108
+ setSelectedExam(null);
109
+ setSelectedUser(null);
110
+ setExamPacks([]);
111
+ setExams([]);
112
+ setUsers([]);
113
+ if (newValue) {
114
+ fetchExamPacks(newValue.subjectId);
115
+ }
116
+ };
117
+ const handleExamPackChange = (event, newValue) => {
118
+ setSelectedExamPack(newValue);
119
+ setSelectedExam(null);
120
+ setSelectedUser(null);
121
+ setExams([]);
122
+ setUsers([]);
123
+ if (newValue) {
124
+ fetchExams(newValue.id);
125
+ }
126
+ };
127
+ const handleExamChange = (event, newValue) => {
128
+ setSelectedExam(newValue);
129
+ setSelectedUser(null);
130
+ setUsers([]);
131
+ if (newValue) {
132
+ fetchUsers(newValue.id);
133
+ }
134
+ };
135
+ const handleUserChange = (event, newValue) => {
136
+ setSelectedUser(newValue);
137
+ };
138
+ const handleDownload = async () => {
139
+ setLoading(true);
140
+ try {
141
+ const url = `${baseURL}api/generateReportForExam?subjectId=${selectedSubject.subjectId}&examPackId=${selectedExamPack.id}&examId=${selectedExam.id}`;
142
+ const response = await _axios.default.get(url, {
143
+ responseType: 'blob',
144
+ headers: {
145
+ Authorization: `Bearer ${token}`
146
+ }
147
+ });
148
+ const blob = new Blob([response.data], {
149
+ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
150
+ });
151
+ const blobUrl = URL.createObjectURL(blob);
152
+ const link = document.createElement('a');
153
+ link.href = blobUrl;
154
+ link.setAttribute('download', 'QuestionewiseExamReport.xlsx');
155
+ document.body.appendChild(link);
156
+ link.click();
157
+ link.parentNode.removeChild(link);
158
+ URL.revokeObjectURL(blobUrl);
159
+ } catch (error) {
160
+ console.error('Error downloading report:', error);
161
+ } finally {
162
+ setLoading(false);
163
+ }
164
+ };
165
+ return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_Header.default, null), /*#__PURE__*/_react.default.createElement(_sidebar.default, null), /*#__PURE__*/_react.default.createElement("div", {
166
+ style: {
167
+ padding: "100px 0px 0px 100px",
168
+ marginLeft: "140px"
169
+ }
170
+ }, /*#__PURE__*/_react.default.createElement(_material.Box, {
171
+ sx: {
172
+ maxWidth: 800,
173
+ mx: 'auto',
174
+ my: 4,
175
+ p: 3,
176
+ backgroundColor: '#f5f5f5',
177
+ borderRadius: 2
178
+ }
179
+ }, /*#__PURE__*/_react.default.createElement(_material.Paper, {
180
+ elevation: 6,
181
+ sx: {
182
+ p: 5,
183
+ textAlign: 'center',
184
+ backgroundColor: '#fff'
185
+ }
186
+ }, /*#__PURE__*/_react.default.createElement(_material.Typography, {
187
+ variant: "h4",
188
+ component: "h1",
189
+ gutterBottom: true,
190
+ sx: {
191
+ color: '#3f51b5',
192
+ marginBottom: "20px"
193
+ }
194
+ }, "Exam Questions Report"), /*#__PURE__*/_react.default.createElement(_material.Grid, {
195
+ container: true,
196
+ spacing: 2,
197
+ justifyContent: "center"
198
+ }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
199
+ item: true,
200
+ xs: 12,
201
+ sm: 6
202
+ }, /*#__PURE__*/_react.default.createElement(_material.FormControl, {
203
+ fullWidth: true
204
+ }, /*#__PURE__*/_react.default.createElement(_material.Autocomplete, {
205
+ id: "ddlSubject",
206
+ options: subjects,
207
+ getOptionLabel: option => option.subjectName,
208
+ value: selectedSubject,
209
+ onChange: handleSubjectChange,
210
+ renderInput: params => /*#__PURE__*/_react.default.createElement(_material.TextField, _extends({}, params, {
211
+ label: "Subject"
212
+ }))
213
+ }))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
214
+ item: true,
215
+ xs: 12,
216
+ sm: 6
217
+ }, /*#__PURE__*/_react.default.createElement(_material.FormControl, {
218
+ fullWidth: true
219
+ }, /*#__PURE__*/_react.default.createElement(_material.Autocomplete, {
220
+ id: "ddlExamPack",
221
+ options: examPacks,
222
+ getOptionLabel: option => option.name,
223
+ value: selectedExamPack,
224
+ onChange: handleExamPackChange,
225
+ renderInput: params => /*#__PURE__*/_react.default.createElement(_material.TextField, _extends({}, params, {
226
+ label: "Exam Pack"
227
+ }))
228
+ }))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
229
+ item: true,
230
+ xs: 12,
231
+ sm: 6
232
+ }, /*#__PURE__*/_react.default.createElement(_material.FormControl, {
233
+ fullWidth: true
234
+ }, /*#__PURE__*/_react.default.createElement(_material.Autocomplete, {
235
+ id: "ddlExam",
236
+ options: exams,
237
+ getOptionLabel: option => option.examName,
238
+ value: selectedExam,
239
+ onChange: handleExamChange,
240
+ renderInput: params => /*#__PURE__*/_react.default.createElement(_material.TextField, _extends({}, params, {
241
+ label: "Exam"
242
+ }))
243
+ })))), /*#__PURE__*/_react.default.createElement(_material.Box, {
244
+ sx: {
245
+ mt: 3,
246
+ position: 'relative'
247
+ }
248
+ }, /*#__PURE__*/_react.default.createElement(_material.Box, {
249
+ sx: {
250
+ mt: 2,
251
+ position: 'relative'
252
+ }
253
+ }, /*#__PURE__*/_react.default.createElement(_material.Button, {
254
+ variant: "contained",
255
+ color: "primary",
256
+ onClick: handleDownload,
257
+ disabled: !selectedSubject || !selectedExamPack || !selectedExam || loading,
258
+ sx: {
259
+ width: 'auto',
260
+ backgroundColor: '#3f51b5',
261
+ '&:hover': {
262
+ backgroundColor: '#303f9f'
263
+ }
264
+ }
265
+ }, loading ? 'Downloading...' : 'Download Report'), loading && /*#__PURE__*/_react.default.createElement(_material.CircularProgress, {
266
+ size: 24,
267
+ sx: {
268
+ position: 'absolute',
269
+ top: '50%',
270
+ left: '50%',
271
+ marginTop: '-12px',
272
+ marginLeft: '-12px'
273
+ }
274
+ }))))), /*#__PURE__*/_react.default.createElement(_material.Snackbar, {
275
+ open: openAlert,
276
+ autoHideDuration: 6000,
277
+ onClose: () => setOpenAlert(false),
278
+ anchorOrigin: {
279
+ vertical: 'top',
280
+ horizontal: 'center'
281
+ }
282
+ }, /*#__PURE__*/_react.default.createElement(_material.Alert, {
283
+ onClose: () => setOpenAlert(false),
284
+ severity: "info",
285
+ sx: {
286
+ width: '100%'
287
+ }
288
+ }, alertMessage))));
289
+ }
290
+ var _default = exports.default = ExamReport;
@@ -0,0 +1,299 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _material = require("@mui/material");
9
+ var _reactRouterDom = require("react-router-dom");
10
+ var _Header = _interopRequireDefault(require("../components/Header"));
11
+ var _sidebar = _interopRequireDefault(require("../components/sidebar"));
12
+ var _TenantProvider = require("../context/TenantProvider");
13
+ require("../App.css");
14
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
16
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
17
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } // ADD THIS
18
+ function Report() {
19
+ const {
20
+ apiClient
21
+ } = (0, _TenantProvider.useTenant)(); // ADD THIS - gets API client with token
22
+ const navigate = (0, _reactRouterDom.useNavigate)();
23
+ const [subjects, setSubjects] = (0, _react.useState)([]);
24
+ const [examPacks, setExamPacks] = (0, _react.useState)([]);
25
+ const [exams, setExams] = (0, _react.useState)([]);
26
+ const [users, setUsers] = (0, _react.useState)([]);
27
+ const [selectedSubject, setSelectedSubject] = (0, _react.useState)(null);
28
+ const [selectedExamPack, setSelectedExamPack] = (0, _react.useState)(null);
29
+ const [selectedExam, setSelectedExam] = (0, _react.useState)(null);
30
+ const [selectedUser, setSelectedUser] = (0, _react.useState)(null);
31
+ const [alertMessage, setAlertMessage] = (0, _react.useState)('');
32
+ const [openAlert, setOpenAlert] = (0, _react.useState)(false);
33
+ const [loading, setLoading] = (0, _react.useState)(false);
34
+ const [onlyWrongAnswers, setOnlyWrongAnswers] = (0, _react.useState)(false);
35
+ const baseURL = process.env.REACT_APP_BASE_URL;
36
+ (0, _react.useEffect)(() => {
37
+ // REMOVE token check - no more JWT
38
+ fetchAllSubjects();
39
+ }, []);
40
+ const fetchAllSubjects = async () => {
41
+ try {
42
+ // OLD WAY with axios and JWT
43
+ // const response = await axios({
44
+ // method: "get",
45
+ // url: `${baseURL}api/showAllSubjects`,
46
+ // headers: { Authorization: `Bearer ${token}` },
47
+ // });
48
+
49
+ // NEW WAY with apiClient
50
+ const data = await apiClient.get('/api/showAllSubjects');
51
+ setSubjects(data);
52
+ } catch (error) {
53
+ console.error('Error fetching subjects:', error);
54
+ }
55
+ };
56
+ const fetchExamPacks = async subjectId => {
57
+ try {
58
+ // OLD WAY
59
+ // const response = await axios({
60
+ // method: "get",
61
+ // params: { subjectId },
62
+ // url: `${baseURL}api/getAllExamPacks`,
63
+ // headers: { Authorization: `Bearer ${token}` },
64
+ // });
65
+
66
+ // NEW WAY
67
+ const data = await apiClient.get(`/api/getAllExamPacks?subjectId=${subjectId}`);
68
+ setExamPacks(data);
69
+ } catch (error) {
70
+ console.error('Error fetching exam packs:', error);
71
+ }
72
+ };
73
+ const fetchExams = async examPackId => {
74
+ try {
75
+ const data = await apiClient.get(`/api/getAllExams?examPackId=${examPackId}`);
76
+ setExams(data);
77
+ } catch (error) {
78
+ console.error('Error fetching exams:', error);
79
+ }
80
+ };
81
+ const fetchUsers = async examId => {
82
+ try {
83
+ const data = await apiClient.get(`/api/getAllUsers?examId=${examId}`);
84
+ setUsers(data);
85
+ } catch (error) {
86
+ console.error('Error fetching users:', error);
87
+ }
88
+ };
89
+ const handleSubjectChange = (event, newValue) => {
90
+ setSelectedSubject(newValue);
91
+ setSelectedExamPack(null);
92
+ setSelectedExam(null);
93
+ setSelectedUser(null);
94
+ setExamPacks([]);
95
+ setExams([]);
96
+ setUsers([]);
97
+ if (newValue) {
98
+ fetchExamPacks(newValue.subjectId);
99
+ }
100
+ };
101
+ const handleExamPackChange = (event, newValue) => {
102
+ setSelectedExamPack(newValue);
103
+ setSelectedExam(null);
104
+ setSelectedUser(null);
105
+ setExams([]);
106
+ setUsers([]);
107
+ if (newValue) {
108
+ fetchExams(newValue.id);
109
+ }
110
+ };
111
+ const handleExamChange = (event, newValue) => {
112
+ setSelectedExam(newValue);
113
+ setSelectedUser(null);
114
+ setUsers([]);
115
+ if (newValue) {
116
+ fetchUsers(newValue.id);
117
+ }
118
+ };
119
+ const handleUserChange = (event, newValue) => {
120
+ setSelectedUser(newValue);
121
+ };
122
+ const handleDownload = async () => {
123
+ setLoading(true);
124
+ try {
125
+ // OLD WAY with axios
126
+ // const url = `${baseURL}api/generateReportForSingleUser?subjectId=${selectedSubject.subjectId}&examPackId=${selectedExamPack.id}&examId=${selectedExam.id}&userId=${selectedUser.id}&wrongAnswerFlag=${onlyWrongAnswers}`;
127
+ // const response = await axios.get(url, {
128
+ // responseType: 'blob',
129
+ // headers: { Authorization: `Bearer ${token}` }
130
+ // });
131
+
132
+ // NEW WAY - need blob response
133
+ const response = await fetch(`${baseURL}api/generateReportForSingleUser?subjectId=${selectedSubject.subjectId}&examPackId=${selectedExamPack.id}&examId=${selectedExam.id}&userId=${selectedUser.id}&wrongAnswerFlag=${onlyWrongAnswers}`, {
134
+ headers: {
135
+ 'X-Tenant-Token': apiClient.tenantToken
136
+ }
137
+ });
138
+ const blob = await response.blob();
139
+ const blobUrl = URL.createObjectURL(blob);
140
+ const link = document.createElement('a');
141
+ link.href = blobUrl;
142
+ link.setAttribute('download', 'Report.xlsx');
143
+ document.body.appendChild(link);
144
+ link.click();
145
+ link.parentNode.removeChild(link);
146
+ URL.revokeObjectURL(blobUrl);
147
+ } catch (error) {
148
+ console.error('Error downloading report:', error);
149
+ } finally {
150
+ setLoading(false);
151
+ }
152
+ };
153
+ return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_Header.default, null), /*#__PURE__*/_react.default.createElement(_sidebar.default, null), /*#__PURE__*/_react.default.createElement("div", {
154
+ style: {
155
+ padding: "100px 0px 0px 100px",
156
+ marginLeft: "140px"
157
+ }
158
+ }, /*#__PURE__*/_react.default.createElement(_material.Box, {
159
+ sx: {
160
+ maxWidth: 800,
161
+ mx: 'auto',
162
+ my: 4,
163
+ p: 3,
164
+ backgroundColor: '#f5f5f5',
165
+ borderRadius: 2
166
+ }
167
+ }, /*#__PURE__*/_react.default.createElement(_material.Paper, {
168
+ elevation: 6,
169
+ sx: {
170
+ p: 5,
171
+ textAlign: 'center',
172
+ backgroundColor: '#fff'
173
+ }
174
+ }, /*#__PURE__*/_react.default.createElement(_material.Typography, {
175
+ variant: "h4",
176
+ component: "h1",
177
+ gutterBottom: true,
178
+ sx: {
179
+ color: '#3f51b5',
180
+ marginBottom: "20px"
181
+ }
182
+ }, "Exam Report"), /*#__PURE__*/_react.default.createElement(_material.Grid, {
183
+ container: true,
184
+ spacing: 2,
185
+ justifyContent: "center"
186
+ }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
187
+ item: true,
188
+ xs: 12,
189
+ sm: 6
190
+ }, /*#__PURE__*/_react.default.createElement(_material.FormControl, {
191
+ fullWidth: true
192
+ }, /*#__PURE__*/_react.default.createElement(_material.Autocomplete, {
193
+ id: "ddlSubject",
194
+ options: subjects,
195
+ getOptionLabel: option => option.subjectName,
196
+ value: selectedSubject,
197
+ onChange: handleSubjectChange,
198
+ renderInput: params => /*#__PURE__*/_react.default.createElement(_material.TextField, _extends({}, params, {
199
+ label: "Subject"
200
+ }))
201
+ }))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
202
+ item: true,
203
+ xs: 12,
204
+ sm: 6
205
+ }, /*#__PURE__*/_react.default.createElement(_material.FormControl, {
206
+ fullWidth: true
207
+ }, /*#__PURE__*/_react.default.createElement(_material.Autocomplete, {
208
+ id: "ddlExamPack",
209
+ options: examPacks,
210
+ getOptionLabel: option => option.name,
211
+ value: selectedExamPack,
212
+ onChange: handleExamPackChange,
213
+ renderInput: params => /*#__PURE__*/_react.default.createElement(_material.TextField, _extends({}, params, {
214
+ label: "Exam Pack"
215
+ }))
216
+ }))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
217
+ item: true,
218
+ xs: 12,
219
+ sm: 6
220
+ }, /*#__PURE__*/_react.default.createElement(_material.FormControl, {
221
+ fullWidth: true
222
+ }, /*#__PURE__*/_react.default.createElement(_material.Autocomplete, {
223
+ id: "ddlExam",
224
+ options: exams,
225
+ getOptionLabel: option => option.examName,
226
+ value: selectedExam,
227
+ onChange: handleExamChange,
228
+ renderInput: params => /*#__PURE__*/_react.default.createElement(_material.TextField, _extends({}, params, {
229
+ label: "Exam"
230
+ }))
231
+ }))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
232
+ item: true,
233
+ xs: 12,
234
+ sm: 6
235
+ }, /*#__PURE__*/_react.default.createElement(_material.FormControl, {
236
+ fullWidth: true
237
+ }, /*#__PURE__*/_react.default.createElement(_material.Autocomplete, {
238
+ id: "ddlUser",
239
+ options: users,
240
+ getOptionLabel: option => option.userName,
241
+ value: selectedUser,
242
+ onChange: handleUserChange,
243
+ renderInput: params => /*#__PURE__*/_react.default.createElement(_material.TextField, _extends({}, params, {
244
+ label: "User"
245
+ }))
246
+ })))), /*#__PURE__*/_react.default.createElement(_material.Box, {
247
+ sx: {
248
+ mt: 3,
249
+ position: 'relative'
250
+ }
251
+ }, /*#__PURE__*/_react.default.createElement(_material.FormControlLabel, {
252
+ control: /*#__PURE__*/_react.default.createElement(_material.Checkbox, {
253
+ checked: onlyWrongAnswers,
254
+ onChange: e => setOnlyWrongAnswers(e.target.checked)
255
+ }),
256
+ label: "Only Wrong Answers"
257
+ }), /*#__PURE__*/_react.default.createElement(_material.Box, {
258
+ sx: {
259
+ mt: 2,
260
+ position: 'relative'
261
+ }
262
+ }, /*#__PURE__*/_react.default.createElement(_material.Button, {
263
+ variant: "contained",
264
+ color: "primary",
265
+ onClick: handleDownload,
266
+ disabled: !selectedSubject || !selectedExamPack || !selectedExam || !selectedUser || loading,
267
+ sx: {
268
+ width: 'auto',
269
+ backgroundColor: '#3f51b5',
270
+ '&:hover': {
271
+ backgroundColor: '#303f9f'
272
+ }
273
+ }
274
+ }, loading ? 'Downloading...' : 'Download Report'), loading && /*#__PURE__*/_react.default.createElement(_material.CircularProgress, {
275
+ size: 24,
276
+ sx: {
277
+ position: 'absolute',
278
+ top: '50%',
279
+ left: '50%',
280
+ marginTop: '-12px',
281
+ marginLeft: '-12px'
282
+ }
283
+ }))))), /*#__PURE__*/_react.default.createElement(_material.Snackbar, {
284
+ open: openAlert,
285
+ autoHideDuration: 6000,
286
+ onClose: () => setOpenAlert(false),
287
+ anchorOrigin: {
288
+ vertical: 'top',
289
+ horizontal: 'center'
290
+ }
291
+ }, /*#__PURE__*/_react.default.createElement(_material.Alert, {
292
+ onClose: () => setOpenAlert(false),
293
+ severity: "info",
294
+ sx: {
295
+ width: '100%'
296
+ }
297
+ }, alertMessage))));
298
+ }
299
+ var _default = exports.default = Report;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ class TenantApiClient {
8
+ constructor(config) {
9
+ this.baseURL = config.baseURL;
10
+ this.tenantToken = config.tenantToken;
11
+ }
12
+ async request(endpoint) {
13
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
14
+ // Remove double slashes
15
+ const cleanEndpoint = endpoint.startsWith('/') ? endpoint.slice(1) : endpoint;
16
+ const url = `${this.baseURL}/${cleanEndpoint}`;
17
+ console.log('FULL URL BEING SENT:', url); // Add this
18
+
19
+ const response = await fetch(url, {
20
+ ...options,
21
+ headers: {
22
+ 'X-Tenant-Token': this.tenantToken,
23
+ 'Content-Type': 'application/json',
24
+ ...options.headers
25
+ }
26
+ });
27
+ if (response.status === 401) {
28
+ throw new Error('Invalid or missing tenant token');
29
+ }
30
+ return response.json();
31
+ }
32
+
33
+ // Add your API methods
34
+ async get(endpoint) {
35
+ return this.request(endpoint);
36
+ }
37
+ async post(endpoint, data) {
38
+ return this.request(endpoint, {
39
+ method: 'POST',
40
+ body: JSON.stringify(data)
41
+ });
42
+ }
43
+ }
44
+ var _default = exports.default = TenantApiClient;