From bf13ebdb9d941d0cf67c73fa557c19e9fa24fe27 Mon Sep 17 00:00:00 2001
From: faiza-jahanzeb <95882212+faiza-jahanzeb@users.noreply.github.com>
Date: Thu, 27 Feb 2025 10:56:33 -0500
Subject: [PATCH] review screen (#286)
---
.../app/.server/locales/protected-en.json | 7 +
.../app/.server/locales/protected-fr.json | 7 +
frontend/app/components/description-list.tsx | 20 ++
frontend/app/i18n-routes.ts | 8 +
.../routes/protected/person-case/review.tsx | 216 ++++++++++++++++++
5 files changed, 258 insertions(+)
create mode 100644 frontend/app/components/description-list.tsx
create mode 100644 frontend/app/routes/protected/person-case/review.tsx
diff --git a/frontend/app/.server/locales/protected-en.json b/frontend/app/.server/locales/protected-en.json
index e9863d56..b2063196 100644
--- a/frontend/app/.server/locales/protected-en.json
+++ b/frontend/app/.server/locales/protected-en.json
@@ -391,5 +391,12 @@
"required-city": "City, town, or village of birth is required.",
"invalid-city": "City, town, or village of birth is invalid."
}
+ },
+ "review": {
+ "page-title": "Review",
+ "read-carefully": "Review information below for accuracy before creating case.",
+ "document-uploaded": "Document uploaded",
+ "choosen-file": "File_chosen.pdf",
+ "edit-primary-identity-document": "Edit primary identity document"
}
}
diff --git a/frontend/app/.server/locales/protected-fr.json b/frontend/app/.server/locales/protected-fr.json
index b5104915..86b4dd54 100644
--- a/frontend/app/.server/locales/protected-fr.json
+++ b/frontend/app/.server/locales/protected-fr.json
@@ -392,5 +392,12 @@
"required-city": "La ville, la commune ou le village de naissance est requis.",
"invalid-city": "La ville, la commune ou le village de naissance est invalide."
}
+ },
+ "review": {
+ "page-title": "Review",
+ "read-carefully": "Veuillez examiner les informations ci-dessous pour en vérifier l'exactitude avant de créer le dossier.",
+ "document-uploaded": "Document téléchargé",
+ "choosen-file": "Fichier_choisi.pdf",
+ "edit-primary-identity-document": "Modifier le document d'identité principal"
}
}
diff --git a/frontend/app/components/description-list.tsx b/frontend/app/components/description-list.tsx
new file mode 100644
index 00000000..fc139242
--- /dev/null
+++ b/frontend/app/components/description-list.tsx
@@ -0,0 +1,20 @@
+import type { ComponentProps, ReactNode } from 'react';
+
+import { cn } from '~/utils/tailwind-utils';
+
+export interface DescriptionListItemProps extends ComponentProps<'div'> {
+ term: ReactNode;
+}
+export function DescriptionListItem({ className, children, term, ...rest }: DescriptionListItemProps) {
+ return (
+
+
{term}
+ {children}
+
+ );
+}
+
+export interface DescriptionListProps extends ComponentProps<'dl'> {}
+export function DescriptionList(props: DescriptionListProps) {
+ return
;
+}
diff --git a/frontend/app/i18n-routes.ts b/frontend/app/i18n-routes.ts
index 4ae3db3d..a7afb386 100644
--- a/frontend/app/i18n-routes.ts
+++ b/frontend/app/i18n-routes.ts
@@ -174,6 +174,14 @@ export const i18nRoutes = [
fr: '/fr/protege/cas-personnel/contact-information',
},
},
+ {
+ id: 'PROT-0014',
+ file: 'routes/protected/person-case/review.tsx',
+ paths: {
+ en: '/en/protected/person-case/review',
+ fr: '/fr/protege/cas-personnel/revision',
+ },
+ },
//
// XState-driven in-person flow (poc)
//
diff --git a/frontend/app/routes/protected/person-case/review.tsx b/frontend/app/routes/protected/person-case/review.tsx
new file mode 100644
index 00000000..a10f223c
--- /dev/null
+++ b/frontend/app/routes/protected/person-case/review.tsx
@@ -0,0 +1,216 @@
+import { useId } from 'react';
+
+import type { RouteHandle } from 'react-router';
+import { useFetcher } from 'react-router';
+
+import type { SessionData } from 'express-session';
+import { useTranslation } from 'react-i18next';
+
+import type { Info, Route } from './+types/review';
+
+import { requireAuth } from '~/.server/utils/auth-utils';
+import { i18nRedirect } from '~/.server/utils/route-utils';
+import { Button } from '~/components/button';
+import { ButtonLink } from '~/components/button-link';
+import { DescriptionList, DescriptionListItem } from '~/components/description-list';
+import { PageTitle } from '~/components/page-title';
+import { AppError } from '~/errors/app-error';
+import { ErrorCodes } from '~/errors/error-codes';
+import { getTranslation } from '~/i18n-config.server';
+import { handle as parentHandle } from '~/routes/protected/layout';
+
+export const handle = {
+ i18nNamespace: [...parentHandle.i18nNamespace, 'protected'],
+} as const satisfies RouteHandle;
+
+export async function loader({ context, request }: Route.LoaderArgs) {
+ requireAuth(context.session, new URL(request.url), ['user']);
+ const { t } = await getTranslation(request, handle.i18nNamespace);
+ const inPersonSINCase = validateInPersonSINCaseSession(context.session, request);
+ return { documentTitle: t('protected:review.page-title'), inPersonSINCase };
+}
+
+/**
+ *
+ * @param session
+ * @param request
+ * @returns
+ */
+function validateInPersonSINCaseSession(
+ session: AppSession,
+ request: Request,
+): Required> {
+ const inPersonSINCase = session.inPersonSINCase;
+
+ if (inPersonSINCase === undefined) {
+ throw i18nRedirect('routes/protected/person-case/privacy-statement.tsx', request);
+ }
+
+ const {
+ birthDetails,
+ contactInformation,
+ currentNameInfo,
+ parentDetails,
+ personalInformation,
+ previousSin,
+ primaryDocuments,
+ privacyStatement,
+ requestDetails,
+ secondaryDocument,
+ } = inPersonSINCase;
+
+ if (privacyStatement === undefined) {
+ throw i18nRedirect('routes/protected/index.tsx', request);
+ }
+
+ if (requestDetails === undefined) {
+ throw i18nRedirect('routes/protected/person-case/request-details.tsx', request);
+ }
+
+ if (primaryDocuments === undefined) {
+ throw i18nRedirect('routes/protected/person-case/primary-docs.tsx', request);
+ }
+
+ if (secondaryDocument === undefined) {
+ throw i18nRedirect('routes/protected/person-case/secondary-doc.tsx', request);
+ }
+
+ if (currentNameInfo === undefined) {
+ throw i18nRedirect('routes/protected/person-case/current-name.tsx', request);
+ }
+
+ if (personalInformation === undefined) {
+ throw i18nRedirect('routes/protected/person-case/personal-info.tsx', request);
+ }
+
+ if (birthDetails === undefined) {
+ throw i18nRedirect('routes/protected/person-case/birth-details.tsx', request);
+ }
+
+ if (parentDetails === undefined) {
+ throw i18nRedirect('routes/protected/person-case/parent-details.tsx', request);
+ }
+
+ if (previousSin === undefined) {
+ throw i18nRedirect('routes/protected/person-case/previous-sin.tsx', request);
+ }
+
+ if (contactInformation === undefined) {
+ throw i18nRedirect('routes/protected/person-case/contact-information.tsx', request);
+ }
+
+ return {
+ birthDetails,
+ contactInformation,
+ currentNameInfo,
+ parentDetails,
+ personalInformation,
+ previousSin,
+ primaryDocuments,
+ privacyStatement,
+ requestDetails,
+ secondaryDocument,
+ };
+}
+
+export function meta({ data }: Route.MetaArgs) {
+ return [{ title: data.documentTitle }];
+}
+
+export async function action({ context, request }: Route.ActionArgs) {
+ requireAuth(context.session, new URL(request.url), ['user']);
+ // const inPersonSINCase = validateInPersonSINCaseSession(context.session, request);
+
+ const formData = await request.formData();
+ const action = formData.get('action');
+
+ switch (action) {
+ case 'back': {
+ throw i18nRedirect('routes/protected/person-case/contact-information.tsx', request);
+ }
+
+ case 'next': {
+ throw i18nRedirect('routes/protected/index.tsx', request);
+ }
+ default: {
+ throw new AppError(`Unrecognized action: ${action}`, ErrorCodes.UNRECOGNIZED_ACTION);
+ }
+ }
+}
+
+export default function Review({ loaderData, actionData, params }: Route.ComponentProps) {
+ const { inPersonSINCase } = loaderData;
+ const { t } = useTranslation(handle.i18nNamespace);
+ const fetcherKey = useId();
+ const fetcher = useFetcher({ key: fetcherKey });
+ const isSubmitting = fetcher.state !== 'idle';
+
+ return (
+ <>
+ {t('protected:review.page-title')}
+
+
+ {t('protected:review.read-carefully')}
+
+
+ {t('protected:primary-identity-document.page-title')}
+
+
+
+ {/* TODO: Code Table Value */}
+ {t(
+ `protected:primary-identity-document.current-status-in-canada.options.${inPersonSINCase.primaryDocuments.currentStatusInCanada}` as 'protected:primary-identity-document.current-status-in-canada.options.select-option',
+ )}
+
+
+
+
+ {/* TODO: Code Table Value */}
+ {t(
+ `protected:primary-identity-document.document-type.options.${inPersonSINCase.primaryDocuments.documentType}` as 'protected:primary-identity-document.document-type.options.select-option',
+ )}
+
+
+
+ {inPersonSINCase.primaryDocuments.registrationNumber}
+
+
+ {inPersonSINCase.primaryDocuments.clientNumber}
+
+
+ {inPersonSINCase.primaryDocuments.givenName}
+
+
+ {inPersonSINCase.primaryDocuments.lastName}
+
+
+ {inPersonSINCase.primaryDocuments.dateOfBirth}
+
+
+ {inPersonSINCase.primaryDocuments.gender}
+
+
+ {inPersonSINCase.primaryDocuments.citizenshipDate}
+
+
+ {t('protected:review.choosen-file')}
+
+
+
+ {t('protected:review.edit-primary-identity-document')}
+
+
+
+
+
+
+
+
+
+ >
+ );
+}