@openedx/frontend-app-instructor-dashboard 1.0.0-alpha.39 → 1.0.0-alpha.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/Main.js +2 -1
  2. package/dist/Main.js.map +1 -1
  3. package/dist/certificates/CertificatesPage.js +78 -6
  4. package/dist/certificates/CertificatesPage.js.map +1 -1
  5. package/dist/certificates/components/CertificatesToolbar.js +21 -20
  6. package/dist/certificates/components/CertificatesToolbar.js.map +1 -1
  7. package/dist/certificates/components/GenerateCertificatesModal.d.ts +9 -0
  8. package/dist/certificates/components/GenerateCertificatesModal.js +19 -0
  9. package/dist/certificates/components/GenerateCertificatesModal.js.map +1 -0
  10. package/dist/certificates/components/RegenerateCertificatesModal.d.ts +11 -0
  11. package/dist/certificates/components/RegenerateCertificatesModal.js +46 -0
  12. package/dist/certificates/components/RegenerateCertificatesModal.js.map +1 -0
  13. package/dist/certificates/data/api.d.ts +1 -1
  14. package/dist/certificates/data/api.js +3 -2
  15. package/dist/certificates/data/api.js.map +1 -1
  16. package/dist/certificates/data/apiHook.d.ts +4 -1
  17. package/dist/certificates/data/apiHook.js +1 -1
  18. package/dist/certificates/data/apiHook.js.map +1 -1
  19. package/dist/certificates/messages.d.ts +105 -0
  20. package/dist/certificates/messages.js +105 -0
  21. package/dist/certificates/messages.js.map +1 -1
  22. package/dist/certificates/utils/errorHandling.d.ts +3 -1
  23. package/dist/certificates/utils/errorHandling.js +22 -1
  24. package/dist/certificates/utils/errorHandling.js.map +1 -1
  25. package/dist/data/apiHook.js +1 -0
  26. package/dist/data/apiHook.js.map +1 -1
  27. package/dist/data/utils.d.ts +2 -0
  28. package/dist/data/utils.js +9 -0
  29. package/dist/data/utils.js.map +1 -0
  30. package/dist/instructorNav/InstructorNav.js +11 -4
  31. package/dist/instructorNav/InstructorNav.js.map +1 -1
  32. package/dist/pageWrapper/PageWrapper.js +3 -1
  33. package/dist/pageWrapper/PageWrapper.js.map +1 -1
  34. package/dist/providers/AccessErrorObserver.d.ts +9 -0
  35. package/dist/providers/AccessErrorObserver.js +35 -0
  36. package/dist/providers/AccessErrorObserver.js.map +1 -0
  37. package/dist/providers/AccessErrorProvider.d.ts +19 -0
  38. package/dist/providers/AccessErrorProvider.js +51 -0
  39. package/dist/providers/AccessErrorProvider.js.map +1 -0
  40. package/dist/providers/messages.d.ts +33 -0
  41. package/dist/providers/messages.js +35 -0
  42. package/dist/providers/messages.js.map +1 -0
  43. package/package.json +1 -1
package/dist/Main.js CHANGED
@@ -3,6 +3,7 @@ import { CurrentAppProvider, getSiteConfig, useIntl } from '@openedx/frontend-ba
3
3
  import { Helmet } from 'react-helmet';
4
4
  import { Outlet } from 'react-router-dom';
5
5
  import { AlertProvider } from './providers/AlertProvider';
6
+ import { AccessErrorProvider } from './providers/AccessErrorProvider';
6
7
  import { appId } from './constants';
7
8
  import messages from './messages';
8
9
  import PageWrapper from './pageWrapper/PageWrapper';
@@ -11,7 +12,7 @@ const Main = () => {
11
12
  const { formatMessage } = useIntl();
12
13
  return (_jsxs(CurrentAppProvider, { appId: appId, children: [_jsx(Helmet, { children: _jsx("title", { children: formatMessage(messages['instructor-dashboard.page.title'], {
13
14
  siteName: getSiteConfig().siteName,
14
- }) }) }), _jsx(AlertProvider, { children: _jsx("main", { className: "d-flex flex-column flex-grow-1", children: _jsx(PageWrapper, { children: _jsx(Outlet, {}) }) }) })] }));
15
+ }) }) }), _jsx(AlertProvider, { children: _jsx(AccessErrorProvider, { children: _jsx("main", { className: "d-flex flex-column flex-grow-1", children: _jsx(PageWrapper, { children: _jsx(Outlet, {}) }) }) }) })] }));
15
16
  };
16
17
  export default Main;
17
18
  //# sourceMappingURL=Main.js.map
package/dist/Main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Main.js","sourceRoot":"","sources":["../src/Main.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,WAAW,MAAM,2BAA2B,CAAC;AAEpD,OAAO,cAAc,CAAC;AAEtB,MAAM,IAAI,GAAG,GAAG,EAAE;IAChB,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IACpC,OAAO,CACL,MAAC,kBAAkB,IAAC,KAAK,EAAE,KAAK,aAC9B,KAAC,MAAM,cACL,0BACG,aAAa,CAAC,QAAQ,CAAC,iCAAiC,CAAC,EAAE;wBAC1D,QAAQ,EAAE,aAAa,EAAE,CAAC,QAAQ;qBACnC,CAAC,GACI,GACD,EACT,KAAC,aAAa,cACZ,eAAM,SAAS,EAAC,gCAAgC,YAC9C,KAAC,WAAW,cACV,KAAC,MAAM,KAAG,GACE,GACT,GACO,IACG,CACtB,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC","sourcesContent":["import { CurrentAppProvider, getSiteConfig, useIntl } from '@openedx/frontend-base';\nimport { Helmet } from 'react-helmet';\nimport { Outlet } from 'react-router-dom';\nimport { AlertProvider } from './providers/AlertProvider';\nimport { appId } from './constants';\nimport messages from './messages';\nimport PageWrapper from './pageWrapper/PageWrapper';\n\nimport './style.scss';\n\nconst Main = () => {\n const { formatMessage } = useIntl();\n return (\n <CurrentAppProvider appId={appId}>\n <Helmet>\n <title>\n {formatMessage(messages['instructor-dashboard.page.title'], {\n siteName: getSiteConfig().siteName,\n })}\n </title>\n </Helmet>\n <AlertProvider>\n <main className=\"d-flex flex-column flex-grow-1\">\n <PageWrapper>\n <Outlet />\n </PageWrapper>\n </main>\n </AlertProvider>\n </CurrentAppProvider>\n );\n};\n\nexport default Main;\n"]}
1
+ {"version":3,"file":"Main.js","sourceRoot":"","sources":["../src/Main.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,WAAW,MAAM,2BAA2B,CAAC;AAEpD,OAAO,cAAc,CAAC;AAEtB,MAAM,IAAI,GAAG,GAAG,EAAE;IAChB,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IACpC,OAAO,CACL,MAAC,kBAAkB,IAAC,KAAK,EAAE,KAAK,aAC9B,KAAC,MAAM,cACL,0BACG,aAAa,CAAC,QAAQ,CAAC,iCAAiC,CAAC,EAAE;wBAC1D,QAAQ,EAAE,aAAa,EAAE,CAAC,QAAQ;qBACnC,CAAC,GACI,GACD,EACT,KAAC,aAAa,cACZ,KAAC,mBAAmB,cAClB,eAAM,SAAS,EAAC,gCAAgC,YAC9C,KAAC,WAAW,cACV,KAAC,MAAM,KAAG,GACE,GACT,GACa,GACR,IACG,CACtB,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC","sourcesContent":["import { CurrentAppProvider, getSiteConfig, useIntl } from '@openedx/frontend-base';\nimport { Helmet } from 'react-helmet';\nimport { Outlet } from 'react-router-dom';\nimport { AlertProvider } from './providers/AlertProvider';\nimport { AccessErrorProvider } from './providers/AccessErrorProvider';\nimport { appId } from './constants';\nimport messages from './messages';\nimport PageWrapper from './pageWrapper/PageWrapper';\n\nimport './style.scss';\n\nconst Main = () => {\n const { formatMessage } = useIntl();\n return (\n <CurrentAppProvider appId={appId}>\n <Helmet>\n <title>\n {formatMessage(messages['instructor-dashboard.page.title'], {\n siteName: getSiteConfig().siteName,\n })}\n </title>\n </Helmet>\n <AlertProvider>\n <AccessErrorProvider>\n <main className=\"d-flex flex-column flex-grow-1\">\n <PageWrapper>\n <Outlet />\n </PageWrapper>\n </main>\n </AccessErrorProvider>\n </AlertProvider>\n </CurrentAppProvider>\n );\n};\n\nexport default Main;\n"]}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useCallback } from 'react';
3
3
  import { useParams } from 'react-router-dom';
