@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.
- package/dist/Main.js +2 -1
- package/dist/Main.js.map +1 -1
- package/dist/certificates/CertificatesPage.js +78 -6
- package/dist/certificates/CertificatesPage.js.map +1 -1
- package/dist/certificates/components/CertificatesToolbar.js +21 -20
- package/dist/certificates/components/CertificatesToolbar.js.map +1 -1
- package/dist/certificates/components/GenerateCertificatesModal.d.ts +9 -0
- package/dist/certificates/components/GenerateCertificatesModal.js +19 -0
- package/dist/certificates/components/GenerateCertificatesModal.js.map +1 -0
- package/dist/certificates/components/RegenerateCertificatesModal.d.ts +11 -0
- package/dist/certificates/components/RegenerateCertificatesModal.js +46 -0
- package/dist/certificates/components/RegenerateCertificatesModal.js.map +1 -0
- package/dist/certificates/data/api.d.ts +1 -1
- package/dist/certificates/data/api.js +3 -2
- package/dist/certificates/data/api.js.map +1 -1
- package/dist/certificates/data/apiHook.d.ts +4 -1
- package/dist/certificates/data/apiHook.js +1 -1
- package/dist/certificates/data/apiHook.js.map +1 -1
- package/dist/certificates/messages.d.ts +105 -0
- package/dist/certificates/messages.js +105 -0
- package/dist/certificates/messages.js.map +1 -1
- package/dist/certificates/utils/errorHandling.d.ts +3 -1
- package/dist/certificates/utils/errorHandling.js +22 -1
- package/dist/certificates/utils/errorHandling.js.map +1 -1
- package/dist/data/apiHook.js +1 -0
- package/dist/data/apiHook.js.map +1 -1
- package/dist/data/utils.d.ts +2 -0
- package/dist/data/utils.js +9 -0
- package/dist/data/utils.js.map +1 -0
- package/dist/instructorNav/InstructorNav.js +11 -4
- package/dist/instructorNav/InstructorNav.js.map +1 -1
- package/dist/pageWrapper/PageWrapper.js +3 -1
- package/dist/pageWrapper/PageWrapper.js.map +1 -1
- package/dist/providers/AccessErrorObserver.d.ts +9 -0
- package/dist/providers/AccessErrorObserver.js +35 -0
- package/dist/providers/AccessErrorObserver.js.map +1 -0
- package/dist/providers/AccessErrorProvider.d.ts +19 -0
- package/dist/providers/AccessErrorProvider.js +51 -0
- package/dist/providers/AccessErrorProvider.js.map +1 -0
- package/dist/providers/messages.d.ts +33 -0
- package/dist/providers/messages.js +35 -0
- package/dist/providers/messages.js.map +1 -0
- package/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,
|
|
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,
|
|
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
|
|
216
|
-
|
|
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:
|
|
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) }),
|
|
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":";AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,sBAAsB,MAAM,qDAAqD,CAAC;AACzF,OAAO,qBAAqB,MAAM,oDAAoD,CAAC;AACvF,OAAO,sBAAsB,MAAM,qDAAqD,CAAC;AACzF,OAAO,oBAAoB,MAAM,mDAAmD,CAAC;AACrF,OAAO,0BAA0B,MAAM,yDAAyD,CAAC;AACjG,OAAO,oBAAoB,MAAM,mDAAmD,CAAC;AACrF,OAAO,uBAAuB,MAAM,sDAAsD,CAAC;AAC3F,OAAO,wBAAwB,MAAM,uDAAuD,CAAC;AAC7F,OAAO,EACL,+BAA+B,EAC/B,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,EACrB,yBAAyB,EACzB,kBAAkB,EAClB,qBAAqB,EACrB,8BAA8B,EAC9B,0BAA0B,GAC3B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7G,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAClD,OAAO,yBAAyB,CAAC;AAEjC,MAAM,gBAAgB,GAAG,GAAG,EAAE;IAC5B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,EAAE,QAAQ,GAAG,EAAE,EAAE,GAAG,SAAS,EAAwB,CAAC;IAC5D,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC5C,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAErD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAoB,iBAAiB,CAAC,YAAY,CAAC,CAAC;IACxF,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzC,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7D,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,CAAC,8BAA8B,EAAE,iCAAiC,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE3F,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,CAAC,2BAA2B,EAAE,8BAA8B,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtF,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,CAAC,wBAAwB,EAAE,2BAA2B,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChF,MAAM,CAAC,yBAAyB,EAAE,4BAA4B,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAElF,MAAM,EACJ,IAAI,EAAE,gBAAgB,EACtB,SAAS,EAAE,qBAAqB,GACjC,GAAG,qBAAqB,CAAC,QAAQ,EAAE;QAClC,IAAI,EAAE,gBAAgB;QACtB,QAAQ,EAAE,sBAAsB;QAChC,MAAM;QACN,MAAM;KACP,CAAC,CAAC;IAEH,MAAM,EACJ,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,gBAAgB,GAC5B,GAAG,+BAA+B,CAAC,QAAQ,EAAE;QAC5C,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,sBAAsB;KACjC,CAAC,CAAC;IAEH,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IACtG,MAAM,EAAE,MAAM,EAAE,mBAAmB,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IACxG,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IACjG,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC9F,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,sBAAsB,EAAE,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACnG,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,8BAA8B,CAAC,QAAQ,CAAC,CAAC;IAC/G,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IAExE,MAAM,qBAAqB,GAAG,WAAW,CAAC,CAAC,QAAkB,EAAE,KAAa,EAAE,EAAE;QAC9E,eAAe,CACb,EAAE,QAAQ,EAAE,KAAK,EAAE,EACnB;YACE,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;gBAClB,wBAAwB,CAAC,KAAK,CAAC,CAAC;gBAChC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1C,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC1F,SAAS,CAAC;wBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;wBACnD,OAAO,EAAE,4BAA4B,aAAa,EAAE;wBACpD,OAAO,EAAE,cAAc,CAAC,OAAO;qBAChC,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC5C,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,sBAAsB,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBACjG,CAAC;YACH,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;oBACnD,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;oBACjF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,eAAe,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAElD,MAAM,yBAAyB,GAAG,WAAW,CAAC,CAAC,IAAU,EAAE,EAAE;QAC3D,mBAAmB,CACjB,IAAI,EACJ;YACE,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;gBAClB,wBAAwB,CAAC,KAAK,CAAC,CAAC;gBAChC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1C,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC1F,SAAS,CAAC;wBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;wBACnD,OAAO,EAAE,4BAA4B,aAAa,EAAE;wBACpD,OAAO,EAAE,cAAc,CAAC,OAAO;qBAChC,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC5C,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,sBAAsB,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBACjG,CAAC;YACH,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;oBACnD,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;oBACjF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,mBAAmB,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAEtD,MAAM,2BAA2B,GAAG,WAAW,CAAC,CAAC,QAAkB,EAAE,KAAa,EAAE,EAAE;QACpF,cAAc,CACZ,EAAE,QAAQ,EAAE,KAAK,EAAE,EACnB;YACE,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;gBAClB,8BAA8B,CAAC,KAAK,CAAC,CAAC;gBACtC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1C,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC1F,SAAS,CAAC;wBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;wBACnD,OAAO,EAAE,+BAA+B,aAAa,EAAE;wBACvD,OAAO,EAAE,cAAc,CAAC,OAAO;qBAChC,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC5C,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBACvG,CAAC;YACH,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;oBACnD,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAAC;oBACxF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAEjD,MAAM,0BAA0B,GAAG,WAAW,CAAC,CAAC,QAAgB,EAAE,KAAa,EAAE,EAAE;QACjF,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC9B,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACxB,wBAAwB,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,4BAA4B,GAAG,WAAW,CAAC,GAAG,EAAE;QACpD,wEAAwE;QACxE,MAAM,UAAU,GAAG,gBAAgB,IAAI,aAAa,CAAC;QAErD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,SAAS,CAAC;gBACR,KAAK,EAAE,YAAY,CAAC,KAAK;gBACzB,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,oBAAoB,CAAC,GAAG,iCAAiC;gBAC9F,OAAO,EAAE,cAAc,CAAC,MAAM;aAC/B,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,YAAY,CACV,EAAE,QAAQ,EAAE,UAAU,EAAE,EACxB;YACE,SAAS,EAAE,GAAG,EAAE;gBACd,wBAAwB,CAAC,KAAK,CAAC,CAAC;gBAChC,mBAAmB,CAAC,EAAE,CAAC,CAAC;gBACxB,gBAAgB,CAAC,EAAE,CAAC,CAAC;gBACrB,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;YAC1F,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;oBACnD,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;oBAClF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAEhF,MAAM,6BAA6B,GAAG,WAAW,CAAC,CAAC,QAAgB,EAAE,KAAa,EAAE,EAAE;QACpF,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC9B,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACxB,2BAA2B,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,+BAA+B,GAAG,WAAW,CAAC,GAAG,EAAE;QACvD,wEAAwE;QACxE,MAAM,UAAU,GAAG,gBAAgB,IAAI,aAAa,CAAC;QAErD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,SAAS,CAAC;gBACR,KAAK,EAAE,YAAY,CAAC,KAAK;gBACzB,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,uBAAuB,CAAC,GAAG,iCAAiC;gBACjG,OAAO,EAAE,cAAc,CAAC,MAAM;aAC/B,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,WAAW,CACT,EAAE,QAAQ,EAAE,UAAU,EAAE,EACxB;YACE,SAAS,EAAE,GAAG,EAAE;gBACd,2BAA2B,CAAC,KAAK,CAAC,CAAC;gBACnC,mBAAmB,CAAC,EAAE,CAAC,CAAC;gBACxB,gBAAgB,CAAC,EAAE,CAAC,CAAC;gBACrB,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;YAC7F,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;oBACnD,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC;oBACrF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAE/E,MAAM,iCAAiC,GAAG,WAAW,CAAC,GAAG,EAAE;QACzD,MAAM,QAAQ,GAAG,CAAC,8BAA8B,CAAC;QACjD,gBAAgB,CAAC,QAAQ,EAAE;YACzB,SAAS,EAAE,GAAG,EAAE;gBACd,iCAAiC,CAAC,QAAQ,CAAC,CAAC;gBAC5C,4BAA4B,CAAC,KAAK,CAAC,CAAC;gBACpC,SAAS,CACP,QAAQ;oBACN,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC;oBACxD,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAC5D,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,YAAY,CAAC,KAAK;oBACzB,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,gCAAgC,CAAC,CAAC;oBAC9F,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,8BAA8B,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAEnF,MAAM,4BAA4B,GAAG,WAAW,CAAC,GAAG,EAAE;QACpD,eAAe,CAAC,MAAM,EAAE;YACtB,SAAS,EAAE,GAAG,EAAE;gBACd,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC,CAAC;YACvE,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,YAAY,CAAC,KAAK;oBACzB,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CAAC;oBACzF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAE1D,8CAA8C;IAC9C,IAAI,UAAU,IAAI,CAAC,UAAU,CAAC,mBAAmB,EAAE,CAAC;QAClD,OAAO,CACL,KAAC,SAAS,IAAC,SAAS,EAAC,aAAa,EAAC,KAAK,kBACtC,KAAC,KAAK,IAAC,OAAO,EAAC,SAAS,YACrB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC,GACnD,GACE,CACb,CAAC;IACJ,CAAC;IAED,OAAO,CACL,MAAC,SAAS,IAAC,SAAS,EAAC,aAAa,EAAC,KAAK,mBACtC,KAAC,sBAAsB,IACrB,iBAAiB,EAAE,GAAG,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,EACvD,uBAAuB,EAAE,GAAG,EAAE,CAAC,8BAA8B,CAAC,IAAI,CAAC,EACnE,8BAA8B,EAAE,GAAG,EAAE,CAAC,4BAA4B,CAAC,IAAI,CAAC,GACxE,EAEF,KAAC,IAAI,IAAC,OAAO,EAAC,OAAO,EAAC,SAAS,EAAC,6CAA6C,YAC3E,MAAC,IAAI,IACH,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,EACvD,SAAS,EAAC,MAAM,EAChB,OAAO,EAAC,cAAc,aAEtB,KAAC,GAAG,IAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,qBAAqB,CAAC,YACvF,KAAC,qBAAqB,IACpB,IAAI,EAAE,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,OAAO,KAAI,EAAE,EACrC,SAAS,EAAE,qBAAqB,EAChC,SAAS,EAAE,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,KAAK,KAAI,CAAC,EACvC,SAAS,EAAE,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,QAAQ,KAAI,CAAC,EAC1C,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,SAAS,EACzB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,SAAS,EACzB,WAAW,EAAE,gBAAgB,EAC7B,YAAY,EAAE,mBAAmB,EACjC,iBAAiB,EAAE,0BAA0B,EAC7C,oBAAoB,EAAE,6BAA6B,EACnD,wBAAwB,EAAE,4BAA4B,GACtD,GACE,EACN,KAAC,GAAG,IAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,oBAAoB,CAAC,YACvF,cAAK,SAAS,EAAC,iCAAiC,YAC9C,KAAC,sBAAsB,IACrB,IAAI,EAAE,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,OAAO,KAAI,EAAE,EAChC,SAAS,EAAE,gBAAgB,EAC3B,SAAS,EAAE,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,KAAK,KAAI,CAAC,EAClC,SAAS,EAAE,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,QAAQ,KAAI,CAAC,EACrC,WAAW,EAAE,SAAS,EACtB,YAAY,EAAE,YAAY,GAC1B,GACE,GACF,IACD,GACF,EAEP,KAAC,oBAAoB,IACnB,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,GAAG,EAAE,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAC9C,QAAQ,EAAE,qBAAqB,EAC/B,WAAW,EAAE,yBAAyB,EACtC,YAAY,EAAE,oBAAoB,IAAI,cAAc,GACpD,EACF,KAAC,0BAA0B,IACzB,MAAM,EAAE,2BAA2B,EACnC,OAAO,EAAE,GAAG,EAAE,CAAC,8BAA8B,CAAC,KAAK,CAAC,EACpD,QAAQ,EAAE,2BAA2B,EACrC,YAAY,EAAE,cAAc,GAC5B,EACF,KAAC,oBAAoB,IACnB,MAAM,EAAE,qBAAqB,EAC7B,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,GAAG,EAAE;oBACZ,wBAAwB,CAAC,KAAK,CAAC,CAAC;oBAChC,mBAAmB,CAAC,EAAE,CAAC,CAAC;oBACxB,gBAAgB,CAAC,EAAE,CAAC,CAAC;gBACvB,CAAC,EACD,SAAS,EAAE,4BAA4B,EACvC,YAAY,EAAE,mBAAmB,GACjC,EACF,KAAC,uBAAuB,IACtB,MAAM,EAAE,wBAAwB,EAChC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,GAAG,EAAE;oBACZ,2BAA2B,CAAC,KAAK,CAAC,CAAC;oBACnC,mBAAmB,CAAC,EAAE,CAAC,CAAC;oBACxB,gBAAgB,CAAC,EAAE,CAAC,CAAC;gBACvB,CAAC,EACD,SAAS,EAAE,+BAA+B,EAC1C,YAAY,EAAE,sBAAsB,GACpC,EACF,KAAC,wBAAwB,IACvB,MAAM,EAAE,yBAAyB,EACjC,SAAS,EAAE,8BAA8B,EACzC,OAAO,EAAE,GAAG,EAAE,CAAC,4BAA4B,CAAC,KAAK,CAAC,EAClD,SAAS,EAAE,iCAAiC,EAC5C,YAAY,EAAE,oBAAoB,GAClC,IACQ,CACb,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC","sourcesContent":["import { useState, 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":";AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,sBAAsB,MAAM,qDAAqD,CAAC;AACzF,OAAO,qBAAqB,MAAM,oDAAoD,CAAC;AACvF,OAAO,sBAAsB,MAAM,qDAAqD,CAAC;AACzF,OAAO,oBAAoB,MAAM,mDAAmD,CAAC;AACrF,OAAO,0BAA0B,MAAM,yDAAyD,CAAC;AACjG,OAAO,oBAAoB,MAAM,mDAAmD,CAAC;AACrF,OAAO,uBAAuB,MAAM,sDAAsD,CAAC;AAC3F,OAAO,wBAAwB,MAAM,uDAAuD,CAAC;AAC7F,OAAO,2BAA2B,MAAM,0DAA0D,CAAC;AACnG,OAAO,yBAAyB,MAAM,wDAAwD,CAAC;AAC/F,OAAO,EACL,+BAA+B,EAC/B,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,EACrB,yBAAyB,EACzB,kBAAkB,EAClB,qBAAqB,EACrB,8BAA8B,EAC9B,0BAA0B,GAC3B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7G,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAClD,OAAO,yBAAyB,CAAC;AAEjC,MAAM,gBAAgB,GAAG,GAAG,EAAE;IAC5B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,EAAE,QAAQ,GAAG,EAAE,EAAE,GAAG,SAAS,EAAwB,CAAC;IAC5D,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC5C,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAErD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAoB,iBAAiB,CAAC,YAAY,CAAC,CAAC;IACxF,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzC,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAmD,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9G,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7D,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,CAAC,8BAA8B,EAAE,iCAAiC,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE3F,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,CAAC,2BAA2B,EAAE,8BAA8B,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtF,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,CAAC,wBAAwB,EAAE,2BAA2B,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChF,MAAM,CAAC,yBAAyB,EAAE,4BAA4B,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClF,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEtE,MAAM,EACJ,IAAI,EAAE,gBAAgB,EACtB,SAAS,EAAE,qBAAqB,GACjC,GAAG,qBAAqB,CAAC,QAAQ,EAAE;QAClC,IAAI,EAAE,gBAAgB;QACtB,QAAQ,EAAE,sBAAsB;QAChC,MAAM;QACN,MAAM;KACP,CAAC,CAAC;IAEH,MAAM,EACJ,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,gBAAgB,GAC5B,GAAG,+BAA+B,CAAC,QAAQ,EAAE;QAC5C,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,sBAAsB;KACjC,CAAC,CAAC;IAEH,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IACtG,MAAM,EAAE,MAAM,EAAE,mBAAmB,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IACxG,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IACjG,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC9F,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,sBAAsB,EAAE,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACnG,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,8BAA8B,CAAC,QAAQ,CAAC,CAAC;IAC/G,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IAExE,MAAM,qBAAqB,GAAG,WAAW,CAAC,CAAC,QAAkB,EAAE,KAAa,EAAE,EAAE;QAC9E,eAAe,CACb,EAAE,QAAQ,EAAE,KAAK,EAAE,EACnB;YACE,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;gBAClB,wBAAwB,CAAC,KAAK,CAAC,CAAC;gBAChC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1C,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC1F,SAAS,CAAC;wBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;wBACnD,OAAO,EAAE,4BAA4B,aAAa,EAAE;wBACpD,OAAO,EAAE,cAAc,CAAC,OAAO;qBAChC,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC5C,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,sBAAsB,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBACjG,CAAC;YACH,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;oBACnD,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;oBACjF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,eAAe,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAElD,MAAM,yBAAyB,GAAG,WAAW,CAAC,CAAC,IAAU,EAAE,EAAE;QAC3D,mBAAmB,CACjB,IAAI,EACJ;YACE,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;gBAClB,wBAAwB,CAAC,KAAK,CAAC,CAAC;gBAChC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1C,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC1F,SAAS,CAAC;wBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;wBACnD,OAAO,EAAE,4BAA4B,aAAa,EAAE;wBACpD,OAAO,EAAE,cAAc,CAAC,OAAO;qBAChC,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC5C,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,sBAAsB,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBACjG,CAAC;YACH,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;oBACnD,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;oBACjF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,mBAAmB,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAEtD,MAAM,2BAA2B,GAAG,WAAW,CAAC,CAAC,QAAkB,EAAE,KAAa,EAAE,EAAE;QACpF,cAAc,CACZ,EAAE,QAAQ,EAAE,KAAK,EAAE,EACnB;YACE,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;gBAClB,8BAA8B,CAAC,KAAK,CAAC,CAAC;gBACtC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1C,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC1F,SAAS,CAAC;wBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;wBACnD,OAAO,EAAE,+BAA+B,aAAa,EAAE;wBACvD,OAAO,EAAE,cAAc,CAAC,OAAO;qBAChC,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC5C,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBACvG,CAAC;YACH,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;oBACnD,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAAC;oBACxF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAEjD,MAAM,0BAA0B,GAAG,WAAW,CAAC,CAAC,QAAgB,EAAE,KAAa,EAAE,EAAE;QACjF,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC9B,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACxB,wBAAwB,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,4BAA4B,GAAG,WAAW,CAAC,GAAG,EAAE;QACpD,wEAAwE;QACxE,MAAM,UAAU,GAAG,gBAAgB,IAAI,aAAa,CAAC;QAErD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,SAAS,CAAC;gBACR,KAAK,EAAE,YAAY,CAAC,KAAK;gBACzB,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,oBAAoB,CAAC,GAAG,iCAAiC;gBAC9F,OAAO,EAAE,cAAc,CAAC,MAAM;aAC/B,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,YAAY,CACV,EAAE,QAAQ,EAAE,UAAU,EAAE,EACxB;YACE,SAAS,EAAE,GAAG,EAAE;gBACd,wBAAwB,CAAC,KAAK,CAAC,CAAC;gBAChC,mBAAmB,CAAC,EAAE,CAAC,CAAC;gBACxB,gBAAgB,CAAC,EAAE,CAAC,CAAC;gBACrB,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;YAC1F,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;oBACnD,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;oBAClF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAEhF,MAAM,6BAA6B,GAAG,WAAW,CAAC,CAAC,QAAgB,EAAE,KAAa,EAAE,EAAE;QACpF,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC9B,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACxB,2BAA2B,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,+BAA+B,GAAG,WAAW,CAAC,GAAG,EAAE;QACvD,wEAAwE;QACxE,MAAM,UAAU,GAAG,gBAAgB,IAAI,aAAa,CAAC;QAErD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,SAAS,CAAC;gBACR,KAAK,EAAE,YAAY,CAAC,KAAK;gBACzB,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,uBAAuB,CAAC,GAAG,iCAAiC;gBACjG,OAAO,EAAE,cAAc,CAAC,MAAM;aAC/B,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,WAAW,CACT,EAAE,QAAQ,EAAE,UAAU,EAAE,EACxB;YACE,SAAS,EAAE,GAAG,EAAE;gBACd,2BAA2B,CAAC,KAAK,CAAC,CAAC;gBACnC,mBAAmB,CAAC,EAAE,CAAC,CAAC;gBACxB,gBAAgB,CAAC,EAAE,CAAC,CAAC;gBACrB,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;YAC7F,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;oBACnD,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC;oBACrF,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAE/E,MAAM,iCAAiC,GAAG,WAAW,CAAC,GAAG,EAAE;QACzD,MAAM,QAAQ,GAAG,CAAC,8BAA8B,CAAC;QACjD,gBAAgB,CAAC,QAAQ,EAAE;YACzB,SAAS,EAAE,GAAG,EAAE;gBACd,iCAAiC,CAAC,QAAQ,CAAC,CAAC;gBAC5C,4BAA4B,CAAC,KAAK,CAAC,CAAC;gBACpC,SAAS,CACP,QAAQ;oBACN,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC;oBACxD,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAC5D,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,SAAS,CAAC;oBACR,KAAK,EAAE,YAAY,CAAC,KAAK;oBACzB,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,gCAAgC,CAAC,CAAC;oBAC9F,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,8BAA8B,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAEnF,MAAM,iCAAiC,GAAG,WAAW,CAAC,GAAG,EAAE;QACzD,wCAAwC;QACxC,IAAI,MAAM,KAAK,iBAAiB,CAAC,YAAY,IAAI,MAAM,KAAK,iBAAiB,CAAC,WAAW,EAAE,CAAC;YAC1F,OAAO;QACT,CAAC;QAED,kDAAkD;QAClD,IAAI,MAAM,KAAK,iBAAiB,CAAC,kBAAkB,EAAE,CAAC;YACpD,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,+CAA+C;YAC/C,wBAAwB,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,MAAM,mCAAmC,GAAG,WAAW,CAAC,GAAG,EAAE;QAC3D,eAAe,CAAC,EAAE,MAAM,EAAE,sBAAsB,EAAE,KAAK,EAAE,EAAE;YACzD,SAAS,EAAE,GAAG,EAAE;gBACd,wBAAwB,CAAC,KAAK,CAAC,CAAC;gBAChC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC,CAAC;YACvE,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,wBAAwB,CAAC,KAAK,CAAC,CAAC;gBAChC,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CAAC,CAAC;gBACtG,SAAS,CAAC;oBACR,KAAK,EAAE,YAAY,CAAC,KAAK;oBACzB,OAAO,EAAE,YAAY;oBACrB,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAE1D,MAAM,iCAAiC,GAAG,WAAW,CAAC,CAAC,sBAA+B,EAAE,EAAE;QACxF,eAAe,CAAC,EAAE,MAAM,EAAE,sBAAsB,EAAE,EAAE;YAClD,SAAS,EAAE,GAAG,EAAE;gBACd,sBAAsB,CAAC,KAAK,CAAC,CAAC;gBAC9B,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC,CAAC;YACvE,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjB,sBAAsB,CAAC,KAAK,CAAC,CAAC;gBAC9B,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CAAC,CAAC;gBACtG,SAAS,CAAC;oBACR,KAAK,EAAE,YAAY,CAAC,KAAK;oBACzB,OAAO,EAAE,YAAY;oBACrB,OAAO,EAAE,cAAc,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;SACF,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAE1D,MAAM,gBAAgB,GAAG,WAAW,CAAC,CAAC,KAA0B,EAAE,EAAE;QAClE,MAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAE7C,IAAI,SAAS,GAAG,YAAY,CAAC;QAE7B,QAAQ,KAAK,CAAC,GAAG,EAAE,CAAC;YAClB,KAAK,YAAY,CAAC;YAClB,KAAK,WAAW;gBACd,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,SAAS,GAAG,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;gBAC7C,MAAM;YACR,KAAK,WAAW,CAAC;YACjB,KAAK,SAAS;gBACZ,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,SAAS,GAAG,CAAC,YAAY,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;gBAC3D,MAAM;YACR,KAAK,MAAM;gBACT,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,SAAS,GAAG,CAAC,CAAC;gBACd,MAAM;YACR,KAAK,KAAK;gBACR,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC5B,MAAM;YACR;gBACE,OAAO;QACX,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;QAChC,YAAY,CAAC,OAAO,CAAC,CAAC;QAEtB,oBAAoB;QACpB,UAAU,CAAC,GAAG,EAAE;;YACd,MAAA,QAAQ,CAAC,cAAc,CAAC,oBAAoB,OAAO,EAAE,CAAC,0CAAE,KAAK,EAAE,CAAC;QAClE,CAAC,EAAE,CAAC,CAAC,CAAC;IACR,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAEhB,8CAA8C;IAC9C,IAAI,UAAU,IAAI,CAAC,UAAU,CAAC,mBAAmB,EAAE,CAAC;QAClD,OAAO,CACL,KAAC,SAAS,IAAC,SAAS,EAAC,aAAa,EAAC,KAAK,kBACtC,KAAC,KAAK,IAAC,OAAO,EAAC,SAAS,YACrB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC,GACnD,GACE,CACb,CAAC;IACJ,CAAC;IAED,OAAO,CACL,MAAC,SAAS,IAAC,SAAS,EAAC,aAAa,EAAC,KAAK,mBACtC,KAAC,sBAAsB,IACrB,iBAAiB,EAAE,GAAG,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,EACvD,uBAAuB,EAAE,GAAG,EAAE,CAAC,8BAA8B,CAAC,IAAI,CAAC,EACnE,8BAA8B,EAAE,GAAG,EAAE,CAAC,4BAA4B,CAAC,IAAI,CAAC,GACxE,EAEF,MAAC,IAAI,IAAC,OAAO,EAAC,OAAO,EAAC,SAAS,EAAC,6CAA6C,aAC3E,MAAC,WAAW,IAAC,SAAS,EAAC,cAAc,EAAC,IAAI,EAAC,SAAS,aAClD,KAAC,MAAM,IACL,EAAE,EAAC,yBAAyB,EAC5B,IAAI,EAAC,KAAK,mBACI,8BAA8B,mBAC7B,SAAS,KAAK,QAAQ,CAAC,MAAM,EAC5C,QAAQ,EAAE,SAAS,KAAK,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAChD,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,EAC5C,SAAS,EAAE,gBAAgB,EAC3B,OAAO,EAAE,SAAS,KAAK,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,YAErE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,qBAAqB,CAAC,GAC5C,EACT,KAAC,MAAM,IACL,EAAE,EAAC,0BAA0B,EAC7B,IAAI,EAAC,KAAK,mBACI,+BAA+B,mBAC9B,SAAS,KAAK,QAAQ,CAAC,OAAO,EAC7C,QAAQ,EAAE,SAAS,KAAK,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACjD,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,EAC7C,SAAS,EAAE,gBAAgB,EAC3B,OAAO,EAAE,SAAS,KAAK,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,YAEtE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,oBAAoB,CAAC,GAC3C,IACG,EACd,cACE,EAAE,EAAC,8BAA8B,EACjC,IAAI,EAAC,UAAU,qBACC,yBAAyB,EACzC,MAAM,EAAE,SAAS,KAAK,QAAQ,CAAC,MAAM,YAEpC,SAAS,KAAK,QAAQ,CAAC,MAAM,IAAI,CAChC,KAAC,qBAAqB,IACpB,IAAI,EAAE,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,OAAO,KAAI,EAAE,EACrC,SAAS,EAAE,qBAAqB,EAChC,SAAS,EAAE,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,KAAK,KAAI,CAAC,EACvC,SAAS,EAAE,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,QAAQ,KAAI,CAAC,EAC1C,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,SAAS,EACzB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,SAAS,EACzB,WAAW,EAAE,gBAAgB,EAC7B,YAAY,EAAE,mBAAmB,EACjC,iBAAiB,EAAE,0BAA0B,EAC7C,oBAAoB,EAAE,6BAA6B,EACnD,wBAAwB,EAAE,iCAAiC,GAC3D,CACH,GACG,EACN,cACE,EAAE,EAAC,+BAA+B,EAClC,IAAI,EAAC,UAAU,qBACC,0BAA0B,EAC1C,MAAM,EAAE,SAAS,KAAK,QAAQ,CAAC,OAAO,YAErC,SAAS,KAAK,QAAQ,CAAC,OAAO,IAAI,CACjC,cAAK,SAAS,EAAC,iCAAiC,YAC9C,KAAC,sBAAsB,IACrB,IAAI,EAAE,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,OAAO,KAAI,EAAE,EAChC,SAAS,EAAE,gBAAgB,EAC3B,SAAS,EAAE,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,KAAK,KAAI,CAAC,EAClC,SAAS,EAAE,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,QAAQ,KAAI,CAAC,EACrC,WAAW,EAAE,SAAS,EACtB,YAAY,EAAE,YAAY,GAC1B,GACE,CACP,GACG,IACD,EAEP,KAAC,oBAAoB,IACnB,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,GAAG,EAAE,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAC9C,QAAQ,EAAE,qBAAqB,EAC/B,WAAW,EAAE,yBAAyB,EACtC,YAAY,EAAE,oBAAoB,IAAI,cAAc,GACpD,EACF,KAAC,0BAA0B,IACzB,MAAM,EAAE,2BAA2B,EACnC,OAAO,EAAE,GAAG,EAAE,CAAC,8BAA8B,CAAC,KAAK,CAAC,EACpD,QAAQ,EAAE,2BAA2B,EACrC,YAAY,EAAE,cAAc,GAC5B,EACF,KAAC,oBAAoB,IACnB,MAAM,EAAE,qBAAqB,EAC7B,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,GAAG,EAAE;oBACZ,wBAAwB,CAAC,KAAK,CAAC,CAAC;oBAChC,mBAAmB,CAAC,EAAE,CAAC,CAAC;oBACxB,gBAAgB,CAAC,EAAE,CAAC,CAAC;gBACvB,CAAC,EACD,SAAS,EAAE,4BAA4B,EACvC,YAAY,EAAE,mBAAmB,GACjC,EACF,KAAC,uBAAuB,IACtB,MAAM,EAAE,wBAAwB,EAChC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,GAAG,EAAE;oBACZ,2BAA2B,CAAC,KAAK,CAAC,CAAC;oBACnC,mBAAmB,CAAC,EAAE,CAAC,CAAC;oBACxB,gBAAgB,CAAC,EAAE,CAAC,CAAC;gBACvB,CAAC,EACD,SAAS,EAAE,+BAA+B,EAC1C,YAAY,EAAE,sBAAsB,GACpC,EACF,KAAC,wBAAwB,IACvB,MAAM,EAAE,yBAAyB,EACjC,SAAS,EAAE,8BAA8B,EACzC,OAAO,EAAE,GAAG,EAAE,CAAC,4BAA4B,CAAC,KAAK,CAAC,EAClD,SAAS,EAAE,iCAAiC,EAC5C,YAAY,EAAE,oBAAoB,GAClC,EACF,KAAC,2BAA2B,IAC1B,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,GAAG,EAAE,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAC9C,SAAS,EAAE,mCAAmC,EAC9C,YAAY,EAAE,KAAK,EACnB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,KAAK,KAAI,CAAC,GAC1C,EACF,KAAC,yBAAyB,IACxB,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,GAAG,EAAE,CAAC,sBAAsB,CAAC,KAAK,CAAC,EAC5C,SAAS,EAAE,iCAAiC,EAC5C,YAAY,EAAE,KAAK,EACnB,YAAY,EAAE,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,KAAK,KAAI,CAAC,GAC1C,IACQ,CACb,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC","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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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;
|
|
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
|
-
|
|
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
|