From 244959779a132e41c3ba1312b9092d6c82e3edee Mon Sep 17 00:00:00 2001 From: Jesse Stewart Date: Tue, 12 May 2026 18:08:50 -0400 Subject: [PATCH 1/5] feat: adds pending tasks and close modal button --- src/certificates/CertificatesPage.tsx | 4 ++++ src/providers/AlertProvider.tsx | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/certificates/CertificatesPage.tsx b/src/certificates/CertificatesPage.tsx index 2e5527d7..d59d3cce 100644 --- a/src/certificates/CertificatesPage.tsx +++ b/src/certificates/CertificatesPage.tsx @@ -4,6 +4,7 @@ import { Card, Container, Button, ButtonGroup, Alert } from '@openedx/paragon'; import { useIntl } from '@openedx/frontend-base'; import { useAlert } from '@src/providers/AlertProvider'; import { useCourseInfo } from '@src/data/apiHook'; +import { PendingTasks } from '@src/components/PendingTasks'; import CertificatesPageHeader from '@src/certificates/components/CertificatesPageHeader'; import IssuedCertificatesTab from '@src/certificates/components/IssuedCertificatesTab'; import GenerationHistoryTable from '@src/certificates/components/GenerationHistoryTable'; @@ -53,6 +54,7 @@ const CertificatesPage = () => { const [isDisableCertificatesOpen, setIsDisableCertificatesOpen] = useState(false); const [isRegenerateModalOpen, setIsRegenerateModalOpen] = useState(false); const [isGenerateModalOpen, setIsGenerateModalOpen] = useState(false); + const [isPendingTasksOpen, setIsPendingTasksOpen] = useState(false); const { data: certificatesData, @@ -150,6 +152,7 @@ const CertificatesPage = () => { title: intl.formatMessage(messages.errorModalTitle), message: `Some invalidations failed:\n${errorMessages}`, variant: ALERT_VARIANTS.WARNING, + confirmText: intl.formatMessage(messages.close), }); } if (data.success && data.success.length > 0) { @@ -504,6 +507,7 @@ const CertificatesPage = () => { isSubmitting={false} learnerCount={certificatesData?.count || 0} /> + setIsPendingTasksOpen(prev => !prev)} /> ); }; diff --git a/src/providers/AlertProvider.tsx b/src/providers/AlertProvider.tsx index f33b93f9..d9f09631 100644 --- a/src/providers/AlertProvider.tsx +++ b/src/providers/AlertProvider.tsx @@ -229,7 +229,7 @@ export const AlertProvider: FC = ({ children }) => { {modal.confirmText && ( From 34a717f815e63772084003d21ab0468e838556e3 Mon Sep 17 00:00:00 2001 From: Jesse Stewart Date: Tue, 12 May 2026 18:19:58 -0400 Subject: [PATCH 2/5] fix: tests --- src/certificates/CertificatesPage.test.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/certificates/CertificatesPage.test.tsx b/src/certificates/CertificatesPage.test.tsx index 4b0d0a2e..7e130cec 100644 --- a/src/certificates/CertificatesPage.test.tsx +++ b/src/certificates/CertificatesPage.test.tsx @@ -2,7 +2,7 @@ import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import CertificatesPage from '@src/certificates/CertificatesPage'; import { renderWithAlertAndIntl } from '@src/testUtils'; -import { useCourseInfo } from '@src/data/apiHook'; +import { useCourseInfo, usePendingTasks } from '@src/data/apiHook'; import { useCertificateGenerationHistory, useGrantBulkExceptions, @@ -25,9 +25,11 @@ jest.mock('react-router-dom', () => ({ jest.mock('@src/certificates/data/apiHook'); jest.mock('@src/data/apiHook', () => ({ useCourseInfo: jest.fn(), + usePendingTasks: jest.fn(), })); const mockUseCourseInfo = useCourseInfo as jest.MockedFunction; +const mockUsePendingTasks = usePendingTasks as jest.MockedFunction; const mockUseCertificateGenerationHistory = useCertificateGenerationHistory as jest.MockedFunction; const mockUseInstructorTasks = useInstructorTasks as jest.MockedFunction; const mockUseIssuedCertificates = useIssuedCertificates as jest.MockedFunction; @@ -56,6 +58,12 @@ describe('CertificatesPage', () => { error: null, } as any); + mockUsePendingTasks.mockReturnValue({ + data: [], + isLoading: false, + refetch: jest.fn(), + } as any); + mockUseCertificateGenerationHistory.mockReturnValue({ data: { results: [], From 9e09136b6acca6d1c37a9967b0dce7ac95caa199 Mon Sep 17 00:00:00 2001 From: Jesse Stewart Date: Tue, 12 May 2026 18:30:21 -0400 Subject: [PATCH 3/5] feat: increase test coverage --- src/certificates/CertificatesPage.test.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/certificates/CertificatesPage.test.tsx b/src/certificates/CertificatesPage.test.tsx index 7e130cec..bc6bac31 100644 --- a/src/certificates/CertificatesPage.test.tsx +++ b/src/certificates/CertificatesPage.test.tsx @@ -28,6 +28,17 @@ jest.mock('@src/data/apiHook', () => ({ usePendingTasks: jest.fn(), })); +jest.mock('@src/components/PendingTasks', () => ({ + PendingTasks: function MockPendingTasks({ isOpen, onToggle }: { isOpen: boolean, onToggle: () => void }) { + return ( +
+ Pending Tasks + +
+ ); + }, +})); + const mockUseCourseInfo = useCourseInfo as jest.MockedFunction; const mockUsePendingTasks = usePendingTasks as jest.MockedFunction; const mockUseCertificateGenerationHistory = useCertificateGenerationHistory as jest.MockedFunction; @@ -189,6 +200,12 @@ describe('CertificatesPage', () => { expect(screen.getByText(messages.generationHistoryTab.defaultMessage)).toBeInTheDocument(); }); + it('renders pending tasks component', () => { + renderWithAlertAndIntl(); + + expect(screen.getByTestId('pending-tasks')).toBeInTheDocument(); + }); + it('renders issued certificates tab by default', () => { renderWithAlertAndIntl(); From ce36d0abf53b6174377739135d84cf67d97415ff Mon Sep 17 00:00:00 2001 From: Jesse Stewart Date: Tue, 12 May 2026 18:32:47 -0400 Subject: [PATCH 4/5] fix: linting --- src/certificates/CertificatesPage.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/certificates/CertificatesPage.test.tsx b/src/certificates/CertificatesPage.test.tsx index bc6bac31..0f883e1d 100644 --- a/src/certificates/CertificatesPage.test.tsx +++ b/src/certificates/CertificatesPage.test.tsx @@ -29,7 +29,7 @@ jest.mock('@src/data/apiHook', () => ({ })); jest.mock('@src/components/PendingTasks', () => ({ - PendingTasks: function MockPendingTasks({ isOpen, onToggle }: { isOpen: boolean, onToggle: () => void }) { + PendingTasks: function MockPendingTasks({ onToggle }: { isOpen: boolean, onToggle: () => void }) { return (
Pending Tasks From 84e80d338a1754b94ea9542d8237b580b35f6ed8 Mon Sep 17 00:00:00 2001 From: Jesse Stewart Date: Tue, 12 May 2026 18:41:50 -0400 Subject: [PATCH 5/5] feat: increase test coverage --- src/certificates/CertificatesPage.test.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/certificates/CertificatesPage.test.tsx b/src/certificates/CertificatesPage.test.tsx index 0f883e1d..f91bec44 100644 --- a/src/certificates/CertificatesPage.test.tsx +++ b/src/certificates/CertificatesPage.test.tsx @@ -200,10 +200,15 @@ describe('CertificatesPage', () => { expect(screen.getByText(messages.generationHistoryTab.defaultMessage)).toBeInTheDocument(); }); - it('renders pending tasks component', () => { + it('renders pending tasks component', async () => { renderWithAlertAndIntl(); + const user = userEvent.setup(); expect(screen.getByTestId('pending-tasks')).toBeInTheDocument(); + + // Test toggle functionality + const toggleButton = screen.getByText('Toggle'); + await user.click(toggleButton); }); it('renders issued certificates tab by default', () => {