4
- import { Card, Container, Tab, Tabs, Alert } from '@openedx/paragon';
4
+ import { Card, Container, Button, ButtonGroup, Alert } from '@openedx/paragon';
5
5
  import { useIntl } from '@openedx/frontend-base';
6
6
  import { useAlert } from '../providers/AlertProvider';
7
7
  import { useCourseInfo } from '../data/apiHook';
@@ -13,6 +13,8 @@ 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 RegenerateCertificatesModal from '../certificates/components/RegenerateCertificatesModal';
17
+ import GenerateCertificatesModal from '../certificates/components/GenerateCertificatesModal';
16
18
  import { useCertificateGenerationHistory, useGrantBulkExceptions, useInvalidateCertificate, useIssuedCertificates, useRegenerateCertificates, useRemoveException, useRemoveInvalidation, useToggleCertificateGeneration, useUploadBulkExceptionsCsv, } from '../certificates/data/apiHook';
17
19
  import { CertificateFilter } from '../certificates/types';
18
20
  import { CERTIFICATES_PAGE_SIZE, TAB_KEYS, MODAL_TITLES, ALERT_VARIANTS } from '../certificates/constants';
@@ -37,6 +39,8 @@ const CertificatesPage = () => {
37
39
  const [isRemoveExceptionOpen, setIsRemoveExceptionOpen] = useState(false);
38
40
  const [isRemoveInvalidationOpen, setIsRemoveInvalidationOpen] = useState(false);
39
41
  const [isDisableCertificatesOpen, setIsDisableCertificatesOpen] = useState(false);
42
+ const [isRegenerateModalOpen, setIsRegenerateModalOpen] = useState(false);
43
+ const [isGenerateModalOpen, setIsGenerateModalOpen] = useState(false);
40
44
  const { data: certificatesData, isLoading: isLoadingCertificates, } = useIssuedCertificates(courseId, {
41
45
  page: certificatesPage,
42
46
  pageSize: CERTIFICATES_PAGE_SIZE,
@@ -212,25 +216,93 @@ const CertificatesPage = () => {
212
216
  },
213
217
  });
214
218
  }, [isCertificateGenerationEnabled, toggleGeneration, showToast, showModal, intl]);
