diff --git a/app/src/pages/adminPage/AdminPage.test.tsx b/app/src/pages/adminPage/AdminPage.test.tsx new file mode 100644 index 000000000..7043854a3 --- /dev/null +++ b/app/src/pages/adminPage/AdminPage.test.tsx @@ -0,0 +1,46 @@ +import { render, screen } from '@testing-library/react'; +import { AdminPage } from './AdminPage'; +import { runAxeTest } from '../../helpers/test/axeTestHelper'; +import { describe, expect, it, vi } from 'vitest'; +import { routeChildren } from '../../types/generic/routes'; + +vi.mock('../../../helpers/hooks/useTitle'); + +describe('AdminPage', (): void => { + describe('Rendering', (): void => { + it('renders the admin console heading', (): void => { + render(); + expect(screen.getByRole('heading', { name: 'Admin console' })).toBeInTheDocument(); + }); + + it('renders the Reviews card', (): void => { + render(); + const reviewsLink = screen.getByTestId('admin-reviews-btn'); + expect(reviewsLink).toBeInTheDocument(); + expect(reviewsLink).toHaveTextContent('Reviews'); + }); + + it('renders the Reviews card with correct href', (): void => { + render(); + const reviewsLink = screen.getByTestId('admin-reviews-btn'); + expect(reviewsLink).toHaveAttribute('href', routeChildren.ADMIN_REVIEW); + }); + + it('renders the Reviews card description', (): void => { + render(); + expect( + screen.getByText( + 'Review documents from practice to practice transfers and rejections from bulk transfer into this service.', + ), + ).toBeInTheDocument(); + }); + }); + + describe('Accessibility', (): void => { + it('passes accessibility checks', async (): Promise => { + render(); + const results = await runAxeTest(document.body); + expect(results).toHaveNoViolations(); + }); + }); +}); diff --git a/app/src/pages/adminPage/AdminPage.tsx b/app/src/pages/adminPage/AdminPage.tsx new file mode 100644 index 000000000..5a5fd365a --- /dev/null +++ b/app/src/pages/adminPage/AdminPage.tsx @@ -0,0 +1,37 @@ +import { Card } from 'nhsuk-react-components'; +import { JSX } from 'react'; +import useTitle from '../../helpers/hooks/useTitle'; +import { routeChildren } from '../../types/generic/routes'; +import { ReactComponent as RightCircleIcon } from '../../styles/right-chevron-circle.svg'; + +export const AdminPage = (): JSX.Element => { + useTitle({ pageTitle: 'Admin console' }); + + return ( + <> +

Admin console

+ + + {/* Reviews */} + + + + + Reviews + + + + Review documents from practice to practice transfers and rejections + from bulk transfer into this service. + + + + + + + + ); +}; diff --git a/app/src/pages/adminRoutesPage/AdminRoutesPage.tsx b/app/src/pages/adminRoutesPage/AdminRoutesPage.tsx new file mode 100644 index 000000000..7ab069038 --- /dev/null +++ b/app/src/pages/adminRoutesPage/AdminRoutesPage.tsx @@ -0,0 +1,14 @@ +import { JSX } from 'react'; +import { Routes, Route } from 'react-router'; +import { AdminPage } from '../adminPage/AdminPage'; +import { routeChildren } from '../../types/generic/routes'; +import { getLastURLPath } from '../../helpers/utils/urlManipulations'; + +export const AdminRoutesPage = (): JSX.Element => { + return ( + + } /> + } /> + + ); +}; diff --git a/app/src/pages/homePage/HomePage.test.tsx b/app/src/pages/homePage/HomePage.test.tsx index 37f7f7d93..f61c22c85 100644 --- a/app/src/pages/homePage/HomePage.test.tsx +++ b/app/src/pages/homePage/HomePage.test.tsx @@ -1,9 +1,8 @@ import { render, screen } from '@testing-library/react'; import HomePage from './HomePage'; -import useRole from '../../helpers/hooks/useRole'; -import { REPOSITORY_ROLE } from '../../types/generic/authRole'; import { buildConfig } from '../../helpers/test/testBuilders'; import useConfig from '../../helpers/hooks/useConfig'; +import { routes } from '../../types/generic/routes'; import { afterEach, beforeEach, describe, expect, it, vi, Mock } from 'vitest'; const mockedUseNavigate = vi.fn(); @@ -15,9 +14,7 @@ vi.mock('react-router-dom', async () => { }; }); -vi.mock('../../helpers/hooks/useRole'); vi.mock('../../helpers/hooks/useConfig'); -const mockUseRole = useRole as Mock; const mockUseConfig = useConfig as Mock; describe('HomePage', () => { @@ -27,33 +24,40 @@ describe('HomePage', () => { afterEach(() => { vi.clearAllMocks(); }); - const gpRoles = [REPOSITORY_ROLE.GP_ADMIN, REPOSITORY_ROLE.GP_CLINICAL]; - const validateHomePageRendered = () => { - render(); + describe('Rendering', () => { + it('should render home page with patient search and download report', async () => { + render(); - const searchPatientButton = screen.getByTestId('search-patient-btn') as HTMLAnchorElement; - const downloadReportButton = screen.getByTestId('download-report-btn') as HTMLAnchorElement; - expect(searchPatientButton).toBeInTheDocument(); - expect(downloadReportButton).toBeInTheDocument(); - }; + const searchPatientButton = screen.getByTestId('search-patient-btn') as HTMLAnchorElement; + const downloadReportButton = screen.getByTestId('download-report-btn') as HTMLAnchorElement; + expect(searchPatientButton).toBeInTheDocument(); + expect(downloadReportButton).toBeInTheDocument(); + }); + }); - describe('Rendering for GP roles', () => { - it.each(gpRoles)( - '[%s] render home page with patient search and download report', - async (role) => { - mockUseRole.mockReturnValue(role); + describe('Admin Console button', () => { + it('renders admin console button when feature flag is enabled', () => { + mockUseConfig.mockReturnValue( + buildConfig(undefined, { uploadDocumentIteration3Enabled: true }), + ); - validateHomePageRendered(); - }, - ); - }); + render(); - describe('PCSE Rendering', () => { - it('should render home page with patient search and download report', async () => { - mockUseRole.mockReturnValue(REPOSITORY_ROLE.PCSE); + const adminConsoleButton = screen.getByTestId('admin-console-btn') as HTMLAnchorElement; + expect(adminConsoleButton).toBeInTheDocument(); + expect(adminConsoleButton).toHaveTextContent('Admin console'); + expect(adminConsoleButton).toHaveAttribute('href', routes.ADMIN_ROUTE); + }); + + it('does not render admin console button when feature flag is disabled', () => { + mockUseConfig.mockReturnValue( + buildConfig(undefined, { uploadDocumentIteration3Enabled: false }), + ); + + render(); - validateHomePageRendered(); + expect(screen.queryByTestId('admin-console-btn')).not.toBeInTheDocument(); }); }); }); diff --git a/app/src/pages/homePage/HomePage.tsx b/app/src/pages/homePage/HomePage.tsx index a6568909d..9418decd7 100644 --- a/app/src/pages/homePage/HomePage.tsx +++ b/app/src/pages/homePage/HomePage.tsx @@ -74,6 +74,26 @@ const HomePage = (): React.JSX.Element => { + {config.featureFlags.uploadDocumentIteration3Enabled && + + + + + + Admin console + + + + Review records and actions for incoming patients + + + + + + } ); diff --git a/app/src/router/AppRouter.tsx b/app/src/router/AppRouter.tsx index 4e0e73adc..aa9e261ed 100644 --- a/app/src/router/AppRouter.tsx +++ b/app/src/router/AppRouter.tsx @@ -27,6 +27,7 @@ import NonAuthGuard from './guards/notAuthGuard/NonAuthGuard'; import PatientAccessAuditPage from '../pages/patientAccessAuditPage/PatientAccessAuditPage'; import MockLoginPage from '../pages/mockLoginPage/MockLoginPage'; import DocumentUploadPage from '../pages/documentUploadPage/DocumentUploadPage'; +import { AdminRoutesPage } from '../pages/adminRoutesPage/AdminRoutesPage'; const { START, @@ -55,6 +56,8 @@ const { MOCK_LOGIN, DOCUMENT_UPLOAD, DOCUMENT_UPLOAD_WILDCARD, + ADMIN_ROUTE, + ADMIN_ROUTE_WILDCARD, } = routes; type Routes = { @@ -146,6 +149,10 @@ export const childRoutes = [ route: routeChildren.DOCUMENT_UPLOAD_FILE_ERRORS, parent: DOCUMENT_UPLOAD, }, + { + route: routeChildren.ADMIN_REVIEW, + parent: ADMIN_ROUTE, + }, ]; export const routeMap: Routes = { @@ -227,6 +234,14 @@ export const routeMap: Routes = { page: , type: ROUTE_TYPE.PRIVATE, }, + [ADMIN_ROUTE]: { + page: , + type: ROUTE_TYPE.PRIVATE, + }, + [ADMIN_ROUTE_WILDCARD]: { + page: , + type: ROUTE_TYPE.PRIVATE, + }, // App guard routes [VERIFY_PATIENT]: { diff --git a/app/src/types/generic/routes.ts b/app/src/types/generic/routes.ts index 157916363..efcc05ee3 100644 --- a/app/src/types/generic/routes.ts +++ b/app/src/types/generic/routes.ts @@ -29,6 +29,9 @@ export enum routes { DOCUMENT_UPLOAD_WILDCARD = '/patient/document-upload/*', MOCK_LOGIN = 'Auth/MockLogin', + + ADMIN_ROUTE = '/admin', + ADMIN_ROUTE_WILDCARD = '/admin/*', } export enum routeChildren { @@ -55,6 +58,8 @@ export enum routeChildren { DOCUMENT_DELETE = '/patient/documents/delete', DOCUMENT_DELETE_CONFIRMATION = '/patient/documents/delete/confirmation', DOCUMENT_DELETE_COMPLETE = '/patient/documents/delete/complete', + + ADMIN_REVIEW = '/admin/reviews', } export enum ROUTE_TYPE {