diff --git a/app/src/components/layout/Layout.tsx b/app/src/components/layout/Layout.tsx
index 5408daa4a..752bf546b 100644
--- a/app/src/components/layout/Layout.tsx
+++ b/app/src/components/layout/Layout.tsx
@@ -1,8 +1,8 @@
import React from 'react';
import type { ReactNode } from 'react';
import Header from './header/Header';
-import { Footer } from 'nhsuk-react-components';
import PhaseBanner from './phaseBanner/PhaseBanner';
+import Footer from './footer/Footer';
type Props = {
children: ReactNode;
@@ -28,9 +28,7 @@ function Layout({ children }: Props) {
-
- © {'Crown copyright'}
-
+
);
}
diff --git a/app/src/components/layout/footer/Footer.test.tsx b/app/src/components/layout/footer/Footer.test.tsx
new file mode 100644
index 000000000..258b5728c
--- /dev/null
+++ b/app/src/components/layout/footer/Footer.test.tsx
@@ -0,0 +1,25 @@
+import { render, screen } from '@testing-library/react';
+import Footer from './Footer';
+import { routes } from '../../../types/generic/routes';
+
+describe('Footer', () => {
+ describe('Rendering', () => {
+ it('renders privacy policy link', () => {
+ render();
+ expect(screen.getByTestId('privacy-link')).toBeInTheDocument();
+ });
+ });
+
+ describe('Navigation', () => {
+ it('navigates to privacy policy when link is clicked', () => {
+ render();
+ expect(screen.getByTestId('privacy-link')).toBeInTheDocument();
+ expect(screen.getByTestId('privacy-link')).toHaveAttribute(
+ 'href',
+ routes.PRIVACY_POLICY,
+ );
+ expect(screen.getByTestId('privacy-link')).toHaveAttribute('rel', 'opener');
+ expect(screen.getByTestId('privacy-link')).toHaveAttribute('target', '_blank');
+ });
+ });
+});
diff --git a/app/src/components/layout/footer/Footer.tsx b/app/src/components/layout/footer/Footer.tsx
new file mode 100644
index 000000000..4bb537dc9
--- /dev/null
+++ b/app/src/components/layout/footer/Footer.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import { Footer as NHSFooter } from 'nhsuk-react-components';
+import { routes } from '../../../types/generic/routes';
+
+function Footer() {
+ return (
+
+
+
+ Privacy notice
+
+
+ © {'Crown copyright'}
+
+ );
+}
+
+export default Footer;
diff --git a/app/src/pages/privacyPage/PrivacyPage.test.tsx b/app/src/pages/privacyPage/PrivacyPage.test.tsx
new file mode 100644
index 000000000..610d23a2c
--- /dev/null
+++ b/app/src/pages/privacyPage/PrivacyPage.test.tsx
@@ -0,0 +1,114 @@
+import { LinkProps } from 'react-router-dom';
+import useRole from '../../helpers/hooks/useRole';
+import { render, screen, waitFor } from '@testing-library/react';
+import PrivacyPage from './PrivacyPage';
+import { REPOSITORY_ROLE } from '../../types/generic/authRole';
+import userEvent from '@testing-library/user-event';
+import { act } from 'react-dom/test-utils';
+import { routes } from '../../types/generic/routes';
+const mockedUseNavigate = jest.fn();
+jest.mock('../../helpers/hooks/useRole');
+const mockedUseRole = useRole as jest.Mock;
+jest.mock('react-router-dom', () => ({
+ __esModule: true,
+ Link: (props: LinkProps) => ,
+ useNavigate: () => mockedUseNavigate,
+}));
+
+describe('PrivacyPage', () => {
+ beforeEach(() => {
+ process.env.REACT_APP_ENVIRONMENT = 'jest';
+ mockedUseRole.mockReturnValue(null);
+ });
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('Rendering', () => {
+ it('renders page headers', () => {
+ render( );
+
+ const contentHeaders = [
+ 'Privacy notice',
+ 'What happens with my personal information?',
+ 'Feedback form privacy notice',
+ ];
+ contentHeaders.forEach((str) => {
+ expect(screen.getByRole('heading', { name: str })).toBeInTheDocument();
+ });
+ });
+
+ it('renders legal privacy content', () => {
+ render( );
+
+ const contentHeaders = [
+ /If you access the Lloyd George patient records digital service using your/i,
+ /credentials, your NHS Care Identity credentials are managed by NHS England/i,
+ /This means NHS England is the data controller for any personal information/i,
+ /that you provided to get NHS Care Identity credentials/i,
+ /NHS England uses this information only to verify your identity/i,
+ /When verifying your identity, our role is a "processor"/i,
+ /We must act under instructions provided by NHS England \(the "controller"\)/i,
+ /To find out more about NHS England's Privacy Notice/i,
+ /and its Terms and Conditions, view the/i,
+ /This only applies to information you provide through NHS England/i,
+ /When submitting your details using our/i,
+ /any personal information you give to us will be processed in accordance with the/i,
+ /We use the information you submitted to process your request and provide/i,
+ /relevant information or services you have requested/i,
+ /This will help support us in developing this service/i,
+ ];
+ contentHeaders.forEach((str) => {
+ expect(screen.getByText(str)).toBeInTheDocument();
+ });
+ });
+
+ it('renders public clickable links', () => {
+ render( );
+ expect(screen.getByTestId('cis2-link')).toHaveAttribute(
+ 'href',
+ 'https://am.nhsidentity.spineservices.nhs.uk/openam/XUI/?realm=/#/',
+ );
+ expect(screen.getByTestId('cis2-service-link')).toHaveAttribute(
+ 'href',
+ 'https://digital.nhs.uk/services/care-identity-service',
+ );
+ expect(screen.getByTestId('gdpr-link')).toHaveAttribute(
+ 'href',
+ 'https://digital.nhs.uk/data-and-information/keeping-data-safe-and-benefitting-the-public/gdpr#:~:text=The%20GDPR%20came%20into%20effect,in%20line%20with%20the%20regulations',
+ );
+ });
+
+ it('does not render a clickable link for feedback form if user logged out', () => {
+ mockedUseRole.mockReturnValue(null);
+ render( );
+ expect(screen.queryByTestId('feedback-link')).not.toHaveAttribute('href');
+ expect(screen.queryByTestId('feedback-link')).not.toHaveAttribute('to');
+ });
+
+ it('renders a clickable link for feedback form if user logged in', () => {
+ mockedUseRole.mockReturnValue(REPOSITORY_ROLE.GP_ADMIN);
+ render( );
+ expect(screen.queryByTestId('feedback-link')).not.toHaveAttribute('href');
+ expect(screen.getByTestId('feedback-link')).toHaveAttribute('to', '#');
+ });
+ describe('Navigation', () => {
+ it('navigates to feedback form when link is clicked and user is logged in', async () => {
+ mockedUseRole.mockReturnValue(REPOSITORY_ROLE.GP_ADMIN);
+ render( );
+ expect(screen.queryByTestId('feedback-link')).not.toHaveAttribute('href');
+ expect(screen.getByTestId('feedback-link')).toHaveAttribute('to', '#');
+ act(() => {
+ userEvent.click(
+ screen.getByRole('link', {
+ name: 'feedback form',
+ }),
+ );
+ });
+ await waitFor(() => {
+ expect(mockedUseNavigate).toHaveBeenCalledWith(routes.FEEDBACK);
+ });
+ });
+ });
+ });
+});
diff --git a/app/src/pages/privacyPage/PrivacyPage.tsx b/app/src/pages/privacyPage/PrivacyPage.tsx
new file mode 100644
index 000000000..eae0f9abf
--- /dev/null
+++ b/app/src/pages/privacyPage/PrivacyPage.tsx
@@ -0,0 +1,85 @@
+import React from 'react';
+import useRole from '../../helpers/hooks/useRole';
+import { routes } from '../../types/generic/routes';
+import { Link, useNavigate } from 'react-router-dom';
+
+function PrivacyPage() {
+ const isLoggedIn = !!useRole();
+ const navigate = useNavigate();
+ return (
+ <>
+
Privacy notice
+
+ If you access the Lloyd George patient records digital service using your{' '}
+
+ NHS Care Identity
+ {' '}
+ credentials, your NHS Care Identity credentials are managed by NHS England.
+
+
+ This means NHS England is the data controller for any personal information that you
+ provided to get NHS Care Identity credentials.
+
+ What happens with my personal information?
+ NHS England uses this information only to verify your identity.
+
+ When verifying your identity, our role is a "processor". We must act under
+ instructions provided by NHS England (the "controller").
+
+
+ To find out more about NHS England's Privacy Notice and its Terms and Conditions,
+ view the{' '}
+
+ NHS Care Identity Service
+ {' '}
+ .
+
+ This only applies to information you provide through NHS England.
+ Feedback form privacy notice
+
+ When submitting your details using our{' '}
+ {isLoggedIn ? (
+ {
+ e.preventDefault();
+ navigate(routes.FEEDBACK);
+ }}
+ >
+ feedback form
+
+ ) : (
+ feedback form
+ )}
+ , any personal information you give to us will be processed in accordance with the{' '}
+
+ UK General Data Protection Regulation (GDPR) 2018
+ {' '}
+ .
+
+
+ We use the information you submitted to process your request and provide relevant
+ information or services you have requested.
+
+ This will help support us in developing this service.
+ >
+ );
+}
+
+export default PrivacyPage;
diff --git a/app/src/router/AppRouter.tsx b/app/src/router/AppRouter.tsx
index cabc3102d..48b817559 100644
--- a/app/src/router/AppRouter.tsx
+++ b/app/src/router/AppRouter.tsx
@@ -21,6 +21,7 @@ import HomePage from '../pages/homePage/HomePage';
import UnauthorisedLoginPage from '../pages/unauthorisedLoginPage/UnauthorisedLoginPage';
import FeedbackPage from '../pages/feedbackPage/FeedbackPage';
import ServerErrorPage from '../pages/serverErrorPage/ServerErrorPage';
+import PrivacyPage from '../pages/privacyPage/PrivacyPage';
const {
START,
@@ -38,6 +39,7 @@ const {
SEARCH_PATIENT,
VERIFY_PATIENT,
UPLOAD_DOCUMENTS,
+ PRIVACY_POLICY,
} = routes;
type Routes = {
@@ -74,6 +76,11 @@ export const routeMap: Routes = {
page: ,
type: ROUTE_TYPE.PUBLIC,
},
+ [PRIVACY_POLICY]: {
+ page: ,
+ type: ROUTE_TYPE.PUBLIC,
+ },
+
// Auth guard routes
[LOGOUT]: {
page: ,
diff --git a/app/src/types/generic/routes.ts b/app/src/types/generic/routes.ts
index 8babed87a..2cea76a7c 100644
--- a/app/src/types/generic/routes.ts
+++ b/app/src/types/generic/routes.ts
@@ -9,6 +9,7 @@ export enum routes {
AUTH_ERROR = '/auth-error',
UNAUTHORISED_LOGIN = '/unauthorised-login',
SERVER_ERROR = '/server-error',
+ PRIVACY_POLICY = '/privacy-policy',
LOGOUT = '/logout',
FEEDBACK = '/feedback',
SEARCH_PATIENT = '/search/patient',