215
- const handleRegenerateCertificates = useCallback(() => {
216
- regenerateCerts(filter, {
219
+ const handleRegenerateCertificatesClick = useCallback(() => {
220
+ // Don't open modal for disabled filters
221
+ if (filter === CertificateFilter.ALL_LEARNERS || filter === CertificateFilter.INVALIDATED) {
222
+ return;
223
+ }
224
+ // For granted exceptions, open the generate modal
225
+ if (filter === CertificateFilter.GRANTED_EXCEPTIONS) {
226
+ setIsGenerateModalOpen(true);
227
+ }
228
+ else {
229
+ // For other filters, open the regenerate modal
230
+ setIsRegenerateModalOpen(true);
231
+ }
232
+ }, [filter]);
233
+ const handleRegenerateCertificatesConfirm = useCallback(() => {
234
+ regenerateCerts({ filter, onlyWithoutCertificate: false }, {
235
+ onSuccess: () => {
236
+ setIsRegenerateModalOpen(false);
237
+ showToast(intl.formatMessage(messages.certificatesRegeneratedToast));
238
+ },
239
+ onError: (error) => {
240
+ setIsRegenerateModalOpen(false);
241
+ const errorMessage = getErrorMessage(error, intl.formatMessage(messages.errorRegenerateCertificates));
242
+ showModal({
243
+ title: MODAL_TITLES.ERROR,
244
+ message: errorMessage,
245
+ variant: ALERT_VARIANTS.DANGER,
246
+ });
247
+ },
248
+ });
249
+ }, [regenerateCerts, filter, showToast, showModal, intl]);
250
+ const handleGenerateCertificatesConfirm = useCallback((onlyWithoutCertificate) => {
251
+ regenerateCerts({ filter, onlyWithoutCertificate }, {
217
252
  onSuccess: () => {
253
+ setIsGenerateModalOpen(false);
218
254
  showToast(intl.formatMessage(messages.certificatesRegeneratedToast));
219
255
  },
220
256
  onError: (error) => {
257
+ setIsGenerateModalOpen(false);
258
+ const errorMessage = getErrorMessage(error, intl.formatMessage(messages.errorRegenerateCertificates));
221
259
  showModal({
222
260
  title: MODAL_TITLES.ERROR,
223
- message: getErrorMessage(error, intl.formatMessage(messages.errorRegenerateCertificates)),
261
+ message: errorMessage,
224
262
  variant: ALERT_VARIANTS.DANGER,
225
263
  });
226
264
  },
227
265
  });
228
266
  }, [regenerateCerts, filter, showToast, showModal, intl]);
267
+ const handleTabKeyDown = useCallback((event) => {
268
+ const tabs = [TAB_KEYS.ISSUED, TAB_KEYS.HISTORY];
269
+ const currentIndex = tabs.indexOf(activeTab);
270
+ let nextIndex = currentIndex;
271
+ switch (event.key) {
272
+ case 'ArrowRight':
273
+ case 'ArrowDown':
274
+ event.preventDefault();
275
+ nextIndex = (currentIndex + 1) % tabs.length;
276
+ break;
277
+ case 'ArrowLeft':
278
+ case 'ArrowUp':
279
+ event.preventDefault();
280
+ nextIndex = (currentIndex - 1 + tabs.length) % tabs.length;
281
+ break;
282
+ case 'Home':
283
+ event.preventDefault();
284
+ nextIndex = 0;
285
+ break;
286
+ case 'End':
287
+ event.preventDefault();
288
+ nextIndex = tabs.length - 1;
289
+ break;
290
+ default:
291
+ return;
292
+ }
293
+ const nextTab = tabs[nextIndex];
294
+ setActiveTab(nextTab);
295
+ // Focus the new tab
296
+ setTimeout(() => {
297
+ var _a;
298
+ (_a = document.getElementById(`certificates-tab-${nextTab}`)) === null || _a === void 0 ? void 0 : _a.focus();
299
+ }, 0);
300
+ }, [activeTab]);
229
301
  // Check if certificate management is disabled
230
302
  if (courseInfo && !courseInfo.certificatesEnabled) {
231
303
  return (_jsx(Container, { className: "mt-4.5 mb-4", fluid: true, children: _jsx(Alert, { variant: "warning", children: intl.formatMessage(messages.certificatesDisabledMessage) }) }));
232
304
  }
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: () => {
305
+ return (_jsxs(Container, { className: "mt-4.5 mb-4", fluid: true, children: [_jsx(CertificatesPageHeader, { onGrantExceptions: () => setIsGrantExceptionsOpen(true), onInvalidateCertificate: () => setIsInvalidateCertificateOpen(true), onStudentGeneratedCertificates: () => setIsDisableCertificatesOpen(true) }), _jsxs(Card, { variant: "muted", className: "pt-3 pt-md-4 pb-4 pb-md-6 certificates-card", children: [_jsxs(ButtonGroup, { className: "d-block mx-4", role: "tablist", children: [_jsx(Button, { id: "certificates-tab-issued", role: "tab", "aria-controls": "certificates-tabpanel-issued", "aria-selected": activeTab === TAB_KEYS.ISSUED, tabIndex: activeTab === TAB_KEYS.ISSUED ? 0 : -1, onClick: () => setActiveTab(TAB_KEYS.ISSUED), onKeyDown: handleTabKeyDown, variant: activeTab === TAB_KEYS.ISSUED ? 'primary' : 'outline-primary', children: intl.formatMessage(messages.issuedCertificatesTab) }), _jsx(Button, { id: "certificates-tab-history", role: "tab", "aria-controls": "certificates-tabpanel-history", "aria-selected": activeTab === TAB_KEYS.HISTORY, tabIndex: activeTab === TAB_KEYS.HISTORY ? 0 : -1, onClick: () => setActiveTab(TAB_KEYS.HISTORY), onKeyDown: handleTabKeyDown, variant: activeTab === TAB_KEYS.HISTORY ? 'primary' : 'outline-primary', children: intl.formatMessage(messages.generationHistoryTab) })] }), _jsx("div", { id: "certificates-tabpanel-issued", role: "tabpanel", "aria-labelledby": "certificates-tab-issued", hidden: activeTab !== TAB_KEYS.ISSUED, children: activeTab === TAB_KEYS.ISSUED && (_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: handleRegenerateCertificatesClick })) }), _jsx("div", { id: "certificates-tabpanel-history", role: "tabpanel", "aria-labelledby": "certificates-tab-history", hidden: activeTab !== TAB_KEYS.HISTORY, children: activeTab === TAB_KEYS.HISTORY && (_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: () => {
234
306
  setIsRemoveExceptionOpen(false);
235
307
  setSelectedUsername('');
236
308
  setSelectedEmail('');
@@ -238,7 +310,7 @@ const CertificatesPage = () => {
238
310
  setIsRemoveInvalidationOpen(false);
239
311
  setSelectedUsername('');
240
312
  setSelectedEmail('');
241
- }, onConfirm: handleRemoveInvalidationConfirm, isSubmitting: isRemovingInvalidation }), _jsx(DisableCertificatesModal, { isOpen: isDisableCertificatesOpen, isEnabled: isCertificateGenerationEnabled, onClose: () => setIsDisableCertificatesOpen(false), onConfirm: handleToggleCertificateGeneration, isSubmitting: isTogglingGeneration })] }));
313
+ }, onConfirm: handleRemoveInvalidationConfirm, isSubmitting: isRemovingInvalidation }), _jsx(DisableCertificatesModal, { isOpen: isDisableCertificatesOpen, isEnabled: isCertificateGenerationEnabled, onClose: () => setIsDisableCertificatesOpen(false), onConfirm: handleToggleCertificateGeneration, isSubmitting: isTogglingGeneration }), _jsx(RegenerateCertificatesModal, { isOpen: isRegenerateModalOpen, onClose: () => setIsRegenerateModalOpen(false), onConfirm: handleRegenerateCertificatesConfirm, isSubmitting: false, filter: filter, learnerCount: (certificatesData === null || certificatesData === void 0 ? void 0 : certificatesData.count) || 0 }), _jsx(GenerateCertificatesModal, { isOpen: isGenerateModalOpen, onClose: () => setIsGenerateModalOpen(false), onConfirm: handleGenerateCertificatesConfirm, isSubmitting: false, learnerCount: (certificatesData === null || certificatesData === void 0 ? void 0 : certificatesData.count) || 0 })] }));
242
314
  };
243
315
  export default CertificatesPage;
244
316
  //# sourceMappingURL=CertificatesPage.js.map
