@openedx/frontend-app-instructor-dashboard 1.0.0-alpha.25 → 1.0.0-alpha.27
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.
- package/dist/certificates/CertificatesPage.d.ts +1 -1
- package/dist/certificates/CertificatesPage.js +107 -55
- package/dist/certificates/CertificatesPage.js.map +1 -1
- package/dist/certificates/CertificatesPage.scss +9 -0
- package/dist/certificates/components/CertificateTable.d.ts +1 -1
- package/dist/certificates/components/CertificateTable.js +9 -6
- package/dist/certificates/components/CertificateTable.js.map +1 -1
- package/dist/certificates/components/CertificatesPageHeader.js +3 -3
- package/dist/certificates/components/CertificatesPageHeader.js.map +1 -1
- package/dist/certificates/components/CertificatesToolbar.d.ts +2 -1
- package/dist/certificates/components/CertificatesToolbar.js +23 -3
- package/dist/certificates/components/CertificatesToolbar.js.map +1 -1
- package/dist/certificates/components/DisableCertificatesModal.js +1 -1
- package/dist/certificates/components/DisableCertificatesModal.js.map +1 -1
- package/dist/certificates/components/FilterDropdown.d.ts +1 -1
- package/dist/certificates/components/FilterDropdown.js +2 -2
- package/dist/certificates/components/FilterDropdown.js.map +1 -1
- package/dist/certificates/components/GenerationHistoryTable.d.ts +2 -2
- package/dist/certificates/components/GenerationHistoryTable.js +3 -18
- package/dist/certificates/components/GenerationHistoryTable.js.map +1 -1
- package/dist/certificates/components/GrantExceptionsModal.d.ts +1 -1
- package/dist/certificates/components/GrantExceptionsModal.js +2 -2
- package/dist/certificates/components/GrantExceptionsModal.js.map +1 -1
- package/dist/certificates/components/InvalidateCertificateModal.d.ts +1 -1
- package/dist/certificates/components/InvalidateCertificateModal.js +2 -2
- package/dist/certificates/components/InvalidateCertificateModal.js.map +1 -1
- package/dist/certificates/components/IssuedCertificatesTab.d.ts +1 -1
- package/dist/certificates/components/IssuedCertificatesTab.js +2 -2
- package/dist/certificates/components/IssuedCertificatesTab.js.map +1 -1
- package/dist/certificates/components/LearnerActionModal.d.ts +1 -1
- package/dist/certificates/components/LearnerActionModal.js +7 -2
- package/dist/certificates/components/LearnerActionModal.js.map +1 -1
- package/dist/certificates/components/RemoveExceptionModal.d.ts +9 -0
- package/dist/certificates/components/RemoveExceptionModal.js +10 -0
- package/dist/certificates/components/RemoveExceptionModal.js.map +1 -0
- package/dist/certificates/components/RemoveInvalidationModal.js +1 -1
- package/dist/certificates/components/RemoveInvalidationModal.js.map +1 -1
- package/dist/certificates/data/api.d.ts +17 -3
- package/dist/certificates/data/api.js +60 -8
- package/dist/certificates/data/api.js.map +1 -1
- package/dist/certificates/data/apiHook.d.ts +25 -5
- package/dist/certificates/data/apiHook.js +30 -2
- package/dist/certificates/data/apiHook.js.map +1 -1
- package/dist/certificates/data/queryKeys.d.ts +2 -1
- package/dist/certificates/data/queryKeys.js +1 -0
- package/dist/certificates/data/queryKeys.js.map +1 -1
- package/dist/certificates/messages.d.ts +30 -0
- package/dist/certificates/messages.js +30 -0
- package/dist/certificates/messages.js.map +1 -1
- package/dist/certificates/types.d.ts +7 -2
- package/dist/certificates/types.js.map +1 -1
- package/dist/certificates/utils/filterUtils.d.ts +1 -1
- package/dist/certificates/utils/filterUtils.js +1 -1
- package/dist/certificates/utils/filterUtils.js.map +1 -1
- package/dist/certificates/utils/index.d.ts +2 -2
- package/dist/certificates/utils/index.js +1 -1
- package/dist/certificates/utils/index.js.map +1 -1
- package/dist/components/SpecifyLearnerField.js +10 -4
- package/dist/components/SpecifyLearnerField.js.map +1 -1
- package/dist/components/messages.d.ts +5 -0
- package/dist/components/messages.js +6 -1
- package/dist/components/messages.js.map +1 -1
- package/dist/courseInfo/types.d.ts +2 -0
- package/dist/courseInfo/types.js.map +1 -1
- package/dist/courseTeam/CourseTeamPage.js +7 -2
- package/dist/courseTeam/CourseTeamPage.js.map +1 -1
- package/dist/courseTeam/messages.d.ts +5 -0
- package/dist/courseTeam/messages.js +5 -0
- package/dist/courseTeam/messages.js.map +1 -1
- package/dist/specialExams/SpecialExamsPage.js +6 -2
- package/dist/specialExams/SpecialExamsPage.js.map +1 -1
- package/dist/specialExams/components/AddAllowanceModal.d.ts +6 -0
- package/dist/specialExams/components/AddAllowanceModal.js +84 -0
- package/dist/specialExams/components/AddAllowanceModal.js.map +1 -0
- package/dist/specialExams/components/Allowances.js +28 -2
- package/dist/specialExams/components/Allowances.js.map +1 -1
- package/dist/specialExams/components/AllowancesList.d.ts +8 -0
- package/dist/specialExams/components/AllowancesList.js +58 -0
- package/dist/specialExams/components/AllowancesList.js.map +1 -0
- package/dist/specialExams/components/AttemptsList.js +8 -7
- package/dist/specialExams/components/AttemptsList.js.map +1 -1
- package/dist/specialExams/components/DeleteAllowanceModal.d.ts +8 -0
- package/dist/specialExams/components/DeleteAllowanceModal.js +29 -0
- package/dist/specialExams/components/DeleteAllowanceModal.js.map +1 -0
- package/dist/specialExams/components/EditAllowanceModal.d.ts +8 -0
- package/dist/specialExams/components/EditAllowanceModal.js +62 -0
- package/dist/specialExams/components/EditAllowanceModal.js.map +1 -0
- package/dist/specialExams/constants.d.ts +43 -0
- package/dist/specialExams/constants.js +19 -0
- package/dist/specialExams/constants.js.map +1 -0
- package/dist/specialExams/data/api.d.ts +5 -1
- package/dist/specialExams/data/api.js +28 -2
- package/dist/specialExams/data/api.js.map +1 -1
- package/dist/specialExams/data/apiHook.d.ts +5 -1
- package/dist/specialExams/data/apiHook.js +30 -2
- package/dist/specialExams/data/apiHook.js.map +1 -1
- package/dist/specialExams/data/queryKeys.d.ts +4 -1
- package/dist/specialExams/data/queryKeys.js +4 -1
- package/dist/specialExams/data/queryKeys.js.map +1 -1
- package/dist/specialExams/messages.d.ts +165 -0
- package/dist/specialExams/messages.js +165 -0
- package/dist/specialExams/messages.js.map +1 -1
- package/dist/specialExams/types.d.ts +55 -4
- package/dist/specialExams/types.js.map +1 -1
- package/package.json +1 -1
- package/dist/certificates/data/dummyData.d.ts +0 -2
- package/dist/certificates/data/dummyData.js +0 -234
- package/dist/certificates/data/dummyData.js.map +0 -1
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState,
|
|
2
|
+
import { useState, useCallback } from 'react';
|
|
3
3
|
import { useParams } from 'react-router-dom';
|
|
4
|
-
import { Card, Container, Tab, Tabs } from '@openedx/paragon';
|
|
4
|
+
import { Card, Container, Tab, Tabs, Alert } from '@openedx/paragon';
|
|
5
5
|
import { useIntl } from '@openedx/frontend-base';
|
|
6
6
|
import { useAlert } from '../providers/AlertProvider';
|
|
7
|
-
import {
|
|
8
|
-
import CertificatesPageHeader from '
|
|
9
|
-
import IssuedCertificatesTab from '
|
|
10
|
-
import GenerationHistoryTable from '
|
|
11
|
-
import GrantExceptionsModal from '
|
|
12
|
-
import InvalidateCertificateModal from '
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import {
|
|
17
|
-
import { CertificateFilter
|
|
18
|
-
import { CERTIFICATES_PAGE_SIZE, TAB_KEYS, MODAL_TITLES, ALERT_VARIANTS } from '
|
|
19
|
-
import { getErrorMessage } from '
|
|
20
|
-
import messages from '
|
|
21
|
-
import '
|
|
7
|
+
import { useCourseInfo } from '../data/apiHook';
|
|
8
|
+
import CertificatesPageHeader from '../certificates/components/CertificatesPageHeader';
|
|
9
|
+
import IssuedCertificatesTab from '../certificates/components/IssuedCertificatesTab';
|
|
10
|
+
import GenerationHistoryTable from '../certificates/components/GenerationHistoryTable';
|
|
11
|
+
import GrantExceptionsModal from '../certificates/components/GrantExceptionsModal';
|
|
12
|
+
import InvalidateCertificateModal from '../certificates/components/InvalidateCertificateModal';
|
|
13
|
+
import RemoveExceptionModal from '../certificates/components/RemoveExceptionModal';
|
|
14
|
+
import RemoveInvalidationModal from '../certificates/components/RemoveInvalidationModal';
|
|
15
|
+
import DisableCertificatesModal from '../certificates/components/DisableCertificatesModal';
|
|
16
|
+
import { useCertificateGenerationHistory, useGrantBulkExceptions, useInvalidateCertificate, useIssuedCertificates, useRegenerateCertificates, useRemoveException, useRemoveInvalidation, useToggleCertificateGeneration, } from '../certificates/data/apiHook';
|
|
17
|
+
import { CertificateFilter } from '../certificates/types';
|
|
18
|
+
import { CERTIFICATES_PAGE_SIZE, TAB_KEYS, MODAL_TITLES, ALERT_VARIANTS } from '../certificates/constants';
|
|
19
|
+
import { getErrorMessage } from '../certificates/utils/errorHandling';
|
|
20
|
+
import messages from '../certificates/messages';
|
|
21
|
+
import '@src/certificates/CertificatesPage.scss';
|
|
22
22
|
const CertificatesPage = () => {
|
|
23
23
|
const intl = useIntl();
|
|
24
24
|
const { courseId = '' } = useParams();
|
|
25
25
|
const { showToast, showModal } = useAlert();
|
|
26
|
+
const { data: courseInfo } = useCourseInfo(courseId);
|
|
26
27
|
const [filter, setFilter] = useState(CertificateFilter.ALL_LEARNERS);
|
|
27
28
|
const [search, setSearch] = useState('');
|
|
28
29
|
const [certificatesPage, setCertificatesPage] = useState(0);
|
|
@@ -33,45 +34,40 @@ const CertificatesPage = () => {
|
|
|
33
34
|
const [isCertificateGenerationEnabled, setIsCertificateGenerationEnabled] = useState(true);
|
|
34
35
|
const [isGrantExceptionsOpen, setIsGrantExceptionsOpen] = useState(false);
|
|
35
36
|
const [isInvalidateCertificateOpen, setIsInvalidateCertificateOpen] = useState(false);
|
|
37
|
+
const [isRemoveExceptionOpen, setIsRemoveExceptionOpen] = useState(false);
|
|
36
38
|
const [isRemoveInvalidationOpen, setIsRemoveInvalidationOpen] = useState(false);
|
|
37
39
|
const [isDisableCertificatesOpen, setIsDisableCertificatesOpen] = useState(false);
|
|
38
|
-
const { data:
|
|
40
|
+
const { data: certificatesData, isLoading: isLoadingCertificates, } = useIssuedCertificates(courseId, {
|
|
41
|
+
page: certificatesPage,
|
|
42
|
+
pageSize: CERTIFICATES_PAGE_SIZE,
|
|
43
|
+
filter,
|
|
44
|
+
search,
|
|
45
|
+
});
|
|
46
|
+
const { data: historyData, isLoading: isLoadingHistory, } = useCertificateGenerationHistory(courseId, {
|
|
39
47
|
page: tasksPage,
|
|
40
48
|
pageSize: CERTIFICATES_PAGE_SIZE,
|
|
41
49
|
});
|
|
42
50
|
const { mutate: grantExceptions, isPending: isGrantingExceptions } = useGrantBulkExceptions(courseId);
|
|
43
51
|
const { mutate: invalidateCert, isPending: isInvalidating } = useInvalidateCertificate(courseId);
|
|
44
|
-
const { mutate: removeExcept } = useRemoveException(courseId);
|
|
52
|
+
const { mutate: removeExcept, isPending: isRemovingException } = useRemoveException(courseId);
|
|
45
53
|
const { mutate: removeInval, isPending: isRemovingInvalidation } = useRemoveInvalidation(courseId);
|
|
46
54
|
const { mutate: toggleGeneration, isPending: isTogglingGeneration } = useToggleCertificateGeneration(courseId);
|
|
47
|
-
const
|
|
48
|
-
switch (filter) {
|
|
49
|
-
case CertificateFilter.RECEIVED:
|
|
50
|
-
return item.certificateStatus === CertificateStatus.RECEIVED;
|
|
51
|
-
case CertificateFilter.NOT_RECEIVED:
|
|
52
|
-
return item.certificateStatus === CertificateStatus.NOT_RECEIVED;
|
|
53
|
-
case CertificateFilter.AUDIT_PASSING:
|
|
54
|
-
return item.certificateStatus === CertificateStatus.AUDIT_PASSING;
|
|
55
|
-
case CertificateFilter.AUDIT_NOT_PASSING:
|
|
56
|
-
return item.certificateStatus === CertificateStatus.AUDIT_NOT_PASSING;
|
|
57
|
-
case CertificateFilter.ERROR_STATE:
|
|
58
|
-
return item.certificateStatus === CertificateStatus.ERROR_STATE;
|
|
59
|
-
case CertificateFilter.GRANTED_EXCEPTIONS:
|
|
60
|
-
return item.specialCase === SpecialCase.EXCEPTION;
|
|
61
|
-
case CertificateFilter.INVALIDATED:
|
|
62
|
-
return item.specialCase === SpecialCase.INVALIDATION;
|
|
63
|
-
case CertificateFilter.ALL_LEARNERS:
|
|
64
|
-
default:
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
}, [filter]);
|
|
68
|
-
const filteredData = useMemo(() => filterCertificates(dummyCertificateData, matchesFilter, search), [matchesFilter, search]);
|
|
55
|
+
const { mutate: regenerateCerts } = useRegenerateCertificates(courseId);
|
|
69
56
|
const handleGrantExceptions = useCallback((learners, notes) => {
|
|
70
|
-
const count = parseLearnersCount(learners);
|
|
71
57
|
grantExceptions({ learners, notes }, {
|
|
72
|
-
onSuccess: () => {
|
|
58
|
+
onSuccess: (data) => {
|
|
73
59
|
setIsGrantExceptionsOpen(false);
|
|
74
|
-
|
|
60
|
+
if (data.errors && data.errors.length > 0) {
|
|
61
|
+
const errorMessages = data.errors.map(err => `${err.learner}: ${err.message}`).join('\n');
|
|
62
|
+
showModal({
|
|
63
|
+
title: MODAL_TITLES.ERROR,
|
|
64
|
+
message: `Some exceptions failed:\n${errorMessages}`,
|
|
65
|
+
variant: ALERT_VARIANTS.WARNING,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (data.success && data.success.length > 0) {
|
|
69
|
+
showToast(intl.formatMessage(messages.exceptionsGrantedToast, { count: data.success.length }));
|
|
70
|
+
}
|
|
75
71
|
},
|
|
76
72
|
onError: (error) => {
|
|
77
73
|
showModal({
|
|
@@ -83,11 +79,20 @@ const CertificatesPage = () => {
|
|
|
83
79
|
});
|
|
84
80
|
}, [grantExceptions, showToast, showModal, intl]);
|
|
85
81
|
const handleInvalidateCertificate = useCallback((learners, notes) => {
|
|
86
|
-
const count = parseLearnersCount(learners);
|
|
87
82
|
invalidateCert({ learners, notes }, {
|
|
88
|
-
onSuccess: () => {
|
|
83
|
+
onSuccess: (data) => {
|
|
89
84
|
setIsInvalidateCertificateOpen(false);
|
|
90
|
-
|
|
85
|
+
if (data.errors && data.errors.length > 0) {
|
|
86
|
+
const errorMessages = data.errors.map(err => `${err.learner}: ${err.message}`).join('\n');
|
|
87
|
+
showModal({
|
|
88
|
+
title: MODAL_TITLES.ERROR,
|
|
89
|
+
message: `Some invalidations failed:\n${errorMessages}`,
|
|
90
|
+
variant: ALERT_VARIANTS.WARNING,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (data.success && data.success.length > 0) {
|
|
94
|
+
showToast(intl.formatMessage(messages.certificatesInvalidatedToast, { count: data.success.length }));
|
|
95
|
+
}
|
|
91
96
|
},
|
|
92
97
|
onError: (error) => {
|
|
93
98
|
showModal({
|
|
@@ -98,10 +103,28 @@ const CertificatesPage = () => {
|
|
|
98
103
|
},
|
|
99
104
|
});
|
|
100
105
|
}, [invalidateCert, showToast, showModal, intl]);
|
|
101
|
-
const
|
|
102
|
-
|
|
106
|
+
const handleRemoveExceptionClick = useCallback((username, email) => {
|
|
107
|
+
setSelectedUsername(username);
|
|
108
|
+
setSelectedEmail(email);
|
|
109
|
+
setIsRemoveExceptionOpen(true);
|
|
110
|
+
}, []);
|
|
111
|
+
const handleRemoveExceptionConfirm = useCallback(() => {
|
|
112
|
+
// Backend accepts either username or email - use whichever is available
|
|
113
|
+
const identifier = selectedUsername || selectedEmail;
|
|
114
|
+
if (!identifier) {
|
|
115
|
+
showModal({
|
|
116
|
+
title: MODAL_TITLES.ERROR,
|
|
117
|
+
message: intl.formatMessage(messages.errorRemoveException) + ': Username or email is required',
|
|
118
|
+
variant: ALERT_VARIANTS.DANGER,
|
|
119
|
+
});
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
removeExcept({ username: identifier }, {
|
|
103
123
|
onSuccess: () => {
|
|
104
|
-
|
|
124
|
+
setIsRemoveExceptionOpen(false);
|
|
125
|
+
setSelectedUsername('');
|
|
126
|
+
setSelectedEmail('');
|
|
127
|
+
showToast(intl.formatMessage(messages.exceptionRemovedToast, { email: selectedEmail }));
|
|
105
128
|
},
|
|
106
129
|
onError: (error) => {
|
|
107
130
|
showModal({
|
|
@@ -111,14 +134,24 @@ const CertificatesPage = () => {
|
|
|
111
134
|
});
|
|
112
135
|
},
|
|
113
136
|
});
|
|
114
|
-
}, [removeExcept, showToast, showModal, intl]);
|
|
137
|
+
}, [removeExcept, selectedUsername, selectedEmail, showToast, showModal, intl]);
|
|
115
138
|
const handleRemoveInvalidationClick = useCallback((username, email) => {
|
|
116
139
|
setSelectedUsername(username);
|
|
117
140
|
setSelectedEmail(email);
|
|
118
141
|
setIsRemoveInvalidationOpen(true);
|
|
119
142
|
}, []);
|
|
120
143
|
const handleRemoveInvalidationConfirm = useCallback(() => {
|
|
121
|
-
|
|
144
|
+
// Backend accepts either username or email - use whichever is available
|
|
145
|
+
const identifier = selectedUsername || selectedEmail;
|
|
146
|
+
if (!identifier) {
|
|
147
|
+
showModal({
|
|
148
|
+
title: MODAL_TITLES.ERROR,
|
|
149
|
+
message: intl.formatMessage(messages.errorRemoveInvalidation) + ': Username or email is required',
|
|
150
|
+
variant: ALERT_VARIANTS.DANGER,
|
|
151
|
+
});
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
removeInval({ username: identifier }, {
|
|
122
155
|
onSuccess: () => {
|
|
123
156
|
setIsRemoveInvalidationOpen(false);
|
|
124
157
|
setSelectedUsername('');
|
|
@@ -154,9 +187,28 @@ const CertificatesPage = () => {
|
|
|
154
187
|
});
|
|
155
188
|
}, [isCertificateGenerationEnabled, toggleGeneration, showToast, showModal, intl]);
|
|
156
189
|
const handleRegenerateCertificates = useCallback(() => {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
190
|
+
regenerateCerts(filter, {
|
|
191
|
+
onSuccess: () => {
|
|
192
|
+
showToast(intl.formatMessage(messages.certificatesRegeneratedToast));
|
|
193
|
+
},
|
|
194
|
+
onError: (error) => {
|
|
195
|
+
showModal({
|
|
196
|
+
title: MODAL_TITLES.ERROR,
|
|
197
|
+
message: getErrorMessage(error, intl.formatMessage(messages.errorRegenerateCertificates)),
|
|
198
|
+
variant: ALERT_VARIANTS.DANGER,
|
|
199
|
+
});
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
}, [regenerateCerts, filter, showToast, showModal, intl]);
|
|
203
|
+
// Check if certificate management is disabled
|
|
204
|
+
if (courseInfo && !courseInfo.certificatesEnabled) {
|
|
205
|
+
return (_jsx(Container, { className: "mt-4.5 mb-4", fluid: true, children: _jsx(Alert, { variant: "warning", children: intl.formatMessage(messages.certificatesDisabledMessage) }) }));
|
|
206
|
+
}
|
|
207
|
+
return (_jsxs(Container, { className: "mt-4.5 mb-4", fluid: true, children: [_jsx(CertificatesPageHeader, { onGrantExceptions: () => setIsGrantExceptionsOpen(true), onInvalidateCertificate: () => setIsInvalidateCertificateOpen(true), onDisableCertificates: () => setIsDisableCertificatesOpen(true) }), _jsx(Card, { variant: "muted", className: "pt-3 pt-md-4 pb-4 pb-md-6 certificates-card", children: _jsxs(Tabs, { activeKey: activeTab, onSelect: (key) => setActiveTab(key || TAB_KEYS.ISSUED), className: "mx-4", variant: "button-group", children: [_jsx(Tab, { eventKey: TAB_KEYS.ISSUED, title: intl.formatMessage(messages.issuedCertificatesTab), children: _jsx(IssuedCertificatesTab, { data: (certificatesData === null || certificatesData === void 0 ? void 0 : certificatesData.results) || [], isLoading: isLoadingCertificates, itemCount: (certificatesData === null || certificatesData === void 0 ? void 0 : certificatesData.count) || 0, pageCount: (certificatesData === null || certificatesData === void 0 ? void 0 : certificatesData.numPages) || 0, search: search, onSearchChange: setSearch, filter: filter, onFilterChange: setFilter, currentPage: certificatesPage, onPageChange: setCertificatesPage, onRemoveException: handleRemoveExceptionClick, onRemoveInvalidation: handleRemoveInvalidationClick, onRegenerateCertificates: handleRegenerateCertificates }) }), _jsx(Tab, { eventKey: TAB_KEYS.HISTORY, title: intl.formatMessage(messages.generationHistoryTab), children: _jsx("div", { className: "d-flex flex-column mt-3 mt-md-4", children: _jsx(GenerationHistoryTable, { data: (historyData === null || historyData === void 0 ? void 0 : historyData.results) || [], isLoading: isLoadingHistory, itemCount: (historyData === null || historyData === void 0 ? void 0 : historyData.count) || 0, pageCount: (historyData === null || historyData === void 0 ? void 0 : historyData.numPages) || 0, currentPage: tasksPage, onPageChange: setTasksPage }) }) })] }) }), _jsx(GrantExceptionsModal, { isOpen: isGrantExceptionsOpen, onClose: () => setIsGrantExceptionsOpen(false), onSubmit: handleGrantExceptions, isSubmitting: isGrantingExceptions }), _jsx(InvalidateCertificateModal, { isOpen: isInvalidateCertificateOpen, onClose: () => setIsInvalidateCertificateOpen(false), onSubmit: handleInvalidateCertificate, isSubmitting: isInvalidating }), _jsx(RemoveExceptionModal, { isOpen: isRemoveExceptionOpen, email: selectedEmail, onClose: () => {
|
|
208
|
+
setIsRemoveExceptionOpen(false);
|
|
209
|
+
setSelectedUsername('');
|
|
210
|
+
setSelectedEmail('');
|
|
211
|
+
}, onConfirm: handleRemoveExceptionConfirm, isSubmitting: isRemovingException }), _jsx(RemoveInvalidationModal, { isOpen: isRemoveInvalidationOpen, email: selectedEmail, onClose: () => {
|
|
160
212
|
setIsRemoveInvalidationOpen(false);
|
|
161
213
|
setSelectedUsername('');
|
|
162
214
|
setSelectedEmail('');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CertificatesPage.js","sourceRoot":"","sources":["../../src/certificates/CertificatesPage.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,sBAAsB,MAAM,qCAAqC,CAAC;AACzE,OAAO,qBAAqB,MAAM,oCAAoC,CAAC;AACvE,OAAO,sBAAsB,MAAM,qCAAqC,CAAC;AACzE,OAAO,oBAAoB,MAAM,mCAAmC,CAAC;AACrE,OAAO,0BAA0B,MAAM,yCAAyC,CAAC;AACjF,OAAO,uBAAuB,MAAM,sCAAsC,CAAC;AAC3E,OAAO,wBAAwB,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EAClB,qBAAqB,EACrB,8BAA8B,GAC/B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,yBAAyB,CAAC;AAEjC,MAAM,gBAAgB,GAAG,GAAG,EAAE;IAC5B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,EAAE,QAAQ,GAAG,EAAE,EAAE,GAAG,SAAS,EAAwB,CAAC;IAC5D,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,CAAC;IAE5C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAoB,iBAAiB,CAAC,YAAY,CAAC,CAAC;IACxF,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzC,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7D,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,CAAC,8BAA8B,EAAE,iCAAiC,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE3F,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,CAAC,2BAA2B,EAAE,8BAA8B,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtF,MAAM,CAAC,wBAAwB,EAAE,2BAA2B,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChF,MAAM,CAAC,yBAAyB,EAAE,4BAA4B,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAElF,MAAM,EACJ,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,cAAc,GAC1B,GAAG,kBAAkB,CAAC,QAAQ,EAAE;QAC/B,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,sBAAsB;KACjC,CAAC,CAAC;IAEH,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IACtG,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IACjG,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC9D,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,sBAAsB,EAAE,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACnG,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,8BAA8B,CAAC,QAAQ,CAAC,CAAC;IAE/G,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,IAAoC,EAAE,EAAE;QACzE,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,iBAAiB,CAAC,QAAQ;gBAC7B,OAAO,IAAI,CAAC,iBAAiB,KAAK,iBAAiB,CAAC,QAAQ,CAAC;YAC/D,KAAK,iBAAiB,CAAC,YAAY;gBACjC,OAAO,IAAI,CAAC,iBAAiB,KAAK,iBAAiB,CAAC,YAAY,CAAC;YACnE,KAAK,iBAAiB,CAAC,aAAa;gBAClC,OAAO,IAAI,CAAC,iBAAiB,KAAK,iBAAiB,CAAC,aAAa,CAAC;YACpE,KAAK,iBAAiB,CAAC,iBAAiB;gBACtC,OAAO,IAAI,CAAC,iBAAiB,KAAK,iBAAiB,CAAC,iBAAiB,CAAC;YACxE,KAAK,iBAAiB,CAAC,WAAW;gBAChC,OAAO,IAAI,CAAC,iBAAiB,KAAK,iBAAiB,CAAC,WAAW,CAAC;YAClE,KAAK,iBAAiB,CAAC,kBAAkB;gBACvC,OAAO,IAAI,CAAC,WAAW,KAAK,WAAW,CAAC,SAAS,CAAC;YACpD,KAAK,iBAAiB,CAAC,WAAW;gBAChC,OAAO,IAAI,CAAC,WAAW,KAAK,WAAW,CAAC,YAAY,CAAC;YACvD,KAAK,iBAAiB,CAAC,YAAY,CAAC;YACpC;gBACE,OAAO,IAAI,CAAC;QAChB,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,MAAM,YAAY,GAAG,OAAO,CAC1B,GAAG,EAAE,CAAC,kBAAkB,CAAC,oBAAoB,EAAE,aAAa,EAAE,MAAM,CAAC,EACrE,CAAC,aAAa,EAAE,MAAM,CAAC,CACxB,CAAC;IAEF,MAAM,qBAAqB,GAAG,WAAW,CAAC,CAAC,QAAgB,EAAE,KAAa,EAAE,EAAE;QAC5E,MAAM,KAAK,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAC3C,eAAe,CACb,EAAE,QAAQ,EAAE,KAAK,EAAE,EACnB;YACE,SAAS,EAAE,GAAG,EAAE;gBACd,wBAAwB,CAAC,KAAK,CAAC,CAAC;gBAChC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,sBAAsB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YAC5E,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,YAAY,CAAC,KAAK;oBACzB,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;oBACjF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,eAAe,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAElD,MAAM,2BAA2B,GAAG,WAAW,CAAC,CAAC,QAAgB,EAAE,KAAa,EAAE,EAAE;QAClF,MAAM,KAAK,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAC3C,cAAc,CACZ,EAAE,QAAQ,EAAE,KAAK,EAAE,EACnB;YACE,SAAS,EAAE,GAAG,EAAE;gBACd,8BAA8B,CAAC,KAAK,CAAC,CAAC;gBACtC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YAClF,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,YAAY,CAAC,KAAK;oBACzB,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAAC;oBACxF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAEjD,MAAM,qBAAqB,GAAG,WAAW,CAAC,CAAC,QAAgB,EAAE,KAAa,EAAE,EAAE;QAC5E,YAAY,CACV,EAAE,QAAQ,EAAE,EACZ;YACE,SAAS,EAAE,GAAG,EAAE;gBACd,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YAC3E,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,YAAY,CAAC,KAAK;oBACzB,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;oBAClF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAE/C,MAAM,6BAA6B,GAAG,WAAW,CAAC,CAAC,QAAgB,EAAE,KAAa,EAAE,EAAE;QACpF,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC9B,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACxB,2BAA2B,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,+BAA+B,GAAG,WAAW,CAAC,GAAG,EAAE;QACvD,WAAW,CACT,EAAE,QAAQ,EAAE,gBAAgB,EAAE,EAC9B;YACE,SAAS,EAAE,GAAG,EAAE;gBACd,2BAA2B,CAAC,KAAK,CAAC,CAAC;gBACnC,mBAAmB,CAAC,EAAE,CAAC,CAAC;gBACxB,gBAAgB,CAAC,EAAE,CAAC,CAAC;gBACrB,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;YAC7F,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,YAAY,CAAC,KAAK;oBACzB,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC;oBACrF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAE/E,MAAM,iCAAiC,GAAG,WAAW,CAAC,GAAG,EAAE;QACzD,MAAM,QAAQ,GAAG,CAAC,8BAA8B,CAAC;QACjD,gBAAgB,CAAC,QAAQ,EAAE;YACzB,SAAS,EAAE,GAAG,EAAE;gBACd,iCAAiC,CAAC,QAAQ,CAAC,CAAC;gBAC5C,4BAA4B,CAAC,KAAK,CAAC,CAAC;gBACpC,SAAS,CACP,QAAQ;oBACN,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC;oBACxD,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAC5D,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,YAAY,CAAC,KAAK;oBACzB,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,gCAAgC,CAAC,CAAC;oBAC9F,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,8BAA8B,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAEnF,MAAM,4BAA4B,GAAG,WAAW,CAAC,GAAG,EAAE;QACpD,oCAAoC;IACtC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,MAAC,SAAS,IAAC,SAAS,EAAC,aAAa,EAAC,KAAK,mBACtC,KAAC,sBAAsB,IACrB,iBAAiB,EAAE,GAAG,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,EACvD,uBAAuB,EAAE,GAAG,EAAE,CAAC,8BAA8B,CAAC,IAAI,CAAC,EACnE,qBAAqB,EAAE,GAAG,EAAE,CAAC,4BAA4B,CAAC,IAAI,CAAC,GAC/D,EAEF,KAAC,IAAI,IAAC,OAAO,EAAC,OAAO,EAAC,SAAS,EAAC,6CAA6C,YAC3E,MAAC,IAAI,IACH,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,EACvD,SAAS,EAAC,MAAM,EAChB,OAAO,EAAC,cAAc,aAEtB,KAAC,GAAG,IAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,qBAAqB,CAAC,YACvF,KAAC,qBAAqB,IACpB,IAAI,EAAE,YAAY,EAClB,SAAS,EAAE,KAAK,EAChB,SAAS,EAAE,YAAY,CAAC,MAAM,EAC9B,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,sBAAsB,CAAC,EAClE,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,SAAS,EACzB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,SAAS,EACzB,WAAW,EAAE,gBAAgB,EAC7B,YAAY,EAAE,mBAAmB,EACjC,iBAAiB,EAAE,qBAAqB,EACxC,oBAAoB,EAAE,6BAA6B,EACnD,wBAAwB,EAAE,4BAA4B,GACtD,GACE,EACN,KAAC,GAAG,IAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,oBAAoB,CAAC,YACvF,cAAK,SAAS,EAAC,iCAAiC,YAC9C,KAAC,sBAAsB,IACrB,IAAI,EAAE,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,OAAO,KAAI,EAAE,EAC9B,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,KAAK,KAAI,CAAC,EAChC,SAAS,EAAE,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,QAAQ,KAAI,CAAC,EACnC,WAAW,EAAE,SAAS,EACtB,YAAY,EAAE,YAAY,GAC1B,GACE,GACF,IACD,GACF,EAEP,KAAC,oBAAoB,IACnB,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,GAAG,EAAE,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAC9C,QAAQ,EAAE,qBAAqB,EAC/B,YAAY,EAAE,oBAAoB,GAClC,EACF,KAAC,0BAA0B,IACzB,MAAM,EAAE,2BAA2B,EACnC,OAAO,EAAE,GAAG,EAAE,CAAC,8BAA8B,CAAC,KAAK,CAAC,EACpD,QAAQ,EAAE,2BAA2B,EACrC,YAAY,EAAE,cAAc,GAC5B,EACF,KAAC,uBAAuB,IACtB,MAAM,EAAE,wBAAwB,EAChC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,GAAG,EAAE;oBACZ,2BAA2B,CAAC,KAAK,CAAC,CAAC;oBACnC,mBAAmB,CAAC,EAAE,CAAC,CAAC;oBACxB,gBAAgB,CAAC,EAAE,CAAC,CAAC;gBACvB,CAAC,EACD,SAAS,EAAE,+BAA+B,EAC1C,YAAY,EAAE,sBAAsB,GACpC,EACF,KAAC,wBAAwB,IACvB,MAAM,EAAE,yBAAyB,EACjC,SAAS,EAAE,8BAA8B,EACzC,OAAO,EAAE,GAAG,EAAE,CAAC,4BAA4B,CAAC,KAAK,CAAC,EAClD,SAAS,EAAE,iCAAiC,EAC5C,YAAY,EAAE,oBAAoB,GAClC,IACQ,CACb,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC","sourcesContent":["import { useState, useMemo, useCallback } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { Card, Container, Tab, Tabs } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport { useAlert } from '@src/providers/AlertProvider';\nimport { filterCertificates, parseLearnersCount } from '@src/utils/formatters';\nimport CertificatesPageHeader from './components/CertificatesPageHeader';\nimport IssuedCertificatesTab from './components/IssuedCertificatesTab';\nimport GenerationHistoryTable from './components/GenerationHistoryTable';\nimport GrantExceptionsModal from './components/GrantExceptionsModal';\nimport InvalidateCertificateModal from './components/InvalidateCertificateModal';\nimport RemoveInvalidationModal from './components/RemoveInvalidationModal';\nimport DisableCertificatesModal from './components/DisableCertificatesModal';\nimport { dummyCertificateData } from './data/dummyData';\nimport {\n useGrantBulkExceptions,\n useInstructorTasks,\n useInvalidateCertificate,\n useRemoveException,\n useRemoveInvalidation,\n useToggleCertificateGeneration,\n} from './data/apiHook';\nimport { CertificateFilter, CertificateStatus, SpecialCase } from './types';\nimport { CERTIFICATES_PAGE_SIZE, TAB_KEYS, MODAL_TITLES, ALERT_VARIANTS } from './constants';\nimport { getErrorMessage } from './utils/errorHandling';\nimport messages from './messages';\nimport './CertificatesPage.scss';\n\nconst CertificatesPage = () => {\n const intl = useIntl();\n const { courseId = '' } = useParams<{ courseId: string }>();\n const { showToast, showModal } = useAlert();\n\n const [filter, setFilter] = useState<CertificateFilter>(CertificateFilter.ALL_LEARNERS);\n const [search, setSearch] = useState('');\n const [certificatesPage, setCertificatesPage] = useState(0);\n const [tasksPage, setTasksPage] = useState(0);\n const [activeTab, setActiveTab] = useState(TAB_KEYS.ISSUED);\n const [selectedUsername, setSelectedUsername] = useState('');\n const [selectedEmail, setSelectedEmail] = useState('');\n const [isCertificateGenerationEnabled, setIsCertificateGenerationEnabled] = useState(true);\n\n const [isGrantExceptionsOpen, setIsGrantExceptionsOpen] = useState(false);\n const [isInvalidateCertificateOpen, setIsInvalidateCertificateOpen] = useState(false);\n const [isRemoveInvalidationOpen, setIsRemoveInvalidationOpen] = useState(false);\n const [isDisableCertificatesOpen, setIsDisableCertificatesOpen] = useState(false);\n\n const {\n data: tasksData,\n isLoading: isLoadingTasks,\n } = useInstructorTasks(courseId, {\n page: tasksPage,\n pageSize: CERTIFICATES_PAGE_SIZE,\n });\n\n const { mutate: grantExceptions, isPending: isGrantingExceptions } = useGrantBulkExceptions(courseId);\n const { mutate: invalidateCert, isPending: isInvalidating } = useInvalidateCertificate(courseId);\n const { mutate: removeExcept } = useRemoveException(courseId);\n const { mutate: removeInval, isPending: isRemovingInvalidation } = useRemoveInvalidation(courseId);\n const { mutate: toggleGeneration, isPending: isTogglingGeneration } = useToggleCertificateGeneration(courseId);\n\n const matchesFilter = useCallback((item: typeof dummyCertificateData[0]) => {\n switch (filter) {\n case CertificateFilter.RECEIVED:\n return item.certificateStatus === CertificateStatus.RECEIVED;\n case CertificateFilter.NOT_RECEIVED:\n return item.certificateStatus === CertificateStatus.NOT_RECEIVED;\n case CertificateFilter.AUDIT_PASSING:\n return item.certificateStatus === CertificateStatus.AUDIT_PASSING;\n case CertificateFilter.AUDIT_NOT_PASSING:\n return item.certificateStatus === CertificateStatus.AUDIT_NOT_PASSING;\n case CertificateFilter.ERROR_STATE:\n return item.certificateStatus === CertificateStatus.ERROR_STATE;\n case CertificateFilter.GRANTED_EXCEPTIONS:\n return item.specialCase === SpecialCase.EXCEPTION;\n case CertificateFilter.INVALIDATED:\n return item.specialCase === SpecialCase.INVALIDATION;\n case CertificateFilter.ALL_LEARNERS:\n default:\n return true;\n }\n }, [filter]);\n\n const filteredData = useMemo(\n () => filterCertificates(dummyCertificateData, matchesFilter, search),\n [matchesFilter, search],\n );\n\n const handleGrantExceptions = useCallback((learners: string, notes: string) => {\n const count = parseLearnersCount(learners);\n grantExceptions(\n { learners, notes },\n {\n onSuccess: () => {\n setIsGrantExceptionsOpen(false);\n showToast(intl.formatMessage(messages.exceptionsGrantedToast, { count }));\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorGrantException)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n },\n );\n }, [grantExceptions, showToast, showModal, intl]);\n\n const handleInvalidateCertificate = useCallback((learners: string, notes: string) => {\n const count = parseLearnersCount(learners);\n invalidateCert(\n { learners, notes },\n {\n onSuccess: () => {\n setIsInvalidateCertificateOpen(false);\n showToast(intl.formatMessage(messages.certificatesInvalidatedToast, { count }));\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorInvalidateCertificate)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n },\n );\n }, [invalidateCert, showToast, showModal, intl]);\n\n const handleRemoveException = useCallback((username: string, email: string) => {\n removeExcept(\n { username },\n {\n onSuccess: () => {\n showToast(intl.formatMessage(messages.exceptionRemovedToast, { email }));\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorRemoveException)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n },\n );\n }, [removeExcept, showToast, showModal, intl]);\n\n const handleRemoveInvalidationClick = useCallback((username: string, email: string) => {\n setSelectedUsername(username);\n setSelectedEmail(email);\n setIsRemoveInvalidationOpen(true);\n }, []);\n\n const handleRemoveInvalidationConfirm = useCallback(() => {\n removeInval(\n { username: selectedUsername },\n {\n onSuccess: () => {\n setIsRemoveInvalidationOpen(false);\n setSelectedUsername('');\n setSelectedEmail('');\n showToast(intl.formatMessage(messages.invalidationRemovedToast, { email: selectedEmail }));\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorRemoveInvalidation)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n },\n );\n }, [removeInval, selectedUsername, selectedEmail, showToast, showModal, intl]);\n\n const handleToggleCertificateGeneration = useCallback(() => {\n const newState = !isCertificateGenerationEnabled;\n toggleGeneration(newState, {\n onSuccess: () => {\n setIsCertificateGenerationEnabled(newState);\n setIsDisableCertificatesOpen(false);\n showToast(\n newState\n ? intl.formatMessage(messages.successEnableCertificates)\n : intl.formatMessage(messages.successDisableCertificates),\n );\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorToggleCertificateGeneration)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n });\n }, [isCertificateGenerationEnabled, toggleGeneration, showToast, showModal, intl]);\n\n const handleRegenerateCertificates = useCallback(() => {\n // TODO: Implement when API is ready\n }, []);\n\n return (\n <Container className=\"mt-4.5 mb-4\" fluid>\n <CertificatesPageHeader\n onGrantExceptions={() => setIsGrantExceptionsOpen(true)}\n onInvalidateCertificate={() => setIsInvalidateCertificateOpen(true)}\n onDisableCertificates={() => setIsDisableCertificatesOpen(true)}\n />\n\n <Card variant=\"muted\" className=\"pt-3 pt-md-4 pb-4 pb-md-6 certificates-card\">\n <Tabs\n activeKey={activeTab}\n onSelect={(key) => setActiveTab(key || TAB_KEYS.ISSUED)}\n className=\"mx-4\"\n variant=\"button-group\"\n >\n <Tab eventKey={TAB_KEYS.ISSUED} title={intl.formatMessage(messages.issuedCertificatesTab)}>\n <IssuedCertificatesTab\n data={filteredData}\n isLoading={false}\n itemCount={filteredData.length}\n pageCount={Math.ceil(filteredData.length / CERTIFICATES_PAGE_SIZE)}\n search={search}\n onSearchChange={setSearch}\n filter={filter}\n onFilterChange={setFilter}\n currentPage={certificatesPage}\n onPageChange={setCertificatesPage}\n onRemoveException={handleRemoveException}\n onRemoveInvalidation={handleRemoveInvalidationClick}\n onRegenerateCertificates={handleRegenerateCertificates}\n />\n </Tab>\n <Tab eventKey={TAB_KEYS.HISTORY} title={intl.formatMessage(messages.generationHistoryTab)}>\n <div className=\"d-flex flex-column mt-3 mt-md-4\">\n <GenerationHistoryTable\n data={tasksData?.results || []}\n isLoading={isLoadingTasks}\n itemCount={tasksData?.count || 0}\n pageCount={tasksData?.numPages || 0}\n currentPage={tasksPage}\n onPageChange={setTasksPage}\n />\n </div>\n </Tab>\n </Tabs>\n </Card>\n\n <GrantExceptionsModal\n isOpen={isGrantExceptionsOpen}\n onClose={() => setIsGrantExceptionsOpen(false)}\n onSubmit={handleGrantExceptions}\n isSubmitting={isGrantingExceptions}\n />\n <InvalidateCertificateModal\n isOpen={isInvalidateCertificateOpen}\n onClose={() => setIsInvalidateCertificateOpen(false)}\n onSubmit={handleInvalidateCertificate}\n isSubmitting={isInvalidating}\n />\n <RemoveInvalidationModal\n isOpen={isRemoveInvalidationOpen}\n email={selectedEmail}\n onClose={() => {\n setIsRemoveInvalidationOpen(false);\n setSelectedUsername('');\n setSelectedEmail('');\n }}\n onConfirm={handleRemoveInvalidationConfirm}\n isSubmitting={isRemovingInvalidation}\n />\n <DisableCertificatesModal\n isOpen={isDisableCertificatesOpen}\n isEnabled={isCertificateGenerationEnabled}\n onClose={() => setIsDisableCertificatesOpen(false)}\n onConfirm={handleToggleCertificateGeneration}\n isSubmitting={isTogglingGeneration}\n />\n </Container>\n );\n};\n\nexport default CertificatesPage;\n"]}
|
|
1
|
+
{"version":3,"file":"CertificatesPage.js","sourceRoot":"","sources":["../../src/certificates/CertificatesPage.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState, useCallback } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { Card, Container, Tab, Tabs, Alert } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport { useAlert } from '@src/providers/AlertProvider';\nimport { useCourseInfo } from '@src/data/apiHook';\nimport CertificatesPageHeader from '@src/certificates/components/CertificatesPageHeader';\nimport IssuedCertificatesTab from '@src/certificates/components/IssuedCertificatesTab';\nimport GenerationHistoryTable from '@src/certificates/components/GenerationHistoryTable';\nimport GrantExceptionsModal from '@src/certificates/components/GrantExceptionsModal';\nimport InvalidateCertificateModal from '@src/certificates/components/InvalidateCertificateModal';\nimport RemoveExceptionModal from '@src/certificates/components/RemoveExceptionModal';\nimport RemoveInvalidationModal from '@src/certificates/components/RemoveInvalidationModal';\nimport DisableCertificatesModal from '@src/certificates/components/DisableCertificatesModal';\nimport {\n useCertificateGenerationHistory,\n useGrantBulkExceptions,\n useInvalidateCertificate,\n useIssuedCertificates,\n useRegenerateCertificates,\n useRemoveException,\n useRemoveInvalidation,\n useToggleCertificateGeneration,\n} from '@src/certificates/data/apiHook';\nimport { CertificateFilter } from '@src/certificates/types';\nimport { CERTIFICATES_PAGE_SIZE, TAB_KEYS, MODAL_TITLES, ALERT_VARIANTS } from '@src/certificates/constants';\nimport { getErrorMessage } from '@src/certificates/utils/errorHandling';\nimport messages from '@src/certificates/messages';\nimport '@src/certificates/CertificatesPage.scss';\n\nconst CertificatesPage = () => {\n const intl = useIntl();\n const { courseId = '' } = useParams<{ courseId: string }>();\n const { showToast, showModal } = useAlert();\n const { data: courseInfo } = useCourseInfo(courseId);\n\n const [filter, setFilter] = useState<CertificateFilter>(CertificateFilter.ALL_LEARNERS);\n const [search, setSearch] = useState('');\n const [certificatesPage, setCertificatesPage] = useState(0);\n const [tasksPage, setTasksPage] = useState(0);\n const [activeTab, setActiveTab] = useState(TAB_KEYS.ISSUED);\n const [selectedUsername, setSelectedUsername] = useState('');\n const [selectedEmail, setSelectedEmail] = useState('');\n const [isCertificateGenerationEnabled, setIsCertificateGenerationEnabled] = useState(true);\n\n const [isGrantExceptionsOpen, setIsGrantExceptionsOpen] = useState(false);\n const [isInvalidateCertificateOpen, setIsInvalidateCertificateOpen] = useState(false);\n const [isRemoveExceptionOpen, setIsRemoveExceptionOpen] = useState(false);\n const [isRemoveInvalidationOpen, setIsRemoveInvalidationOpen] = useState(false);\n const [isDisableCertificatesOpen, setIsDisableCertificatesOpen] = useState(false);\n\n const {\n data: certificatesData,\n isLoading: isLoadingCertificates,\n } = useIssuedCertificates(courseId, {\n page: certificatesPage,\n pageSize: CERTIFICATES_PAGE_SIZE,\n filter,\n search,\n });\n\n const {\n data: historyData,\n isLoading: isLoadingHistory,\n } = useCertificateGenerationHistory(courseId, {\n page: tasksPage,\n pageSize: CERTIFICATES_PAGE_SIZE,\n });\n\n const { mutate: grantExceptions, isPending: isGrantingExceptions } = useGrantBulkExceptions(courseId);\n const { mutate: invalidateCert, isPending: isInvalidating } = useInvalidateCertificate(courseId);\n const { mutate: removeExcept, isPending: isRemovingException } = useRemoveException(courseId);\n const { mutate: removeInval, isPending: isRemovingInvalidation } = useRemoveInvalidation(courseId);\n const { mutate: toggleGeneration, isPending: isTogglingGeneration } = useToggleCertificateGeneration(courseId);\n const { mutate: regenerateCerts } = useRegenerateCertificates(courseId);\n\n const handleGrantExceptions = useCallback((learners: string[], notes: string) => {\n grantExceptions(\n { learners, notes },\n {\n onSuccess: (data) => {\n setIsGrantExceptionsOpen(false);\n if (data.errors && data.errors.length > 0) {\n const errorMessages = data.errors.map(err => `${err.learner}: ${err.message}`).join('\\n');\n showModal({\n title: MODAL_TITLES.ERROR,\n message: `Some exceptions failed:\\n${errorMessages}`,\n variant: ALERT_VARIANTS.WARNING,\n });\n }\n if (data.success && data.success.length > 0) {\n showToast(intl.formatMessage(messages.exceptionsGrantedToast, { count: data.success.length }));\n }\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorGrantException)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n },\n );\n }, [grantExceptions, showToast, showModal, intl]);\n\n const handleInvalidateCertificate = useCallback((learners: string[], notes: string) => {\n invalidateCert(\n { learners, notes },\n {\n onSuccess: (data) => {\n setIsInvalidateCertificateOpen(false);\n if (data.errors && data.errors.length > 0) {\n const errorMessages = data.errors.map(err => `${err.learner}: ${err.message}`).join('\\n');\n showModal({\n title: MODAL_TITLES.ERROR,\n message: `Some invalidations failed:\\n${errorMessages}`,\n variant: ALERT_VARIANTS.WARNING,\n });\n }\n if (data.success && data.success.length > 0) {\n showToast(intl.formatMessage(messages.certificatesInvalidatedToast, { count: data.success.length }));\n }\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorInvalidateCertificate)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n },\n );\n }, [invalidateCert, showToast, showModal, intl]);\n\n const handleRemoveExceptionClick = useCallback((username: string, email: string) => {\n setSelectedUsername(username);\n setSelectedEmail(email);\n setIsRemoveExceptionOpen(true);\n }, []);\n\n const handleRemoveExceptionConfirm = useCallback(() => {\n // Backend accepts either username or email - use whichever is available\n const identifier = selectedUsername || selectedEmail;\n\n if (!identifier) {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: intl.formatMessage(messages.errorRemoveException) + ': Username or email is required',\n variant: ALERT_VARIANTS.DANGER,\n });\n return;\n }\n\n removeExcept(\n { username: identifier },\n {\n onSuccess: () => {\n setIsRemoveExceptionOpen(false);\n setSelectedUsername('');\n setSelectedEmail('');\n showToast(intl.formatMessage(messages.exceptionRemovedToast, { email: selectedEmail }));\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorRemoveException)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n },\n );\n }, [removeExcept, selectedUsername, selectedEmail, showToast, showModal, intl]);\n\n const handleRemoveInvalidationClick = useCallback((username: string, email: string) => {\n setSelectedUsername(username);\n setSelectedEmail(email);\n setIsRemoveInvalidationOpen(true);\n }, []);\n\n const handleRemoveInvalidationConfirm = useCallback(() => {\n // Backend accepts either username or email - use whichever is available\n const identifier = selectedUsername || selectedEmail;\n\n if (!identifier) {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: intl.formatMessage(messages.errorRemoveInvalidation) + ': Username or email is required',\n variant: ALERT_VARIANTS.DANGER,\n });\n return;\n }\n\n removeInval(\n { username: identifier },\n {\n onSuccess: () => {\n setIsRemoveInvalidationOpen(false);\n setSelectedUsername('');\n setSelectedEmail('');\n showToast(intl.formatMessage(messages.invalidationRemovedToast, { email: selectedEmail }));\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorRemoveInvalidation)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n },\n );\n }, [removeInval, selectedUsername, selectedEmail, showToast, showModal, intl]);\n\n const handleToggleCertificateGeneration = useCallback(() => {\n const newState = !isCertificateGenerationEnabled;\n toggleGeneration(newState, {\n onSuccess: () => {\n setIsCertificateGenerationEnabled(newState);\n setIsDisableCertificatesOpen(false);\n showToast(\n newState\n ? intl.formatMessage(messages.successEnableCertificates)\n : intl.formatMessage(messages.successDisableCertificates),\n );\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorToggleCertificateGeneration)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n });\n }, [isCertificateGenerationEnabled, toggleGeneration, showToast, showModal, intl]);\n\n const handleRegenerateCertificates = useCallback(() => {\n regenerateCerts(filter, {\n onSuccess: () => {\n showToast(intl.formatMessage(messages.certificatesRegeneratedToast));\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorRegenerateCertificates)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n });\n }, [regenerateCerts, filter, showToast, showModal, intl]);\n\n // Check if certificate management is disabled\n if (courseInfo && !courseInfo.certificatesEnabled) {\n return (\n <Container className=\"mt-4.5 mb-4\" fluid>\n <Alert variant=\"warning\">\n {intl.formatMessage(messages.certificatesDisabledMessage)}\n </Alert>\n </Container>\n );\n }\n\n return (\n <Container className=\"mt-4.5 mb-4\" fluid>\n <CertificatesPageHeader\n onGrantExceptions={() => setIsGrantExceptionsOpen(true)}\n onInvalidateCertificate={() => setIsInvalidateCertificateOpen(true)}\n onDisableCertificates={() => setIsDisableCertificatesOpen(true)}\n />\n\n <Card variant=\"muted\" className=\"pt-3 pt-md-4 pb-4 pb-md-6 certificates-card\">\n <Tabs\n activeKey={activeTab}\n onSelect={(key) => setActiveTab(key || TAB_KEYS.ISSUED)}\n className=\"mx-4\"\n variant=\"button-group\"\n >\n <Tab eventKey={TAB_KEYS.ISSUED} title={intl.formatMessage(messages.issuedCertificatesTab)}>\n <IssuedCertificatesTab\n data={certificatesData?.results || []}\n isLoading={isLoadingCertificates}\n itemCount={certificatesData?.count || 0}\n pageCount={certificatesData?.numPages || 0}\n search={search}\n onSearchChange={setSearch}\n filter={filter}\n onFilterChange={setFilter}\n currentPage={certificatesPage}\n onPageChange={setCertificatesPage}\n onRemoveException={handleRemoveExceptionClick}\n onRemoveInvalidation={handleRemoveInvalidationClick}\n onRegenerateCertificates={handleRegenerateCertificates}\n />\n </Tab>\n <Tab eventKey={TAB_KEYS.HISTORY} title={intl.formatMessage(messages.generationHistoryTab)}>\n <div className=\"d-flex flex-column mt-3 mt-md-4\">\n <GenerationHistoryTable\n data={historyData?.results || []}\n isLoading={isLoadingHistory}\n itemCount={historyData?.count || 0}\n pageCount={historyData?.numPages || 0}\n currentPage={tasksPage}\n onPageChange={setTasksPage}\n />\n </div>\n </Tab>\n </Tabs>\n </Card>\n\n <GrantExceptionsModal\n isOpen={isGrantExceptionsOpen}\n onClose={() => setIsGrantExceptionsOpen(false)}\n onSubmit={handleGrantExceptions}\n isSubmitting={isGrantingExceptions}\n />\n <InvalidateCertificateModal\n isOpen={isInvalidateCertificateOpen}\n onClose={() => setIsInvalidateCertificateOpen(false)}\n onSubmit={handleInvalidateCertificate}\n isSubmitting={isInvalidating}\n />\n <RemoveExceptionModal\n isOpen={isRemoveExceptionOpen}\n email={selectedEmail}\n onClose={() => {\n setIsRemoveExceptionOpen(false);\n setSelectedUsername('');\n setSelectedEmail('');\n }}\n onConfirm={handleRemoveExceptionConfirm}\n isSubmitting={isRemovingException}\n />\n <RemoveInvalidationModal\n isOpen={isRemoveInvalidationOpen}\n email={selectedEmail}\n onClose={() => {\n setIsRemoveInvalidationOpen(false);\n setSelectedUsername('');\n setSelectedEmail('');\n }}\n onConfirm={handleRemoveInvalidationConfirm}\n isSubmitting={isRemovingInvalidation}\n />\n <DisableCertificatesModal\n isOpen={isDisableCertificatesOpen}\n isEnabled={isCertificateGenerationEnabled}\n onClose={() => setIsDisableCertificatesOpen(false)}\n onConfirm={handleToggleCertificateGeneration}\n isSubmitting={isTogglingGeneration}\n />\n </Container>\n );\n};\n\nexport default CertificatesPage;\n"]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
|
-
import { DataTable,
|
|
3
|
+
import { DataTable, IconButton, OverlayTrigger, Popover, TableFooter } from '@openedx/paragon';
|
|
4
4
|
import { MoreVert } from '@openedx/paragon/icons';
|
|
5
5
|
import { useIntl } from '@openedx/frontend-base';
|
|
6
|
-
import { CertificateFilter as FilterEnum } from '
|
|
7
|
-
import { CERTIFICATES_TABLE_PAGE_SIZE } from '
|
|
8
|
-
import messages from '
|
|
6
|
+
import { CertificateFilter as FilterEnum } from '../../certificates/types';
|
|
7
|
+
import { CERTIFICATES_TABLE_PAGE_SIZE } from '../../certificates/constants';
|
|
8
|
+
import messages from '../../certificates/messages';
|
|
9
9
|
const CertificateTable = ({ data, isLoading, itemCount, filter, onRemoveException, onRemoveInvalidation, }) => {
|
|
10
10
|
const intl = useIntl();
|
|
11
11
|
const baseColumns = useMemo(() => [
|
|
@@ -72,9 +72,12 @@ const CertificateTable = ({ data, isLoading, itemCount, filter, onRemoveExceptio
|
|
|
72
72
|
}
|
|
73
73
|
return [
|
|
74
74
|
{
|
|
75
|
-
id: '
|
|
75
|
+
id: 'action',
|
|
76
76
|
Header: intl.formatMessage(messages.columnActions),
|
|
77
|
-
Cell: ({ row }) =>
|
|
77
|
+
Cell: ({ row }) => {
|
|
78
|
+
const popoverContent = (_jsx(Popover, { id: `popover-${row.original.username}`, className: "border-0 shadow-sm", children: _jsx(Popover.Content, { className: "p-0 border-0", children: _jsxs("div", { className: "dropdown-menu show position-static border shadow-sm", children: [filter === FilterEnum.GRANTED_EXCEPTIONS && (_jsx("button", { type: "button", className: "dropdown-item", onClick: () => onRemoveException(row.original.username, row.original.email), children: intl.formatMessage(messages.removeExceptionAction) })), filter === FilterEnum.INVALIDATED && (_jsx("button", { type: "button", className: "dropdown-item", onClick: () => onRemoveInvalidation(row.original.username, row.original.email), children: intl.formatMessage(messages.removeInvalidationAction) }))] }) }) }));
|
|
79
|
+
return (_jsx(OverlayTrigger, { trigger: "click", placement: "bottom-end", overlay: popoverContent, rootClose: true, children: _jsx(IconButton, { alt: intl.formatMessage(messages.columnActions), iconAs: MoreVert }) }));
|
|
80
|
+
},
|
|
78
81
|
},
|
|
79
82
|
];
|
|
80
83
|
}, [filter, intl, onRemoveException, onRemoveInvalidation]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CertificateTable.js","sourceRoot":"","sources":["../../../src/certificates/components/CertificateTable.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACtF,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,iBAAiB,IAAI,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,4BAA4B,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,QAAQ,MAAM,aAAa,CAAC;AAqBnC,MAAM,gBAAgB,GAAG,CAAC,EACxB,IAAI,EACJ,SAAS,EACT,SAAS,EACT,MAAM,EACN,iBAAiB,EACjB,oBAAoB,GACE,EAAE,EAAE;IAC1B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,MAAM,WAAW,GAAG,OAAO,CACzB,GAAG,EAAE,CAAC;QACJ;YACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,cAAc,CAAC;YACnD,QAAQ,EAAE,UAAU;SACrB;QACD;YACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,WAAW,CAAC;YAChD,QAAQ,EAAE,OAAO;SAClB;QACD;YACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,qBAAqB,CAAC;YAC1D,QAAQ,EAAE,iBAAiB;SAC5B;QACD;YACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,uBAAuB,CAAC;YAC5D,QAAQ,EAAE,mBAAmB;SAC9B;QACD;YACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YACtD,QAAQ,EAAE,aAAa;SACxB;KACF,EACD,CAAC,IAAI,CAAC,CACP,CAAC;IAEF,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,EAAE;QACtC,MAAM,OAAO,GAAiB,EAAE,CAAC;QAEjC,IAAI,MAAM,KAAK,UAAU,CAAC,YAAY,IAAI,MAAM,KAAK,UAAU,CAAC,kBAAkB,EAAE,CAAC;YACnF,OAAO,CAAC,IAAI,CACV;gBACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,sBAAsB,CAAC;gBAC3D,QAAQ,EAAE,kBAAkB;aAC7B,EACD;gBACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,oBAAoB,CAAC;gBACzD,QAAQ,EAAE,gBAAgB;aAC3B,CACF,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,KAAK,UAAU,CAAC,YAAY,IAAI,MAAM,KAAK,UAAU,CAAC,WAAW,EAAE,CAAC;YAC5E,OAAO,CAAC,IAAI,CACV;gBACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,mBAAmB,CAAC;gBACxD,QAAQ,EAAE,eAAe;aAC1B,EACD;gBACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,sBAAsB,CAAC;gBAC3D,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,CAAC,EAAE,KAAK,EAAsB,EAAE,EAAE;oBACtC,IAAI,CAAC,KAAK;wBAAE,OAAO,IAAI,CAAC;oBACxB,OAAO,CACL,4BACG,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE;4BAChC,IAAI,EAAE,SAAS;4BACf,KAAK,EAAE,SAAS;4BAChB,GAAG,EAAE,SAAS;4BACd,IAAI,EAAE,SAAS;4BACf,MAAM,EAAE,SAAS;yBAClB,CAAC,GACD,CACJ,CAAC;gBACJ,CAAC;aACF,EACD;gBACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,sBAAsB,CAAC;gBAC3D,QAAQ,EAAE,kBAAkB;aAC7B,CACF,CAAC;QACJ,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAEnB,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,EAAE;QACrC,IAAI,MAAM,KAAK,UAAU,CAAC,kBAAkB,IAAI,MAAM,KAAK,UAAU,CAAC,WAAW,EAAE,CAAC;YAClF,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO;YACL;gBACE,EAAE,EAAE,SAAS;gBACb,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC;gBAClD,IAAI,EAAE,CAAC,EAAE,GAAG,EAA0C,EAAE,EAAE,CAAC,CACzD,MAAC,QAAQ,IAAC,SAAS,EAAC,8BAA8B,aAChD,KAAC,QAAQ,CAAC,MAAM,IACd,EAAE,EAAE,oBAAoB,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAC/C,EAAE,EAAE,UAAU,EACd,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE,IAAI,EACZ,OAAO,EAAC,WAAW,EACnB,GAAG,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,GAC/C,EACF,MAAC,QAAQ,CAAC,IAAI,IAAC,UAAU,mBACtB,MAAM,KAAK,UAAU,CAAC,kBAAkB,IAAI,CAC3C,KAAC,QAAQ,CAAC,IAAI,IACZ,OAAO,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,YAE1E,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,qBAAqB,CAAC,GACrC,CACjB,EACA,MAAM,KAAK,UAAU,CAAC,WAAW,IAAI,CACpC,KAAC,QAAQ,CAAC,IAAI,IACZ,OAAO,EAAE,GAAG,EAAE,CAAC,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,YAE7E,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,wBAAwB,CAAC,GACxC,CACjB,IACa,IACP,CACZ;aACF;SACF,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAE5D,MAAM,UAAU,GAAG,OAAO,CACxB,GAAG,EAAE,CAAC,CAAC,GAAG,WAAW,EAAE,GAAG,kBAAkB,EAAE,GAAG,iBAAiB,CAAC,EACnE,CAAC,WAAW,EAAE,kBAAkB,EAAE,iBAAiB,CAAC,CACrD,CAAC;IAEF,OAAO,CACL,MAAC,SAAS,IACR,OAAO,EAAE,UAAU,EACnB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,SAAS,EACpB,WAAW,QACX,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,4BAA4B,EAAE,aAEtE,KAAC,SAAS,CAAC,KAAK,KAAG,EACnB,KAAC,SAAS,CAAC,UAAU,IAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAI,EAC7E,KAAC,WAAW,KAAG,IACL,CACb,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC","sourcesContent":["import { useMemo } from 'react';\nimport { DataTable, Dropdown, IconButton, Icon, TableFooter } from '@openedx/paragon';\nimport { MoreVert } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport type { CertificateData, CertificateFilter } from '../types';\nimport { CertificateFilter as FilterEnum } from '../types';\nimport { CERTIFICATES_TABLE_PAGE_SIZE } from '../constants';\nimport messages from '../messages';\n\ninterface CertificateTableProps {\n data: CertificateData[],\n isLoading: boolean,\n itemCount: number,\n pageCount: number,\n currentPage: number,\n filter: CertificateFilter,\n onPageChange: (pageIndex: number) => void,\n onRemoveException: (username: string, email: string) => void,\n onRemoveInvalidation: (username: string, email: string) => void,\n}\n\ninterface ColumnType {\n Header: string,\n accessor?: string,\n id?: string,\n Cell?: ({ row, value }: { row?: { original: CertificateData }, value?: string }) => JSX.Element | null,\n}\n\nconst CertificateTable = ({\n data,\n isLoading,\n itemCount,\n filter,\n onRemoveException,\n onRemoveInvalidation,\n}: CertificateTableProps) => {\n const intl = useIntl();\n\n const baseColumns = useMemo(\n () => [\n {\n Header: intl.formatMessage(messages.columnUsername),\n accessor: 'username',\n },\n {\n Header: intl.formatMessage(messages.columnEmail),\n accessor: 'email',\n },\n {\n Header: intl.formatMessage(messages.columnEnrollmentTrack),\n accessor: 'enrollmentTrack',\n },\n {\n Header: intl.formatMessage(messages.columnCertificateStatus),\n accessor: 'certificateStatus',\n },\n {\n Header: intl.formatMessage(messages.columnSpecialCase),\n accessor: 'specialCase',\n },\n ],\n [intl],\n );\n\n const conditionalColumns = useMemo(() => {\n const columns: ColumnType[] = [];\n\n if (filter === FilterEnum.ALL_LEARNERS || filter === FilterEnum.GRANTED_EXCEPTIONS) {\n columns.push(\n {\n Header: intl.formatMessage(messages.columnExceptionGranted),\n accessor: 'exceptionGranted',\n },\n {\n Header: intl.formatMessage(messages.columnExceptionNotes),\n accessor: 'exceptionNotes',\n },\n );\n }\n\n if (filter === FilterEnum.ALL_LEARNERS || filter === FilterEnum.INVALIDATED) {\n columns.push(\n {\n Header: intl.formatMessage(messages.columnInvalidatedBy),\n accessor: 'invalidatedBy',\n },\n {\n Header: intl.formatMessage(messages.columnInvalidationDate),\n accessor: 'invalidationDate',\n Cell: ({ value }: { value?: string }) => {\n if (!value) return null;\n return (\n <>\n {intl.formatDate(new Date(value), {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n })}\n </>\n );\n },\n },\n {\n Header: intl.formatMessage(messages.columnInvalidationNote),\n accessor: 'invalidationNote',\n },\n );\n }\n\n return columns;\n }, [filter, intl]);\n\n const additionalColumns = useMemo(() => {\n if (filter !== FilterEnum.GRANTED_EXCEPTIONS && filter !== FilterEnum.INVALIDATED) {\n return [];\n }\n\n return [\n {\n id: 'actions',\n Header: intl.formatMessage(messages.columnActions),\n Cell: ({ row }: { row: { original: CertificateData } }) => (\n <Dropdown className=\"certificate-actions-dropdown\">\n <Dropdown.Toggle\n id={`actions-dropdown-${row.original.username}`}\n as={IconButton}\n src={MoreVert}\n iconAs={Icon}\n variant=\"secondary\"\n alt={intl.formatMessage(messages.columnActions)}\n />\n <Dropdown.Menu alignRight>\n {filter === FilterEnum.GRANTED_EXCEPTIONS && (\n <Dropdown.Item\n onClick={() => onRemoveException(row.original.username, row.original.email)}\n >\n {intl.formatMessage(messages.removeExceptionAction)}\n </Dropdown.Item>\n )}\n {filter === FilterEnum.INVALIDATED && (\n <Dropdown.Item\n onClick={() => onRemoveInvalidation(row.original.username, row.original.email)}\n >\n {intl.formatMessage(messages.removeInvalidationAction)}\n </Dropdown.Item>\n )}\n </Dropdown.Menu>\n </Dropdown>\n ),\n },\n ];\n }, [filter, intl, onRemoveException, onRemoveInvalidation]);\n\n const allColumns = useMemo(\n () => [...baseColumns, ...conditionalColumns, ...additionalColumns],\n [baseColumns, conditionalColumns, additionalColumns],\n );\n\n return (\n <DataTable\n columns={allColumns}\n data={data}\n isLoading={isLoading}\n isPaginated\n itemCount={itemCount}\n initialState={{ pageIndex: 0, pageSize: CERTIFICATES_TABLE_PAGE_SIZE }}\n >\n <DataTable.Table />\n <DataTable.EmptyTable content={intl.formatMessage(messages.noDataMessage)} />\n <TableFooter />\n </DataTable>\n );\n};\n\nexport default CertificateTable;\n"]}
|
|
1
|
+
{"version":3,"file":"CertificateTable.js","sourceRoot":"","sources":["../../../src/certificates/components/CertificateTable.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo } from 'react';\nimport { DataTable, IconButton, OverlayTrigger, Popover, TableFooter } from '@openedx/paragon';\nimport { MoreVert } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport type { CertificateData, CertificateFilter } from '@src/certificates/types';\nimport { CertificateFilter as FilterEnum } from '@src/certificates/types';\nimport { CERTIFICATES_TABLE_PAGE_SIZE } from '@src/certificates/constants';\nimport messages from '@src/certificates/messages';\n\ninterface CertificateTableProps {\n data: CertificateData[],\n isLoading: boolean,\n itemCount: number,\n pageCount: number,\n currentPage: number,\n filter: CertificateFilter,\n onPageChange: (pageIndex: number) => void,\n onRemoveException: (username: string, email: string) => void,\n onRemoveInvalidation: (username: string, email: string) => void,\n}\n\ninterface ColumnType {\n Header: string,\n accessor?: string,\n id?: string,\n Cell?: ({ row, value }: { row?: { original: CertificateData }, value?: string }) => JSX.Element | null,\n}\n\nconst CertificateTable = ({\n data,\n isLoading,\n itemCount,\n filter,\n onRemoveException,\n onRemoveInvalidation,\n}: CertificateTableProps) => {\n const intl = useIntl();\n\n const baseColumns = useMemo(\n () => [\n {\n Header: intl.formatMessage(messages.columnUsername),\n accessor: 'username',\n },\n {\n Header: intl.formatMessage(messages.columnEmail),\n accessor: 'email',\n },\n {\n Header: intl.formatMessage(messages.columnEnrollmentTrack),\n accessor: 'enrollmentTrack',\n },\n {\n Header: intl.formatMessage(messages.columnCertificateStatus),\n accessor: 'certificateStatus',\n },\n {\n Header: intl.formatMessage(messages.columnSpecialCase),\n accessor: 'specialCase',\n },\n ],\n [intl],\n );\n\n const conditionalColumns = useMemo(() => {\n const columns: ColumnType[] = [];\n\n if (filter === FilterEnum.ALL_LEARNERS || filter === FilterEnum.GRANTED_EXCEPTIONS) {\n columns.push(\n {\n Header: intl.formatMessage(messages.columnExceptionGranted),\n accessor: 'exceptionGranted',\n },\n {\n Header: intl.formatMessage(messages.columnExceptionNotes),\n accessor: 'exceptionNotes',\n },\n );\n }\n\n if (filter === FilterEnum.ALL_LEARNERS || filter === FilterEnum.INVALIDATED) {\n columns.push(\n {\n Header: intl.formatMessage(messages.columnInvalidatedBy),\n accessor: 'invalidatedBy',\n },\n {\n Header: intl.formatMessage(messages.columnInvalidationDate),\n accessor: 'invalidationDate',\n Cell: ({ value }: { value?: string }) => {\n if (!value) return null;\n return (\n <>\n {intl.formatDate(new Date(value), {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n })}\n </>\n );\n },\n },\n {\n Header: intl.formatMessage(messages.columnInvalidationNote),\n accessor: 'invalidationNote',\n },\n );\n }\n\n return columns;\n }, [filter, intl]);\n\n const additionalColumns = useMemo(() => {\n if (filter !== FilterEnum.GRANTED_EXCEPTIONS && filter !== FilterEnum.INVALIDATED) {\n return [];\n }\n\n return [\n {\n id: 'action',\n Header: intl.formatMessage(messages.columnActions),\n Cell: ({ row }: { row: { original: CertificateData } }) => {\n const popoverContent = (\n <Popover\n id={`popover-${row.original.username}`}\n className=\"border-0 shadow-sm\"\n >\n <Popover.Content className=\"p-0 border-0\">\n <div className=\"dropdown-menu show position-static border shadow-sm\">\n {filter === FilterEnum.GRANTED_EXCEPTIONS && (\n <button\n type=\"button\"\n className=\"dropdown-item\"\n onClick={() => onRemoveException(row.original.username, row.original.email)}\n >\n {intl.formatMessage(messages.removeExceptionAction)}\n </button>\n )}\n {filter === FilterEnum.INVALIDATED && (\n <button\n type=\"button\"\n className=\"dropdown-item\"\n onClick={() => onRemoveInvalidation(row.original.username, row.original.email)}\n >\n {intl.formatMessage(messages.removeInvalidationAction)}\n </button>\n )}\n </div>\n </Popover.Content>\n </Popover>\n );\n\n return (\n <OverlayTrigger\n trigger=\"click\"\n placement=\"bottom-end\"\n overlay={popoverContent}\n rootClose\n >\n <IconButton\n alt={intl.formatMessage(messages.columnActions)}\n iconAs={MoreVert}\n />\n </OverlayTrigger>\n );\n },\n },\n ];\n }, [filter, intl, onRemoveException, onRemoveInvalidation]);\n\n const allColumns = useMemo(\n () => [...baseColumns, ...conditionalColumns, ...additionalColumns],\n [baseColumns, conditionalColumns, additionalColumns],\n );\n\n return (\n <DataTable\n columns={allColumns}\n data={data}\n isLoading={isLoading}\n isPaginated\n itemCount={itemCount}\n initialState={{ pageIndex: 0, pageSize: CERTIFICATES_TABLE_PAGE_SIZE }}\n >\n <DataTable.Table />\n <DataTable.EmptyTable content={intl.formatMessage(messages.noDataMessage)} />\n <TableFooter />\n </DataTable>\n );\n};\n\nexport default CertificateTable;\n"]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Button, IconButton, Stack } from '@openedx/paragon';
|
|
2
|
+
import { Button, Dropdown, IconButton, Stack } from '@openedx/paragon';
|
|
3
3
|
import { Add, Close, MoreVert } from '@openedx/paragon/icons';
|
|
4
4
|
import { useIntl } from '@openedx/frontend-base';
|
|
5
|
-
import messages from '
|
|
5
|
+
import messages from '../../certificates/messages';
|
|
6
6
|
const CertificatesPageHeader = ({ onGrantExceptions, onInvalidateCertificate, onDisableCertificates, }) => {
|
|
7
7
|
const intl = useIntl();
|
|
8
|
-
return (_jsxs("div", { className: "d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center mb-4 gap-3", children: [_jsx("h3", { className: "text-primary-700 mb-0", children: intl.formatMessage(messages.pageTitle) }), _jsxs(Stack, { direction: "horizontal", gap: 2, className: "flex-wrap", children: [_jsx(
|
|
8
|
+
return (_jsxs("div", { className: "d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center mb-4 gap-3", children: [_jsx("h3", { className: "text-primary-700 mb-0", children: intl.formatMessage(messages.pageTitle) }), _jsxs(Stack, { direction: "horizontal", gap: 2, className: "flex-wrap", children: [_jsxs(Dropdown, { children: [_jsx(Dropdown.Toggle, { as: IconButton, src: MoreVert, alt: intl.formatMessage(messages.disableCertificatesButton), id: "certificates-more-menu" }), _jsx(Dropdown.Menu, { children: _jsx(Dropdown.Item, { onClick: onDisableCertificates, children: intl.formatMessage(messages.disableCertificatesButton) }) })] }), _jsx(Button, { variant: "outline-primary", iconBefore: Close, onClick: onInvalidateCertificate, className: "text-nowrap", children: intl.formatMessage(messages.invalidateCertificateButton) }), _jsx(Button, { variant: "primary", iconBefore: Add, onClick: onGrantExceptions, className: "text-nowrap", children: intl.formatMessage(messages.grantExceptionsButton) })] })] }));
|
|
9
9
|
};
|
|
10
10
|
export default CertificatesPageHeader;
|
|
11
11
|
//# sourceMappingURL=CertificatesPageHeader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CertificatesPageHeader.js","sourceRoot":"","sources":["../../../src/certificates/components/CertificatesPageHeader.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"CertificatesPageHeader.js","sourceRoot":"","sources":["../../../src/certificates/components/CertificatesPageHeader.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAQlD,MAAM,sBAAsB,GAAG,CAAC,EAC9B,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,GACO,EAAE,EAAE;IAChC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,OAAO,CACL,eAAK,SAAS,EAAC,2GAA2G,aACxH,aAAI,SAAS,EAAC,uBAAuB,YAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAM,EACnF,MAAC,KAAK,IAAC,SAAS,EAAC,YAAY,EAAC,GAAG,EAAE,CAAC,EAAE,SAAS,EAAC,WAAW,aACzD,MAAC,QAAQ,eACP,KAAC,QAAQ,CAAC,MAAM,IACd,EAAE,EAAE,UAAU,EACd,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EAC3D,EAAE,EAAC,wBAAwB,GAC3B,EACF,KAAC,QAAQ,CAAC,IAAI,cACZ,KAAC,QAAQ,CAAC,IAAI,IAAC,OAAO,EAAE,qBAAqB,YAC1C,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC,GACzC,GACF,IACP,EACX,KAAC,MAAM,IACL,OAAO,EAAC,iBAAiB,EACzB,UAAU,EAAE,KAAK,EACjB,OAAO,EAAE,uBAAuB,EAChC,SAAS,EAAC,aAAa,YAEtB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC,GAClD,EACT,KAAC,MAAM,IACL,OAAO,EAAC,SAAS,EACjB,UAAU,EAAE,GAAG,EACf,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAC,aAAa,YAEtB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,qBAAqB,CAAC,GAC5C,IACH,IACJ,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,sBAAsB,CAAC","sourcesContent":["import { Button, Dropdown, IconButton, Stack } from '@openedx/paragon';\nimport { Add, Close, MoreVert } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport messages from '@src/certificates/messages';\n\ninterface CertificatesPageHeaderProps {\n onGrantExceptions: () => void,\n onInvalidateCertificate: () => void,\n onDisableCertificates: () => void,\n}\n\nconst CertificatesPageHeader = ({\n onGrantExceptions,\n onInvalidateCertificate,\n onDisableCertificates,\n}: CertificatesPageHeaderProps) => {\n const intl = useIntl();\n\n return (\n <div className=\"d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center mb-4 gap-3\">\n <h3 className=\"text-primary-700 mb-0\">{intl.formatMessage(messages.pageTitle)}</h3>\n <Stack direction=\"horizontal\" gap={2} className=\"flex-wrap\">\n <Dropdown>\n <Dropdown.Toggle\n as={IconButton}\n src={MoreVert}\n alt={intl.formatMessage(messages.disableCertificatesButton)}\n id=\"certificates-more-menu\"\n />\n <Dropdown.Menu>\n <Dropdown.Item onClick={onDisableCertificates}>\n {intl.formatMessage(messages.disableCertificatesButton)}\n </Dropdown.Item>\n </Dropdown.Menu>\n </Dropdown>\n <Button\n variant=\"outline-primary\"\n iconBefore={Close}\n onClick={onInvalidateCertificate}\n className=\"text-nowrap\"\n >\n {intl.formatMessage(messages.invalidateCertificateButton)}\n </Button>\n <Button\n variant=\"primary\"\n iconBefore={Add}\n onClick={onGrantExceptions}\n className=\"text-nowrap\"\n >\n {intl.formatMessage(messages.grantExceptionsButton)}\n </Button>\n </Stack>\n </div>\n );\n};\n\nexport default CertificatesPageHeader;\n"]}
|
|
@@ -2,11 +2,31 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Button, SearchField } from '@openedx/paragon';
|
|
3
3
|
import { SpinnerIcon } from '@openedx/paragon/icons';
|
|
4
4
|
import { useIntl } from '@openedx/frontend-base';
|
|
5
|
-
import FilterDropdown from '
|
|
6
|
-
import
|
|
5
|
+
import FilterDropdown from '../../certificates/components/FilterDropdown';
|
|
6
|
+
import { CertificateFilter } from '../../certificates/types';
|
|
7
|
+
import messages from '../../certificates/messages';
|
|
8
|
+
import '@src/certificates/CertificatesPage.scss';
|
|
9
|
+
const getFilterLabel = (filter, intl) => {
|
|
10
|
+
const filterMessages = {
|
|
11
|
+
[CertificateFilter.ALL_LEARNERS]: messages.filterAllLearners,
|
|
12
|
+
[CertificateFilter.RECEIVED]: messages.filterReceived,
|
|
13
|
+
[CertificateFilter.NOT_RECEIVED]: messages.filterNotReceived,
|
|
14
|
+
[CertificateFilter.AUDIT_PASSING]: messages.filterAuditPassing,
|
|
15
|
+
[CertificateFilter.AUDIT_NOT_PASSING]: messages.filterAuditNotPassing,
|
|
16
|
+
[CertificateFilter.ERROR_STATE]: messages.filterErrorState,
|
|
17
|
+
[CertificateFilter.GRANTED_EXCEPTIONS]: messages.filterGrantedExceptions,
|
|
18
|
+
[CertificateFilter.INVALIDATED]: messages.filterInvalidated,
|
|
19
|
+
};
|
|
20
|
+
return intl.formatMessage(filterMessages[filter]);
|
|
21
|
+
};
|
|
7
22
|
const CertificatesToolbar = ({ search, onSearchChange, filter, onFilterChange, onRegenerateCertificates, }) => {
|
|
8
23
|
const intl = useIntl();
|
|
9
|
-
|
|
24
|
+
const buttonText = filter === CertificateFilter.ALL_LEARNERS
|
|
25
|
+
? intl.formatMessage(messages.regenerateCertificatesButton)
|
|
26
|
+
: intl.formatMessage(messages.regenerateCertificatesButtonWithFilter, {
|
|
27
|
+
filter: getFilterLabel(filter, intl),
|
|
28
|
+
});
|
|
29
|
+
return (_jsxs("div", { className: "d-flex flex-wrap align-items-center justify-content-between mb-4 mx-4 mt-3 gap-3", children: [_jsxs("div", { className: "d-flex align-items-center gap-3 flex-shrink-1 certificates-toolbar-wrapper", children: [_jsx(SearchField, { onSubmit: onSearchChange, onChange: onSearchChange, placeholder: intl.formatMessage(messages.searchPlaceholder), value: search, className: "flex-shrink-1 certificates-search-field" }), _jsx(FilterDropdown, { value: filter, onChange: onFilterChange, className: "flex-shrink-0" })] }), _jsx(Button, { variant: "outline-primary", iconBefore: SpinnerIcon, onClick: onRegenerateCertificates, className: "text-nowrap flex-shrink-0", children: buttonText })] }));
|
|
10
30
|
};
|
|
11
31
|
export default CertificatesToolbar;
|
|
12
32
|
//# sourceMappingURL=CertificatesToolbar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CertificatesToolbar.js","sourceRoot":"","sources":["../../../src/certificates/components/CertificatesToolbar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,cAAc,MAAM,
|
|
1
|
+
{"version":3,"file":"CertificatesToolbar.js","sourceRoot":"","sources":["../../../src/certificates/components/CertificatesToolbar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,cAAc,MAAM,6CAA6C,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAClD,OAAO,yCAAyC,CAAC;AAUjD,MAAM,cAAc,GAAG,CAAC,MAAyB,EAAE,IAAS,EAAE,EAAE;IAC9D,MAAM,cAAc,GAAmC;QACrD,CAAC,iBAAiB,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,iBAAiB;QAC5D,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,cAAc;QACrD,CAAC,iBAAiB,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,iBAAiB;QAC5D,CAAC,iBAAiB,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,kBAAkB;QAC9D,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,EAAE,QAAQ,CAAC,qBAAqB;QACrE,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,gBAAgB;QAC1D,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,EAAE,QAAQ,CAAC,uBAAuB;QACxE,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,iBAAiB;KAC5D,CAAC;IACF,OAAO,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;AACpD,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,EAC3B,MAAM,EACN,cAAc,EACd,MAAM,EACN,cAAc,EACd,wBAAwB,GACC,EAAE,EAAE;IAC7B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,MAAM,UAAU,GAAG,MAAM,KAAK,iBAAiB,CAAC,YAAY;QAC1D,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC;QAC3D,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,sCAAsC,EAAE;YAClE,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC;SACrC,CAAC,CAAC;IAEP,OAAO,CACL,eAAK,SAAS,EAAC,kFAAkF,aAC/F,eAAK,SAAS,EAAC,4EAA4E,aACzF,KAAC,WAAW,IACV,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,cAAc,EACxB,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAC3D,KAAK,EAAE,MAAM,EACb,SAAS,EAAC,yCAAyC,GACnD,EACF,KAAC,cAAc,IACb,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAC,eAAe,GACzB,IACE,EACN,KAAC,MAAM,IACL,OAAO,EAAC,iBAAiB,EACzB,UAAU,EAAE,WAAW,EACvB,OAAO,EAAE,wBAAwB,EACjC,SAAS,EAAC,2BAA2B,YAEpC,UAAU,GACJ,IACL,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,mBAAmB,CAAC","sourcesContent":["import { Button, SearchField } from '@openedx/paragon';\nimport { SpinnerIcon } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport FilterDropdown from '@src/certificates/components/FilterDropdown';\nimport { CertificateFilter } from '@src/certificates/types';\nimport messages from '@src/certificates/messages';\nimport '@src/certificates/CertificatesPage.scss';\n\ninterface CertificatesToolbarProps {\n search: string,\n onSearchChange: (value: string) => void,\n filter: CertificateFilter,\n onFilterChange: (value: CertificateFilter) => void,\n onRegenerateCertificates: () => void,\n}\n\nconst getFilterLabel = (filter: CertificateFilter, intl: any) => {\n const filterMessages: Record<CertificateFilter, any> = {\n [CertificateFilter.ALL_LEARNERS]: messages.filterAllLearners,\n [CertificateFilter.RECEIVED]: messages.filterReceived,\n [CertificateFilter.NOT_RECEIVED]: messages.filterNotReceived,\n [CertificateFilter.AUDIT_PASSING]: messages.filterAuditPassing,\n [CertificateFilter.AUDIT_NOT_PASSING]: messages.filterAuditNotPassing,\n [CertificateFilter.ERROR_STATE]: messages.filterErrorState,\n [CertificateFilter.GRANTED_EXCEPTIONS]: messages.filterGrantedExceptions,\n [CertificateFilter.INVALIDATED]: messages.filterInvalidated,\n };\n return intl.formatMessage(filterMessages[filter]);\n};\n\nconst CertificatesToolbar = ({\n search,\n onSearchChange,\n filter,\n onFilterChange,\n onRegenerateCertificates,\n}: CertificatesToolbarProps) => {\n const intl = useIntl();\n\n const buttonText = filter === CertificateFilter.ALL_LEARNERS\n ? intl.formatMessage(messages.regenerateCertificatesButton)\n : intl.formatMessage(messages.regenerateCertificatesButtonWithFilter, {\n filter: getFilterLabel(filter, intl),\n });\n\n return (\n <div className=\"d-flex flex-wrap align-items-center justify-content-between mb-4 mx-4 mt-3 gap-3\">\n <div className=\"d-flex align-items-center gap-3 flex-shrink-1 certificates-toolbar-wrapper\">\n <SearchField\n onSubmit={onSearchChange}\n onChange={onSearchChange}\n placeholder={intl.formatMessage(messages.searchPlaceholder)}\n value={search}\n className=\"flex-shrink-1 certificates-search-field\"\n />\n <FilterDropdown\n value={filter}\n onChange={onFilterChange}\n className=\"flex-shrink-0\"\n />\n </div>\n <Button\n variant=\"outline-primary\"\n iconBefore={SpinnerIcon}\n onClick={onRegenerateCertificates}\n className=\"text-nowrap flex-shrink-0\"\n >\n {buttonText}\n </Button>\n </div>\n );\n};\n\nexport default CertificatesToolbar;\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ActionRow, Button, ModalDialog } from '@openedx/paragon';
|
|
3
3
|
import { useIntl } from '@openedx/frontend-base';
|
|
4
|
-
import messages from '
|
|
4
|
+
import messages from '../../certificates/messages';
|
|
5
5
|
const DisableCertificatesModal = ({ isOpen, isEnabled, onClose, onConfirm, isSubmitting, }) => {
|
|
6
6
|
const intl = useIntl();
|
|
7
7
|
const title = isEnabled
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DisableCertificatesModal.js","sourceRoot":"","sources":["../../../src/certificates/components/DisableCertificatesModal.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,QAAQ,MAAM,
|
|
1
|
+
{"version":3,"file":"DisableCertificatesModal.js","sourceRoot":"","sources":["../../../src/certificates/components/DisableCertificatesModal.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAUlD,MAAM,wBAAwB,GAAG,CAAC,EAChC,MAAM,EACN,SAAS,EACT,OAAO,EACP,SAAS,EACT,YAAY,GACkB,EAAE,EAAE;IAClC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,MAAM,KAAK,GAAG,SAAS;QACrB,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QAC5D,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;IAE9D,MAAM,OAAO,GAAG,SAAS;QACvB,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,+BAA+B,CAAC;QAC9D,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,8BAA8B,CAAC,CAAC;IAEhE,OAAO,CACL,MAAC,WAAW,IACV,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAC,IAAI,EACT,cAAc,EAAE,KAAK,EACrB,iBAAiB,EAAE,KAAK,aAExB,cAAK,SAAS,EAAC,kBAAkB,YAC/B,sBAAI,OAAO,GAAK,GACZ,EACN,KAAC,WAAW,CAAC,MAAM,cACjB,MAAC,SAAS,eACR,KAAC,MAAM,IAAC,OAAO,EAAC,UAAU,EAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,YAChE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,GAC7B,EACT,KAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,YACjE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,GAC9B,IACC,GACO,IACT,CACf,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,wBAAwB,CAAC","sourcesContent":["import { ActionRow, Button, ModalDialog } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport messages from '@src/certificates/messages';\n\ninterface DisableCertificatesModalProps {\n isOpen: boolean,\n isEnabled: boolean,\n onClose: () => void,\n onConfirm: () => void,\n isSubmitting: boolean,\n}\n\nconst DisableCertificatesModal = ({\n isOpen,\n isEnabled,\n onClose,\n onConfirm,\n isSubmitting,\n}: DisableCertificatesModalProps) => {\n const intl = useIntl();\n\n const title = isEnabled\n ? intl.formatMessage(messages.disableCertificatesModalTitle)\n : intl.formatMessage(messages.enableCertificatesModalTitle);\n\n const message = isEnabled\n ? intl.formatMessage(messages.disableCertificatesModalMessage)\n : intl.formatMessage(messages.enableCertificatesModalMessage);\n\n return (\n <ModalDialog\n title={title}\n onClose={onClose}\n isOpen={isOpen}\n size=\"sm\"\n hasCloseButton={false}\n isOverflowVisible={false}\n >\n <div className=\"mx-4 mt-4 mb-2.5\">\n <p>{message}</p>\n </div>\n <ModalDialog.Footer>\n <ActionRow>\n <Button variant=\"tertiary\" onClick={onClose} disabled={isSubmitting}>\n {intl.formatMessage(messages.cancel)}\n </Button>\n <Button variant=\"primary\" onClick={onConfirm} disabled={isSubmitting}>\n {intl.formatMessage(messages.confirm)}\n </Button>\n </ActionRow>\n </ModalDialog.Footer>\n </ModalDialog>\n );\n};\n\nexport default DisableCertificatesModal;\n"]}
|