@openedx/frontend-app-instructor-dashboard 1.0.0-alpha.4 → 1.0.0-alpha.40
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/Main.d.ts +1 -1
- package/dist/Main.js +11 -18
- package/dist/Main.js.map +1 -1
- package/dist/app.js +0 -6
- package/dist/app.js.map +1 -1
- package/dist/certificates/CertificatesPage.d.ts +1 -0
- package/dist/certificates/CertificatesPage.js +312 -2
- package/dist/certificates/CertificatesPage.js.map +1 -1
- package/dist/certificates/CertificatesPage.scss +90 -0
- package/dist/certificates/components/CertificateTable.d.ts +14 -0
- package/dist/certificates/components/CertificateTable.js +88 -0
- package/dist/certificates/components/CertificateTable.js.map +1 -0
- package/dist/certificates/components/CertificatesPageHeader.d.ts +7 -0
- package/dist/certificates/components/CertificatesPageHeader.js +11 -0
- package/dist/certificates/components/CertificatesPageHeader.js.map +1 -0
- package/dist/certificates/components/CertificatesToolbar.d.ts +11 -0
- package/dist/certificates/components/CertificatesToolbar.js +33 -0
- package/dist/certificates/components/CertificatesToolbar.js.map +1 -0
- package/dist/certificates/components/DisableCertificatesModal.d.ts +9 -0
- package/dist/certificates/components/DisableCertificatesModal.js +24 -0
- package/dist/certificates/components/DisableCertificatesModal.js.map +1 -0
- package/dist/certificates/components/FilterDropdown.d.ts +8 -0
- package/dist/certificates/components/FilterDropdown.js +50 -0
- package/dist/certificates/components/FilterDropdown.js.map +1 -0
- package/dist/certificates/components/GenerateCertificatesModal.d.ts +9 -0
- package/dist/certificates/components/GenerateCertificatesModal.js +19 -0
- package/dist/certificates/components/GenerateCertificatesModal.js.map +1 -0
- package/dist/certificates/components/GenerationHistoryTable.d.ts +11 -0
- package/dist/certificates/components/GenerationHistoryTable.js +25 -0
- package/dist/certificates/components/GenerationHistoryTable.js.map +1 -0
- package/dist/certificates/components/GrantExceptionsModal.d.ts +9 -0
- package/dist/certificates/components/GrantExceptionsModal.js +55 -0
- package/dist/certificates/components/GrantExceptionsModal.js.map +1 -0
- package/dist/certificates/components/InvalidateCertificateModal.d.ts +8 -0
- package/dist/certificates/components/InvalidateCertificateModal.js +26 -0
- package/dist/certificates/components/InvalidateCertificateModal.js.map +1 -0
- package/dist/certificates/components/IssuedCertificatesTab.d.ts +18 -0
- package/dist/certificates/components/IssuedCertificatesTab.js +6 -0
- package/dist/certificates/components/IssuedCertificatesTab.js.map +1 -0
- package/dist/certificates/components/LearnerActionModal.d.ts +16 -0
- package/dist/certificates/components/LearnerActionModal.js +27 -0
- package/dist/certificates/components/LearnerActionModal.js.map +1 -0
- package/dist/certificates/components/RegenerateCertificatesModal.d.ts +11 -0
- package/dist/certificates/components/RegenerateCertificatesModal.js +46 -0
- package/dist/certificates/components/RegenerateCertificatesModal.js.map +1 -0
- 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.d.ts +9 -0
- package/dist/certificates/components/RemoveInvalidationModal.js +10 -0
- package/dist/certificates/components/RemoveInvalidationModal.js.map +1 -0
- package/dist/certificates/constants.d.ts +15 -0
- package/dist/certificates/constants.js +16 -0
- package/dist/certificates/constants.js.map +1 -0
- package/dist/certificates/data/api.d.ts +30 -0
- package/dist/certificates/data/api.js +126 -0
- package/dist/certificates/data/api.js.map +1 -0
- package/dist/certificates/data/apiHook.d.ts +63 -0
- package/dist/certificates/data/apiHook.js +133 -0
- package/dist/certificates/data/apiHook.js.map +1 -0
- package/dist/certificates/data/queryKeys.d.ts +9 -0
- package/dist/certificates/data/queryKeys.js +9 -0
- package/dist/certificates/data/queryKeys.js.map +1 -0
- package/dist/certificates/messages.d.ts +548 -0
- package/dist/certificates/messages.js +550 -0
- package/dist/certificates/messages.js.map +1 -0
- package/dist/certificates/types.d.ts +66 -0
- package/dist/certificates/types.js +26 -0
- package/dist/certificates/types.js.map +1 -0
- package/dist/certificates/utils/errorHandling.d.ts +12 -0
- package/dist/certificates/utils/errorHandling.js +24 -0
- package/dist/certificates/utils/errorHandling.js.map +1 -0
- package/dist/certificates/utils/filterUtils.d.ts +4 -0
- package/dist/certificates/utils/filterUtils.js +31 -0
- package/dist/certificates/utils/filterUtils.js.map +1 -0
- package/dist/certificates/utils/index.d.ts +2 -0
- package/dist/certificates/utils/index.js +2 -0
- package/dist/certificates/utils/index.js.map +1 -0
- package/dist/components/ActionCard.d.ts +2 -2
- package/dist/components/ActionCard.js +1 -1
- package/dist/components/ActionCard.js.map +1 -1
- package/dist/components/CodeEditor.d.ts +5 -0
- package/dist/components/CodeEditor.js +34 -0
- package/dist/components/CodeEditor.js.map +1 -0
- package/dist/components/PendingTasks.d.ts +3 -1
- package/dist/components/PendingTasks.js +3 -2
- package/dist/components/PendingTasks.js.map +1 -1
- package/dist/components/SpecifyLearnerField.d.ts +4 -1
- package/dist/components/SpecifyLearnerField.js +55 -15
- package/dist/components/SpecifyLearnerField.js.map +1 -1
- package/dist/components/SpecifyProblemField.d.ts +13 -0
- package/dist/components/SpecifyProblemField.js +52 -0
- package/dist/components/SpecifyProblemField.js.map +1 -0
- package/dist/components/UsernameFilter.d.ts +7 -0
- package/dist/components/UsernameFilter.js +19 -0
- package/dist/components/UsernameFilter.js.map +1 -0
- package/dist/components/messages.d.ts +45 -0
- package/dist/components/messages.js +45 -0
- package/dist/components/messages.js.map +1 -1
- package/dist/courseInfo/types.d.ts +5 -0
- package/dist/courseInfo/types.js.map +1 -1
- package/dist/courseTeam/CourseTeamPage.js +25 -2
- package/dist/courseTeam/CourseTeamPage.js.map +1 -1
- package/dist/courseTeam/components/AddTeamMemberModal.d.ts +6 -0
- package/dist/courseTeam/components/AddTeamMemberModal.js +61 -0
- package/dist/courseTeam/components/AddTeamMemberModal.js.map +1 -0
- package/dist/courseTeam/components/EditTeamMemberModal.d.ts +8 -0
- package/dist/courseTeam/components/EditTeamMemberModal.js +102 -0
- package/dist/courseTeam/components/EditTeamMemberModal.js.map +1 -0
- package/dist/courseTeam/components/MembersContent.d.ts +6 -0
- package/dist/courseTeam/components/MembersContent.js +48 -0
- package/dist/courseTeam/components/MembersContent.js.map +1 -0
- package/dist/courseTeam/components/RoleFilter.d.ts +7 -0
- package/dist/courseTeam/components/RoleFilter.js +22 -0
- package/dist/courseTeam/components/RoleFilter.js.map +1 -0
- package/dist/courseTeam/components/RolesContent.d.ts +3 -0
- package/dist/courseTeam/components/RolesContent.js +25 -0
- package/dist/courseTeam/components/RolesContent.js.map +1 -0
- package/dist/courseTeam/constants.d.ts +3 -0
- package/dist/courseTeam/constants.js +4 -0
- package/dist/courseTeam/constants.js.map +1 -0
- package/dist/courseTeam/data/api.d.ts +6 -0
- package/dist/courseTeam/data/api.js +38 -0
- package/dist/courseTeam/data/api.js.map +1 -0
- package/dist/courseTeam/data/apiHook.d.ts +8 -0
- package/dist/courseTeam/data/apiHook.js +32 -0
- package/dist/courseTeam/data/apiHook.js.map +1 -0
- package/dist/courseTeam/data/queryKeys.d.ts +7 -0
- package/dist/courseTeam/data/queryKeys.js +14 -0
- package/dist/courseTeam/data/queryKeys.js.map +1 -0
- package/dist/courseTeam/messages.d.ts +258 -0
- package/dist/courseTeam/messages.js +260 -0
- package/dist/courseTeam/messages.js.map +1 -0
- package/dist/courseTeam/types.d.ts +29 -0
- package/dist/courseTeam/types.js +3 -0
- package/dist/courseTeam/types.js.map +1 -0
- package/dist/data/api.d.ts +2 -1
- package/dist/data/api.js +9 -3
- package/dist/data/api.js.map +1 -1
- package/dist/data/apiHook.d.ts +1 -0
- package/dist/data/apiHook.js +11 -2
- package/dist/data/apiHook.js.map +1 -1
- package/dist/data/queryKeys.d.ts +4 -0
- package/dist/data/queryKeys.js +4 -0
- package/dist/data/queryKeys.js.map +1 -1
- package/dist/data/utils.d.ts +2 -0
- package/dist/data/utils.js +9 -0
- package/dist/data/utils.js.map +1 -0
- package/dist/dateExtensions/components/AddExtensionModal.d.ts +1 -1
- package/dist/dateExtensions/components/AddExtensionModal.js +6 -7
- package/dist/dateExtensions/components/AddExtensionModal.js.map +1 -1
- package/dist/dateExtensions/components/DateExtensionsList.js +3 -14
- package/dist/dateExtensions/components/DateExtensionsList.js.map +1 -1
- package/dist/dateExtensions/data/apiHook.d.ts +2 -2
- package/dist/dateExtensions/data/apiHook.js +4 -4
- package/dist/dateExtensions/data/apiHook.js.map +1 -1
- package/dist/dateExtensions/messages.d.ts +0 -5
- package/dist/dateExtensions/messages.js +1 -6
- package/dist/dateExtensions/messages.js.map +1 -1
- package/dist/enrollments/EnrollmentsPage.js +34 -7
- package/dist/enrollments/EnrollmentsPage.js.map +1 -1
- package/dist/enrollments/components/AddBetaTestersModal.d.ts +6 -0
- package/dist/enrollments/components/AddBetaTestersModal.js +69 -0
- package/dist/enrollments/components/AddBetaTestersModal.js.map +1 -0
- package/dist/enrollments/components/EnrollLearnersModal.d.ts +6 -0
- package/dist/enrollments/components/EnrollLearnersModal.js +53 -0
- package/dist/enrollments/components/EnrollLearnersModal.js.map +1 -0
- package/dist/enrollments/components/EnrollmentStatusModal.js +3 -3
- package/dist/enrollments/components/EnrollmentStatusModal.js.map +1 -1
- package/dist/enrollments/components/EnrollmentsList.d.ts +3 -2
- package/dist/enrollments/components/EnrollmentsList.js +13 -14
- package/dist/enrollments/components/EnrollmentsList.js.map +1 -1
- package/dist/enrollments/components/UnenrollModal.d.ts +1 -1
- package/dist/enrollments/components/UnenrollModal.js +29 -3
- package/dist/enrollments/components/UnenrollModal.js.map +1 -1
- package/dist/enrollments/components/UpdateBetaTesterModal.d.ts +8 -0
- package/dist/enrollments/components/UpdateBetaTesterModal.js +72 -0
- package/dist/enrollments/components/UpdateBetaTesterModal.js.map +1 -0
- package/dist/enrollments/data/api.d.ts +3 -1
- package/dist/enrollments/data/api.js +11 -1
- package/dist/enrollments/data/api.js.map +1 -1
- package/dist/enrollments/data/apiHook.d.ts +5 -3
- package/dist/enrollments/data/apiHook.js +21 -3
- package/dist/enrollments/data/apiHook.js.map +1 -1
- package/dist/enrollments/data/queryKeys.d.ts +1 -1
- package/dist/enrollments/data/queryKeys.js.map +1 -1
- package/dist/enrollments/messages.d.ts +131 -1
- package/dist/enrollments/messages.js +136 -6
- package/dist/enrollments/messages.js.map +1 -1
- package/dist/enrollments/types.d.ts +25 -0
- package/dist/enrollments/types.js.map +1 -1
- package/dist/grading/GradingPage.js +15 -2
- package/dist/grading/GradingPage.js.map +1 -1
- package/dist/grading/components/GradingActionRow.d.ts +2 -0
- package/dist/grading/components/GradingActionRow.js +20 -0
- package/dist/grading/components/GradingActionRow.js.map +1 -0
- package/dist/grading/components/GradingConfigurationModal.d.ts +6 -0
- package/dist/grading/components/GradingConfigurationModal.js +15 -0
- package/dist/grading/components/GradingConfigurationModal.js.map +1 -0
- package/dist/grading/components/GradingLearnerContent.d.ts +7 -0
- package/dist/grading/components/GradingLearnerContent.js +199 -0
- package/dist/grading/components/GradingLearnerContent.js.map +1 -0
- package/dist/grading/data/api.d.ts +6 -0
- package/dist/grading/data/api.js +59 -0
- package/dist/grading/data/api.js.map +1 -0
- package/dist/grading/data/apiHook.d.ts +6 -0
- package/dist/grading/data/apiHook.js +29 -0
- package/dist/grading/data/apiHook.js.map +1 -0
- package/dist/grading/data/queryKeys.d.ts +9 -0
- package/dist/grading/data/queryKeys.js +8 -0
- package/dist/grading/data/queryKeys.js.map +1 -0
- package/dist/grading/messages.d.ts +248 -0
- package/dist/grading/messages.js +250 -0
- package/dist/grading/messages.js.map +1 -0
- package/dist/grading/types.d.ts +11 -0
- package/dist/grading/types.js +2 -0
- package/dist/grading/types.js.map +1 -0
- package/dist/hooks/useDebouncedFilter.d.ts +1 -0
- package/dist/hooks/useDebouncedFilter.js +5 -0
- package/dist/hooks/useDebouncedFilter.js.map +1 -1
- package/dist/instructorNav/InstructorNav.js +16 -4
- package/dist/instructorNav/InstructorNav.js.map +1 -1
- package/dist/messages.d.ts +8 -0
- package/dist/messages.js +10 -0
- package/dist/messages.js.map +1 -0
- package/dist/pageWrapper/PageWrapper.js +3 -1
- package/dist/pageWrapper/PageWrapper.js.map +1 -1
- package/dist/providers/AccessErrorObserver.d.ts +9 -0
- package/dist/providers/AccessErrorObserver.js +35 -0
- package/dist/providers/AccessErrorObserver.js.map +1 -0
- package/dist/providers/AccessErrorProvider.d.ts +19 -0
- package/dist/providers/AccessErrorProvider.js +51 -0
- package/dist/providers/AccessErrorProvider.js.map +1 -0
- package/dist/providers/messages.d.ts +33 -0
- package/dist/providers/messages.js +35 -0
- package/dist/providers/messages.js.map +1 -0
- package/dist/provides.d.ts +2 -1
- package/dist/provides.js +3 -2
- package/dist/provides.js.map +1 -1
- package/dist/routes.d.ts +1 -1
- package/dist/routes.js +2 -2
- package/dist/routes.js.map +1 -1
- package/dist/slots/CourseInfoSlot/CourseInfoSlot.d.ts +2 -0
- package/dist/slots/CourseInfoSlot/CourseInfoSlot.js +14 -0
- package/dist/slots/CourseInfoSlot/CourseInfoSlot.js.map +1 -0
- package/dist/slots.js +13 -1
- package/dist/slots.js.map +1 -1
- package/dist/specialExams/SpecialExamsPage.js +14 -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.d.ts +2 -0
- package/dist/specialExams/components/Allowances.js +89 -0
- package/dist/specialExams/components/Allowances.js.map +1 -0
- package/dist/specialExams/components/AllowancesList.d.ts +8 -0
- package/dist/specialExams/components/AllowancesList.js +63 -0
- package/dist/specialExams/components/AllowancesList.js.map +1 -0
- package/dist/specialExams/components/AttemptsList.d.ts +3 -0
- package/dist/specialExams/components/AttemptsList.js +50 -0
- package/dist/specialExams/components/AttemptsList.js.map +1 -0
- 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 +7 -0
- package/dist/specialExams/data/api.js +55 -0
- package/dist/specialExams/data/api.js.map +1 -0
- package/dist/specialExams/data/apiHook.d.ts +6 -0
- package/dist/specialExams/data/apiHook.js +37 -0
- package/dist/specialExams/data/apiHook.js.map +1 -0
- package/dist/specialExams/data/queryKeys.d.ts +8 -0
- package/dist/specialExams/data/queryKeys.js +9 -0
- package/dist/specialExams/data/queryKeys.js.map +1 -0
- package/dist/specialExams/messages.d.ts +228 -0
- package/dist/specialExams/messages.js +230 -0
- package/dist/specialExams/messages.js.map +1 -0
- package/dist/specialExams/types.d.ts +65 -0
- package/dist/specialExams/types.js +2 -0
- package/dist/specialExams/types.js.map +1 -0
- package/dist/style.scss +16 -0
- package/dist/testUtils.js +2 -2
- package/dist/testUtils.js.map +1 -1
- package/dist/types/index.d.ts +15 -0
- package/dist/types/index.js.map +1 -1
- package/dist/utils/formatters.d.ts +5 -0
- package/dist/utils/formatters.js +10 -0
- package/dist/utils/formatters.js.map +1 -1
- package/package.json +6 -6
- package/dist/app.scss +0 -10
- package/dist/providers/QueryProvider.d.ts +0 -6
- package/dist/providers/QueryProvider.js +0 -16
- package/dist/providers/QueryProvider.js.map +0 -1
- package/dist/providers.d.ts +0 -3
- package/dist/providers.js +0 -8
- package/dist/providers.js.map +0 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { DataTable, IconButton, OverlayTrigger, Popover, TableFooter } from '@openedx/paragon';
|
|
4
|
+
import { MoreVert } from '@openedx/paragon/icons';
|
|
5
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
6
|
+
import { CertificateFilter as FilterEnum } from '../../certificates/types';
|
|
7
|
+
import { CERTIFICATES_TABLE_PAGE_SIZE } from '../../certificates/constants';
|
|
8
|
+
import messages from '../../certificates/messages';
|
|
9
|
+
const CertificateTable = ({ data, isLoading, itemCount, filter, onRemoveException, onRemoveInvalidation, }) => {
|
|
10
|
+
const intl = useIntl();
|
|
11
|
+
const baseColumns = useMemo(() => [
|
|
12
|
+
{
|
|
13
|
+
Header: intl.formatMessage(messages.columnUsername),
|
|
14
|
+
accessor: 'username',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
Header: intl.formatMessage(messages.columnEmail),
|
|
18
|
+
accessor: 'email',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
Header: intl.formatMessage(messages.columnEnrollmentTrack),
|
|
22
|
+
accessor: 'enrollmentTrack',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
Header: intl.formatMessage(messages.columnCertificateStatus),
|
|
26
|
+
accessor: 'certificateStatus',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
Header: intl.formatMessage(messages.columnSpecialCase),
|
|
30
|
+
accessor: 'specialCase',
|
|
31
|
+
},
|
|
32
|
+
], [intl]);
|
|
33
|
+
const conditionalColumns = useMemo(() => {
|
|
34
|
+
const columns = [];
|
|
35
|
+
if (filter === FilterEnum.ALL_LEARNERS || filter === FilterEnum.GRANTED_EXCEPTIONS) {
|
|
36
|
+
columns.push({
|
|
37
|
+
Header: intl.formatMessage(messages.columnExceptionGranted),
|
|
38
|
+
accessor: 'exceptionGranted',
|
|
39
|
+
}, {
|
|
40
|
+
Header: intl.formatMessage(messages.columnExceptionNotes),
|
|
41
|
+
accessor: 'exceptionNotes',
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
if (filter === FilterEnum.ALL_LEARNERS || filter === FilterEnum.INVALIDATED) {
|
|
45
|
+
columns.push({
|
|
46
|
+
Header: intl.formatMessage(messages.columnInvalidatedBy),
|
|
47
|
+
accessor: 'invalidatedBy',
|
|
48
|
+
}, {
|
|
49
|
+
Header: intl.formatMessage(messages.columnInvalidationDate),
|
|
50
|
+
accessor: 'invalidationDate',
|
|
51
|
+
Cell: ({ value }) => {
|
|
52
|
+
if (!value)
|
|
53
|
+
return null;
|
|
54
|
+
return (_jsx(_Fragment, { children: intl.formatDate(new Date(value), {
|
|
55
|
+
year: 'numeric',
|
|
56
|
+
month: '2-digit',
|
|
57
|
+
day: '2-digit',
|
|
58
|
+
hour: '2-digit',
|
|
59
|
+
minute: '2-digit',
|
|
60
|
+
}) }));
|
|
61
|
+
},
|
|
62
|
+
}, {
|
|
63
|
+
Header: intl.formatMessage(messages.columnInvalidationNote),
|
|
64
|
+
accessor: 'invalidationNote',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return columns;
|
|
68
|
+
}, [filter, intl]);
|
|
69
|
+
const additionalColumns = useMemo(() => {
|
|
70
|
+
if (filter !== FilterEnum.GRANTED_EXCEPTIONS && filter !== FilterEnum.INVALIDATED) {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
return [
|
|
74
|
+
{
|
|
75
|
+
id: 'action',
|
|
76
|
+
Header: intl.formatMessage(messages.columnActions),
|
|
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
|
+
},
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
}, [filter, intl, onRemoveException, onRemoveInvalidation]);
|
|
84
|
+
const allColumns = useMemo(() => [...baseColumns, ...conditionalColumns, ...additionalColumns], [baseColumns, conditionalColumns, additionalColumns]);
|
|
85
|
+
return (_jsxs(DataTable, { columns: allColumns, data: data, isLoading: isLoading, isPaginated: true, itemCount: itemCount, initialState: { pageIndex: 0, pageSize: CERTIFICATES_TABLE_PAGE_SIZE }, children: [_jsx(DataTable.Table, {}), _jsx(DataTable.EmptyTable, { content: intl.formatMessage(messages.noDataMessage) }), _jsx(TableFooter, {})] }));
|
|
86
|
+
};
|
|
87
|
+
export default CertificateTable;
|
|
88
|
+
//# sourceMappingURL=CertificateTable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface CertificatesPageHeaderProps {
|
|
2
|
+
onGrantExceptions: () => void;
|
|
3
|
+
onInvalidateCertificate: () => void;
|
|
4
|
+
onStudentGeneratedCertificates?: () => void;
|
|
5
|
+
}
|
|
6
|
+
declare const CertificatesPageHeader: ({ onGrantExceptions, onInvalidateCertificate, onStudentGeneratedCertificates, }: CertificatesPageHeaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default CertificatesPageHeader;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Dropdown, IconButton, Stack } from '@openedx/paragon';
|
|
3
|
+
import { Add, Cancel, MoreVert } from '@openedx/paragon/icons';
|
|
4
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
5
|
+
import messages from '../../certificates/messages';
|
|
6
|
+
const CertificatesPageHeader = ({ onGrantExceptions, onInvalidateCertificate, onStudentGeneratedCertificates, }) => {
|
|
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: [_jsxs(Dropdown, { children: [_jsx(Dropdown.Toggle, { as: IconButton, src: MoreVert, alt: intl.formatMessage(messages.moreActionsButton), id: "certificates-more-menu" }), _jsx(Dropdown.Menu, { children: onStudentGeneratedCertificates && (_jsx(Dropdown.Item, { onClick: onStudentGeneratedCertificates, children: intl.formatMessage(messages.studentGeneratedCertificatesMenuItem) })) })] }), _jsx(Button, { variant: "outline-primary", iconBefore: Cancel, 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
|
+
};
|
|
10
|
+
export default CertificatesPageHeader;
|
|
11
|
+
//# sourceMappingURL=CertificatesPageHeader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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,MAAM,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAQlD,MAAM,sBAAsB,GAAG,CAAC,EAC9B,iBAAiB,EACjB,uBAAuB,EACvB,8BAA8B,GACF,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,iBAAiB,CAAC,EACnD,EAAE,EAAC,wBAAwB,GAC3B,EACF,KAAC,QAAQ,CAAC,IAAI,cACX,8BAA8B,IAAI,CACjC,KAAC,QAAQ,CAAC,IAAI,IAAC,OAAO,EAAE,8BAA8B,YACnD,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,oCAAoC,CAAC,GACpD,CACjB,GACa,IACP,EACX,KAAC,MAAM,IACL,OAAO,EAAC,iBAAiB,EACzB,UAAU,EAAE,MAAM,EAClB,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, Cancel, 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 onStudentGeneratedCertificates?: () => void,\n}\n\nconst CertificatesPageHeader = ({\n onGrantExceptions,\n onInvalidateCertificate,\n onStudentGeneratedCertificates,\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.moreActionsButton)}\n id=\"certificates-more-menu\"\n />\n <Dropdown.Menu>\n {onStudentGeneratedCertificates && (\n <Dropdown.Item onClick={onStudentGeneratedCertificates}>\n {intl.formatMessage(messages.studentGeneratedCertificatesMenuItem)}\n </Dropdown.Item>\n )}\n </Dropdown.Menu>\n </Dropdown>\n <Button\n variant=\"outline-primary\"\n iconBefore={Cancel}\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"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CertificateFilter } from '../../certificates/types';
|
|
2
|
+
import '../CertificatesPage.scss';
|
|
3
|
+
interface CertificatesToolbarProps {
|
|
4
|
+
search: string;
|
|
5
|
+
onSearchChange: (value: string) => void;
|
|
6
|
+
filter: CertificateFilter;
|
|
7
|
+
onFilterChange: (value: CertificateFilter) => void;
|
|
8
|
+
onRegenerateCertificates: () => void;
|
|
9
|
+
}
|
|
10
|
+
declare const CertificatesToolbar: ({ search, onSearchChange, filter, onFilterChange, onRegenerateCertificates, }: CertificatesToolbarProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export default CertificatesToolbar;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, SearchField, OverlayTrigger, Tooltip } from '@openedx/paragon';
|
|
3
|
+
import { SpinnerIcon } from '@openedx/paragon/icons';
|
|
4
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
5
|
+
import FilterDropdown from '../../certificates/components/FilterDropdown';
|
|
6
|
+
import { CertificateFilter } from '../../certificates/types';
|
|
7
|
+
import messages from '../../certificates/messages';
|
|
8
|
+
import '../CertificatesPage.scss';
|
|
9
|
+
const CertificatesToolbar = ({ search, onSearchChange, filter, onFilterChange, onRegenerateCertificates, }) => {
|
|
10
|
+
const intl = useIntl();
|
|
11
|
+
// Determine button state based on filter
|
|
12
|
+
const isButtonDisabled = filter === CertificateFilter.ALL_LEARNERS || filter === CertificateFilter.INVALIDATED;
|
|
13
|
+
// Determine button text based on filter
|
|
14
|
+
let buttonText;
|
|
15
|
+
if (filter === CertificateFilter.GRANTED_EXCEPTIONS) {
|
|
16
|
+
buttonText = intl.formatMessage(messages.generateCertificatesButton);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
buttonText = intl.formatMessage(messages.regenerateCertificatesButton);
|
|
20
|
+
}
|
|
21
|
+
// Determine tooltip text based on filter
|
|
22
|
+
let tooltipText = null;
|
|
23
|
+
if (filter === CertificateFilter.ALL_LEARNERS) {
|
|
24
|
+
tooltipText = intl.formatMessage(messages.regenerateTooltipAllLearners);
|
|
25
|
+
}
|
|
26
|
+
else if (filter === CertificateFilter.INVALIDATED) {
|
|
27
|
+
tooltipText = intl.formatMessage(messages.regenerateTooltipInvalidated);
|
|
28
|
+
}
|
|
29
|
+
const button = (_jsx(Button, { variant: "outline-primary", iconBefore: SpinnerIcon, onClick: onRegenerateCertificates, className: "text-nowrap flex-shrink-0", disabled: isButtonDisabled, children: buttonText }));
|
|
30
|
+
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" })] }), tooltipText && isButtonDisabled ? (_jsx(OverlayTrigger, { placement: "top", overlay: _jsx(Tooltip, { id: "regenerate-tooltip", children: tooltipText }), children: _jsx("span", { className: "d-inline-block", children: button }) })) : (button)] }));
|
|
31
|
+
};
|
|
32
|
+
export default CertificatesToolbar;
|
|
33
|
+
//# sourceMappingURL=CertificatesToolbar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CertificatesToolbar.js","sourceRoot":"","sources":["../../../src/certificates/components/CertificatesToolbar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChF,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,0BAA0B,CAAC;AAUlC,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,yCAAyC;IACzC,MAAM,gBAAgB,GAAG,MAAM,KAAK,iBAAiB,CAAC,YAAY,IAAI,MAAM,KAAK,iBAAiB,CAAC,WAAW,CAAC;IAE/G,wCAAwC;IACxC,IAAI,UAAkB,CAAC;IACvB,IAAI,MAAM,KAAK,iBAAiB,CAAC,kBAAkB,EAAE,CAAC;QACpD,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAAC;IACvE,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;IACzE,CAAC;IAED,yCAAyC;IACzC,IAAI,WAAW,GAAkB,IAAI,CAAC;IACtC,IAAI,MAAM,KAAK,iBAAiB,CAAC,YAAY,EAAE,CAAC;QAC9C,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;IAC1E,CAAC;SAAM,IAAI,MAAM,KAAK,iBAAiB,CAAC,WAAW,EAAE,CAAC;QACpD,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,MAAM,GAAG,CACb,KAAC,MAAM,IACL,OAAO,EAAC,iBAAiB,EACzB,UAAU,EAAE,WAAW,EACvB,OAAO,EAAE,wBAAwB,EACjC,SAAS,EAAC,2BAA2B,EACrC,QAAQ,EAAE,gBAAgB,YAEzB,UAAU,GACJ,CACV,CAAC;IAEF,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,EACL,WAAW,IAAI,gBAAgB,CAAC,CAAC,CAAC,CACjC,KAAC,cAAc,IACb,SAAS,EAAC,KAAK,EACf,OAAO,EAAE,KAAC,OAAO,IAAC,EAAE,EAAC,oBAAoB,YAAE,WAAW,GAAW,YAEjE,eAAM,SAAS,EAAC,gBAAgB,YAC7B,MAAM,GACF,GACQ,CAClB,CAAC,CAAC,CAAC,CACF,MAAM,CACP,IACG,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,mBAAmB,CAAC","sourcesContent":["import { Button, SearchField, OverlayTrigger, Tooltip } 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 '../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 CertificatesToolbar = ({\n search,\n onSearchChange,\n filter,\n onFilterChange,\n onRegenerateCertificates,\n}: CertificatesToolbarProps) => {\n const intl = useIntl();\n\n // Determine button state based on filter\n const isButtonDisabled = filter === CertificateFilter.ALL_LEARNERS || filter === CertificateFilter.INVALIDATED;\n\n // Determine button text based on filter\n let buttonText: string;\n if (filter === CertificateFilter.GRANTED_EXCEPTIONS) {\n buttonText = intl.formatMessage(messages.generateCertificatesButton);\n } else {\n buttonText = intl.formatMessage(messages.regenerateCertificatesButton);\n }\n\n // Determine tooltip text based on filter\n let tooltipText: string | null = null;\n if (filter === CertificateFilter.ALL_LEARNERS) {\n tooltipText = intl.formatMessage(messages.regenerateTooltipAllLearners);\n } else if (filter === CertificateFilter.INVALIDATED) {\n tooltipText = intl.formatMessage(messages.regenerateTooltipInvalidated);\n }\n\n const button = (\n <Button\n variant=\"outline-primary\"\n iconBefore={SpinnerIcon}\n onClick={onRegenerateCertificates}\n className=\"text-nowrap flex-shrink-0\"\n disabled={isButtonDisabled}\n >\n {buttonText}\n </Button>\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 {tooltipText && isButtonDisabled ? (\n <OverlayTrigger\n placement=\"top\"\n overlay={<Tooltip id=\"regenerate-tooltip\">{tooltipText}</Tooltip>}\n >\n <span className=\"d-inline-block\">\n {button}\n </span>\n </OverlayTrigger>\n ) : (\n button\n )}\n </div>\n );\n};\n\nexport default CertificatesToolbar;\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface DisableCertificatesModalProps {
|
|
2
|
+
isOpen: boolean;
|
|
3
|
+
isEnabled: boolean;
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
onConfirm: () => void;
|
|
6
|
+
isSubmitting: boolean;
|
|
7
|
+
}
|
|
8
|
+
declare const DisableCertificatesModal: ({ isOpen, isEnabled, onClose, onConfirm, isSubmitting, }: DisableCertificatesModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export default DisableCertificatesModal;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { ActionRow, Button, Form, ModalDialog } from '@openedx/paragon';
|
|
4
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
5
|
+
import messages from '../../certificates/messages';
|
|
6
|
+
const DisableCertificatesModal = ({ isOpen, isEnabled, onClose, onConfirm, isSubmitting, }) => {
|
|
7
|
+
const intl = useIntl();
|
|
8
|
+
const [enabled, setEnabled] = useState(isEnabled);
|
|
9
|
+
const handleSave = () => {
|
|
10
|
+
if (enabled !== isEnabled) {
|
|
11
|
+
onConfirm();
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
onClose();
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const handleClose = () => {
|
|
18
|
+
setEnabled(isEnabled); // Reset to original value
|
|
19
|
+
onClose();
|
|
20
|
+
};
|
|
21
|
+
return (_jsxs(ModalDialog, { title: intl.formatMessage(messages.studentGeneratedCertificatesModalTitle), onClose: handleClose, isOpen: isOpen, size: "md", hasCloseButton: true, isOverflowVisible: false, children: [_jsx(ModalDialog.Header, { className: "border-bottom", children: _jsx(ModalDialog.Title, { children: intl.formatMessage(messages.studentGeneratedCertificatesModalTitle) }) }), _jsx(ModalDialog.Body, { className: "px-4 py-3", children: _jsxs(Form.Group, { children: [_jsx(Form.Checkbox, { checked: enabled, onChange: (e) => setEnabled(e.target.checked), children: intl.formatMessage(messages.enableStudentGeneratedCertificates) }), _jsx(Form.Text, { className: "text-muted", children: intl.formatMessage(messages.studentGeneratedCertificatesDescription) })] }) }), _jsx(ModalDialog.Footer, { children: _jsxs(ActionRow, { children: [_jsx(Button, { variant: "tertiary", onClick: handleClose, disabled: isSubmitting, children: intl.formatMessage(messages.close) }), _jsx(Button, { variant: "primary", onClick: handleSave, disabled: isSubmitting, children: intl.formatMessage(messages.save) })] }) })] }));
|
|
22
|
+
};
|
|
23
|
+
export default DisableCertificatesModal;
|
|
24
|
+
//# sourceMappingURL=DisableCertificatesModal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DisableCertificatesModal.js","sourceRoot":"","sources":["../../../src/certificates/components/DisableCertificatesModal.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACxE,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;IACvB,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAElD,MAAM,UAAU,GAAG,GAAG,EAAE;QACtB,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,SAAS,EAAE,CAAC;QACd,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,0BAA0B;QACjD,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;IAEF,OAAO,CACL,MAAC,WAAW,IACV,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,sCAAsC,CAAC,EAC1E,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,EACd,IAAI,EAAC,IAAI,EACT,cAAc,QACd,iBAAiB,EAAE,KAAK,aAExB,KAAC,WAAW,CAAC,MAAM,IAAC,SAAS,EAAC,eAAe,YAC3C,KAAC,WAAW,CAAC,KAAK,cACf,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,sCAAsC,CAAC,GAClD,GACD,EACrB,KAAC,WAAW,CAAC,IAAI,IAAC,SAAS,EAAC,WAAW,YACrC,MAAC,IAAI,CAAC,KAAK,eACT,KAAC,IAAI,CAAC,QAAQ,IACZ,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,YAE5C,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,kCAAkC,CAAC,GAClD,EAChB,KAAC,IAAI,CAAC,IAAI,IAAC,SAAS,EAAC,YAAY,YAC9B,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,uCAAuC,CAAC,GAC3D,IACD,GACI,EACnB,KAAC,WAAW,CAAC,MAAM,cACjB,MAAC,SAAS,eACR,KAAC,MAAM,IAAC,OAAO,EAAC,UAAU,EAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,YACpE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,GAC5B,EACT,KAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,YAClE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,GAC3B,IACC,GACO,IACT,CACf,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,wBAAwB,CAAC","sourcesContent":["import { useState } from 'react';\nimport { ActionRow, Button, Form, 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 const [enabled, setEnabled] = useState(isEnabled);\n\n const handleSave = () => {\n if (enabled !== isEnabled) {\n onConfirm();\n } else {\n onClose();\n }\n };\n\n const handleClose = () => {\n setEnabled(isEnabled); // Reset to original value\n onClose();\n };\n\n return (\n <ModalDialog\n title={intl.formatMessage(messages.studentGeneratedCertificatesModalTitle)}\n onClose={handleClose}\n isOpen={isOpen}\n size=\"md\"\n hasCloseButton\n isOverflowVisible={false}\n >\n <ModalDialog.Header className=\"border-bottom\">\n <ModalDialog.Title>\n {intl.formatMessage(messages.studentGeneratedCertificatesModalTitle)}\n </ModalDialog.Title>\n </ModalDialog.Header>\n <ModalDialog.Body className=\"px-4 py-3\">\n <Form.Group>\n <Form.Checkbox\n checked={enabled}\n onChange={(e) => setEnabled(e.target.checked)}\n >\n {intl.formatMessage(messages.enableStudentGeneratedCertificates)}\n </Form.Checkbox>\n <Form.Text className=\"text-muted\">\n {intl.formatMessage(messages.studentGeneratedCertificatesDescription)}\n </Form.Text>\n </Form.Group>\n </ModalDialog.Body>\n <ModalDialog.Footer>\n <ActionRow>\n <Button variant=\"tertiary\" onClick={handleClose} disabled={isSubmitting}>\n {intl.formatMessage(messages.close)}\n </Button>\n <Button variant=\"primary\" onClick={handleSave} disabled={isSubmitting}>\n {intl.formatMessage(messages.save)}\n </Button>\n </ActionRow>\n </ModalDialog.Footer>\n </ModalDialog>\n );\n};\n\nexport default DisableCertificatesModal;\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CertificateFilter } from '../../certificates/types';
|
|
2
|
+
interface FilterDropdownProps {
|
|
3
|
+
value: CertificateFilter;
|
|
4
|
+
onChange: (value: CertificateFilter) => void;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const FilterDropdown: ({ value, onChange, className }: FilterDropdownProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default FilterDropdown;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Dropdown } from '@openedx/paragon';
|
|
3
|
+
import { FilterList } from '@openedx/paragon/icons';
|
|
4
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
5
|
+
import { CertificateFilter } from '../../certificates/types';
|
|
6
|
+
import messages from '../../certificates/messages';
|
|
7
|
+
const FILTER_OPTIONS = [
|
|
8
|
+
{
|
|
9
|
+
value: CertificateFilter.ALL_LEARNERS,
|
|
10
|
+
messageKey: 'filterAllLearners',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
value: CertificateFilter.RECEIVED,
|
|
14
|
+
messageKey: 'filterReceived',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
value: CertificateFilter.NOT_RECEIVED,
|
|
18
|
+
messageKey: 'filterNotReceived',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
value: CertificateFilter.AUDIT_PASSING,
|
|
22
|
+
messageKey: 'filterAuditPassing',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
value: CertificateFilter.AUDIT_NOT_PASSING,
|
|
26
|
+
messageKey: 'filterAuditNotPassing',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
value: CertificateFilter.ERROR_STATE,
|
|
30
|
+
messageKey: 'filterErrorState',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
value: CertificateFilter.GRANTED_EXCEPTIONS,
|
|
34
|
+
messageKey: 'filterGrantedExceptions',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
value: CertificateFilter.INVALIDATED,
|
|
38
|
+
messageKey: 'filterInvalidated',
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
const FilterDropdown = ({ value, onChange, className }) => {
|
|
42
|
+
const intl = useIntl();
|
|
43
|
+
const selectedOption = FILTER_OPTIONS.find((option) => option.value === value);
|
|
44
|
+
const selectedLabel = selectedOption
|
|
45
|
+
? intl.formatMessage(messages[selectedOption.messageKey])
|
|
46
|
+
: intl.formatMessage(messages.filterAllLearners);
|
|
47
|
+
return (_jsxs(Dropdown, { className: `certificates-filter-dropdown ${className || ''}`, children: [_jsx(Dropdown.Toggle, { id: "filter-dropdown", variant: "outline-primary", className: "d-flex align-items-center justify-content-between w-100", children: _jsxs("span", { className: "d-flex align-items-center", children: [_jsx(FilterList, { className: "mr-2" }), selectedLabel] }) }), _jsx(Dropdown.Menu, { children: FILTER_OPTIONS.map((option) => (_jsx(Dropdown.Item, { active: option.value === value, onClick: () => onChange(option.value), className: "filter-dropdown-item", children: intl.formatMessage(messages[option.messageKey]) }, option.value))) })] }));
|
|
48
|
+
};
|
|
49
|
+
export default FilterDropdown;
|
|
50
|
+
//# sourceMappingURL=FilterDropdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilterDropdown.js","sourceRoot":"","sources":["../../../src/certificates/components/FilterDropdown.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAQlD,MAAM,cAAc,GAAG;IACrB;QACE,KAAK,EAAE,iBAAiB,CAAC,YAAY;QACrC,UAAU,EAAE,mBAAmB;KAChC;IACD;QACE,KAAK,EAAE,iBAAiB,CAAC,QAAQ;QACjC,UAAU,EAAE,gBAAgB;KAC7B;IACD;QACE,KAAK,EAAE,iBAAiB,CAAC,YAAY;QACrC,UAAU,EAAE,mBAAmB;KAChC;IACD;QACE,KAAK,EAAE,iBAAiB,CAAC,aAAa;QACtC,UAAU,EAAE,oBAAoB;KACjC;IACD;QACE,KAAK,EAAE,iBAAiB,CAAC,iBAAiB;QAC1C,UAAU,EAAE,uBAAuB;KACpC;IACD;QACE,KAAK,EAAE,iBAAiB,CAAC,WAAW;QACpC,UAAU,EAAE,kBAAkB;KAC/B;IACD;QACE,KAAK,EAAE,iBAAiB,CAAC,kBAAkB;QAC3C,UAAU,EAAE,yBAAyB;KACtC;IACD;QACE,KAAK,EAAE,iBAAiB,CAAC,WAAW;QACpC,UAAU,EAAE,mBAAmB;KAChC;CACO,CAAC;AAEX,MAAM,cAAc,GAAG,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAuB,EAAE,EAAE;IAC7E,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,MAAM,cAAc,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;IAC/E,MAAM,aAAa,GAAG,cAAc;QAClC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QACzD,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAEnD,OAAO,CACL,MAAC,QAAQ,IAAC,SAAS,EAAE,gCAAgC,SAAS,IAAI,EAAE,EAAE,aACpE,KAAC,QAAQ,CAAC,MAAM,IACd,EAAE,EAAC,iBAAiB,EACpB,OAAO,EAAC,iBAAiB,EACzB,SAAS,EAAC,yDAAyD,YAEnE,gBAAM,SAAS,EAAC,2BAA2B,aACzC,KAAC,UAAU,IAAC,SAAS,EAAC,MAAM,GAAG,EAC9B,aAAa,IACT,GACS,EAClB,KAAC,QAAQ,CAAC,IAAI,cACX,cAAc,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAC9B,KAAC,QAAQ,CAAC,IAAI,IAEZ,MAAM,EAAE,MAAM,CAAC,KAAK,KAAK,KAAK,EAC9B,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EACrC,SAAS,EAAC,sBAAsB,YAE/B,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAL3C,MAAM,CAAC,KAAK,CAMH,CACjB,CAAC,GACY,IACP,CACZ,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,cAAc,CAAC","sourcesContent":["import { Dropdown } from '@openedx/paragon';\nimport { FilterList } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport { CertificateFilter } from '@src/certificates/types';\nimport messages from '@src/certificates/messages';\n\ninterface FilterDropdownProps {\n value: CertificateFilter,\n onChange: (value: CertificateFilter) => void,\n className?: string,\n}\n\nconst FILTER_OPTIONS = [\n {\n value: CertificateFilter.ALL_LEARNERS,\n messageKey: 'filterAllLearners',\n },\n {\n value: CertificateFilter.RECEIVED,\n messageKey: 'filterReceived',\n },\n {\n value: CertificateFilter.NOT_RECEIVED,\n messageKey: 'filterNotReceived',\n },\n {\n value: CertificateFilter.AUDIT_PASSING,\n messageKey: 'filterAuditPassing',\n },\n {\n value: CertificateFilter.AUDIT_NOT_PASSING,\n messageKey: 'filterAuditNotPassing',\n },\n {\n value: CertificateFilter.ERROR_STATE,\n messageKey: 'filterErrorState',\n },\n {\n value: CertificateFilter.GRANTED_EXCEPTIONS,\n messageKey: 'filterGrantedExceptions',\n },\n {\n value: CertificateFilter.INVALIDATED,\n messageKey: 'filterInvalidated',\n },\n] as const;\n\nconst FilterDropdown = ({ value, onChange, className }: FilterDropdownProps) => {\n const intl = useIntl();\n\n const selectedOption = FILTER_OPTIONS.find((option) => option.value === value);\n const selectedLabel = selectedOption\n ? intl.formatMessage(messages[selectedOption.messageKey])\n : intl.formatMessage(messages.filterAllLearners);\n\n return (\n <Dropdown className={`certificates-filter-dropdown ${className || ''}`}>\n <Dropdown.Toggle\n id=\"filter-dropdown\"\n variant=\"outline-primary\"\n className=\"d-flex align-items-center justify-content-between w-100\"\n >\n <span className=\"d-flex align-items-center\">\n <FilterList className=\"mr-2\" />\n {selectedLabel}\n </span>\n </Dropdown.Toggle>\n <Dropdown.Menu>\n {FILTER_OPTIONS.map((option) => (\n <Dropdown.Item\n key={option.value}\n active={option.value === value}\n onClick={() => onChange(option.value)}\n className=\"filter-dropdown-item\"\n >\n {intl.formatMessage(messages[option.messageKey])}\n </Dropdown.Item>\n ))}\n </Dropdown.Menu>\n </Dropdown>\n );\n};\n\nexport default FilterDropdown;\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface GenerateCertificatesModalProps {
|
|
2
|
+
isOpen: boolean;
|
|
3
|
+
onClose: () => void;
|
|
4
|
+
onConfirm: (onlyWithoutCertificate: boolean) => void;
|
|
5
|
+
isSubmitting: boolean;
|
|
6
|
+
learnerCount: number;
|
|
7
|
+
}
|
|
8
|
+
declare const GenerateCertificatesModal: ({ isOpen, onClose, onConfirm, isSubmitting, learnerCount, }: GenerateCertificatesModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export default GenerateCertificatesModal;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { ActionRow, Button, Form, ModalDialog } from '@openedx/paragon';
|
|
4
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
5
|
+
import messages from '../../certificates/messages';
|
|
6
|
+
const GenerateCertificatesModal = ({ isOpen, onClose, onConfirm, isSubmitting, learnerCount, }) => {
|
|
7
|
+
const intl = useIntl();
|
|
8
|
+
const [selectedOption, setSelectedOption] = useState('all');
|
|
9
|
+
const handleConfirm = () => {
|
|
10
|
+
onConfirm(selectedOption === 'without_certificate');
|
|
11
|
+
};
|
|
12
|
+
const handleClose = () => {
|
|
13
|
+
setSelectedOption('all');
|
|
14
|
+
onClose();
|
|
15
|
+
};
|
|
16
|
+
return (_jsxs(ModalDialog, { title: intl.formatMessage(messages.generateModalTitle), onClose: handleClose, isOpen: isOpen, size: "md", hasCloseButton: false, isOverflowVisible: false, children: [_jsxs("div", { className: "mx-4 mt-4 mb-3", children: [_jsx("p", { className: "mb-3", children: intl.formatMessage(messages.generateModalDescription, { number: learnerCount }) }), _jsx(Form.Group, { children: _jsxs(Form.RadioSet, { name: "generate-option", onChange: (e) => setSelectedOption(e.target.value), value: selectedOption, children: [_jsx(Form.Radio, { value: "all", children: intl.formatMessage(messages.generateOptionAll) }), _jsx(Form.Radio, { value: "without_certificate", children: intl.formatMessage(messages.generateOptionWithoutCertificate) })] }) })] }), _jsx(ModalDialog.Footer, { children: _jsxs(ActionRow, { children: [_jsx(Button, { variant: "tertiary", onClick: handleClose, disabled: isSubmitting, children: intl.formatMessage(messages.cancel) }), _jsx(Button, { variant: "primary", onClick: handleConfirm, disabled: isSubmitting, children: intl.formatMessage(messages.generate) })] }) })] }));
|
|
17
|
+
};
|
|
18
|
+
export default GenerateCertificatesModal;
|
|
19
|
+
//# sourceMappingURL=GenerateCertificatesModal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GenerateCertificatesModal.js","sourceRoot":"","sources":["../../../src/certificates/components/GenerateCertificatesModal.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAUlD,MAAM,yBAAyB,GAAG,CAAC,EACjC,MAAM,EACN,OAAO,EACP,SAAS,EACT,YAAY,EACZ,YAAY,GACmB,EAAE,EAAE;IACnC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAgC,KAAK,CAAC,CAAC;IAE3F,MAAM,aAAa,GAAG,GAAG,EAAE;QACzB,SAAS,CAAC,cAAc,KAAK,qBAAqB,CAAC,CAAC;IACtD,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;IAEF,OAAO,CACL,MAAC,WAAW,IACV,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EACtD,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,EACd,IAAI,EAAC,IAAI,EACT,cAAc,EAAE,KAAK,EACrB,iBAAiB,EAAE,KAAK,aAExB,eAAK,SAAS,EAAC,gBAAgB,aAC7B,YAAG,SAAS,EAAC,MAAM,YAChB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,GAC9E,EACJ,KAAC,IAAI,CAAC,KAAK,cACT,MAAC,IAAI,CAAC,QAAQ,IACZ,IAAI,EAAC,iBAAiB,EACtB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAsC,CAAC,EACnF,KAAK,EAAE,cAAc,aAErB,KAAC,IAAI,CAAC,KAAK,IAAC,KAAK,EAAC,KAAK,YACpB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC,GACpC,EACb,KAAC,IAAI,CAAC,KAAK,IAAC,KAAK,EAAC,qBAAqB,YACpC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,gCAAgC,CAAC,GACnD,IACC,GACL,IACT,EACN,KAAC,WAAW,CAAC,MAAM,cACjB,MAAC,SAAS,eACR,KAAC,MAAM,IAAC,OAAO,EAAC,UAAU,EAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,YACpE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,GAC7B,EACT,KAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,YACrE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAC/B,IACC,GACO,IACT,CACf,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,yBAAyB,CAAC","sourcesContent":["import { useState } from 'react';\nimport { ActionRow, Button, Form, ModalDialog } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport messages from '@src/certificates/messages';\n\ninterface GenerateCertificatesModalProps {\n isOpen: boolean,\n onClose: () => void,\n onConfirm: (onlyWithoutCertificate: boolean) => void,\n isSubmitting: boolean,\n learnerCount: number,\n}\n\nconst GenerateCertificatesModal = ({\n isOpen,\n onClose,\n onConfirm,\n isSubmitting,\n learnerCount,\n}: GenerateCertificatesModalProps) => {\n const intl = useIntl();\n const [selectedOption, setSelectedOption] = useState<'all' | 'without_certificate'>('all');\n\n const handleConfirm = () => {\n onConfirm(selectedOption === 'without_certificate');\n };\n\n const handleClose = () => {\n setSelectedOption('all');\n onClose();\n };\n\n return (\n <ModalDialog\n title={intl.formatMessage(messages.generateModalTitle)}\n onClose={handleClose}\n isOpen={isOpen}\n size=\"md\"\n hasCloseButton={false}\n isOverflowVisible={false}\n >\n <div className=\"mx-4 mt-4 mb-3\">\n <p className=\"mb-3\">\n {intl.formatMessage(messages.generateModalDescription, { number: learnerCount })}\n </p>\n <Form.Group>\n <Form.RadioSet\n name=\"generate-option\"\n onChange={(e) => setSelectedOption(e.target.value as 'all' | 'without_certificate')}\n value={selectedOption}\n >\n <Form.Radio value=\"all\">\n {intl.formatMessage(messages.generateOptionAll)}\n </Form.Radio>\n <Form.Radio value=\"without_certificate\">\n {intl.formatMessage(messages.generateOptionWithoutCertificate)}\n </Form.Radio>\n </Form.RadioSet>\n </Form.Group>\n </div>\n <ModalDialog.Footer>\n <ActionRow>\n <Button variant=\"tertiary\" onClick={handleClose} disabled={isSubmitting}>\n {intl.formatMessage(messages.cancel)}\n </Button>\n <Button variant=\"primary\" onClick={handleConfirm} disabled={isSubmitting}>\n {intl.formatMessage(messages.generate)}\n </Button>\n </ActionRow>\n </ModalDialog.Footer>\n </ModalDialog>\n );\n};\n\nexport default GenerateCertificatesModal;\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CertificateGenerationHistory } from '../../certificates/types';
|
|
2
|
+
interface GenerationHistoryTableProps {
|
|
3
|
+
data: CertificateGenerationHistory[];
|
|
4
|
+
isLoading: boolean;
|
|
5
|
+
itemCount: number;
|
|
6
|
+
pageCount: number;
|
|
7
|
+
currentPage: number;
|
|
8
|
+
onPageChange: (pageIndex: number) => void;
|
|
9
|
+
}
|
|
10
|
+
declare const GenerationHistoryTable: ({ data, isLoading, itemCount, pageCount, currentPage, onPageChange, }: GenerationHistoryTableProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export default GenerationHistoryTable;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { DataTable } from '@openedx/paragon';
|
|
4
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
5
|
+
import messages from '../../certificates/messages';
|
|
6
|
+
const GenerationHistoryTable = ({ data, isLoading, itemCount, pageCount, currentPage, onPageChange, }) => {
|
|
7
|
+
const intl = useIntl();
|
|
8
|
+
const columns = useMemo(() => [
|
|
9
|
+
{
|
|
10
|
+
Header: intl.formatMessage(messages.columnTaskName),
|
|
11
|
+
accessor: 'taskName',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
Header: intl.formatMessage(messages.columnDate),
|
|
15
|
+
accessor: 'date',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
Header: intl.formatMessage(messages.columnDetails),
|
|
19
|
+
accessor: 'details',
|
|
20
|
+
},
|
|
21
|
+
], [intl]);
|
|
22
|
+
return (_jsxs(DataTable, { columns: columns, data: data, isLoading: isLoading, isPaginated: true, itemCount: itemCount, pageCount: pageCount, manualPagination: true, fetchData: ({ pageIndex }) => onPageChange(pageIndex), initialState: { pageIndex: currentPage, pageSize: 25 }, children: [_jsx(DataTable.Table, {}), _jsx(DataTable.EmptyTable, { content: intl.formatMessage(messages.noTasksMessage) }), itemCount > 0 && (_jsxs(DataTable.TableFooter, { children: [_jsx(DataTable.RowStatus, {}), _jsx(DataTable.TablePagination, {})] }))] }));
|
|
23
|
+
};
|
|
24
|
+
export default GenerationHistoryTable;
|
|
25
|
+
//# sourceMappingURL=GenerationHistoryTable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GenerationHistoryTable.js","sourceRoot":"","sources":["../../../src/certificates/components/GenerationHistoryTable.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAWlD,MAAM,sBAAsB,GAAG,CAAC,EAC9B,IAAI,EACJ,SAAS,EACT,SAAS,EACT,SAAS,EACT,WAAW,EACX,YAAY,GACgB,EAAE,EAAE;IAChC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,MAAM,OAAO,GAAG,OAAO,CACrB,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,UAAU,CAAC;YAC/C,QAAQ,EAAE,MAAM;SACjB;QACD;YACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC;YAClD,QAAQ,EAAE,SAAS;SACpB;KACF,EACD,CAAC,IAAI,CAAC,CACP,CAAC;IAEF,OAAO,CACL,MAAC,SAAS,IACR,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,SAAS,EACpB,WAAW,QACX,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,SAAS,EACpB,gBAAgB,QAChB,SAAS,EAAE,CAAC,EAAE,SAAS,EAAyB,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,EAC5E,YAAY,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,EAAE,aAEtD,KAAC,SAAS,CAAC,KAAK,KAAG,EACnB,KAAC,SAAS,CAAC,UAAU,IAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,cAAc,CAAC,GAAI,EAC7E,SAAS,GAAG,CAAC,IAAI,CAChB,MAAC,SAAS,CAAC,WAAW,eACpB,KAAC,SAAS,CAAC,SAAS,KAAG,EACvB,KAAC,SAAS,CAAC,eAAe,KAAG,IACP,CACzB,IACS,CACb,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,sBAAsB,CAAC","sourcesContent":["import { useMemo } from 'react';\nimport { DataTable } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport type { CertificateGenerationHistory } from '@src/certificates/types';\nimport messages from '@src/certificates/messages';\n\ninterface GenerationHistoryTableProps {\n data: CertificateGenerationHistory[],\n isLoading: boolean,\n itemCount: number,\n pageCount: number,\n currentPage: number,\n onPageChange: (pageIndex: number) => void,\n}\n\nconst GenerationHistoryTable = ({\n data,\n isLoading,\n itemCount,\n pageCount,\n currentPage,\n onPageChange,\n}: GenerationHistoryTableProps) => {\n const intl = useIntl();\n\n const columns = useMemo(\n () => [\n {\n Header: intl.formatMessage(messages.columnTaskName),\n accessor: 'taskName',\n },\n {\n Header: intl.formatMessage(messages.columnDate),\n accessor: 'date',\n },\n {\n Header: intl.formatMessage(messages.columnDetails),\n accessor: 'details',\n },\n ],\n [intl],\n );\n\n return (\n <DataTable\n columns={columns}\n data={data}\n isLoading={isLoading}\n isPaginated\n itemCount={itemCount}\n pageCount={pageCount}\n manualPagination\n fetchData={({ pageIndex }: { pageIndex: number }) => onPageChange(pageIndex)}\n initialState={{ pageIndex: currentPage, pageSize: 25 }}\n >\n <DataTable.Table />\n <DataTable.EmptyTable content={intl.formatMessage(messages.noTasksMessage)} />\n {itemCount > 0 && (\n <DataTable.TableFooter>\n <DataTable.RowStatus />\n <DataTable.TablePagination />\n </DataTable.TableFooter>\n )}\n </DataTable>\n );\n};\n\nexport default GenerationHistoryTable;\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface GrantExceptionsModalProps {
|
|
2
|
+
isOpen: boolean;
|
|
3
|
+
onClose: () => void;
|
|
4
|
+
onSubmit: (learners: string[], notes: string) => void;
|
|
5
|
+
onUploadCsv: (file: File) => void;
|
|
6
|
+
isSubmitting: boolean;
|
|
7
|
+
}
|
|
8
|
+
declare const GrantExceptionsModal: ({ isOpen, onClose, onSubmit, onUploadCsv, isSubmitting, }: GrantExceptionsModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export default GrantExceptionsModal;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
4
|
+
import { ActionRow, Button, Dropzone, Form, Hyperlink, Icon, ModalDialog, OverlayTrigger, Tab, Tabs, Tooltip } from '@openedx/paragon';
|
|
5
|
+
import { InfoOutline } from '@openedx/paragon/icons';
|
|
6
|
+
import messages from '../../certificates/messages';
|
|
7
|
+
const GrantExceptionsModal = ({ isOpen, onClose, onSubmit, onUploadCsv, isSubmitting, }) => {
|
|
8
|
+
const intl = useIntl();
|
|
9
|
+
const [learner, setLearner] = useState('');
|
|
10
|
+
const [notes, setNotes] = useState('');
|
|
11
|
+
const [csvFileName, setCsvFileName] = useState('');
|
|
12
|
+
const [csvFile, setCsvFile] = useState(null);
|
|
13
|
+
const [activeTab, setActiveTab] = useState('single');
|
|
14
|
+
const handleSubmit = () => {
|
|
15
|
+
if (activeTab === 'single') {
|
|
16
|
+
const trimmedLearner = learner.trim();
|
|
17
|
+
if (trimmedLearner) {
|
|
18
|
+
onSubmit([trimmedLearner], notes);
|
|
19
|
+
setLearner('');
|
|
20
|
+
setNotes('');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
// Handle CSV upload
|
|
25
|
+
if (csvFile) {
|
|
26
|
+
onUploadCsv(csvFile);
|
|
27
|
+
setCsvFileName('');
|
|
28
|
+
setCsvFile(null);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const handleClose = () => {
|
|
33
|
+
setLearner('');
|
|
34
|
+
setNotes('');
|
|
35
|
+
setCsvFileName('');
|
|
36
|
+
setCsvFile(null);
|
|
37
|
+
setActiveTab('single');
|
|
38
|
+
onClose();
|
|
39
|
+
};
|
|
40
|
+
return (_jsxs(ModalDialog, { isOpen: isOpen, onClose: handleClose, hasCloseButton: true, title: intl.formatMessage(messages.grantExceptionsModalTitle), className: "grant-exceptions-modal", isOverflowVisible: false, children: [_jsx(ModalDialog.Header, { className: "border-bottom", children: _jsx(ModalDialog.Title, { children: intl.formatMessage(messages.grantExceptionsModalTitle) }) }), _jsxs(ModalDialog.Body, { className: "px-4 py-3", children: [_jsx("p", { className: "mb-4", children: intl.formatMessage(messages.grantExceptionsModalDescription) }), _jsxs(Tabs, { activeKey: activeTab, onSelect: (key) => setActiveTab(key), id: "grant-exceptions-tabs", className: "mb-3", children: [_jsx(Tab, { eventKey: "single", title: intl.formatMessage(messages.singleLearnerTab), children: _jsxs("div", { className: "mt-3", children: [_jsx("p", { className: "mb-3", children: intl.formatMessage(messages.individualTabDescription) }), _jsx(Form.Group, { className: "mb-3", children: _jsx(Form.Control, { type: "text", placeholder: intl.formatMessage(messages.studentEmailUsername), value: learner, onChange: (e) => setLearner(e.target.value) }) }), _jsx(Form.Group, { children: _jsx(Form.Control, { as: "textarea", rows: 3, placeholder: intl.formatMessage(messages.notesOptional), value: notes, onChange: (e) => setNotes(e.target.value) }) })] }) }), _jsx(Tab, { eventKey: "bulk", title: intl.formatMessage(messages.bulkUploadTab), children: _jsxs("div", { className: "mt-3", children: [_jsx(Form.Label, { className: "mb-3", children: intl.formatMessage(messages.csvFileLabel) }), csvFileName && (_jsxs("div", { className: "alert alert-success mb-3", role: "alert", children: [_jsx("strong", { children: "\u2713" }), " ", intl.formatMessage(messages.csvFileSelected, { fileName: csvFileName })] })), _jsx(Dropzone, { accept: { 'text/csv': ['.csv'] }, maxSize: 5 * 1024 * 1024, onProcessUpload: ({ fileData, handleError }) => {
|
|
41
|
+
const file = fileData.get('file') || fileData.get('files[0]') || Array.from(fileData.values()).find(value => value instanceof File);
|
|
42
|
+
if (file instanceof File) {
|
|
43
|
+
setCsvFileName(file.name);
|
|
44
|
+
setCsvFile(file);
|
|
45
|
+
}
|
|
46
|
+
else if (handleError) {
|
|
47
|
+
handleError(new Error('No file found'));
|
|
48
|
+
}
|
|
49
|
+
} }), _jsx("div", { className: "d-flex justify-content-end mt-3", children: _jsx(OverlayTrigger, { placement: "top", overlay: (_jsx(Tooltip, { id: "csv-instructions-tooltip", variant: "light", style: { maxWidth: '400px' }, children: intl.formatMessage(messages.csvInstructionsTooltip) })), children: _jsxs("span", { className: "d-inline-flex align-items-center gap-1 text-muted", style: { cursor: 'pointer' }, children: [_jsx(Icon, { src: InfoOutline, size: "sm" }), _jsx(Hyperlink, { destination: "#", onClick: (e) => {
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
// TODO: Link to CSV instructions documentation
|
|
52
|
+
}, className: "text-muted text-decoration-none", children: intl.formatMessage(messages.csvInstructions) })] }) }) })] }) })] })] }), _jsx(ModalDialog.Footer, { children: _jsxs(ActionRow, { children: [_jsx(Button, { variant: "tertiary", onClick: handleClose, disabled: isSubmitting, children: intl.formatMessage(messages.cancel) }), _jsx(Button, { variant: "primary", onClick: handleSubmit, disabled: isSubmitting || (activeTab === 'single' ? !learner.trim() : !csvFile), children: intl.formatMessage(messages.save) })] }) })] }));
|
|
53
|
+
};
|
|
54
|
+
export default GrantExceptionsModal;
|
|
55
|
+
//# sourceMappingURL=GrantExceptionsModal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GrantExceptionsModal.js","sourceRoot":"","sources":["../../../src/certificates/components/GrantExceptionsModal.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { ActionRow, Button, Dropzone, Form, Hyperlink, Icon, ModalDialog, OverlayTrigger, Tab, Tabs, Tooltip } from '@openedx/paragon';\nimport { InfoOutline } from '@openedx/paragon/icons';\nimport messages from '@src/certificates/messages';\n\ninterface GrantExceptionsModalProps {\n isOpen: boolean,\n onClose: () => void,\n onSubmit: (learners: string[], notes: string) => void,\n onUploadCsv: (file: File) => void,\n isSubmitting: boolean,\n}\n\nconst GrantExceptionsModal = ({\n isOpen,\n onClose,\n onSubmit,\n onUploadCsv,\n isSubmitting,\n}: GrantExceptionsModalProps) => {\n const intl = useIntl();\n const [learner, setLearner] = useState('');\n const [notes, setNotes] = useState('');\n const [csvFileName, setCsvFileName] = useState<string>('');\n const [csvFile, setCsvFile] = useState<File | null>(null);\n const [activeTab, setActiveTab] = useState('single');\n\n const handleSubmit = () => {\n if (activeTab === 'single') {\n const trimmedLearner = learner.trim();\n if (trimmedLearner) {\n onSubmit([trimmedLearner], notes);\n setLearner('');\n setNotes('');\n }\n } else {\n // Handle CSV upload\n if (csvFile) {\n onUploadCsv(csvFile);\n setCsvFileName('');\n setCsvFile(null);\n }\n }\n };\n\n const handleClose = () => {\n setLearner('');\n setNotes('');\n setCsvFileName('');\n setCsvFile(null);\n setActiveTab('single');\n onClose();\n };\n\n return (\n <ModalDialog\n isOpen={isOpen}\n onClose={handleClose}\n hasCloseButton\n title={intl.formatMessage(messages.grantExceptionsModalTitle)}\n className=\"grant-exceptions-modal\"\n isOverflowVisible={false}\n >\n <ModalDialog.Header className=\"border-bottom\">\n <ModalDialog.Title>{intl.formatMessage(messages.grantExceptionsModalTitle)}</ModalDialog.Title>\n </ModalDialog.Header>\n <ModalDialog.Body className=\"px-4 py-3\">\n <p className=\"mb-4\">{intl.formatMessage(messages.grantExceptionsModalDescription)}</p>\n <Tabs\n activeKey={activeTab}\n onSelect={(key) => setActiveTab(key as string)}\n id=\"grant-exceptions-tabs\"\n className=\"mb-3\"\n >\n <Tab eventKey=\"single\" title={intl.formatMessage(messages.singleLearnerTab)}>\n <div className=\"mt-3\">\n <p className=\"mb-3\">{intl.formatMessage(messages.individualTabDescription)}</p>\n <Form.Group className=\"mb-3\">\n <Form.Control\n type=\"text\"\n placeholder={intl.formatMessage(messages.studentEmailUsername)}\n value={learner}\n onChange={(e) => setLearner(e.target.value)}\n />\n </Form.Group>\n <Form.Group>\n <Form.Control\n as=\"textarea\"\n rows={3}\n placeholder={intl.formatMessage(messages.notesOptional)}\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n />\n </Form.Group>\n </div>\n </Tab>\n <Tab eventKey=\"bulk\" title={intl.formatMessage(messages.bulkUploadTab)}>\n <div className=\"mt-3\">\n <Form.Label className=\"mb-3\">{intl.formatMessage(messages.csvFileLabel)}</Form.Label>\n {csvFileName && (\n <div className=\"alert alert-success mb-3\" role=\"alert\">\n <strong>✓</strong> {intl.formatMessage(messages.csvFileSelected, { fileName: csvFileName })}\n </div>\n )}\n <Dropzone\n accept={{ 'text/csv': ['.csv'] }}\n maxSize={5 * 1024 * 1024}\n onProcessUpload={({ fileData, handleError }) => {\n const file = fileData.get('file') || fileData.get('files[0]') || Array.from(fileData.values()).find(value => value instanceof File);\n\n if (file instanceof File) {\n setCsvFileName(file.name);\n setCsvFile(file);\n } else if (handleError) {\n handleError(new Error('No file found'));\n }\n }}\n />\n <div className=\"d-flex justify-content-end mt-3\">\n <OverlayTrigger\n placement=\"top\"\n overlay={(\n <Tooltip id=\"csv-instructions-tooltip\" variant=\"light\" style={{ maxWidth: '400px' }}>\n {intl.formatMessage(messages.csvInstructionsTooltip)}\n </Tooltip>\n )}\n >\n <span className=\"d-inline-flex align-items-center gap-1 text-muted\" style={{ cursor: 'pointer' }}>\n <Icon src={InfoOutline} size=\"sm\" />\n <Hyperlink\n destination=\"#\"\n onClick={(e) => {\n e.preventDefault();\n // TODO: Link to CSV instructions documentation\n }}\n className=\"text-muted text-decoration-none\"\n >\n {intl.formatMessage(messages.csvInstructions)}\n </Hyperlink>\n </span>\n </OverlayTrigger>\n </div>\n </div>\n </Tab>\n </Tabs>\n </ModalDialog.Body>\n <ModalDialog.Footer>\n <ActionRow>\n <Button variant=\"tertiary\" onClick={handleClose} disabled={isSubmitting}>\n {intl.formatMessage(messages.cancel)}\n </Button>\n <Button\n variant=\"primary\"\n onClick={handleSubmit}\n disabled={isSubmitting || (activeTab === 'single' ? !learner.trim() : !csvFile)}\n >\n {intl.formatMessage(messages.save)}\n </Button>\n </ActionRow>\n </ModalDialog.Footer>\n </ModalDialog>\n );\n};\n\nexport default GrantExceptionsModal;\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface InvalidateCertificateModalProps {
|
|
2
|
+
isOpen: boolean;
|
|
3
|
+
onClose: () => void;
|
|
4
|
+
onSubmit: (learners: string[], notes: string) => void;
|
|
5
|
+
isSubmitting: boolean;
|
|
6
|
+
}
|
|
7
|
+
declare const InvalidateCertificateModal: ({ isOpen, onClose, onSubmit, isSubmitting, }: InvalidateCertificateModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default InvalidateCertificateModal;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
4
|
+
import { ActionRow, Button, Form, ModalDialog } from '@openedx/paragon';
|
|
5
|
+
import messages from '../../certificates/messages';
|
|
6
|
+
const InvalidateCertificateModal = ({ isOpen, onClose, onSubmit, isSubmitting, }) => {
|
|
7
|
+
const intl = useIntl();
|
|
8
|
+
const [learner, setLearner] = useState('');
|
|
9
|
+
const [notes, setNotes] = useState('');
|
|
10
|
+
const handleSubmit = () => {
|
|
11
|
+
const trimmedLearner = learner.trim();
|
|
12
|
+
if (trimmedLearner) {
|
|
13
|
+
onSubmit([trimmedLearner], notes);
|
|
14
|
+
setLearner('');
|
|
15
|
+
setNotes('');
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const handleClose = () => {
|
|
19
|
+
setLearner('');
|
|
20
|
+
setNotes('');
|
|
21
|
+
onClose();
|
|
22
|
+
};
|
|
23
|
+
return (_jsxs(ModalDialog, { isOpen: isOpen, onClose: handleClose, hasCloseButton: true, title: intl.formatMessage(messages.invalidateCertificateModalTitle), className: "invalidate-certificate-modal", isOverflowVisible: false, children: [_jsx(ModalDialog.Header, { className: "border-bottom", children: _jsx(ModalDialog.Title, { children: intl.formatMessage(messages.invalidateCertificateModalTitle) }) }), _jsxs(ModalDialog.Body, { className: "px-3", children: [_jsx("p", { className: "mb-3", children: intl.formatMessage(messages.invalidateCertificateModalDescription) }), _jsxs(Form.Group, { className: "mb-3", children: [_jsx(Form.Label, { children: intl.formatMessage(messages.learnerLabel) }), _jsx(Form.Control, { type: "text", placeholder: intl.formatMessage(messages.learnerPlaceholder), value: learner, onChange: (e) => setLearner(e.target.value) })] }), _jsxs(Form.Group, { children: [_jsx(Form.Label, { children: intl.formatMessage(messages.notesLabel) }), _jsx(Form.Control, { as: "textarea", rows: 3, placeholder: intl.formatMessage(messages.notesPlaceholder), value: notes, onChange: (e) => setNotes(e.target.value) })] })] }), _jsx(ModalDialog.Footer, { children: _jsxs(ActionRow, { children: [_jsx(Button, { variant: "tertiary", onClick: handleClose, disabled: isSubmitting, children: intl.formatMessage(messages.cancel) }), _jsx(Button, { variant: "primary", onClick: handleSubmit, disabled: isSubmitting || !learner.trim(), children: intl.formatMessage(messages.save) })] }) })] }));
|
|
24
|
+
};
|
|
25
|
+
export default InvalidateCertificateModal;
|
|
26
|
+
//# sourceMappingURL=InvalidateCertificateModal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvalidateCertificateModal.js","sourceRoot":"","sources":["../../../src/certificates/components/InvalidateCertificateModal.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { ActionRow, Button, Form, ModalDialog } from '@openedx/paragon';\nimport messages from '@src/certificates/messages';\n\ninterface InvalidateCertificateModalProps {\n isOpen: boolean,\n onClose: () => void,\n onSubmit: (learners: string[], notes: string) => void,\n isSubmitting: boolean,\n}\n\nconst InvalidateCertificateModal = ({\n isOpen,\n onClose,\n onSubmit,\n isSubmitting,\n}: InvalidateCertificateModalProps) => {\n const intl = useIntl();\n const [learner, setLearner] = useState('');\n const [notes, setNotes] = useState('');\n\n const handleSubmit = () => {\n const trimmedLearner = learner.trim();\n if (trimmedLearner) {\n onSubmit([trimmedLearner], notes);\n setLearner('');\n setNotes('');\n }\n };\n\n const handleClose = () => {\n setLearner('');\n setNotes('');\n onClose();\n };\n\n return (\n <ModalDialog\n isOpen={isOpen}\n onClose={handleClose}\n hasCloseButton\n title={intl.formatMessage(messages.invalidateCertificateModalTitle)}\n className=\"invalidate-certificate-modal\"\n isOverflowVisible={false}\n >\n <ModalDialog.Header className=\"border-bottom\">\n <ModalDialog.Title>{intl.formatMessage(messages.invalidateCertificateModalTitle)}</ModalDialog.Title>\n </ModalDialog.Header>\n <ModalDialog.Body className=\"px-3\">\n <p className=\"mb-3\">{intl.formatMessage(messages.invalidateCertificateModalDescription)}</p>\n <Form.Group className=\"mb-3\">\n <Form.Label>{intl.formatMessage(messages.learnerLabel)}</Form.Label>\n <Form.Control\n type=\"text\"\n placeholder={intl.formatMessage(messages.learnerPlaceholder)}\n value={learner}\n onChange={(e) => setLearner(e.target.value)}\n />\n </Form.Group>\n <Form.Group>\n <Form.Label>{intl.formatMessage(messages.notesLabel)}</Form.Label>\n <Form.Control\n as=\"textarea\"\n rows={3}\n placeholder={intl.formatMessage(messages.notesPlaceholder)}\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n />\n </Form.Group>\n </ModalDialog.Body>\n <ModalDialog.Footer>\n <ActionRow>\n <Button variant=\"tertiary\" onClick={handleClose} disabled={isSubmitting}>\n {intl.formatMessage(messages.cancel)}\n </Button>\n <Button variant=\"primary\" onClick={handleSubmit} disabled={isSubmitting || !learner.trim()}>\n {intl.formatMessage(messages.save)}\n </Button>\n </ActionRow>\n </ModalDialog.Footer>\n </ModalDialog>\n );\n};\n\nexport default InvalidateCertificateModal;\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { CertificateData, CertificateFilter } from '../../certificates/types';
|
|
2
|
+
interface IssuedCertificatesTabProps {
|
|
3
|
+
data: CertificateData[];
|
|
4
|
+
isLoading: boolean;
|
|
5
|
+
itemCount: number;
|
|
6
|
+
pageCount: number;
|
|
7
|
+
search: string;
|
|
8
|
+
onSearchChange: (value: string) => void;
|
|
9
|
+
filter: CertificateFilter;
|
|
10
|
+
onFilterChange: (value: CertificateFilter) => void;
|
|
11
|
+
currentPage: number;
|
|
12
|
+
onPageChange: (page: number) => void;
|
|
13
|
+
onRemoveException: (username: string, email: string) => void;
|
|
14
|
+
onRemoveInvalidation: (username: string, email: string) => void;
|
|
15
|
+
onRegenerateCertificates: () => void;
|
|
16
|
+
}
|
|
17
|
+
declare const IssuedCertificatesTab: ({ data, isLoading, itemCount, pageCount, search, onSearchChange, filter, onFilterChange, currentPage, onPageChange, onRemoveException, onRemoveInvalidation, onRegenerateCertificates, }: IssuedCertificatesTabProps) => import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export default IssuedCertificatesTab;
|