@@ -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 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
+ {"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, Button, ButtonGroup, 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 RegenerateCertificatesModal from '@src/certificates/components/RegenerateCertificatesModal';\nimport GenerateCertificatesModal from '@src/certificates/components/GenerateCertificatesModal';\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<typeof TAB_KEYS.ISSUED | typeof TAB_KEYS.HISTORY>(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 const [isRegenerateModalOpen, setIsRegenerateModalOpen] = useState(false);\n const [isGenerateModalOpen, setIsGenerateModalOpen] = 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 handleRegenerateCertificatesClick = useCallback(() => {\n // Don't open modal for disabled filters\n if (filter === CertificateFilter.ALL_LEARNERS || filter === CertificateFilter.INVALIDATED) {\n return;\n }\n\n // For granted exceptions, open the generate modal\n if (filter === CertificateFilter.GRANTED_EXCEPTIONS) {\n setIsGenerateModalOpen(true);\n } else {\n // For other filters, open the regenerate modal\n setIsRegenerateModalOpen(true);\n }\n }, [filter]);\n\n const handleRegenerateCertificatesConfirm = useCallback(() => {\n regenerateCerts({ filter, onlyWithoutCertificate: false }, {\n onSuccess: () => {\n setIsRegenerateModalOpen(false);\n showToast(intl.formatMessage(messages.certificatesRegeneratedToast));\n },\n onError: (error) => {\n setIsRegenerateModalOpen(false);\n const errorMessage = getErrorMessage(error, intl.formatMessage(messages.errorRegenerateCertificates));\n showModal({\n title: MODAL_TITLES.ERROR,\n message: errorMessage,\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n });\n }, [regenerateCerts, filter, showToast, showModal, intl]);\n\n const handleGenerateCertificatesConfirm = useCallback((onlyWithoutCertificate: boolean) => {\n regenerateCerts({ filter, onlyWithoutCertificate }, {\n onSuccess: () => {\n setIsGenerateModalOpen(false);\n showToast(intl.formatMessage(messages.certificatesRegeneratedToast));\n },\n onError: (error) => {\n setIsGenerateModalOpen(false);\n const errorMessage = getErrorMessage(error, intl.formatMessage(messages.errorRegenerateCertificates));\n showModal({\n title: MODAL_TITLES.ERROR,\n message: errorMessage,\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n });\n }, [regenerateCerts, filter, showToast, showModal, intl]);\n\n const handleTabKeyDown = useCallback((event: React.KeyboardEvent) => {\n const tabs = [TAB_KEYS.ISSUED, TAB_KEYS.HISTORY];\n const currentIndex = tabs.indexOf(activeTab);\n\n let nextIndex = currentIndex;\n\n switch (event.key) {\n case 'ArrowRight':\n case 'ArrowDown':\n event.preventDefault();\n nextIndex = (currentIndex + 1) % tabs.length;\n break;\n case 'ArrowLeft':\n case 'ArrowUp':\n event.preventDefault();\n nextIndex = (currentIndex - 1 + tabs.length) % tabs.length;\n break;\n case 'Home':\n event.preventDefault();\n nextIndex = 0;\n break;\n case 'End':\n event.preventDefault();\n nextIndex = tabs.length - 1;\n break;\n default:\n return;\n }\n\n const nextTab = tabs[nextIndex];\n setActiveTab(nextTab);\n\n // Focus the new tab\n setTimeout(() => {\n document.getElementById(`certificates-tab-${nextTab}`)?.focus();\n }, 0);\n }, [activeTab]);\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 <ButtonGroup className=\"d-block mx-4\" role=\"tablist\">\n <Button\n id=\"certificates-tab-issued\"\n role=\"tab\"\n aria-controls=\"certificates-tabpanel-issued\"\n aria-selected={activeTab === TAB_KEYS.ISSUED}\n tabIndex={activeTab === TAB_KEYS.ISSUED ? 0 : -1}\n onClick={() => setActiveTab(TAB_KEYS.ISSUED)}\n onKeyDown={handleTabKeyDown}\n variant={activeTab === TAB_KEYS.ISSUED ? 'primary' : 'outline-primary'}\n >\n {intl.formatMessage(messages.issuedCertificatesTab)}\n </Button>\n <Button\n id=\"certificates-tab-history\"\n role=\"tab\"\n aria-controls=\"certificates-tabpanel-history\"\n aria-selected={activeTab === TAB_KEYS.HISTORY}\n tabIndex={activeTab === TAB_KEYS.HISTORY ? 0 : -1}\n onClick={() => setActiveTab(TAB_KEYS.HISTORY)}\n onKeyDown={handleTabKeyDown}\n variant={activeTab === TAB_KEYS.HISTORY ? 'primary' : 'outline-primary'}\n >\n {intl.formatMessage(messages.generationHistoryTab)}\n </Button>\n </ButtonGroup>\n <div\n id=\"certificates-tabpanel-issued\"\n role=\"tabpanel\"\n aria-labelledby=\"certificates-tab-issued\"\n hidden={activeTab !== TAB_KEYS.ISSUED}\n >\n {activeTab === TAB_KEYS.ISSUED && (\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={handleRegenerateCertificatesClick}\n />\n )}\n </div>\n <div\n id=\"certificates-tabpanel-history\"\n role=\"tabpanel\"\n aria-labelledby=\"certificates-tab-history\"\n hidden={activeTab !== TAB_KEYS.HISTORY}\n >\n {activeTab === TAB_KEYS.HISTORY && (\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 )}\n </div>\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 <RegenerateCertificatesModal\n isOpen={isRegenerateModalOpen}\n onClose={() => setIsRegenerateModalOpen(false)}\n onConfirm={handleRegenerateCertificatesConfirm}\n isSubmitting={false}\n filter={filter}\n learnerCount={certificatesData?.count || 0}\n />\n <GenerateCertificatesModal\n isOpen={isGenerateModalOpen}\n onClose={() => setIsGenerateModalOpen(false)}\n onConfirm={handleGenerateCertificatesConfirm}\n isSubmitting={false}\n learnerCount={certificatesData?.count || 0}\n />\n </Container>\n );\n};\n\nexport default CertificatesPage;\n"]}
@@ -1,32 +1,33 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button, SearchField } from '@openedx/paragon';
2
+ import { Button, SearchField, OverlayTrigger, Tooltip } from '@openedx/paragon';
3
3
  import { SpinnerIcon } from '@openedx/paragon/icons';
4
4
  import { useIntl } from '@openedx/frontend-base';
5
5
  import FilterDropdown from '../../certificates/components/FilterDropdown';
6
6
  import { CertificateFilter } from '../../certificates/types';
7
7
  import messages from '../../certificates/messages';
8
8
  import '../CertificatesPage.scss';
9
- const getFilterLabel = (filter, intl) => {
10
- const filterMessages = {
11
- [CertificateFilter.ALL_LEARNERS]: messages.filterAllLearners,
12
- [CertificateFilter.RECEIVED]: messages.filterReceived,
13
- [CertificateFilter.NOT_RECEIVED]: messages.filterNotReceived,
14
- [CertificateFilter.AUDIT_PASSING]: messages.filterAuditPassing,
15
- [CertificateFilter.AUDIT_NOT_PASSING]: messages.filterAuditNotPassing,
16
- [CertificateFilter.ERROR_STATE]: messages.filterErrorState,
17
- [CertificateFilter.GRANTED_EXCEPTIONS]: messages.filterGrantedExceptions,
18
- [CertificateFilter.INVALIDATED]: messages.filterInvalidated,
19
- };
20
- return intl.formatMessage(filterMessages[filter]);
21
- };
22
9
  const CertificatesToolbar = ({ search, onSearchChange, filter, onFilterChange, onRegenerateCertificates, }) => {
23
10
  const intl = useIntl();
24
- const buttonText = filter === CertificateFilter.ALL_LEARNERS
25
- ? intl.formatMessage(messages.regenerateCertificatesButton)
26
- : intl.formatMessage(messages.regenerateCertificatesButtonWithFilter, {
27
- filter: getFilterLabel(filter, intl),
28
- });
29
- return (_jsxs("div", { className: "d-flex flex-wrap align-items-center justify-content-between mb-4 mx-4 mt-3 gap-3", children: [_jsxs("div", { className: "d-flex align-items-center gap-3 flex-shrink-1 certificates-toolbar-wrapper", children: [_jsx(SearchField, { onSubmit: onSearchChange, onChange: onSearchChange, placeholder: intl.formatMessage(messages.searchPlaceholder), value: search, className: "flex-shrink-1 certificates-search-field" }), _jsx(FilterDropdown, { value: filter, onChange: onFilterChange, className: "flex-shrink-0" })] }), _jsx(Button, { variant: "outline-primary", iconBefore: SpinnerIcon, onClick: onRegenerateCertificates, className: "text-nowrap flex-shrink-0", children: buttonText })] }));
11
+ // Determine button state based on filter
12
+ const isButtonDisabled = filter === CertificateFilter.ALL_LEARNERS || filter === CertificateFilter.INVALIDATED;
13
+ // Determine button text based on filter
14
+ let buttonText;
15
+ if (filter === CertificateFilter.GRANTED_EXCEPTIONS) {
16
+ buttonText = intl.formatMessage(messages.generateCertificatesButton);
17
+ }
18
+ else {
19
+ buttonText = intl.formatMessage(messages.regenerateCertificatesButton);
20
+ }
21
+ // Determine tooltip text based on filter
22
+ let tooltipText = null;
23
+ if (filter === CertificateFilter.ALL_LEARNERS) {
24
+ tooltipText = intl.formatMessage(messages.regenerateTooltipAllLearners);
25
+ }
26
+ else if (filter === CertificateFilter.INVALIDATED) {
27
+ tooltipText = intl.formatMessage(messages.regenerateTooltipInvalidated);
28
+ }
29
+ const button = (_jsx(Button, { variant: "outline-primary", iconBefore: SpinnerIcon, onClick: onRegenerateCertificates, className: "text-nowrap flex-shrink-0", disabled: isButtonDisabled, children: buttonText }));
30
+ return (_jsxs("div", { className: "d-flex flex-wrap align-items-center justify-content-between mb-4 mx-4 mt-3 gap-3", children: [_jsxs("div", { className: "d-flex align-items-center gap-3 flex-shrink-1 certificates-toolbar-wrapper", children: [_jsx(SearchField, { onSubmit: onSearchChange, onChange: onSearchChange, placeholder: intl.formatMessage(messages.searchPlaceholder), value: search, className: "flex-shrink-1 certificates-search-field" }), _jsx(FilterDropdown, { value: filter, onChange: onFilterChange, className: "flex-shrink-0" })] }), tooltipText && isButtonDisabled ? (_jsx(OverlayTrigger, { placement: "top", overlay: _jsx(Tooltip, { id: "regenerate-tooltip", children: tooltipText }), children: _jsx("span", { className: "d-inline-block", children: button }) })) : (button)] }));
30
31
  };
