@openedx/frontend-app-instructor-dashboard 1.0.0-alpha.34 → 1.0.0-alpha.35
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.js +34 -8
- package/dist/certificates/CertificatesPage.js.map +1 -1
- package/dist/certificates/components/CertificatesPageHeader.d.ts +2 -2
- package/dist/certificates/components/CertificatesPageHeader.js +3 -3
- package/dist/certificates/components/CertificatesPageHeader.js.map +1 -1
- package/dist/certificates/components/DisableCertificatesModal.js +16 -8
- package/dist/certificates/components/DisableCertificatesModal.js.map +1 -1
- package/dist/certificates/components/GrantExceptionsModal.d.ts +2 -1
- package/dist/certificates/components/GrantExceptionsModal.js +49 -4
- package/dist/certificates/components/GrantExceptionsModal.js.map +1 -1
- package/dist/certificates/components/InvalidateCertificateModal.js +19 -3
- package/dist/certificates/components/InvalidateCertificateModal.js.map +1 -1
- package/dist/certificates/data/api.d.ts +7 -0
- package/dist/certificates/data/api.js +10 -0
- package/dist/certificates/data/api.js.map +1 -1
- package/dist/certificates/data/apiHook.d.ts +10 -0
- package/dist/certificates/data/apiHook.js +16 -1
- package/dist/certificates/data/apiHook.js.map +1 -1
- package/dist/certificates/messages.d.ts +100 -0
- package/dist/certificates/messages.js +104 -4
- package/dist/certificates/messages.js.map +1 -1
- package/package.json +1 -1
|
@@ -13,7 +13,7 @@ import InvalidateCertificateModal from '../certificates/components/InvalidateCer
|
|
|
13
13
|
import RemoveExceptionModal from '../certificates/components/RemoveExceptionModal';
|
|
14
14
|
import RemoveInvalidationModal from '../certificates/components/RemoveInvalidationModal';
|
|
15
15
|
import DisableCertificatesModal from '../certificates/components/DisableCertificatesModal';
|
|
16
|
-
import { useCertificateGenerationHistory, useGrantBulkExceptions, useInvalidateCertificate, useIssuedCertificates, useRegenerateCertificates, useRemoveException, useRemoveInvalidation, useToggleCertificateGeneration, } from '../certificates/data/apiHook';
|
|
16
|
+
import { useCertificateGenerationHistory, useGrantBulkExceptions, useInvalidateCertificate, useIssuedCertificates, useRegenerateCertificates, useRemoveException, useRemoveInvalidation, useToggleCertificateGeneration, useUploadBulkExceptionsCsv, } from '../certificates/data/apiHook';
|
|
17
17
|
import { CertificateFilter } from '../certificates/types';
|
|
18
18
|
import { CERTIFICATES_PAGE_SIZE, TAB_KEYS, MODAL_TITLES, ALERT_VARIANTS } from '../certificates/constants';
|
|
19
19
|
import { getErrorMessage } from '../certificates/utils/errorHandling';
|
|
@@ -48,6 +48,7 @@ const CertificatesPage = () => {
|
|
|
48
48
|
pageSize: CERTIFICATES_PAGE_SIZE,
|
|
49
49
|
});
|
|
50
50
|
const { mutate: grantExceptions, isPending: isGrantingExceptions } = useGrantBulkExceptions(courseId);
|
|
51
|
+
const { mutate: uploadCsvExceptions, isPending: isUploadingCsv } = useUploadBulkExceptionsCsv(courseId);
|
|
51
52
|
const { mutate: invalidateCert, isPending: isInvalidating } = useInvalidateCertificate(courseId);
|
|
52
53
|
const { mutate: removeExcept, isPending: isRemovingException } = useRemoveException(courseId);
|
|
53
54
|
const { mutate: removeInval, isPending: isRemovingInvalidation } = useRemoveInvalidation(courseId);
|
|
@@ -60,7 +61,7 @@ const CertificatesPage = () => {
|
|
|
60
61
|
if (data.errors && data.errors.length > 0) {
|
|
61
62
|
const errorMessages = data.errors.map(err => `${err.learner}: ${err.message}`).join('\n');
|
|
62
63
|
showModal({
|
|
63
|
-
title:
|
|
64
|
+
title: intl.formatMessage(messages.errorModalTitle),
|
|
64
65
|
message: `Some exceptions failed:\n${errorMessages}`,
|
|
65
66
|
variant: ALERT_VARIANTS.WARNING,
|
|
66
67
|
});
|
|
@@ -71,13 +72,38 @@ const CertificatesPage = () => {
|
|
|
71
72
|
},
|
|
72
73
|
onError: (error) => {
|
|
73
74
|
showModal({
|
|
74
|
-
title:
|
|
75
|
+
title: intl.formatMessage(messages.errorModalTitle),
|
|
75
76
|
message: getErrorMessage(error, intl.formatMessage(messages.errorGrantException)),
|
|
76
77
|
variant: ALERT_VARIANTS.DANGER,
|
|
77
78
|
});
|
|
78
79
|
},
|
|
79
80
|
});
|
|
80
81
|
}, [grantExceptions, showToast, showModal, intl]);
|
|
82
|
+
const handleUploadCsvExceptions = useCallback((file) => {
|
|
83
|
+
uploadCsvExceptions(file, {
|
|
84
|
+
onSuccess: (data) => {
|
|
85
|
+
setIsGrantExceptionsOpen(false);
|
|
86
|
+
if (data.errors && data.errors.length > 0) {
|
|
87
|
+
const errorMessages = data.errors.map(err => `${err.learner}: ${err.message}`).join('\n');
|
|
88
|
+
showModal({
|
|
89
|
+
title: intl.formatMessage(messages.errorModalTitle),
|
|
90
|
+
message: `Some exceptions failed:\n${errorMessages}`,
|
|
91
|
+
variant: ALERT_VARIANTS.WARNING,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (data.success && data.success.length > 0) {
|
|
95
|
+
showToast(intl.formatMessage(messages.exceptionsGrantedToast, { count: data.success.length }));
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
onError: (error) => {
|
|
99
|
+
showModal({
|
|
100
|
+
title: intl.formatMessage(messages.errorModalTitle),
|
|
101
|
+
message: getErrorMessage(error, intl.formatMessage(messages.errorGrantException)),
|
|
102
|
+
variant: ALERT_VARIANTS.DANGER,
|
|
103
|
+
});
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}, [uploadCsvExceptions, showToast, showModal, intl]);
|
|
81
107
|
const handleInvalidateCertificate = useCallback((learners, notes) => {
|
|
82
108
|
invalidateCert({ learners, notes }, {
|
|
83
109
|
onSuccess: (data) => {
|
|
@@ -85,7 +111,7 @@ const CertificatesPage = () => {
|
|
|
85
111
|
if (data.errors && data.errors.length > 0) {
|
|
86
112
|
const errorMessages = data.errors.map(err => `${err.learner}: ${err.message}`).join('\n');
|
|
87
113
|
showModal({
|
|
88
|
-
title:
|
|
114
|
+
title: intl.formatMessage(messages.errorModalTitle),
|
|
89
115
|
message: `Some invalidations failed:\n${errorMessages}`,
|
|
90
116
|
variant: ALERT_VARIANTS.WARNING,
|
|
91
117
|
});
|
|
@@ -96,7 +122,7 @@ const CertificatesPage = () => {
|
|
|
96
122
|
},
|
|
97
123
|
onError: (error) => {
|
|
98
124
|
showModal({
|
|
99
|
-
title:
|
|
125
|
+
title: intl.formatMessage(messages.errorModalTitle),
|
|
100
126
|
message: getErrorMessage(error, intl.formatMessage(messages.errorInvalidateCertificate)),
|
|
101
127
|
variant: ALERT_VARIANTS.DANGER,
|
|
102
128
|
});
|
|
@@ -128,7 +154,7 @@ const CertificatesPage = () => {
|
|
|
128
154
|
},
|
|
129
155
|
onError: (error) => {
|
|
130
156
|
showModal({
|
|
131
|
-
title:
|
|
157
|
+
title: intl.formatMessage(messages.errorModalTitle),
|
|
132
158
|
message: getErrorMessage(error, intl.formatMessage(messages.errorRemoveException)),
|
|
133
159
|
variant: ALERT_VARIANTS.DANGER,
|
|
134
160
|
});
|
|
@@ -160,7 +186,7 @@ const CertificatesPage = () => {
|
|
|
160
186
|
},
|
|
161
187
|
onError: (error) => {
|
|
162
188
|
showModal({
|
|
163
|
-
title:
|
|
189
|
+
title: intl.formatMessage(messages.errorModalTitle),
|
|
164
190
|
message: getErrorMessage(error, intl.formatMessage(messages.errorRemoveInvalidation)),
|
|
165
191
|
variant: ALERT_VARIANTS.DANGER,
|
|
166
192
|
});
|
|
@@ -204,7 +230,7 @@ const CertificatesPage = () => {
|
|
|
204
230
|
if (courseInfo && !courseInfo.certificatesEnabled) {
|
|
205
231
|
return (_jsx(Container, { className: "mt-4.5 mb-4", fluid: true, children: _jsx(Alert, { variant: "warning", children: intl.formatMessage(messages.certificatesDisabledMessage) }) }));
|
|
206
232
|
}
|
|
207
|
-
return (_jsxs(Container, { className: "mt-4.5 mb-4", fluid: true, children: [_jsx(CertificatesPageHeader, { onGrantExceptions: () => setIsGrantExceptionsOpen(true), onInvalidateCertificate: () => setIsInvalidateCertificateOpen(true),
|
|
233
|
+
return (_jsxs(Container, { className: "mt-4.5 mb-4", fluid: true, children: [_jsx(CertificatesPageHeader, { onGrantExceptions: () => setIsGrantExceptionsOpen(true), onInvalidateCertificate: () => setIsInvalidateCertificateOpen(true), onStudentGeneratedCertificates: () => 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, onUploadCsv: handleUploadCsvExceptions, isSubmitting: isGrantingExceptions || isUploadingCsv }), _jsx(InvalidateCertificateModal, { isOpen: isInvalidateCertificateOpen, onClose: () => setIsInvalidateCertificateOpen(false), onSubmit: handleInvalidateCertificate, isSubmitting: isInvalidating }), _jsx(RemoveExceptionModal, { isOpen: isRemoveExceptionOpen, email: selectedEmail, onClose: () => {
|
|
208
234
|
setIsRemoveExceptionOpen(false);
|
|
209
235
|
setSelectedUsername('');
|
|
210
236
|
setSelectedEmail('');
|
|
@@ -1 +1 @@
|
|
|
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 './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
|
+
{"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 useUploadBulkExceptionsCsv,\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 './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: uploadCsvExceptions, isPending: isUploadingCsv } = useUploadBulkExceptionsCsv(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: intl.formatMessage(messages.errorModalTitle),\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: intl.formatMessage(messages.errorModalTitle),\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 handleUploadCsvExceptions = useCallback((file: File) => {\n uploadCsvExceptions(\n file,\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: intl.formatMessage(messages.errorModalTitle),\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: intl.formatMessage(messages.errorModalTitle),\n message: getErrorMessage(error, intl.formatMessage(messages.errorGrantException)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n },\n );\n }, [uploadCsvExceptions, 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: intl.formatMessage(messages.errorModalTitle),\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: intl.formatMessage(messages.errorModalTitle),\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: intl.formatMessage(messages.errorModalTitle),\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: intl.formatMessage(messages.errorModalTitle),\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 onStudentGeneratedCertificates={() => 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 onUploadCsv={handleUploadCsvExceptions}\n isSubmitting={isGrantingExceptions || isUploadingCsv}\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,7 +1,7 @@
|
|
|
1
1
|
interface CertificatesPageHeaderProps {
|
|
2
2
|
onGrantExceptions: () => void;
|
|
3
3
|
onInvalidateCertificate: () => void;
|
|
4
|
-
|
|
4
|
+
onStudentGeneratedCertificates?: () => void;
|
|
5
5
|
}
|
|
6
|
-
declare const CertificatesPageHeader: ({ onGrantExceptions, onInvalidateCertificate,
|
|
6
|
+
declare const CertificatesPageHeader: ({ onGrantExceptions, onInvalidateCertificate, onStudentGeneratedCertificates, }: CertificatesPageHeaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
7
|
export default CertificatesPageHeader;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Button, Dropdown, IconButton, Stack } from '@openedx/paragon';
|
|
3
|
-
import { Add,
|
|
3
|
+
import { Add, Cancel, MoreVert } from '@openedx/paragon/icons';
|
|
4
4
|
import { useIntl } from '@openedx/frontend-base';
|
|
5
5
|
import messages from '../../certificates/messages';
|
|
6
|
-
const CertificatesPageHeader = ({ onGrantExceptions, onInvalidateCertificate,
|
|
6
|
+
const CertificatesPageHeader = ({ onGrantExceptions, onInvalidateCertificate, onStudentGeneratedCertificates, }) => {
|
|
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: [_jsxs(Dropdown, { children: [_jsx(Dropdown.Toggle, { as: IconButton, src: MoreVert, alt: intl.formatMessage(messages.
|
|
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
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,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,GAAG,EAAE,
|
|
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"]}
|
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { ActionRow, Button, Form, ModalDialog } from '@openedx/paragon';
|
|
3
4
|
import { useIntl } from '@openedx/frontend-base';
|
|
4
5
|
import messages from '../../certificates/messages';
|
|
5
6
|
const DisableCertificatesModal = ({ isOpen, isEnabled, onClose, onConfirm, isSubmitting, }) => {
|
|
6
7
|
const intl = useIntl();
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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) })] }) })] }));
|
|
14
22
|
};
|
|
15
23
|
export default DisableCertificatesModal;
|
|
16
24
|
//# sourceMappingURL=DisableCertificatesModal.js.map
|
|
@@ -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;
|
|
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"]}
|
|
@@ -2,7 +2,8 @@ interface GrantExceptionsModalProps {
|
|
|
2
2
|
isOpen: boolean;
|
|
3
3
|
onClose: () => void;
|
|
4
4
|
onSubmit: (learners: string[], notes: string) => void;
|
|
5
|
+
onUploadCsv: (file: File) => void;
|
|
5
6
|
isSubmitting: boolean;
|
|
6
7
|
}
|
|
7
|
-
declare const GrantExceptionsModal: ({ isOpen, onClose, onSubmit, isSubmitting, }: GrantExceptionsModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
declare const GrantExceptionsModal: ({ isOpen, onClose, onSubmit, onUploadCsv, isSubmitting, }: GrantExceptionsModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
9
|
export default GrantExceptionsModal;
|
|
@@ -1,10 +1,55 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
2
3
|
import { useIntl } from '@openedx/frontend-base';
|
|
3
|
-
import
|
|
4
|
+
import { ActionRow, Button, Dropzone, Form, Hyperlink, Icon, ModalDialog, OverlayTrigger, Tab, Tabs, Tooltip } from '@openedx/paragon';
|
|
5
|
+
import { InfoOutline } from '@openedx/paragon/icons';
|
|
4
6
|
import messages from '../../certificates/messages';
|
|
5
|
-
const GrantExceptionsModal = ({ isOpen, onClose, onSubmit, isSubmitting, }) => {
|
|
7
|
+
const GrantExceptionsModal = ({ isOpen, onClose, onSubmit, onUploadCsv, isSubmitting, }) => {
|
|
6
8
|
const intl = useIntl();
|
|
7
|
-
|
|
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) })] }) })] }));
|
|
8
53
|
};
|
|
9
54
|
export default GrantExceptionsModal;
|
|
10
55
|
//# sourceMappingURL=GrantExceptionsModal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrantExceptionsModal.js","sourceRoot":"","sources":["../../../src/certificates/components/GrantExceptionsModal.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,kBAAkB,MAAM,iDAAiD,CAAC;AACjF,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AASlD,MAAM,oBAAoB,GAAG,CAAC,EAC5B,MAAM,EACN,OAAO,EACP,QAAQ,EACR,YAAY,GACc,EAAE,EAAE;IAC9B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,OAAO,CACL,KAAC,kBAAkB,IACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,YAAY,EAAE,YAAY,EAC1B,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EAC7D,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,+BAA+B,CAAC,EACzE,aAAa,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,EACzD,mBAAmB,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EACrE,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,EACnD,gBAAgB,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAC/D,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,EAChD,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,GAChD,CACH,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,oBAAoB,CAAC","sourcesContent":["import { useIntl } from '@openedx/frontend-base';\nimport LearnerActionModal from '@src/certificates/components/LearnerActionModal';\nimport messages from '@src/certificates/messages';\n\ninterface GrantExceptionsModalProps {\n isOpen: boolean,\n onClose: () => void,\n onSubmit: (learners: string[], notes: string) => void,\n isSubmitting: boolean,\n}\n\nconst GrantExceptionsModal = ({\n isOpen,\n onClose,\n onSubmit,\n isSubmitting,\n}: GrantExceptionsModalProps) => {\n const intl = useIntl();\n\n return (\n <LearnerActionModal\n isOpen={isOpen}\n onClose={onClose}\n onSubmit={onSubmit}\n isSubmitting={isSubmitting}\n title={intl.formatMessage(messages.grantExceptionsModalTitle)}\n description={intl.formatMessage(messages.grantExceptionsModalDescription)}\n learnersLabel={intl.formatMessage(messages.learnersLabel)}\n learnersPlaceholder={intl.formatMessage(messages.learnersPlaceholder)}\n notesLabel={intl.formatMessage(messages.notesLabel)}\n notesPlaceholder={intl.formatMessage(messages.notesPlaceholder)}\n submitLabel={intl.formatMessage(messages.submit)}\n cancelLabel={intl.formatMessage(messages.cancel)}\n />\n );\n};\n\nexport default GrantExceptionsModal;\n"]}
|
|
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"]}
|
|
@@ -1,10 +1,26 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
2
3
|
import { useIntl } from '@openedx/frontend-base';
|
|
3
|
-
import
|
|
4
|
+
import { ActionRow, Button, Form, ModalDialog } from '@openedx/paragon';
|
|
4
5
|
import messages from '../../certificates/messages';
|
|
5
6
|
const InvalidateCertificateModal = ({ isOpen, onClose, onSubmit, isSubmitting, }) => {
|
|
6
7
|
const intl = useIntl();
|
|
7
|
-
|
|
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) })] }) })] }));
|
|
8
24
|
};
|
|
9
25
|
export default InvalidateCertificateModal;
|
|
10
26
|
//# sourceMappingURL=InvalidateCertificateModal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InvalidateCertificateModal.js","sourceRoot":"","sources":["../../../src/certificates/components/InvalidateCertificateModal.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,
|
|
1
|
+
{"version":3,"file":"InvalidateCertificateModal.js","sourceRoot":"","sources":["../../../src/certificates/components/InvalidateCertificateModal.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AASlD,MAAM,0BAA0B,GAAG,CAAC,EAClC,MAAM,EACN,OAAO,EACP,QAAQ,EACR,YAAY,GACoB,EAAE,EAAE;IACpC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC3C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEvC,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,cAAc,EAAE,CAAC;YACnB,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE,KAAK,CAAC,CAAC;YAClC,UAAU,CAAC,EAAE,CAAC,CAAC;YACf,QAAQ,CAAC,EAAE,CAAC,CAAC;QACf,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,UAAU,CAAC,EAAE,CAAC,CAAC;QACf,QAAQ,CAAC,EAAE,CAAC,CAAC;QACb,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;IAEF,OAAO,CACL,MAAC,WAAW,IACV,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,WAAW,EACpB,cAAc,QACd,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,+BAA+B,CAAC,EACnE,SAAS,EAAC,8BAA8B,EACxC,iBAAiB,EAAE,KAAK,aAExB,KAAC,WAAW,CAAC,MAAM,IAAC,SAAS,EAAC,eAAe,YAC3C,KAAC,WAAW,CAAC,KAAK,cAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,+BAA+B,CAAC,GAAqB,GAClF,EACrB,MAAC,WAAW,CAAC,IAAI,IAAC,SAAS,EAAC,MAAM,aAChC,YAAG,SAAS,EAAC,MAAM,YAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,qCAAqC,CAAC,GAAK,EAC5F,MAAC,IAAI,CAAC,KAAK,IAAC,SAAS,EAAC,MAAM,aAC1B,KAAC,IAAI,CAAC,KAAK,cAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAc,EACpE,KAAC,IAAI,CAAC,OAAO,IACX,IAAI,EAAC,MAAM,EACX,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAC5D,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAC3C,IACS,EACb,MAAC,IAAI,CAAC,KAAK,eACT,KAAC,IAAI,CAAC,KAAK,cAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAc,EAClE,KAAC,IAAI,CAAC,OAAO,IACX,EAAE,EAAC,UAAU,EACb,IAAI,EAAE,CAAC,EACP,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAC1D,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GACzC,IACS,IACI,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,MAAM,CAAC,GAC7B,EACT,KAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,YACvF,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,GAC3B,IACC,GACO,IACT,CACf,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,0BAA0B,CAAC","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"]}
|
|
@@ -9,6 +9,13 @@ export declare const grantBulkExceptions: (courseId: string, request: GrantExcep
|
|
|
9
9
|
message: string;
|
|
10
10
|
}[];
|
|
11
11
|
}>;
|
|
12
|
+
export declare const uploadBulkExceptionsCsv: (courseId: string, file: File) => Promise<{
|
|
13
|
+
success: string[];
|
|
14
|
+
errors: {
|
|
15
|
+
learner: string;
|
|
16
|
+
message: string;
|
|
17
|
+
}[];
|
|
18
|
+
}>;
|
|
12
19
|
export declare const invalidateCertificate: (courseId: string, request: InvalidateCertificateRequest) => Promise<{
|
|
13
20
|
success: string[];
|
|
14
21
|
errors: {
|
|
@@ -36,6 +36,16 @@ export const grantBulkExceptions = (courseId, request) => __awaiter(void 0, void
|
|
|
36
36
|
});
|
|
37
37
|
return camelCaseObject(data);
|
|
38
38
|
});
|
|
39
|
+
export const uploadBulkExceptionsCsv = (courseId, file) => __awaiter(void 0, void 0, void 0, function* () {
|
|
40
|
+
const formData = new FormData();
|
|
41
|
+
formData.append('file', file);
|
|
42
|
+
const { data } = yield getAuthenticatedHttpClient().post(`${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/exceptions/bulk`, formData, {
|
|
43
|
+
headers: {
|
|
44
|
+
'Content-Type': 'multipart/form-data',
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
return camelCaseObject(data);
|
|
48
|
+
});
|
|
39
49
|
export const invalidateCertificate = (courseId, request) => __awaiter(void 0, void 0, void 0, function* () {
|
|
40
50
|
const { data } = yield getAuthenticatedHttpClient().post(`${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/invalidations`, {
|
|
41
51
|
learners: request.learners,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/certificates/data/api.ts"],"names":[],"mappings":"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","sourcesContent":["import { camelCaseObject, getAuthenticatedHttpClient } from '@openedx/frontend-base';\nimport { getApiBaseUrl } from '@src/data/api';\nimport type { DataList, PaginationParams } from '@src/types';\nimport type {\n CertificateData,\n CertificateGenerationHistory,\n CertificateQueryParams,\n GrantExceptionRequest,\n InstructorTask,\n InvalidateCertificateRequest,\n RemoveExceptionRequest,\n RemoveInvalidationRequest,\n} from '@src/certificates/types';\n\nexport const getIssuedCertificates = async (\n courseId: string,\n params: CertificateQueryParams,\n): Promise<DataList<CertificateData>> => {\n const { data } = await getAuthenticatedHttpClient().get(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/issued`,\n {\n params: {\n page: params.page + 1,\n page_size: params.pageSize,\n filter: params.filter,\n search: params.search,\n },\n },\n );\n return camelCaseObject(data);\n};\n\nexport const getInstructorTasks = async (\n courseId: string,\n params: PaginationParams,\n): Promise<DataList<InstructorTask>> => {\n const { data } = await getAuthenticatedHttpClient().get(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/instructor_tasks`,\n {\n params: {\n page: params.page + 1,\n page_size: params.pageSize,\n },\n },\n );\n return camelCaseObject(data);\n};\n\nexport const grantBulkExceptions = async (\n courseId: string,\n request: GrantExceptionRequest,\n): Promise<{ success: string[], errors: { learner: string, message: string }[] }> => {\n const { data } = await getAuthenticatedHttpClient().post(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/exceptions`,\n {\n learners: request.learners,\n notes: request.notes,\n },\n );\n return camelCaseObject(data);\n};\n\nexport const invalidateCertificate = async (\n courseId: string,\n request: InvalidateCertificateRequest,\n): Promise<{ success: string[], errors: { learner: string, message: string }[] }> => {\n const { data } = await getAuthenticatedHttpClient().post(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/invalidations`,\n {\n learners: request.learners,\n notes: request.notes,\n },\n );\n return camelCaseObject(data);\n};\n\nexport const removeException = async (\n courseId: string,\n request: RemoveExceptionRequest,\n): Promise<void> => {\n await getAuthenticatedHttpClient().delete(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/exceptions`,\n {\n data: {\n username: request.username,\n },\n },\n );\n};\n\nexport const removeInvalidation = async (\n courseId: string,\n request: RemoveInvalidationRequest,\n): Promise<void> => {\n const httpClient = getAuthenticatedHttpClient();\n const url = `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/invalidations`;\n const payload = {\n username: request.username,\n };\n\n await httpClient.delete(url, {\n data: payload,\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n};\n\nexport const toggleCertificateGeneration = async (\n courseId: string,\n enable: boolean,\n): Promise<void> => {\n await getAuthenticatedHttpClient().post(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/toggle_generation`,\n {\n enabled: enable,\n },\n );\n};\n\nexport const regenerateCertificates = async (\n courseId: string,\n filter: string,\n): Promise<void> => {\n const body: { statuses?: string[], student_set?: string } = {};\n\n // Map filter to backend parameters (must match backend filter logic)\n switch (filter) {\n case 'all':\n body.student_set = 'all';\n break;\n case 'received':\n body.statuses = ['downloadable'];\n break;\n case 'not_received':\n // Match backend filter: notpassing or unavailable\n body.statuses = ['notpassing', 'unavailable'];\n break;\n case 'audit_passing':\n body.statuses = ['audit_passing'];\n break;\n case 'audit_not_passing':\n body.statuses = ['audit_notpassing'];\n break;\n case 'error':\n body.statuses = ['error'];\n break;\n case 'granted_exceptions':\n body.student_set = 'allowlisted';\n break;\n case 'invalidated':\n // Invalidated certificates have unavailable status\n body.statuses = ['unavailable'];\n break;\n default:\n body.student_set = 'all';\n }\n\n await getAuthenticatedHttpClient().post(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/regenerate`,\n body,\n );\n};\n\nexport const getCertificateGenerationHistory = async (\n courseId: string,\n params: PaginationParams,\n): Promise<DataList<CertificateGenerationHistory>> => {\n const { data } = await getAuthenticatedHttpClient().get(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/generation_history`,\n {\n params: {\n page: params.page + 1,\n page_size: params.pageSize,\n },\n },\n );\n return camelCaseObject(data);\n};\n"]}
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/certificates/data/api.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAa9C,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,QAAgB,EAChB,MAA8B,EACM,EAAE;IACtC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE,CAAC,GAAG,CACrD,GAAG,aAAa,EAAE,8BAA8B,QAAQ,sBAAsB,EAC9E;QACE,MAAM,EAAE;YACN,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,CAAC;YACrB,SAAS,EAAE,MAAM,CAAC,QAAQ;YAC1B,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB;KACF,CACF,CAAC;IACF,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,QAAgB,EAChB,MAAwB,EACW,EAAE;IACrC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE,CAAC,GAAG,CACrD,GAAG,aAAa,EAAE,8BAA8B,QAAQ,mBAAmB,EAC3E;QACE,MAAM,EAAE;YACN,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,CAAC;YACrB,SAAS,EAAE,MAAM,CAAC,QAAQ;SAC3B;KACF,CACF,CAAC;IACF,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,QAAgB,EAChB,OAA8B,EACkD,EAAE;IAClF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE,CAAC,IAAI,CACtD,GAAG,aAAa,EAAE,8BAA8B,QAAQ,0BAA0B,EAClF;QACE,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;KACrB,CACF,CAAC;IACF,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,QAAgB,EAChB,IAAU,EACsE,EAAE;IAClF,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAE9B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE,CAAC,IAAI,CACtD,GAAG,aAAa,EAAE,8BAA8B,QAAQ,+BAA+B,EACvF,QAAQ,EACR;QACE,OAAO,EAAE;YACP,cAAc,EAAE,qBAAqB;SACtC;KACF,CACF,CAAC;IACF,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,QAAgB,EAChB,OAAqC,EAC2C,EAAE;IAClF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE,CAAC,IAAI,CACtD,GAAG,aAAa,EAAE,8BAA8B,QAAQ,6BAA6B,EACrF;QACE,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;KACrB,CACF,CAAC;IACF,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,QAAgB,EAChB,OAA+B,EAChB,EAAE;IACjB,MAAM,0BAA0B,EAAE,CAAC,MAAM,CACvC,GAAG,aAAa,EAAE,8BAA8B,QAAQ,0BAA0B,EAClF;QACE,IAAI,EAAE;YACJ,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B;KACF,CACF,CAAC;AACJ,CAAC,CAAA,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,QAAgB,EAChB,OAAkC,EACnB,EAAE;IACjB,MAAM,UAAU,GAAG,0BAA0B,EAAE,CAAC;IAChD,MAAM,GAAG,GAAG,GAAG,aAAa,EAAE,8BAA8B,QAAQ,6BAA6B,CAAC;IAClG,MAAM,OAAO,GAAG;QACd,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC3B,CAAC;IAEF,MAAM,UAAU,CAAC,MAAM,CAAC,GAAG,EAAE;QAC3B,IAAI,EAAE,OAAO;QACb,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;SACnC;KACF,CAAC,CAAC;AACL,CAAC,CAAA,CAAC;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAAG,CACzC,QAAgB,EAChB,MAAe,EACA,EAAE;IACjB,MAAM,0BAA0B,EAAE,CAAC,IAAI,CACrC,GAAG,aAAa,EAAE,8BAA8B,QAAQ,iCAAiC,EACzF;QACE,OAAO,EAAE,MAAM;KAChB,CACF,CAAC;AACJ,CAAC,CAAA,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,QAAgB,EAChB,MAAc,EACC,EAAE;IACjB,MAAM,IAAI,GAAkD,EAAE,CAAC;IAE/D,qEAAqE;IACrE,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,KAAK;YACR,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;YACzB,MAAM;QACR,KAAK,UAAU;YACb,IAAI,CAAC,QAAQ,GAAG,CAAC,cAAc,CAAC,CAAC;YACjC,MAAM;QACR,KAAK,cAAc;YACjB,kDAAkD;YAClD,IAAI,CAAC,QAAQ,GAAG,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;YAC9C,MAAM;QACR,KAAK,eAAe;YAClB,IAAI,CAAC,QAAQ,GAAG,CAAC,eAAe,CAAC,CAAC;YAClC,MAAM;QACR,KAAK,mBAAmB;YACtB,IAAI,CAAC,QAAQ,GAAG,CAAC,kBAAkB,CAAC,CAAC;YACrC,MAAM;QACR,KAAK,OAAO;YACV,IAAI,CAAC,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAC;YAC1B,MAAM;QACR,KAAK,oBAAoB;YACvB,IAAI,CAAC,WAAW,GAAG,aAAa,CAAC;YACjC,MAAM;QACR,KAAK,aAAa;YAChB,mDAAmD;YACnD,IAAI,CAAC,QAAQ,GAAG,CAAC,aAAa,CAAC,CAAC;YAChC,MAAM;QACR;YACE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC7B,CAAC;IAED,MAAM,0BAA0B,EAAE,CAAC,IAAI,CACrC,GAAG,aAAa,EAAE,8BAA8B,QAAQ,0BAA0B,EAClF,IAAI,CACL,CAAC;AACJ,CAAC,CAAA,CAAC;AAEF,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAC7C,QAAgB,EAChB,MAAwB,EACyB,EAAE;IACnD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE,CAAC,GAAG,CACrD,GAAG,aAAa,EAAE,8BAA8B,QAAQ,kCAAkC,EAC1F;QACE,MAAM,EAAE;YACN,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,CAAC;YACrB,SAAS,EAAE,MAAM,CAAC,QAAQ;SAC3B;KACF,CACF,CAAC;IACF,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC","sourcesContent":["import { camelCaseObject, getAuthenticatedHttpClient } from '@openedx/frontend-base';\nimport { getApiBaseUrl } from '@src/data/api';\nimport type { DataList, PaginationParams } from '@src/types';\nimport type {\n CertificateData,\n CertificateGenerationHistory,\n CertificateQueryParams,\n GrantExceptionRequest,\n InstructorTask,\n InvalidateCertificateRequest,\n RemoveExceptionRequest,\n RemoveInvalidationRequest,\n} from '@src/certificates/types';\n\nexport const getIssuedCertificates = async (\n courseId: string,\n params: CertificateQueryParams,\n): Promise<DataList<CertificateData>> => {\n const { data } = await getAuthenticatedHttpClient().get(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/issued`,\n {\n params: {\n page: params.page + 1,\n page_size: params.pageSize,\n filter: params.filter,\n search: params.search,\n },\n },\n );\n return camelCaseObject(data);\n};\n\nexport const getInstructorTasks = async (\n courseId: string,\n params: PaginationParams,\n): Promise<DataList<InstructorTask>> => {\n const { data } = await getAuthenticatedHttpClient().get(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/instructor_tasks`,\n {\n params: {\n page: params.page + 1,\n page_size: params.pageSize,\n },\n },\n );\n return camelCaseObject(data);\n};\n\nexport const grantBulkExceptions = async (\n courseId: string,\n request: GrantExceptionRequest,\n): Promise<{ success: string[], errors: { learner: string, message: string }[] }> => {\n const { data } = await getAuthenticatedHttpClient().post(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/exceptions`,\n {\n learners: request.learners,\n notes: request.notes,\n },\n );\n return camelCaseObject(data);\n};\n\nexport const uploadBulkExceptionsCsv = async (\n courseId: string,\n file: File,\n): Promise<{ success: string[], errors: { learner: string, message: string }[] }> => {\n const formData = new FormData();\n formData.append('file', file);\n\n const { data } = await getAuthenticatedHttpClient().post(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/exceptions/bulk`,\n formData,\n {\n headers: {\n 'Content-Type': 'multipart/form-data',\n },\n },\n );\n return camelCaseObject(data);\n};\n\nexport const invalidateCertificate = async (\n courseId: string,\n request: InvalidateCertificateRequest,\n): Promise<{ success: string[], errors: { learner: string, message: string }[] }> => {\n const { data } = await getAuthenticatedHttpClient().post(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/invalidations`,\n {\n learners: request.learners,\n notes: request.notes,\n },\n );\n return camelCaseObject(data);\n};\n\nexport const removeException = async (\n courseId: string,\n request: RemoveExceptionRequest,\n): Promise<void> => {\n await getAuthenticatedHttpClient().delete(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/exceptions`,\n {\n data: {\n username: request.username,\n },\n },\n );\n};\n\nexport const removeInvalidation = async (\n courseId: string,\n request: RemoveInvalidationRequest,\n): Promise<void> => {\n const httpClient = getAuthenticatedHttpClient();\n const url = `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/invalidations`;\n const payload = {\n username: request.username,\n };\n\n await httpClient.delete(url, {\n data: payload,\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n};\n\nexport const toggleCertificateGeneration = async (\n courseId: string,\n enable: boolean,\n): Promise<void> => {\n await getAuthenticatedHttpClient().post(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/toggle_generation`,\n {\n enabled: enable,\n },\n );\n};\n\nexport const regenerateCertificates = async (\n courseId: string,\n filter: string,\n): Promise<void> => {\n const body: { statuses?: string[], student_set?: string } = {};\n\n // Map filter to backend parameters (must match backend filter logic)\n switch (filter) {\n case 'all':\n body.student_set = 'all';\n break;\n case 'received':\n body.statuses = ['downloadable'];\n break;\n case 'not_received':\n // Match backend filter: notpassing or unavailable\n body.statuses = ['notpassing', 'unavailable'];\n break;\n case 'audit_passing':\n body.statuses = ['audit_passing'];\n break;\n case 'audit_not_passing':\n body.statuses = ['audit_notpassing'];\n break;\n case 'error':\n body.statuses = ['error'];\n break;\n case 'granted_exceptions':\n body.student_set = 'allowlisted';\n break;\n case 'invalidated':\n // Invalidated certificates have unavailable status\n body.statuses = ['unavailable'];\n break;\n default:\n body.student_set = 'all';\n }\n\n await getAuthenticatedHttpClient().post(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/regenerate`,\n body,\n );\n};\n\nexport const getCertificateGenerationHistory = async (\n courseId: string,\n params: PaginationParams,\n): Promise<DataList<CertificateGenerationHistory>> => {\n const { data } = await getAuthenticatedHttpClient().get(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/certificates/generation_history`,\n {\n params: {\n page: params.page + 1,\n page_size: params.pageSize,\n },\n },\n );\n return camelCaseObject(data);\n};\n"]}
|
|
@@ -22,6 +22,16 @@ export declare const useGrantBulkExceptions: (courseId: string) => import("@tans
|
|
|
22
22
|
message: string;
|
|
23
23
|
}[];
|
|
24
24
|
}, Error, GrantExceptionRequest, unknown>;
|
|
25
|
+
/**
|
|
26
|
+
* Hook to upload bulk certificate exceptions via CSV
|
|
27
|
+
*/
|
|
28
|
+
export declare const useUploadBulkExceptionsCsv: (courseId: string) => import("@tanstack/react-query").UseMutationResult<{
|
|
29
|
+
success: string[];
|
|
30
|
+
errors: {
|
|
31
|
+
learner: string;
|
|
32
|
+
message: string;
|
|
33
|
+
}[];
|
|
34
|
+
}, Error, File, unknown>;
|
|
25
35
|
/**
|
|
26
36
|
* Hook to invalidate certificate
|
|
27
37
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
2
|
-
import { getCertificateGenerationHistory, getInstructorTasks, getIssuedCertificates, grantBulkExceptions, invalidateCertificate, regenerateCertificates, removeException, removeInvalidation, toggleCertificateGeneration, } from '../../certificates/data/api';
|
|
2
|
+
import { getCertificateGenerationHistory, getInstructorTasks, getIssuedCertificates, grantBulkExceptions, invalidateCertificate, regenerateCertificates, removeException, removeInvalidation, toggleCertificateGeneration, uploadBulkExceptionsCsv, } from '../../certificates/data/api';
|
|
3
3
|
import { certificatesQueryKeys } from '../../certificates/data/queryKeys';
|
|
4
4
|
/**
|
|
5
5
|
* Hook to fetch issued certificates
|
|
@@ -40,6 +40,21 @@ export const useGrantBulkExceptions = (courseId) => {
|
|
|
40
40
|
},
|
|
41
41
|
});
|
|
42
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Hook to upload bulk certificate exceptions via CSV
|
|
45
|
+
*/
|
|
46
|
+
export const useUploadBulkExceptionsCsv = (courseId) => {
|
|
47
|
+
const queryClient = useQueryClient();
|
|
48
|
+
return useMutation({
|
|
49
|
+
mutationFn: (file) => uploadBulkExceptionsCsv(courseId, file),
|
|
50
|
+
onSuccess: () => {
|
|
51
|
+
queryClient.invalidateQueries({
|
|
52
|
+
queryKey: certificatesQueryKeys.byCourse(courseId),
|
|
53
|
+
exact: false,
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
};
|
|
43
58
|
/**
|
|
44
59
|
* Hook to invalidate certificate
|
|
45
60
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apiHook.js","sourceRoot":"","sources":["../../../src/certificates/data/apiHook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAS9E,OAAO,EACL,+BAA+B,EAC/B,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EACf,kBAAkB,EAClB,2BAA2B,
|
|
1
|
+
{"version":3,"file":"apiHook.js","sourceRoot":"","sources":["../../../src/certificates/data/apiHook.ts"],"names":[],"mappings":"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","sourcesContent":["import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport type { PaginationParams } from '@src/types';\nimport type {\n CertificateQueryParams,\n GrantExceptionRequest,\n InvalidateCertificateRequest,\n RemoveExceptionRequest,\n RemoveInvalidationRequest,\n} from '@src/certificates/types';\nimport {\n getCertificateGenerationHistory,\n getInstructorTasks,\n getIssuedCertificates,\n grantBulkExceptions,\n invalidateCertificate,\n regenerateCertificates,\n removeException,\n removeInvalidation,\n toggleCertificateGeneration,\n uploadBulkExceptionsCsv,\n} from '@src/certificates/data/api';\nimport { certificatesQueryKeys } from '@src/certificates/data/queryKeys';\n\n/**\n * Hook to fetch issued certificates\n */\nexport const useIssuedCertificates = (courseId: string, params: CertificateQueryParams) =>\n useQuery({\n queryKey: certificatesQueryKeys.issued(courseId, params),\n queryFn: () => getIssuedCertificates(courseId, params),\n enabled: !!courseId,\n });\n\n/**\n * Hook to fetch instructor tasks\n */\nexport const useInstructorTasks = (courseId: string, params: PaginationParams) =>\n useQuery({\n queryKey: certificatesQueryKeys.tasks(courseId, params),\n queryFn: () => getInstructorTasks(courseId, params),\n enabled: !!courseId,\n });\n\n/**\n * Hook to fetch certificate generation history\n */\nexport const useCertificateGenerationHistory = (courseId: string, params: PaginationParams) =>\n useQuery({\n queryKey: certificatesQueryKeys.generationHistory(courseId, params),\n queryFn: () => getCertificateGenerationHistory(courseId, params),\n enabled: !!courseId,\n });\n\n/**\n * Hook to grant bulk certificate exceptions\n */\nexport const useGrantBulkExceptions = (courseId: string) => {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (request: GrantExceptionRequest) => grantBulkExceptions(courseId, request),\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: certificatesQueryKeys.byCourse(courseId),\n exact: false,\n });\n },\n });\n};\n\n/**\n * Hook to upload bulk certificate exceptions via CSV\n */\nexport const useUploadBulkExceptionsCsv = (courseId: string) => {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (file: File) => uploadBulkExceptionsCsv(courseId, file),\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: certificatesQueryKeys.byCourse(courseId),\n exact: false,\n });\n },\n });\n};\n\n/**\n * Hook to invalidate certificate\n */\nexport const useInvalidateCertificate = (courseId: string) => {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (request: InvalidateCertificateRequest) => invalidateCertificate(courseId, request),\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: certificatesQueryKeys.byCourse(courseId),\n exact: false,\n });\n },\n });\n};\n\n/**\n * Hook to remove certificate exception\n */\nexport const useRemoveException = (courseId: string) => {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (request: RemoveExceptionRequest) => removeException(courseId, request),\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: certificatesQueryKeys.byCourse(courseId),\n exact: false,\n });\n },\n });\n};\n\n/**\n * Hook to remove certificate invalidation\n */\nexport const useRemoveInvalidation = (courseId: string) => {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (request: RemoveInvalidationRequest) => removeInvalidation(courseId, request),\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: certificatesQueryKeys.byCourse(courseId),\n exact: false,\n });\n },\n });\n};\n\n/**\n * Hook to toggle certificate generation\n */\nexport const useToggleCertificateGeneration = (courseId: string) => {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (enable: boolean) => toggleCertificateGeneration(courseId, enable),\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: certificatesQueryKeys.byCourse(courseId),\n exact: false,\n });\n },\n });\n};\n\n/**\n * Hook to regenerate certificates\n */\nexport const useRegenerateCertificates = (courseId: string) => {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (filter: string) => regenerateCertificates(courseId, filter),\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: certificatesQueryKeys.byCourse(courseId),\n exact: false,\n });\n },\n });\n};\n"]}
|
|
@@ -249,6 +249,96 @@ declare const messages: {
|
|
|
249
249
|
defaultMessage: string;
|
|
250
250
|
description: string;
|
|
251
251
|
};
|
|
252
|
+
learnerLabel: {
|
|
253
|
+
id: string;
|
|
254
|
+
defaultMessage: string;
|
|
255
|
+
description: string;
|
|
256
|
+
};
|
|
257
|
+
learnerPlaceholder: {
|
|
258
|
+
id: string;
|
|
259
|
+
defaultMessage: string;
|
|
260
|
+
description: string;
|
|
261
|
+
};
|
|
262
|
+
bulkUploadTab: {
|
|
263
|
+
id: string;
|
|
264
|
+
defaultMessage: string;
|
|
265
|
+
description: string;
|
|
266
|
+
};
|
|
267
|
+
singleLearnerTab: {
|
|
268
|
+
id: string;
|
|
269
|
+
defaultMessage: string;
|
|
270
|
+
description: string;
|
|
271
|
+
};
|
|
272
|
+
csvFileLabel: {
|
|
273
|
+
id: string;
|
|
274
|
+
defaultMessage: string;
|
|
275
|
+
description: string;
|
|
276
|
+
};
|
|
277
|
+
csvInstructions: {
|
|
278
|
+
id: string;
|
|
279
|
+
defaultMessage: string;
|
|
280
|
+
description: string;
|
|
281
|
+
};
|
|
282
|
+
csvInstructionsTooltip: {
|
|
283
|
+
id: string;
|
|
284
|
+
defaultMessage: string;
|
|
285
|
+
description: string;
|
|
286
|
+
};
|
|
287
|
+
csvFileSelected: {
|
|
288
|
+
id: string;
|
|
289
|
+
defaultMessage: string;
|
|
290
|
+
description: string;
|
|
291
|
+
};
|
|
292
|
+
csvUploadPending: {
|
|
293
|
+
id: string;
|
|
294
|
+
defaultMessage: string;
|
|
295
|
+
description: string;
|
|
296
|
+
};
|
|
297
|
+
studentGeneratedCertificatesMenuItem: {
|
|
298
|
+
id: string;
|
|
299
|
+
defaultMessage: string;
|
|
300
|
+
description: string;
|
|
301
|
+
};
|
|
302
|
+
moreActionsButton: {
|
|
303
|
+
id: string;
|
|
304
|
+
defaultMessage: string;
|
|
305
|
+
description: string;
|
|
306
|
+
};
|
|
307
|
+
studentGeneratedCertificatesModalTitle: {
|
|
308
|
+
id: string;
|
|
309
|
+
defaultMessage: string;
|
|
310
|
+
description: string;
|
|
311
|
+
};
|
|
312
|
+
enableStudentGeneratedCertificates: {
|
|
313
|
+
id: string;
|
|
314
|
+
defaultMessage: string;
|
|
315
|
+
description: string;
|
|
316
|
+
};
|
|
317
|
+
studentGeneratedCertificatesDescription: {
|
|
318
|
+
id: string;
|
|
319
|
+
defaultMessage: string;
|
|
320
|
+
description: string;
|
|
321
|
+
};
|
|
322
|
+
close: {
|
|
323
|
+
id: string;
|
|
324
|
+
defaultMessage: string;
|
|
325
|
+
description: string;
|
|
326
|
+
};
|
|
327
|
+
studentEmailUsername: {
|
|
328
|
+
id: string;
|
|
329
|
+
defaultMessage: string;
|
|
330
|
+
description: string;
|
|
331
|
+
};
|
|
332
|
+
notesOptional: {
|
|
333
|
+
id: string;
|
|
334
|
+
defaultMessage: string;
|
|
335
|
+
description: string;
|
|
336
|
+
};
|
|
337
|
+
individualTabDescription: {
|
|
338
|
+
id: string;
|
|
339
|
+
defaultMessage: string;
|
|
340
|
+
description: string;
|
|
341
|
+
};
|
|
252
342
|
cancel: {
|
|
253
343
|
id: string;
|
|
254
344
|
defaultMessage: string;
|
|
@@ -264,6 +354,11 @@ declare const messages: {
|
|
|
264
354
|
defaultMessage: string;
|
|
265
355
|
description: string;
|
|
266
356
|
};
|
|
357
|
+
save: {
|
|
358
|
+
id: string;
|
|
359
|
+
defaultMessage: string;
|
|
360
|
+
description: string;
|
|
361
|
+
};
|
|
267
362
|
columnTaskName: {
|
|
268
363
|
id: string;
|
|
269
364
|
defaultMessage: string;
|
|
@@ -339,5 +434,10 @@ declare const messages: {
|
|
|
339
434
|
defaultMessage: string;
|
|
340
435
|
description: string;
|
|
341
436
|
};
|
|
437
|
+
errorModalTitle: {
|
|
438
|
+
id: string;
|
|
439
|
+
defaultMessage: string;
|
|
440
|
+
description: string;
|
|
441
|
+
};
|
|
342
442
|
};
|
|
343
443
|
export default messages;
|
|
@@ -172,22 +172,22 @@ const messages = defineMessages({
|
|
|
172
172
|
},
|
|
173
173
|
grantExceptionsModalTitle: {
|
|
174
174
|
id: 'instruct.certificates.grantExceptionsModalTitle',
|
|
175
|
-
defaultMessage: '
|
|
175
|
+
defaultMessage: 'Add to Exceptions List',
|
|
176
176
|
description: 'Title for grant exceptions modal',
|
|
177
177
|
},
|
|
178
178
|
grantExceptionsModalDescription: {
|
|
179
179
|
id: 'instruct.certificates.grantExceptionsModalDescription',
|
|
180
|
-
defaultMessage: '
|
|
180
|
+
defaultMessage: 'Set exceptions to generate certificates for learners who did not qualify for a certificate but have been given an exception by the course team. After you add learners to the exception list, you must Generate Exception Certificates.',
|
|
181
181
|
description: 'Description for grant exceptions modal',
|
|
182
182
|
},
|
|
183
183
|
invalidateCertificateModalTitle: {
|
|
184
184
|
id: 'instruct.certificates.invalidateCertificateModalTitle',
|
|
185
|
-
defaultMessage: 'Invalidate
|
|
185
|
+
defaultMessage: 'Invalidate Certificate',
|
|
186
186
|
description: 'Title for invalidate certificate modal',
|
|
187
187
|
},
|
|
188
188
|
invalidateCertificateModalDescription: {
|
|
189
189
|
id: 'instruct.certificates.invalidateCertificateModalDescription',
|
|
190
|
-
defaultMessage: 'Enter
|
|
190
|
+
defaultMessage: 'Enter username or email to invalidate a certificate.',
|
|
191
191
|
description: 'Description for invalidate certificate modal',
|
|
192
192
|
},
|
|
193
193
|
removeExceptionModalTitle: {
|
|
@@ -250,6 +250,96 @@ const messages = defineMessages({
|
|
|
250
250
|
defaultMessage: 'Enter usernames or emails (one per line)',
|
|
251
251
|
description: 'Placeholder for learners field',
|
|
252
252
|
},
|
|
253
|
+
learnerLabel: {
|
|
254
|
+
id: 'instruct.certificates.learnerLabel',
|
|
255
|
+
defaultMessage: 'Username or Email',
|
|
256
|
+
description: 'Label for single learner field',
|
|
257
|
+
},
|
|
258
|
+
learnerPlaceholder: {
|
|
259
|
+
id: 'instruct.certificates.learnerPlaceholder',
|
|
260
|
+
defaultMessage: 'Enter username or email',
|
|
261
|
+
description: 'Placeholder for single learner field',
|
|
262
|
+
},
|
|
263
|
+
bulkUploadTab: {
|
|
264
|
+
id: 'instruct.certificates.bulkUploadTab',
|
|
265
|
+
defaultMessage: 'Bulk',
|
|
266
|
+
description: 'Tab label for bulk CSV upload',
|
|
267
|
+
},
|
|
268
|
+
singleLearnerTab: {
|
|
269
|
+
id: 'instruct.certificates.singleLearnerTab',
|
|
270
|
+
defaultMessage: 'Individual',
|
|
271
|
+
description: 'Tab label for single learner input',
|
|
272
|
+
},
|
|
273
|
+
csvFileLabel: {
|
|
274
|
+
id: 'instruct.certificates.csvFileLabel',
|
|
275
|
+
defaultMessage: 'Upload CSV',
|
|
276
|
+
description: 'Label for CSV file upload',
|
|
277
|
+
},
|
|
278
|
+
csvInstructions: {
|
|
279
|
+
id: 'instruct.certificates.csvInstructions',
|
|
280
|
+
defaultMessage: 'CSV Instructions',
|
|
281
|
+
description: 'Link text for CSV instructions',
|
|
282
|
+
},
|
|
283
|
+
csvInstructionsTooltip: {
|
|
284
|
+
id: 'instruct.certificates.csvInstructionsTooltip',
|
|
285
|
+
defaultMessage: 'CSV file should contain the usernames or email addresses of learners who will receive exceptions. Include the username or email address in the first comma separated field. You can include an optional note describing the reason for the exception in the second comma separated field.',
|
|
286
|
+
description: 'Tooltip text for CSV instructions',
|
|
287
|
+
},
|
|
288
|
+
csvFileSelected: {
|
|
289
|
+
id: 'instruct.certificates.csvFileSelected',
|
|
290
|
+
defaultMessage: 'File selected: {fileName}',
|
|
291
|
+
description: 'Message shown when CSV file is selected',
|
|
292
|
+
},
|
|
293
|
+
csvUploadPending: {
|
|
294
|
+
id: 'instruct.certificates.csvUploadPending',
|
|
295
|
+
defaultMessage: 'CSV file "{fileName}" is ready. Bulk upload will be processed when the backend API is available.',
|
|
296
|
+
description: 'Message shown when CSV upload is pending backend implementation',
|
|
297
|
+
},
|
|
298
|
+
studentGeneratedCertificatesMenuItem: {
|
|
299
|
+
id: 'instruct.certificates.studentGeneratedCertificatesMenuItem',
|
|
300
|
+
defaultMessage: 'Student Generated Certificates',
|
|
301
|
+
description: 'Menu item for student generated certificates',
|
|
302
|
+
},
|
|
303
|
+
moreActionsButton: {
|
|
304
|
+
id: 'instruct.certificates.moreActionsButton',
|
|
305
|
+
defaultMessage: 'More actions',
|
|
306
|
+
description: 'Button for more actions menu',
|
|
307
|
+
},
|
|
308
|
+
studentGeneratedCertificatesModalTitle: {
|
|
309
|
+
id: 'instruct.certificates.studentGeneratedCertificatesModalTitle',
|
|
310
|
+
defaultMessage: 'Student Generated Certificates',
|
|
311
|
+
description: 'Title for student generated certificates modal',
|
|
312
|
+
},
|
|
313
|
+
enableStudentGeneratedCertificates: {
|
|
314
|
+
id: 'instruct.certificates.enableStudentGeneratedCertificates',
|
|
315
|
+
defaultMessage: 'Enable Student Generated Certificates',
|
|
316
|
+
description: 'Checkbox label for enabling student generated certificates',
|
|
317
|
+
},
|
|
318
|
+
studentGeneratedCertificatesDescription: {
|
|
319
|
+
id: 'instruct.certificates.studentGeneratedCertificatesDescription',
|
|
320
|
+
defaultMessage: 'This functionality is enabled by default',
|
|
321
|
+
description: 'Description text for student generated certificates',
|
|
322
|
+
},
|
|
323
|
+
close: {
|
|
324
|
+
id: 'instruct.certificates.close',
|
|
325
|
+
defaultMessage: 'Close',
|
|
326
|
+
description: 'Close button text',
|
|
327
|
+
},
|
|
328
|
+
studentEmailUsername: {
|
|
329
|
+
id: 'instruct.certificates.studentEmailUsername',
|
|
330
|
+
defaultMessage: 'Student Email/Username',
|
|
331
|
+
description: 'Placeholder for student email or username field',
|
|
332
|
+
},
|
|
333
|
+
notesOptional: {
|
|
334
|
+
id: 'instruct.certificates.notesOptional',
|
|
335
|
+
defaultMessage: 'Notes (optional)',
|
|
336
|
+
description: 'Placeholder for optional notes field',
|
|
337
|
+
},
|
|
338
|
+
individualTabDescription: {
|
|
339
|
+
id: 'instruct.certificates.individualTabDescription',
|
|
340
|
+
defaultMessage: 'Enter the username or email address of each learner that you want to add as an exception.',
|
|
341
|
+
description: 'Description for individual tab',
|
|
342
|
+
},
|
|
253
343
|
cancel: {
|
|
254
344
|
id: 'instruct.certificates.cancel',
|
|
255
345
|
defaultMessage: 'Cancel',
|
|
@@ -265,6 +355,11 @@ const messages = defineMessages({
|
|
|
265
355
|
defaultMessage: 'Submit',
|
|
266
356
|
description: 'Submit button text',
|
|
267
357
|
},
|
|
358
|
+
save: {
|
|
359
|
+
id: 'instruct.certificates.save',
|
|
360
|
+
defaultMessage: 'Save',
|
|
361
|
+
description: 'Save button text',
|
|
362
|
+
},
|
|
268
363
|
columnTaskName: {
|
|
269
364
|
id: 'instruct.certificates.columnTaskName',
|
|
270
365
|
defaultMessage: 'Task Name',
|
|
@@ -340,6 +435,11 @@ const messages = defineMessages({
|
|
|
340
435
|
defaultMessage: 'Regenerate Certificates: {filter}',
|
|
341
436
|
description: 'Button to regenerate certificates with filter applied',
|
|
342
437
|
},
|
|
438
|
+
errorModalTitle: {
|
|
439
|
+
id: 'instruct.certificates.errorModalTitle',
|
|
440
|
+
defaultMessage: 'Error',
|
|
441
|
+
description: 'Title for error modal',
|
|
442
|
+
},
|
|
343
443
|
});
|
|
344
444
|
export default messages;
|
|
345
445
|
//# sourceMappingURL=messages.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/certificates/messages.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n pageTitle: {\n id: 'instruct.certificates.pageTitle',\n defaultMessage: 'Certificates',\n description: 'Title for certificates page',\n },\n grantExceptionsButton: {\n id: 'instruct.certificates.grantExceptionsButton',\n defaultMessage: 'Grant Exception(s)',\n description: 'Button to grant certificate exceptions',\n },\n invalidateCertificateButton: {\n id: 'instruct.certificates.invalidateCertificateButton',\n defaultMessage: 'Invalidate Certificate',\n description: 'Button to invalidate certificates',\n },\n disableCertificatesButton: {\n id: 'instruct.certificates.disableCertificatesButton',\n defaultMessage: 'Disable Certificates',\n description: 'Button to disable certificate generation',\n },\n regenerateCertificatesButton: {\n id: 'instruct.certificates.regenerateCertificatesButton',\n defaultMessage: 'Regenerate Certificates',\n description: 'Button to regenerate certificates',\n },\n issuedCertificatesTab: {\n id: 'instruct.certificates.issuedCertificatesTab',\n defaultMessage: 'Issued Certificates',\n description: 'Tab label for issued certificates',\n },\n generationHistoryTab: {\n id: 'instruct.certificates.generationHistoryTab',\n defaultMessage: 'Certificate Generation History',\n description: 'Tab label for certificate generation history',\n },\n searchPlaceholder: {\n id: 'instruct.certificates.searchPlaceholder',\n defaultMessage: 'Search by username or email',\n description: 'Placeholder text for search input',\n },\n filterAllLearners: {\n id: 'instruct.certificates.filterAllLearners',\n defaultMessage: 'All Learners',\n description: 'Filter option for all learners',\n },\n filterReceived: {\n id: 'instruct.certificates.filterReceived',\n defaultMessage: 'Received',\n description: 'Filter option for learners who received certificates',\n },\n filterNotReceived: {\n id: 'instruct.certificates.filterNotReceived',\n defaultMessage: 'Not Received',\n description: 'Filter option for learners who did not receive certificates',\n },\n filterAuditPassing: {\n id: 'instruct.certificates.filterAuditPassing',\n defaultMessage: 'Audit - Passing',\n description: 'Filter option for audit learners who are passing',\n },\n filterAuditNotPassing: {\n id: 'instruct.certificates.filterAuditNotPassing',\n defaultMessage: 'Audit - Not Passing',\n description: 'Filter option for audit learners who are not passing',\n },\n filterErrorState: {\n id: 'instruct.certificates.filterErrorState',\n defaultMessage: 'Error State',\n description: 'Filter option for error states',\n },\n filterGrantedExceptions: {\n id: 'instruct.certificates.filterGrantedExceptions',\n defaultMessage: 'Granted Exceptions',\n description: 'Filter option for granted exceptions',\n },\n filterInvalidated: {\n id: 'instruct.certificates.filterInvalidated',\n defaultMessage: 'Invalidated',\n description: 'Filter option for invalidated certificates',\n },\n columnUsername: {\n id: 'instruct.certificates.columnUsername',\n defaultMessage: 'Username',\n description: 'Table column header for username',\n },\n columnEmail: {\n id: 'instruct.certificates.columnEmail',\n defaultMessage: 'Email',\n description: 'Table column header for email',\n },\n columnEnrollmentTrack: {\n id: 'instruct.certificates.columnEnrollmentTrack',\n defaultMessage: 'Enrollment Track',\n description: 'Table column header for enrollment track',\n },\n columnCertificateStatus: {\n id: 'instruct.certificates.columnCertificateStatus',\n defaultMessage: 'Certificate Status',\n description: 'Table column header for certificate status',\n },\n columnSpecialCase: {\n id: 'instruct.certificates.columnSpecialCase',\n defaultMessage: 'Special Case',\n description: 'Table column header for special case',\n },\n columnExceptionGranted: {\n id: 'instruct.certificates.columnExceptionGranted',\n defaultMessage: 'Exception Granted',\n description: 'Table column header for exception granted',\n },\n columnExceptionNotes: {\n id: 'instruct.certificates.columnExceptionNotes',\n defaultMessage: 'Exception Notes',\n description: 'Table column header for exception notes',\n },\n columnInvalidatedBy: {\n id: 'instruct.certificates.columnInvalidatedBy',\n defaultMessage: 'Invalidated By',\n description: 'Table column header for invalidated by',\n },\n columnInvalidationDate: {\n id: 'instruct.certificates.columnInvalidationDate',\n defaultMessage: 'Invalidation Date',\n description: 'Table column header for invalidation date',\n },\n columnInvalidationNote: {\n id: 'instruct.certificates.columnInvalidationNote',\n defaultMessage: 'Invalidation Note',\n description: 'Table column header for invalidation note',\n },\n columnActions: {\n id: 'instruct.certificates.columnActions',\n defaultMessage: 'Actions',\n description: 'Table column header for actions',\n },\n removeExceptionAction: {\n id: 'instruct.certificates.removeExceptionAction',\n defaultMessage: 'Remove Exception',\n description: 'Action menu item to remove exception',\n },\n removeInvalidationAction: {\n id: 'instruct.certificates.removeInvalidationAction',\n defaultMessage: 'Remove Invalidation',\n description: 'Action menu item to remove invalidation',\n },\n noDataMessage: {\n id: 'instruct.certificates.noDataMessage',\n defaultMessage: 'No certificates found',\n description: 'Message when no certificates are found',\n },\n exceptionRemovedToast: {\n id: 'instruct.certificates.exceptionRemovedToast',\n defaultMessage: 'Exception removed for {email}',\n description: 'Toast message when exception is removed',\n },\n invalidationRemovedToast: {\n id: 'instruct.certificates.invalidationRemovedToast',\n defaultMessage: 'The certificate for {email} has been re-validated and the system is re-running the grade for this learner.',\n description: 'Toast message when invalidation is removed',\n },\n exceptionsGrantedToast: {\n id: 'instruct.certificates.exceptionsGrantedToast',\n defaultMessage: 'Exceptions granted for {count} learner(s)',\n description: 'Toast message when exceptions are granted',\n },\n certificatesInvalidatedToast: {\n id: 'instruct.certificates.certificatesInvalidatedToast',\n defaultMessage: 'Certificates invalidated for {count} learner(s)',\n description: 'Toast message when certificates are invalidated',\n },\n grantExceptionsModalTitle: {\n id: 'instruct.certificates.grantExceptionsModalTitle',\n defaultMessage: 'Grant Certificate Exceptions',\n description: 'Title for grant exceptions modal',\n },\n grantExceptionsModalDescription: {\n id: 'instruct.certificates.grantExceptionsModalDescription',\n defaultMessage: 'Enter usernames or emails, or upload a CSV file to grant certificate exceptions.',\n description: 'Description for grant exceptions modal',\n },\n invalidateCertificateModalTitle: {\n id: 'instruct.certificates.invalidateCertificateModalTitle',\n defaultMessage: 'Invalidate Certificates',\n description: 'Title for invalidate certificate modal',\n },\n invalidateCertificateModalDescription: {\n id: 'instruct.certificates.invalidateCertificateModalDescription',\n defaultMessage: 'Enter usernames or emails, or upload a CSV file to invalidate certificates.',\n description: 'Description for invalidate certificate modal',\n },\n removeExceptionModalTitle: {\n id: 'instruct.certificates.removeExceptionModalTitle',\n defaultMessage: 'Remove Exception',\n description: 'Title for remove exception modal',\n },\n removeExceptionModalMessage: {\n id: 'instruct.certificates.removeExceptionModalMessage',\n defaultMessage: 'Are you sure you want to remove the certificate exception for {email}?',\n description: 'Message for remove exception confirmation modal',\n },\n removeInvalidationModalTitle: {\n id: 'instruct.certificates.removeInvalidationModalTitle',\n defaultMessage: 'Remove Invalidation',\n description: 'Title for remove invalidation modal',\n },\n removeInvalidationModalMessage: {\n id: 'instruct.certificates.removeInvalidationModalMessage',\n defaultMessage: 'Are you sure you want to remove invalidation for {email}?',\n description: 'Message for remove invalidation confirmation modal',\n },\n disableCertificatesModalTitle: {\n id: 'instruct.certificates.disableCertificatesModalTitle',\n defaultMessage: 'Disable Certificate Generation',\n description: 'Title for disable certificates modal',\n },\n disableCertificatesModalMessage: {\n id: 'instruct.certificates.disableCertificatesModalMessage',\n defaultMessage: 'Students will not be able to receive certificates until certificate generation is re-enabled. Are you sure you want to disable certificate generation?',\n description: 'Message for disable certificates modal',\n },\n enableCertificatesModalTitle: {\n id: 'instruct.certificates.enableCertificatesModalTitle',\n defaultMessage: 'Enable Certificate Generation',\n description: 'Title for enable certificates modal',\n },\n enableCertificatesModalMessage: {\n id: 'instruct.certificates.enableCertificatesModalMessage',\n defaultMessage: 'Are you sure you want to enable certificate generation for this course?',\n description: 'Message for enable certificates modal',\n },\n notesLabel: {\n id: 'instruct.certificates.notesLabel',\n defaultMessage: 'Notes (Optional)',\n description: 'Label for notes field',\n },\n notesPlaceholder: {\n id: 'instruct.certificates.notesPlaceholder',\n defaultMessage: 'Enter notes...',\n description: 'Placeholder for notes field',\n },\n learnersLabel: {\n id: 'instruct.certificates.learnersLabel',\n defaultMessage: 'Username or Email',\n description: 'Label for learners field',\n },\n learnersPlaceholder: {\n id: 'instruct.certificates.learnersPlaceholder',\n defaultMessage: 'Enter usernames or emails (one per line)',\n description: 'Placeholder for learners field',\n },\n cancel: {\n id: 'instruct.certificates.cancel',\n defaultMessage: 'Cancel',\n description: 'Cancel button text',\n },\n confirm: {\n id: 'instruct.certificates.confirm',\n defaultMessage: 'Confirm',\n description: 'Confirm button text',\n },\n submit: {\n id: 'instruct.certificates.submit',\n defaultMessage: 'Submit',\n description: 'Submit button text',\n },\n columnTaskName: {\n id: 'instruct.certificates.columnTaskName',\n defaultMessage: 'Task Name',\n description: 'Table column header for task name',\n },\n columnDate: {\n id: 'instruct.certificates.columnDate',\n defaultMessage: 'Date',\n description: 'Table column header for date',\n },\n columnDetails: {\n id: 'instruct.certificates.columnDetails',\n defaultMessage: 'Details',\n description: 'Table column header for details',\n },\n noTasksMessage: {\n id: 'instruct.certificates.noTasksMessage',\n defaultMessage: 'No certificate generation tasks found',\n description: 'Message when no tasks are found',\n },\n errorGrantException: {\n id: 'instruct.certificates.errorGrantException',\n defaultMessage: 'Failed to grant exceptions',\n description: 'Error message when granting exceptions fails',\n },\n errorInvalidateCertificate: {\n id: 'instruct.certificates.errorInvalidateCertificate',\n defaultMessage: 'Failed to invalidate certificates',\n description: 'Error message when invalidating certificates fails',\n },\n errorRemoveException: {\n id: 'instruct.certificates.errorRemoveException',\n defaultMessage: 'Failed to remove exception',\n description: 'Error message when removing exception fails',\n },\n errorRemoveInvalidation: {\n id: 'instruct.certificates.errorRemoveInvalidation',\n defaultMessage: 'Failed to remove invalidation',\n description: 'Error message when removing invalidation fails',\n },\n errorToggleCertificateGeneration: {\n id: 'instruct.certificates.errorToggleCertificateGeneration',\n defaultMessage: 'Failed to toggle certificate generation',\n description: 'Error message when toggling certificate generation fails',\n },\n successEnableCertificates: {\n id: 'instruct.certificates.successEnableCertificates',\n defaultMessage: 'Certificate generation enabled',\n description: 'Success message when certificate generation is enabled',\n },\n successDisableCertificates: {\n id: 'instruct.certificates.successDisableCertificates',\n defaultMessage: 'Certificate generation disabled',\n description: 'Success message when certificate generation is disabled',\n },\n certificatesDisabledMessage: {\n id: 'instruct.certificates.certificatesDisabledMessage',\n defaultMessage: 'Certificate management features are not enabled for this course. Please contact your system administrator to enable certificate generation.',\n description: 'Message displayed when certificate features are disabled',\n },\n certificatesRegeneratedToast: {\n id: 'instruct.certificates.certificatesRegeneratedToast',\n defaultMessage: 'Certificate regeneration started successfully',\n description: 'Success message when certificates are regenerated',\n },\n errorRegenerateCertificates: {\n id: 'instruct.certificates.errorRegenerateCertificates',\n defaultMessage: 'Failed to regenerate certificates',\n description: 'Error message when certificate regeneration fails',\n },\n regenerateCertificatesButtonWithFilter: {\n id: 'instruct.certificates.regenerateCertificatesButtonWithFilter',\n defaultMessage: 'Regenerate Certificates: {filter}',\n description: 'Button to regenerate certificates with filter applied',\n },\n});\n\nexport default messages;\n"]}
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/certificates/messages.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n pageTitle: {\n id: 'instruct.certificates.pageTitle',\n defaultMessage: 'Certificates',\n description: 'Title for certificates page',\n },\n grantExceptionsButton: {\n id: 'instruct.certificates.grantExceptionsButton',\n defaultMessage: 'Grant Exception(s)',\n description: 'Button to grant certificate exceptions',\n },\n invalidateCertificateButton: {\n id: 'instruct.certificates.invalidateCertificateButton',\n defaultMessage: 'Invalidate Certificate',\n description: 'Button to invalidate certificates',\n },\n disableCertificatesButton: {\n id: 'instruct.certificates.disableCertificatesButton',\n defaultMessage: 'Disable Certificates',\n description: 'Button to disable certificate generation',\n },\n regenerateCertificatesButton: {\n id: 'instruct.certificates.regenerateCertificatesButton',\n defaultMessage: 'Regenerate Certificates',\n description: 'Button to regenerate certificates',\n },\n issuedCertificatesTab: {\n id: 'instruct.certificates.issuedCertificatesTab',\n defaultMessage: 'Issued Certificates',\n description: 'Tab label for issued certificates',\n },\n generationHistoryTab: {\n id: 'instruct.certificates.generationHistoryTab',\n defaultMessage: 'Certificate Generation History',\n description: 'Tab label for certificate generation history',\n },\n searchPlaceholder: {\n id: 'instruct.certificates.searchPlaceholder',\n defaultMessage: 'Search by username or email',\n description: 'Placeholder text for search input',\n },\n filterAllLearners: {\n id: 'instruct.certificates.filterAllLearners',\n defaultMessage: 'All Learners',\n description: 'Filter option for all learners',\n },\n filterReceived: {\n id: 'instruct.certificates.filterReceived',\n defaultMessage: 'Received',\n description: 'Filter option for learners who received certificates',\n },\n filterNotReceived: {\n id: 'instruct.certificates.filterNotReceived',\n defaultMessage: 'Not Received',\n description: 'Filter option for learners who did not receive certificates',\n },\n filterAuditPassing: {\n id: 'instruct.certificates.filterAuditPassing',\n defaultMessage: 'Audit - Passing',\n description: 'Filter option for audit learners who are passing',\n },\n filterAuditNotPassing: {\n id: 'instruct.certificates.filterAuditNotPassing',\n defaultMessage: 'Audit - Not Passing',\n description: 'Filter option for audit learners who are not passing',\n },\n filterErrorState: {\n id: 'instruct.certificates.filterErrorState',\n defaultMessage: 'Error State',\n description: 'Filter option for error states',\n },\n filterGrantedExceptions: {\n id: 'instruct.certificates.filterGrantedExceptions',\n defaultMessage: 'Granted Exceptions',\n description: 'Filter option for granted exceptions',\n },\n filterInvalidated: {\n id: 'instruct.certificates.filterInvalidated',\n defaultMessage: 'Invalidated',\n description: 'Filter option for invalidated certificates',\n },\n columnUsername: {\n id: 'instruct.certificates.columnUsername',\n defaultMessage: 'Username',\n description: 'Table column header for username',\n },\n columnEmail: {\n id: 'instruct.certificates.columnEmail',\n defaultMessage: 'Email',\n description: 'Table column header for email',\n },\n columnEnrollmentTrack: {\n id: 'instruct.certificates.columnEnrollmentTrack',\n defaultMessage: 'Enrollment Track',\n description: 'Table column header for enrollment track',\n },\n columnCertificateStatus: {\n id: 'instruct.certificates.columnCertificateStatus',\n defaultMessage: 'Certificate Status',\n description: 'Table column header for certificate status',\n },\n columnSpecialCase: {\n id: 'instruct.certificates.columnSpecialCase',\n defaultMessage: 'Special Case',\n description: 'Table column header for special case',\n },\n columnExceptionGranted: {\n id: 'instruct.certificates.columnExceptionGranted',\n defaultMessage: 'Exception Granted',\n description: 'Table column header for exception granted',\n },\n columnExceptionNotes: {\n id: 'instruct.certificates.columnExceptionNotes',\n defaultMessage: 'Exception Notes',\n description: 'Table column header for exception notes',\n },\n columnInvalidatedBy: {\n id: 'instruct.certificates.columnInvalidatedBy',\n defaultMessage: 'Invalidated By',\n description: 'Table column header for invalidated by',\n },\n columnInvalidationDate: {\n id: 'instruct.certificates.columnInvalidationDate',\n defaultMessage: 'Invalidation Date',\n description: 'Table column header for invalidation date',\n },\n columnInvalidationNote: {\n id: 'instruct.certificates.columnInvalidationNote',\n defaultMessage: 'Invalidation Note',\n description: 'Table column header for invalidation note',\n },\n columnActions: {\n id: 'instruct.certificates.columnActions',\n defaultMessage: 'Actions',\n description: 'Table column header for actions',\n },\n removeExceptionAction: {\n id: 'instruct.certificates.removeExceptionAction',\n defaultMessage: 'Remove Exception',\n description: 'Action menu item to remove exception',\n },\n removeInvalidationAction: {\n id: 'instruct.certificates.removeInvalidationAction',\n defaultMessage: 'Remove Invalidation',\n description: 'Action menu item to remove invalidation',\n },\n noDataMessage: {\n id: 'instruct.certificates.noDataMessage',\n defaultMessage: 'No certificates found',\n description: 'Message when no certificates are found',\n },\n exceptionRemovedToast: {\n id: 'instruct.certificates.exceptionRemovedToast',\n defaultMessage: 'Exception removed for {email}',\n description: 'Toast message when exception is removed',\n },\n invalidationRemovedToast: {\n id: 'instruct.certificates.invalidationRemovedToast',\n defaultMessage: 'The certificate for {email} has been re-validated and the system is re-running the grade for this learner.',\n description: 'Toast message when invalidation is removed',\n },\n exceptionsGrantedToast: {\n id: 'instruct.certificates.exceptionsGrantedToast',\n defaultMessage: 'Exceptions granted for {count} learner(s)',\n description: 'Toast message when exceptions are granted',\n },\n certificatesInvalidatedToast: {\n id: 'instruct.certificates.certificatesInvalidatedToast',\n defaultMessage: 'Certificates invalidated for {count} learner(s)',\n description: 'Toast message when certificates are invalidated',\n },\n grantExceptionsModalTitle: {\n id: 'instruct.certificates.grantExceptionsModalTitle',\n defaultMessage: 'Add to Exceptions List',\n description: 'Title for grant exceptions modal',\n },\n grantExceptionsModalDescription: {\n id: 'instruct.certificates.grantExceptionsModalDescription',\n defaultMessage: 'Set exceptions to generate certificates for learners who did not qualify for a certificate but have been given an exception by the course team. After you add learners to the exception list, you must Generate Exception Certificates.',\n description: 'Description for grant exceptions modal',\n },\n invalidateCertificateModalTitle: {\n id: 'instruct.certificates.invalidateCertificateModalTitle',\n defaultMessage: 'Invalidate Certificate',\n description: 'Title for invalidate certificate modal',\n },\n invalidateCertificateModalDescription: {\n id: 'instruct.certificates.invalidateCertificateModalDescription',\n defaultMessage: 'Enter username or email to invalidate a certificate.',\n description: 'Description for invalidate certificate modal',\n },\n removeExceptionModalTitle: {\n id: 'instruct.certificates.removeExceptionModalTitle',\n defaultMessage: 'Remove Exception',\n description: 'Title for remove exception modal',\n },\n removeExceptionModalMessage: {\n id: 'instruct.certificates.removeExceptionModalMessage',\n defaultMessage: 'Are you sure you want to remove the certificate exception for {email}?',\n description: 'Message for remove exception confirmation modal',\n },\n removeInvalidationModalTitle: {\n id: 'instruct.certificates.removeInvalidationModalTitle',\n defaultMessage: 'Remove Invalidation',\n description: 'Title for remove invalidation modal',\n },\n removeInvalidationModalMessage: {\n id: 'instruct.certificates.removeInvalidationModalMessage',\n defaultMessage: 'Are you sure you want to remove invalidation for {email}?',\n description: 'Message for remove invalidation confirmation modal',\n },\n disableCertificatesModalTitle: {\n id: 'instruct.certificates.disableCertificatesModalTitle',\n defaultMessage: 'Disable Certificate Generation',\n description: 'Title for disable certificates modal',\n },\n disableCertificatesModalMessage: {\n id: 'instruct.certificates.disableCertificatesModalMessage',\n defaultMessage: 'Students will not be able to receive certificates until certificate generation is re-enabled. Are you sure you want to disable certificate generation?',\n description: 'Message for disable certificates modal',\n },\n enableCertificatesModalTitle: {\n id: 'instruct.certificates.enableCertificatesModalTitle',\n defaultMessage: 'Enable Certificate Generation',\n description: 'Title for enable certificates modal',\n },\n enableCertificatesModalMessage: {\n id: 'instruct.certificates.enableCertificatesModalMessage',\n defaultMessage: 'Are you sure you want to enable certificate generation for this course?',\n description: 'Message for enable certificates modal',\n },\n notesLabel: {\n id: 'instruct.certificates.notesLabel',\n defaultMessage: 'Notes (Optional)',\n description: 'Label for notes field',\n },\n notesPlaceholder: {\n id: 'instruct.certificates.notesPlaceholder',\n defaultMessage: 'Enter notes...',\n description: 'Placeholder for notes field',\n },\n learnersLabel: {\n id: 'instruct.certificates.learnersLabel',\n defaultMessage: 'Username or Email',\n description: 'Label for learners field',\n },\n learnersPlaceholder: {\n id: 'instruct.certificates.learnersPlaceholder',\n defaultMessage: 'Enter usernames or emails (one per line)',\n description: 'Placeholder for learners field',\n },\n learnerLabel: {\n id: 'instruct.certificates.learnerLabel',\n defaultMessage: 'Username or Email',\n description: 'Label for single learner field',\n },\n learnerPlaceholder: {\n id: 'instruct.certificates.learnerPlaceholder',\n defaultMessage: 'Enter username or email',\n description: 'Placeholder for single learner field',\n },\n bulkUploadTab: {\n id: 'instruct.certificates.bulkUploadTab',\n defaultMessage: 'Bulk',\n description: 'Tab label for bulk CSV upload',\n },\n singleLearnerTab: {\n id: 'instruct.certificates.singleLearnerTab',\n defaultMessage: 'Individual',\n description: 'Tab label for single learner input',\n },\n csvFileLabel: {\n id: 'instruct.certificates.csvFileLabel',\n defaultMessage: 'Upload CSV',\n description: 'Label for CSV file upload',\n },\n csvInstructions: {\n id: 'instruct.certificates.csvInstructions',\n defaultMessage: 'CSV Instructions',\n description: 'Link text for CSV instructions',\n },\n csvInstructionsTooltip: {\n id: 'instruct.certificates.csvInstructionsTooltip',\n defaultMessage: 'CSV file should contain the usernames or email addresses of learners who will receive exceptions. Include the username or email address in the first comma separated field. You can include an optional note describing the reason for the exception in the second comma separated field.',\n description: 'Tooltip text for CSV instructions',\n },\n csvFileSelected: {\n id: 'instruct.certificates.csvFileSelected',\n defaultMessage: 'File selected: {fileName}',\n description: 'Message shown when CSV file is selected',\n },\n csvUploadPending: {\n id: 'instruct.certificates.csvUploadPending',\n defaultMessage: 'CSV file \"{fileName}\" is ready. Bulk upload will be processed when the backend API is available.',\n description: 'Message shown when CSV upload is pending backend implementation',\n },\n studentGeneratedCertificatesMenuItem: {\n id: 'instruct.certificates.studentGeneratedCertificatesMenuItem',\n defaultMessage: 'Student Generated Certificates',\n description: 'Menu item for student generated certificates',\n },\n moreActionsButton: {\n id: 'instruct.certificates.moreActionsButton',\n defaultMessage: 'More actions',\n description: 'Button for more actions menu',\n },\n studentGeneratedCertificatesModalTitle: {\n id: 'instruct.certificates.studentGeneratedCertificatesModalTitle',\n defaultMessage: 'Student Generated Certificates',\n description: 'Title for student generated certificates modal',\n },\n enableStudentGeneratedCertificates: {\n id: 'instruct.certificates.enableStudentGeneratedCertificates',\n defaultMessage: 'Enable Student Generated Certificates',\n description: 'Checkbox label for enabling student generated certificates',\n },\n studentGeneratedCertificatesDescription: {\n id: 'instruct.certificates.studentGeneratedCertificatesDescription',\n defaultMessage: 'This functionality is enabled by default',\n description: 'Description text for student generated certificates',\n },\n close: {\n id: 'instruct.certificates.close',\n defaultMessage: 'Close',\n description: 'Close button text',\n },\n studentEmailUsername: {\n id: 'instruct.certificates.studentEmailUsername',\n defaultMessage: 'Student Email/Username',\n description: 'Placeholder for student email or username field',\n },\n notesOptional: {\n id: 'instruct.certificates.notesOptional',\n defaultMessage: 'Notes (optional)',\n description: 'Placeholder for optional notes field',\n },\n individualTabDescription: {\n id: 'instruct.certificates.individualTabDescription',\n defaultMessage: 'Enter the username or email address of each learner that you want to add as an exception.',\n description: 'Description for individual tab',\n },\n cancel: {\n id: 'instruct.certificates.cancel',\n defaultMessage: 'Cancel',\n description: 'Cancel button text',\n },\n confirm: {\n id: 'instruct.certificates.confirm',\n defaultMessage: 'Confirm',\n description: 'Confirm button text',\n },\n submit: {\n id: 'instruct.certificates.submit',\n defaultMessage: 'Submit',\n description: 'Submit button text',\n },\n save: {\n id: 'instruct.certificates.save',\n defaultMessage: 'Save',\n description: 'Save button text',\n },\n columnTaskName: {\n id: 'instruct.certificates.columnTaskName',\n defaultMessage: 'Task Name',\n description: 'Table column header for task name',\n },\n columnDate: {\n id: 'instruct.certificates.columnDate',\n defaultMessage: 'Date',\n description: 'Table column header for date',\n },\n columnDetails: {\n id: 'instruct.certificates.columnDetails',\n defaultMessage: 'Details',\n description: 'Table column header for details',\n },\n noTasksMessage: {\n id: 'instruct.certificates.noTasksMessage',\n defaultMessage: 'No certificate generation tasks found',\n description: 'Message when no tasks are found',\n },\n errorGrantException: {\n id: 'instruct.certificates.errorGrantException',\n defaultMessage: 'Failed to grant exceptions',\n description: 'Error message when granting exceptions fails',\n },\n errorInvalidateCertificate: {\n id: 'instruct.certificates.errorInvalidateCertificate',\n defaultMessage: 'Failed to invalidate certificates',\n description: 'Error message when invalidating certificates fails',\n },\n errorRemoveException: {\n id: 'instruct.certificates.errorRemoveException',\n defaultMessage: 'Failed to remove exception',\n description: 'Error message when removing exception fails',\n },\n errorRemoveInvalidation: {\n id: 'instruct.certificates.errorRemoveInvalidation',\n defaultMessage: 'Failed to remove invalidation',\n description: 'Error message when removing invalidation fails',\n },\n errorToggleCertificateGeneration: {\n id: 'instruct.certificates.errorToggleCertificateGeneration',\n defaultMessage: 'Failed to toggle certificate generation',\n description: 'Error message when toggling certificate generation fails',\n },\n successEnableCertificates: {\n id: 'instruct.certificates.successEnableCertificates',\n defaultMessage: 'Certificate generation enabled',\n description: 'Success message when certificate generation is enabled',\n },\n successDisableCertificates: {\n id: 'instruct.certificates.successDisableCertificates',\n defaultMessage: 'Certificate generation disabled',\n description: 'Success message when certificate generation is disabled',\n },\n certificatesDisabledMessage: {\n id: 'instruct.certificates.certificatesDisabledMessage',\n defaultMessage: 'Certificate management features are not enabled for this course. Please contact your system administrator to enable certificate generation.',\n description: 'Message displayed when certificate features are disabled',\n },\n certificatesRegeneratedToast: {\n id: 'instruct.certificates.certificatesRegeneratedToast',\n defaultMessage: 'Certificate regeneration started successfully',\n description: 'Success message when certificates are regenerated',\n },\n errorRegenerateCertificates: {\n id: 'instruct.certificates.errorRegenerateCertificates',\n defaultMessage: 'Failed to regenerate certificates',\n description: 'Error message when certificate regeneration fails',\n },\n regenerateCertificatesButtonWithFilter: {\n id: 'instruct.certificates.regenerateCertificatesButtonWithFilter',\n defaultMessage: 'Regenerate Certificates: {filter}',\n description: 'Button to regenerate certificates with filter applied',\n },\n errorModalTitle: {\n id: 'instruct.certificates.errorModalTitle',\n defaultMessage: 'Error',\n description: 'Title for error modal',\n },\n});\n\nexport default messages;\n"]}
|