31
32
  export default CertificatesToolbar;
32
33
  //# sourceMappingURL=CertificatesToolbar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CertificatesToolbar.js","sourceRoot":"","sources":["../../../src/certificates/components/CertificatesToolbar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,cAAc,MAAM,6CAA6C,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAClD,OAAO,0BAA0B,CAAC;AAUlC,MAAM,cAAc,GAAG,CAAC,MAAyB,EAAE,IAAS,EAAE,EAAE;IAC9D,MAAM,cAAc,GAAmC;QACrD,CAAC,iBAAiB,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,iBAAiB;QAC5D,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,cAAc;QACrD,CAAC,iBAAiB,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,iBAAiB;QAC5D,CAAC,iBAAiB,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,kBAAkB;QAC9D,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,EAAE,QAAQ,CAAC,qBAAqB;QACrE,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,gBAAgB;QAC1D,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,EAAE,QAAQ,CAAC,uBAAuB;QACxE,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,iBAAiB;KAC5D,CAAC;IACF,OAAO,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;AACpD,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,EAC3B,MAAM,EACN,cAAc,EACd,MAAM,EACN,cAAc,EACd,wBAAwB,GACC,EAAE,EAAE;IAC7B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,MAAM,UAAU,GAAG,MAAM,KAAK,iBAAiB,CAAC,YAAY;QAC1D,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC;QAC3D,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,sCAAsC,EAAE;YAClE,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC;SACrC,CAAC,CAAC;IAEP,OAAO,CACL,eAAK,SAAS,EAAC,kFAAkF,aAC/F,eAAK,SAAS,EAAC,4EAA4E,aACzF,KAAC,WAAW,IACV,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,cAAc,EACxB,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAC3D,KAAK,EAAE,MAAM,EACb,SAAS,EAAC,yCAAyC,GACnD,EACF,KAAC,cAAc,IACb,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAC,eAAe,GACzB,IACE,EACN,KAAC,MAAM,IACL,OAAO,EAAC,iBAAiB,EACzB,UAAU,EAAE,WAAW,EACvB,OAAO,EAAE,wBAAwB,EACjC,SAAS,EAAC,2BAA2B,YAEpC,UAAU,GACJ,IACL,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,mBAAmB,CAAC","sourcesContent":["import { Button, SearchField } from '@openedx/paragon';\nimport { SpinnerIcon } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport FilterDropdown from '@src/certificates/components/FilterDropdown';\nimport { CertificateFilter } from '@src/certificates/types';\nimport messages from '@src/certificates/messages';\nimport '../CertificatesPage.scss';\n\ninterface CertificatesToolbarProps {\n search: string,\n onSearchChange: (value: string) => void,\n filter: CertificateFilter,\n onFilterChange: (value: CertificateFilter) => void,\n onRegenerateCertificates: () => void,\n}\n\nconst getFilterLabel = (filter: CertificateFilter, intl: any) => {\n const filterMessages: Record<CertificateFilter, any> = {\n [CertificateFilter.ALL_LEARNERS]: messages.filterAllLearners,\n [CertificateFilter.RECEIVED]: messages.filterReceived,\n [CertificateFilter.NOT_RECEIVED]: messages.filterNotReceived,\n [CertificateFilter.AUDIT_PASSING]: messages.filterAuditPassing,\n [CertificateFilter.AUDIT_NOT_PASSING]: messages.filterAuditNotPassing,\n [CertificateFilter.ERROR_STATE]: messages.filterErrorState,\n [CertificateFilter.GRANTED_EXCEPTIONS]: messages.filterGrantedExceptions,\n [CertificateFilter.INVALIDATED]: messages.filterInvalidated,\n };\n return intl.formatMessage(filterMessages[filter]);\n};\n\nconst CertificatesToolbar = ({\n search,\n onSearchChange,\n filter,\n onFilterChange,\n onRegenerateCertificates,\n}: CertificatesToolbarProps) => {\n const intl = useIntl();\n\n const buttonText = filter === CertificateFilter.ALL_LEARNERS\n ? intl.formatMessage(messages.regenerateCertificatesButton)\n : intl.formatMessage(messages.regenerateCertificatesButtonWithFilter, {\n filter: getFilterLabel(filter, intl),\n });\n\n return (\n <div className=\"d-flex flex-wrap align-items-center justify-content-between mb-4 mx-4 mt-3 gap-3\">\n <div className=\"d-flex align-items-center gap-3 flex-shrink-1 certificates-toolbar-wrapper\">\n <SearchField\n onSubmit={onSearchChange}\n onChange={onSearchChange}\n placeholder={intl.formatMessage(messages.searchPlaceholder)}\n value={search}\n className=\"flex-shrink-1 certificates-search-field\"\n />\n <FilterDropdown\n value={filter}\n onChange={onFilterChange}\n className=\"flex-shrink-0\"\n />\n </div>\n <Button\n variant=\"outline-primary\"\n iconBefore={SpinnerIcon}\n onClick={onRegenerateCertificates}\n className=\"text-nowrap flex-shrink-0\"\n >\n {buttonText}\n </Button>\n </div>\n );\n};\n\nexport default CertificatesToolbar;\n"]}
1
+ {"version":3,"file":"CertificatesToolbar.js","sourceRoot":"","sources":["../../../src/certificates/components/CertificatesToolbar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,cAAc,MAAM,6CAA6C,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAClD,OAAO,0BAA0B,CAAC;AAUlC,MAAM,mBAAmB,GAAG,CAAC,EAC3B,MAAM,EACN,cAAc,EACd,MAAM,EACN,cAAc,EACd,wBAAwB,GACC,EAAE,EAAE;IAC7B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,yCAAyC;IACzC,MAAM,gBAAgB,GAAG,MAAM,KAAK,iBAAiB,CAAC,YAAY,IAAI,MAAM,KAAK,iBAAiB,CAAC,WAAW,CAAC;IAE/G,wCAAwC;IACxC,IAAI,UAAkB,CAAC;IACvB,IAAI,MAAM,KAAK,iBAAiB,CAAC,kBAAkB,EAAE,CAAC;QACpD,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAAC;IACvE,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;IACzE,CAAC;IAED,yCAAyC;IACzC,IAAI,WAAW,GAAkB,IAAI,CAAC;IACtC,IAAI,MAAM,KAAK,iBAAiB,CAAC,YAAY,EAAE,CAAC;QAC9C,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;IAC1E,CAAC;SAAM,IAAI,MAAM,KAAK,iBAAiB,CAAC,WAAW,EAAE,CAAC;QACpD,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,MAAM,GAAG,CACb,KAAC,MAAM,IACL,OAAO,EAAC,iBAAiB,EACzB,UAAU,EAAE,WAAW,EACvB,OAAO,EAAE,wBAAwB,EACjC,SAAS,EAAC,2BAA2B,EACrC,QAAQ,EAAE,gBAAgB,YAEzB,UAAU,GACJ,CACV,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAC,kFAAkF,aAC/F,eAAK,SAAS,EAAC,4EAA4E,aACzF,KAAC,WAAW,IACV,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,cAAc,EACxB,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAC3D,KAAK,EAAE,MAAM,EACb,SAAS,EAAC,yCAAyC,GACnD,EACF,KAAC,cAAc,IACb,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAC,eAAe,GACzB,IACE,EACL,WAAW,IAAI,gBAAgB,CAAC,CAAC,CAAC,CACjC,KAAC,cAAc,IACb,SAAS,EAAC,KAAK,EACf,OAAO,EAAE,KAAC,OAAO,IAAC,EAAE,EAAC,oBAAoB,YAAE,WAAW,GAAW,YAEjE,eAAM,SAAS,EAAC,gBAAgB,YAC7B,MAAM,GACF,GACQ,CAClB,CAAC,CAAC,CAAC,CACF,MAAM,CACP,IACG,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,mBAAmB,CAAC","sourcesContent":["import { Button, SearchField, OverlayTrigger, Tooltip } from '@openedx/paragon';\nimport { SpinnerIcon } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport FilterDropdown from '@src/certificates/components/FilterDropdown';\nimport { CertificateFilter } from '@src/certificates/types';\nimport messages from '@src/certificates/messages';\nimport '../CertificatesPage.scss';\n\ninterface CertificatesToolbarProps {\n search: string,\n onSearchChange: (value: string) => void,\n filter: CertificateFilter,\n onFilterChange: (value: CertificateFilter) => void,\n onRegenerateCertificates: () => void,\n}\n\nconst CertificatesToolbar = ({\n search,\n onSearchChange,\n filter,\n onFilterChange,\n onRegenerateCertificates,\n}: CertificatesToolbarProps) => {\n const intl = useIntl();\n\n // Determine button state based on filter\n const isButtonDisabled = filter === CertificateFilter.ALL_LEARNERS || filter === CertificateFilter.INVALIDATED;\n\n // Determine button text based on filter\n let buttonText: string;\n if (filter === CertificateFilter.GRANTED_EXCEPTIONS) {\n buttonText = intl.formatMessage(messages.generateCertificatesButton);\n } else {\n buttonText = intl.formatMessage(messages.regenerateCertificatesButton);\n }\n\n // Determine tooltip text based on filter\n let tooltipText: string | null = null;\n if (filter === CertificateFilter.ALL_LEARNERS) {\n tooltipText = intl.formatMessage(messages.regenerateTooltipAllLearners);\n } else if (filter === CertificateFilter.INVALIDATED) {\n tooltipText = intl.formatMessage(messages.regenerateTooltipInvalidated);\n }\n\n const button = (\n <Button\n variant=\"outline-primary\"\n iconBefore={SpinnerIcon}\n onClick={onRegenerateCertificates}\n className=\"text-nowrap flex-shrink-0\"\n disabled={isButtonDisabled}\n >\n {buttonText}\n </Button>\n );\n\n return (\n <div className=\"d-flex flex-wrap align-items-center justify-content-between mb-4 mx-4 mt-3 gap-3\">\n <div className=\"d-flex align-items-center gap-3 flex-shrink-1 certificates-toolbar-wrapper\">\n <SearchField\n onSubmit={onSearchChange}\n onChange={onSearchChange}\n placeholder={intl.formatMessage(messages.searchPlaceholder)}\n value={search}\n className=\"flex-shrink-1 certificates-search-field\"\n />\n <FilterDropdown\n value={filter}\n onChange={onFilterChange}\n className=\"flex-shrink-0\"\n />\n </div>\n {tooltipText && isButtonDisabled ? (\n <OverlayTrigger\n placement=\"top\"\n overlay={<Tooltip id=\"regenerate-tooltip\">{tooltipText}</Tooltip>}\n >\n <span className=\"d-inline-block\">\n {button}\n </span>\n </OverlayTrigger>\n ) : (\n button\n )}\n </div>\n );\n};\n\nexport default CertificatesToolbar;\n"]}
@@ -0,0 +1,9 @@
1
+ interface GenerateCertificatesModalProps {
2
+ isOpen: boolean;
3
+ onClose: () => void;
4
+ onConfirm: (onlyWithoutCertificate: boolean) => void;
5
+ isSubmitting: boolean;
6
+ learnerCount: number;
7
+ }
8
+ declare const GenerateCertificatesModal: ({ isOpen, onClose, onConfirm, isSubmitting, learnerCount, }: GenerateCertificatesModalProps) => import("react/jsx-runtime").JSX.Element;
9
+ export default GenerateCertificatesModal;
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { ActionRow, Button, Form, ModalDialog } from '@openedx/paragon';
4
+ import { useIntl } from '@openedx/frontend-base';
5
+ import messages from '../../certificates/messages';
6
+ const GenerateCertificatesModal = ({ isOpen, onClose, onConfirm, isSubmitting, learnerCount, }) => {
7
+ const intl = useIntl();
8
+ const [selectedOption, setSelectedOption] = useState('all');
9
+ const handleConfirm = () => {
10
+ onConfirm(selectedOption === 'without_certificate');
11
+ };
12
+ const handleClose = () => {
13
+ setSelectedOption('all');
14
+ onClose();
15
+ };
16
+ return (_jsxs(ModalDialog, { title: intl.formatMessage(messages.generateModalTitle), onClose: handleClose, isOpen: isOpen, size: "md", hasCloseButton: false, isOverflowVisible: false, children: [_jsxs("div", { className: "mx-4 mt-4 mb-3", children: [_jsx("p", { className: "mb-3", children: intl.formatMessage(messages.generateModalDescription, { number: learnerCount }) }), _jsx(Form.Group, { children: _jsxs(Form.RadioSet, { name: "generate-option", onChange: (e) => setSelectedOption(e.target.value), value: selectedOption, children: [_jsx(Form.Radio, { value: "all", children: intl.formatMessage(messages.generateOptionAll) }), _jsx(Form.Radio, { value: "without_certificate", children: intl.formatMessage(messages.generateOptionWithoutCertificate) })] }) })] }), _jsx(ModalDialog.Footer, { children: _jsxs(ActionRow, { children: [_jsx(Button, { variant: "tertiary", onClick: handleClose, disabled: isSubmitting, children: intl.formatMessage(messages.cancel) }), _jsx(Button, { variant: "primary", onClick: handleConfirm, disabled: isSubmitting, children: intl.formatMessage(messages.generate) })] }) })] }));
17
+ };
18
+ export default GenerateCertificatesModal;
19
+ //# sourceMappingURL=GenerateCertificatesModal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GenerateCertificatesModal.js","sourceRoot":"","sources":["../../../src/certificates/components/GenerateCertificatesModal.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAUlD,MAAM,yBAAyB,GAAG,CAAC,EACjC,MAAM,EACN,OAAO,EACP,SAAS,EACT,YAAY,EACZ,YAAY,GACmB,EAAE,EAAE;IACnC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAgC,KAAK,CAAC,CAAC;IAE3F,MAAM,aAAa,GAAG,GAAG,EAAE;QACzB,SAAS,CAAC,cAAc,KAAK,qBAAqB,CAAC,CAAC;IACtD,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;IAEF,OAAO,CACL,MAAC,WAAW,IACV,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EACtD,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,EACd,IAAI,EAAC,IAAI,EACT,cAAc,EAAE,KAAK,EACrB,iBAAiB,EAAE,KAAK,aAExB,eAAK,SAAS,EAAC,gBAAgB,aAC7B,YAAG,SAAS,EAAC,MAAM,YAChB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,GAC9E,EACJ,KAAC,IAAI,CAAC,KAAK,cACT,MAAC,IAAI,CAAC,QAAQ,IACZ,IAAI,EAAC,iBAAiB,EACtB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAsC,CAAC,EACnF,KAAK,EAAE,cAAc,aAErB,KAAC,IAAI,CAAC,KAAK,IAAC,KAAK,EAAC,KAAK,YACpB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC,GACpC,EACb,KAAC,IAAI,CAAC,KAAK,IAAC,KAAK,EAAC,qBAAqB,YACpC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,gCAAgC,CAAC,GACnD,IACC,GACL,IACT,EACN,KAAC,WAAW,CAAC,MAAM,cACjB,MAAC,SAAS,eACR,KAAC,MAAM,IAAC,OAAO,EAAC,UAAU,EAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,YACpE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,GAC7B,EACT,KAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,YACrE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAC/B,IACC,GACO,IACT,CACf,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,yBAAyB,CAAC","sourcesContent":["import { useState } from 'react';\nimport { ActionRow, Button, Form, ModalDialog } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport messages from '@src/certificates/messages';\n\ninterface GenerateCertificatesModalProps {\n isOpen: boolean,\n onClose: () => void,\n onConfirm: (onlyWithoutCertificate: boolean) => void,\n isSubmitting: boolean,\n learnerCount: number,\n}\n\nconst GenerateCertificatesModal = ({\n isOpen,\n onClose,\n onConfirm,\n isSubmitting,\n learnerCount,\n}: GenerateCertificatesModalProps) => {\n const intl = useIntl();\n const [selectedOption, setSelectedOption] = useState<'all' | 'without_certificate'>('all');\n\n const handleConfirm = () => {\n onConfirm(selectedOption === 'without_certificate');\n };\n\n const handleClose = () => {\n setSelectedOption('all');\n onClose();\n };\n\n return (\n <ModalDialog\n title={intl.formatMessage(messages.generateModalTitle)}\n onClose={handleClose}\n isOpen={isOpen}\n size=\"md\"\n hasCloseButton={false}\n isOverflowVisible={false}\n >\n <div className=\"mx-4 mt-4 mb-3\">\n <p className=\"mb-3\">\n {intl.formatMessage(messages.generateModalDescription, { number: learnerCount })}\n </p>\n <Form.Group>\n <Form.RadioSet\n name=\"generate-option\"\n onChange={(e) => setSelectedOption(e.target.value as 'all' | 'without_certificate')}\n value={selectedOption}\n >\n <Form.Radio value=\"all\">\n {intl.formatMessage(messages.generateOptionAll)}\n </Form.Radio>\n <Form.Radio value=\"without_certificate\">\n {intl.formatMessage(messages.generateOptionWithoutCertificate)}\n </Form.Radio>\n </Form.RadioSet>\n </Form.Group>\n </div>\n <ModalDialog.Footer>\n <ActionRow>\n <Button variant=\"tertiary\" onClick={handleClose} disabled={isSubmitting}>\n {intl.formatMessage(messages.cancel)}\n </Button>\n <Button variant=\"primary\" onClick={handleConfirm} disabled={isSubmitting}>\n {intl.formatMessage(messages.generate)}\n </Button>\n </ActionRow>\n </ModalDialog.Footer>\n </ModalDialog>\n );\n};\n\nexport default GenerateCertificatesModal;\n"]}
@@ -0,0 +1,11 @@
1
+ import { CertificateFilter } from '../../certificates/types';
2
+ interface RegenerateCertificatesModalProps {
3
+ isOpen: boolean;
4
+ onClose: () => void;
5
+ onConfirm: () => void;
6
+ isSubmitting: boolean;
7
+ filter: CertificateFilter;
8
+ learnerCount: number;
9
+ }
10
+ declare const RegenerateCertificatesModal: ({ isOpen, onClose, onConfirm, isSubmitting, filter, learnerCount, }: RegenerateCertificatesModalProps) => import("react/jsx-runtime").JSX.Element;
11
+ export default RegenerateCertificatesModal;
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ActionRow, Button, ModalDialog } from '@openedx/paragon';
3
+ import { useIntl } from '@openedx/frontend-base';
4
+ import { useMemo } from 'react';
5
+ import { CertificateFilter } from '../../certificates/types';
6
+ import messages from '../../certificates/messages';
7
+ const RegenerateCertificatesModal = ({ isOpen, onClose, onConfirm, isSubmitting, filter, learnerCount, }) => {
8
+ const intl = useIntl();
9
+ const { title, message } = useMemo(() => {
10
+ switch (filter) {
11
+ case CertificateFilter.RECEIVED:
12
+ return {
13
+ title: intl.formatMessage(messages.regenerateModalTitleReceived),
14
+ message: intl.formatMessage(messages.regenerateModalMessageReceived, { number: learnerCount }),
15
+ };
16
+ case CertificateFilter.NOT_RECEIVED:
17
+ return {
18
+ title: intl.formatMessage(messages.regenerateModalTitleNotReceived),
19
+ message: intl.formatMessage(messages.regenerateModalMessageNotReceived, { number: learnerCount }),
20
+ };
21
+ case CertificateFilter.AUDIT_PASSING:
22
+ return {
23
+ title: intl.formatMessage(messages.regenerateModalTitleAuditPassing),
24
+ message: intl.formatMessage(messages.regenerateModalMessageAuditPassing, { number: learnerCount }),
25
+ };
26
+ case CertificateFilter.AUDIT_NOT_PASSING:
27
+ return {
28
+ title: intl.formatMessage(messages.regenerateModalTitleAuditNotPassing),
29
+ message: intl.formatMessage(messages.regenerateModalMessageAuditNotPassing, { number: learnerCount }),
30
+ };
31
+ case CertificateFilter.ERROR_STATE:
32
+ return {
33
+ title: intl.formatMessage(messages.regenerateModalTitleErrorState),
34
+ message: intl.formatMessage(messages.regenerateModalMessageErrorState, { number: learnerCount }),
35
+ };
36
+ default:
37
+ return {
38
+ title: intl.formatMessage(messages.regenerateModalTitleDefault),
39
+ message: intl.formatMessage(messages.regenerateModalMessageDefault, { number: learnerCount }),
40
+ };
41
+ }
42
+ }, [filter, learnerCount, intl]);
43
+ return (_jsxs(ModalDialog, { title: title, onClose: onClose, isOpen: isOpen, size: "md", hasCloseButton: false, isOverflowVisible: false, children: [_jsx(ModalDialog.Body, { children: _jsx("p", { children: message }) }), _jsx(ModalDialog.Footer, { children: _jsxs(ActionRow, { children: [_jsx(Button, { variant: "tertiary", onClick: onClose, disabled: isSubmitting, children: intl.formatMessage(messages.cancel) }), _jsx(Button, { variant: "primary", onClick: onConfirm, disabled: isSubmitting, children: intl.formatMessage(messages.regenerate) })] }) })] }));
44
+ };
45
+ export default RegenerateCertificatesModal;
46
+ //# sourceMappingURL=RegenerateCertificatesModal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RegenerateCertificatesModal.js","sourceRoot":"","sources":["../../../src/certificates/components/RegenerateCertificatesModal.tsx"],"names":[],"mappings":"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","sourcesContent":["import { ActionRow, Button, ModalDialog } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport { useMemo } from 'react';\nimport { CertificateFilter } from '@src/certificates/types';\nimport messages from '@src/certificates/messages';\n\ninterface RegenerateCertificatesModalProps {\n isOpen: boolean,\n onClose: () => void,\n onConfirm: () => void,\n isSubmitting: boolean,\n filter: CertificateFilter,\n learnerCount: number,\n}\n\nconst RegenerateCertificatesModal = ({\n isOpen,\n onClose,\n onConfirm,\n isSubmitting,\n filter,\n learnerCount,\n}: RegenerateCertificatesModalProps) => {\n const intl = useIntl();\n\n const { title, message } = useMemo(() => {\n switch (filter) {\n case CertificateFilter.RECEIVED:\n return {\n title: intl.formatMessage(messages.regenerateModalTitleReceived),\n message: intl.formatMessage(messages.regenerateModalMessageReceived, { number: learnerCount }),\n };\n case CertificateFilter.NOT_RECEIVED:\n return {\n title: intl.formatMessage(messages.regenerateModalTitleNotReceived),\n message: intl.formatMessage(messages.regenerateModalMessageNotReceived, { number: learnerCount }),\n };\n case CertificateFilter.AUDIT_PASSING:\n return {\n title: intl.formatMessage(messages.regenerateModalTitleAuditPassing),\n message: intl.formatMessage(messages.regenerateModalMessageAuditPassing, { number: learnerCount }),\n };\n case CertificateFilter.AUDIT_NOT_PASSING:\n return {\n title: intl.formatMessage(messages.regenerateModalTitleAuditNotPassing),\n message: intl.formatMessage(messages.regenerateModalMessageAuditNotPassing, { number: learnerCount }),\n };\n case CertificateFilter.ERROR_STATE:\n return {\n title: intl.formatMessage(messages.regenerateModalTitleErrorState),\n message: intl.formatMessage(messages.regenerateModalMessageErrorState, { number: learnerCount }),\n };\n default:\n return {\n title: intl.formatMessage(messages.regenerateModalTitleDefault),\n message: intl.formatMessage(messages.regenerateModalMessageDefault, { number: learnerCount }),\n };\n }\n }, [filter, learnerCount, intl]);\n\n return (\n <ModalDialog\n title={title}\n onClose={onClose}\n isOpen={isOpen}\n size=\"md\"\n hasCloseButton={false}\n isOverflowVisible={false}\n >\n <ModalDialog.Body>\n <p>{message}</p>\n </ModalDialog.Body>\n <ModalDialog.Footer>\n <ActionRow>\n <Button variant=\"tertiary\" onClick={onClose} disabled={isSubmitting}>\n {intl.formatMessage(messages.cancel)}\n </Button>\n <Button variant=\"primary\" onClick={onConfirm} disabled={isSubmitting}>\n {intl.formatMessage(messages.regenerate)}\n </Button>\n </ActionRow>\n </ModalDialog.Footer>\n </ModalDialog>\n );\n};\n\nexport default RegenerateCertificatesModal;\n"]}
@@ -26,5 +26,5 @@ export declare const invalidateCertificate: (courseId: string, request: Invalida
26
26
  export declare const removeException: (courseId: string, request: RemoveExceptionRequest) => Promise<void>;
27
27
  export declare const removeInvalidation: (courseId: string, request: RemoveInvalidationRequest) => Promise<void>;
28
28
  export declare const toggleCertificateGeneration: (courseId: string, enable: boolean) => Promise<void>;
29
- export declare const regenerateCertificates: (courseId: string, filter: string) => Promise<void>;
29
+ export declare const regenerateCertificates: (courseId: string, filter: string, onlyWithoutCertificate?: boolean) => Promise<void>;
30
30
  export declare const getCertificateGenerationHistory: (courseId: string, params: PaginationParams) => Promise<DataList<CertificateGenerationHistory>>;
@@ -78,7 +78,7 @@ export const toggleCertificateGeneration = (courseId, enable) => __awaiter(void
78
78
  enabled: enable,
79
79
  });
80
80
  });
81
- export const regenerateCertificates = (courseId, filter) => __awaiter(void 0, void 0, void 0, function* () {
81
+ export const regenerateCertificates = (courseId, filter, onlyWithoutCertificate) => __awaiter(void 0, void 0, void 0, function* () {
82
82
  const body = {};
83
83
  // Map filter to backend parameters (must match backend filter logic)
84
84
  switch (filter) {
@@ -102,7 +102,8 @@ export const regenerateCertificates = (courseId, filter) => __awaiter(void 0, vo
102
102
  body.statuses = ['error'];
103
103
  break;
104
104
  case 'granted_exceptions':
105
- body.student_set = 'allowlisted';
105
+ // For granted exceptions, use different student_set based on option
106
+ body.student_set = onlyWithoutCertificate ? 'allowlisted_not_generated' : 'allowlisted';
106
107
  break;
107
108
  case 'invalidated':
108
109
  // Invalidated certificates have unavailable status