Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change date picker to year input in renew ITA flow #2289

Merged
merged 1 commit into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/app/.server/domain/dtos/benefit-renewal.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type BenefitRenewalRequestDto = Readonly<{
}>;
partnerInformation?: Readonly<{
confirm: boolean;
dateOfBirth: string;
yearOfBirth: string;
socialInsuranceNumber: string;
}>;
maritalStatus: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,13 @@ function toRelatedPersons({ partnerInformation }: ToRelatedPersonArgs) {

interface ToRelatedPersonSpouseArgs {
confirm: boolean;
dateOfBirth: string;
yearOfBirth: string;
socialInsuranceNumber: string;
}

function toRelatedPersonSpouse({ confirm, dateOfBirth, socialInsuranceNumber }: ToRelatedPersonSpouseArgs) {
function toRelatedPersonSpouse({ confirm, yearOfBirth, socialInsuranceNumber }: ToRelatedPersonSpouseArgs) {
return {
PersonBirthDate: toDate(dateOfBirth),
PersonBirthDate: { date: yearOfBirth },
PersonRelationshipCode: {
ReferenceDataName: 'Spouse' as const,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,13 @@ function toRelatedPersons({ partnerInformation }: ToRelatedPersonArgs) {

interface ToRelatedPersonSpouseArgs {
confirm: boolean;
dateOfBirth: string;
yearOfBirth: string;
socialInsuranceNumber: string;
}

function toRelatedPersonSpouse({ confirm, dateOfBirth, socialInsuranceNumber }: ToRelatedPersonSpouseArgs) {
function toRelatedPersonSpouse({ confirm, yearOfBirth, socialInsuranceNumber }: ToRelatedPersonSpouseArgs) {
return {
PersonBirthDate: toDate(dateOfBirth),
PersonBirthDate: { date: yearOfBirth },
PersonRelationshipCode: {
ReferenceDataName: 'Spouse' as const,
},
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/route-helpers/renew-route-helpers.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface RenewState {
};
readonly partnerInformation?: {
confirm: boolean;
dateOfBirth: string;
yearOfBirth: string;
socialInsuranceNumber: string;
};
readonly maritalStatus?: string;
Expand Down
4 changes: 2 additions & 2 deletions frontend/app/routes/public/renew/$id/ita/confirmation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export async function loader({ context: { configProvider, serviceProvider, sessi

const spouseInfo = {
confirm: state.partnerInformation.confirm,
birthday: toLocaleDateString(parseDateString(state.partnerInformation.dateOfBirth), locale),
yearOfBirth: state.partnerInformation.yearOfBirth,
sin: state.partnerInformation.socialInsuranceNumber,
};

Expand Down Expand Up @@ -209,7 +209,7 @@ export default function RenewFlowConfirm() {
<DescriptionListItem term={t('confirm.sin')}>
<span className="text-nowrap">{formatSin(spouseInfo.sin)}</span>
</DescriptionListItem>
<DescriptionListItem term={t('confirm.dob')}>{spouseInfo.birthday}</DescriptionListItem>
<DescriptionListItem term={t('confirm.year-of-birth')}>{spouseInfo.yearOfBirth}</DescriptionListItem>
<DescriptionListItem term={t('confirm.consent')}>{t('confirm.consent-answer')}</DescriptionListItem>
</dl>
</section>
Expand Down
87 changes: 15 additions & 72 deletions frontend/app/routes/public/renew/$id/ita/marital-status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { z } from 'zod';

import pageIds from '../../../../page-ids.json';
import { Button, ButtonLink } from '~/components/buttons';
import { DatePickerField } from '~/components/date-picker-field';
import { useErrorSummary } from '~/components/error-summary';
import { InputCheckbox } from '~/components/input-checkbox';
import { InputPatternField } from '~/components/input-pattern-field';
Expand All @@ -22,7 +21,6 @@ import { Progress } from '~/components/progress';
import { loadRenewItaState } from '~/route-helpers/renew-ita-route-helpers.server';
import type { PartnerInformationState } from '~/route-helpers/renew-route-helpers.server';
import { renewStateHasPartner, saveRenewState } from '~/route-helpers/renew-route-helpers.server';
import { extractDateParts, getAgeFromDateString, isPastDateString, isValidDateString } from '~/utils/date-utils';
import { getEnv } from '~/utils/env-utils.server';
import { getTypedI18nNamespaces } from '~/utils/locale-utils';
import { getFixedT, getLocale } from '~/utils/locale-utils.server';
Expand Down Expand Up @@ -86,59 +84,23 @@ export async function action({ context: { session }, params, request }: ActionFu
.min(1, t('renew-ita:marital-status.error-message.marital-status-required')),
});

const partnerInformationSchema = z
.object({
confirm: z.boolean().refine((val) => val === true, t('renew-ita:marital-status.error-message.confirm-required')),
dateOfBirthYear: z.number({
required_error: t('renew-ita:marital-status.error-message.date-of-birth-year-required'),
invalid_type_error: t('renew-ita:marital-status.error-message.date-of-birth-year-number'),
}),
dateOfBirthMonth: z.number({
required_error: t('renew-ita:marital-status.error-message.date-of-birth-month-required'),
}),
dateOfBirthDay: z.number({
required_error: t('renew-ita:marital-status.error-message.date-of-birth-day-required'),
invalid_type_error: t('renew-ita:marital-status.error-message.date-of-birth-day-number'),
}),
dateOfBirth: z.string(),
socialInsuranceNumber: z
.string()
.trim()
.min(1, t('renew-ita:marital-status.error-message.sin-required'))
.refine(isValidSin, t('renew-ita:marital-status.error-message.sin-valid'))
.refine((sin) => isValidSin(sin) && formatSin(sin, '') !== state.partnerInformation?.socialInsuranceNumber, t('renew-ita:marital-status.error-message.sin-unique')),
})
.superRefine((val, ctx) => {
// At this point the year, month and day should have been validated as positive integer
const dateOfBirthParts = extractDateParts(`${val.dateOfBirthYear}-${val.dateOfBirthMonth}-${val.dateOfBirthDay}`);
const dateOfBirth = `${dateOfBirthParts.year}-${dateOfBirthParts.month}-${dateOfBirthParts.day}`;

if (!isValidDateString(dateOfBirth)) {
ctx.addIssue({ code: z.ZodIssueCode.custom, message: t('renew-ita:marital-status.error-message.date-of-birth-valid'), path: ['dateOfBirth'] });
} else if (!isPastDateString(dateOfBirth)) {
ctx.addIssue({ code: z.ZodIssueCode.custom, message: t('renew-ita:marital-status.error-message.date-of-birth-is-past'), path: ['dateOfBirth'] });
} else if (getAgeFromDateString(dateOfBirth) > 150) {
ctx.addIssue({ code: z.ZodIssueCode.custom, message: t('renew-ita:marital-status.error-message.date-of-birth-is-past-valid'), path: ['dateOfBirth'] });
}
})
.transform((val) => {
// At this point the year, month and day should have been validated as positive integer
const dateOfBirthParts = extractDateParts(`${val.dateOfBirthYear}-${val.dateOfBirthMonth}-${val.dateOfBirthDay}`);
return {
...val,
dateOfBirth: `${dateOfBirthParts.year}-${dateOfBirthParts.month}-${dateOfBirthParts.day}`,
};
}) satisfies z.ZodType<PartnerInformationState>;
const partnerInformationSchema = z.object({
confirm: z.boolean().refine((val) => val === true, t('renew-ita:marital-status.error-message.confirm-required')),
yearOfBirth: z.string().trim().min(1, t('renew-ita:marital-status.error-message.date-of-birth-year-required')),
socialInsuranceNumber: z
.string()
.trim()
.min(1, t('renew-ita:marital-status.error-message.sin-required'))
.refine(isValidSin, t('renew-ita:marital-status.error-message.sin-valid'))
.refine((sin) => isValidSin(sin) && formatSin(sin, '') !== state.partnerInformation?.socialInsuranceNumber, t('renew-ita:marital-status.error-message.sin-unique')),
}) satisfies z.ZodType<PartnerInformationState>;

const maritalStatusData = {
maritalStatus: formData.get('maritalStatus') ? String(formData.get('maritalStatus')) : undefined,
};
const partnerInformationData = {
confirm: formData.get('confirm') === 'yes',
dateOfBirthYear: formData.get('dateOfBirthYear') ? Number(formData.get('dateOfBirthYear')) : undefined,
dateOfBirthMonth: formData.get('dateOfBirthMonth') ? Number(formData.get('dateOfBirthMonth')) : undefined,
dateOfBirthDay: formData.get('dateOfBirthDay') ? Number(formData.get('dateOfBirthDay')) : undefined,
dateOfBirth: '',
yearOfBirth: String(formData.get('yearOfBirth') ?? ''),
socialInsuranceNumber: String(formData.get('socialInsuranceNumber') ?? ''),
};

Expand All @@ -149,7 +111,7 @@ export async function action({ context: { session }, params, request }: ActionFu
return json({
errors: {
...(parsedMaritalStatus.error ? transformFlattenedError(parsedMaritalStatus.error.flatten()) : {}),
...(parsedPartnerInformation.error ? transformFlattenedError(parsedPartnerInformation.error.flatten()) : {}),
...(parsedMaritalStatus.success && renewStateHasPartner(parsedMaritalStatus.data.maritalStatus) && parsedPartnerInformation.error ? transformFlattenedError(parsedPartnerInformation.error.flatten()) : {}),
},
});
}
Expand All @@ -164,7 +126,7 @@ export async function action({ context: { session }, params, request }: ActionFu
}

export default function RenewItaMaritalStatus() {
const { i18n, t } = useTranslation(handle.i18nNamespaces);
const { t } = useTranslation(handle.i18nNamespaces);
const { csrfToken, defaultState, editMode, maritalStatuses, MARITAL_STATUS_CODE_COMMONLAW, MARITAL_STATUS_CODE_MARRIED } = useLoaderData<typeof loader>();
const params = useParams();
const fetcher = useFetcher<typeof action>();
Expand All @@ -175,10 +137,7 @@ export default function RenewItaMaritalStatus() {
const errors = fetcher.data?.errors;
const errorSummary = useErrorSummary(errors, {
maritalStatus: 'input-radio-marital-status-option-0',
...(i18n.language === 'fr'
? { dateOfBirth: 'date-picker-date-of-birth-day', dateOfBirthDay: 'date-picker-date-of-birth-day', dateOfBirthMonth: 'date-picker-date-of-birth-month' }
: { dateOfBirth: 'date-picker-date-of-birth-month', dateOfBirthMonth: 'date-picker-date-of-birth-month', dateOfBirthDay: 'date-picker-date-of-birth-day' }),
dateOfBirthYear: 'date-picker-date-of-birth-year',
yearOfBirth: 'year-of-birth',
socialInsuranceNumber: 'social-insurance-number',
confirm: 'input-checkbox-confirm',
});
Expand Down Expand Up @@ -209,23 +168,7 @@ export default function RenewItaMaritalStatus() {
<h2 className="mb-6 font-lato text-2xl font-bold">{t('renew-ita:marital-status.spouse-or-commonlaw')}</h2>
<p className="mb-4">{t('renew-ita:marital-status.provide-sin')}</p>
<p className="mb-6">{t('renew-ita:marital-status.required-information')}</p>
<DatePickerField
id="date-of-birth"
names={{
day: 'dateOfBirthDay',
month: 'dateOfBirthMonth',
year: 'dateOfBirthYear',
}}
defaultValue={defaultState.dateOfBirth ?? ''}
legend={t('renew-ita:marital-status.date-of-birth')}
errorMessages={{
all: errors?.dateOfBirth,
year: errors?.dateOfBirthYear,
month: errors?.dateOfBirthMonth,
day: errors?.dateOfBirthDay,
}}
required
/>
<InputPatternField id="year-of-birth" name="yearOfBirth" inputMode="numeric" format="####" defaultValue={defaultState.yearOfBirth ?? ''} label={t('renew-ita:marital-status.year-of-birth')} errorMessage={errors?.yearOfBirth} required />
<InputPatternField
id="social-insurance-number"
name="socialInsuranceNumber"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export async function loader({ context: { configProvider, serviceProvider, sessi
};

const spouseInfo = state.partnerInformation && {
birthday: toLocaleDateString(parseDateString(state.partnerInformation.dateOfBirth), locale),
yearOfBirth: state.partnerInformation.yearOfBirth,
sin: state.partnerInformation.socialInsuranceNumber,
consent: state.partnerInformation.confirm,
};
Expand Down Expand Up @@ -272,8 +272,8 @@ export default function RenewItaReviewInformation() {
</InlineLink>
</div>
</DescriptionListItem>
<DescriptionListItem term={t('renew-ita:review-information.dob-title')}>
<p>{spouseInfo.birthday}</p>
<DescriptionListItem term={t('renew-ita:review-information.year-of-birth')}>
<p>{spouseInfo.yearOfBirth}</p>
<div className="mt-4">
<InlineLink id="change-spouse-date-of-birth" routeId="public/renew/$id/ita/marital-status" params={params}>
{t('renew-ita:review-information.dob-change')}
Expand Down
13 changes: 4 additions & 9 deletions frontend/public/locales/en/renew-ita.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"cancel-btn": "Cancel",
"save-btn": "Save",
"sin": "Social Insurance Number (SIN)",
"date-of-birth": "Date of birth",
"year-of-birth": "Year of birth",
"single-legal-name": "If your spouse or common-law partner has a single legal name",
"name-instructions": "If using a single legal name, please enter that name in BOTH the first name and last name fields.",
"confirm-checkbox": "I confirm that my spouse or common-law partner is aware and has agreed to share their personal information.",
Expand All @@ -46,14 +46,7 @@
"marital-status-required": "Select marital status",
"marital-status-no-partner-information": "If you are married or in a common-law relationship you must enter their information on the next page. Select your marital status and press 'Save'.",
"confirm-required": "Checkbox must be selected",
"date-of-birth-day-number": "Day must be a number",
"date-of-birth-day-required": "Date of birth must include a day",
"date-of-birth-is-past": "Date of birth must be in the past",
"date-of-birth-is-past-valid": "Date of birth too far in the past",
"date-of-birth-month-required": "Date of birth must include a month",
"date-of-birth-valid": "Day must be valid for the given month and year",
"date-of-birth-year-number": "Year must be a number, for example 1950",
"date-of-birth-year-required": "Date of birth must include a year",
"date-of-birth-year-required": "Year of birth is required",
"sin-required": "Enter 9-digit SIN, for example 123 456 789",
"sin-valid": "Must be a valid SIN",
"sin-unique": "The Social Insurance Number (SIN) must be unique",
Expand Down Expand Up @@ -213,6 +206,7 @@
"full-name-change": "Change full name",
"marital-title": "Marital status",
"marital-change": "Change marital status",
"year-of-birth": "Year of birth",
"spouse-title": "Spouse or common-law partner information",
"spouse-consent": {
"label": "Consent",
Expand Down Expand Up @@ -267,6 +261,7 @@
"applicant-summary": "Summary of updates",
"applicant-title": "Applicant",
"member-info": "Member information",
"year-of-birth": "Year of birth",
"spouse-info": "Spouse or common-law partner information",
"contact-info": "Contact information",
"dental-insurance": "Access to dental insurance",
Expand Down
13 changes: 4 additions & 9 deletions frontend/public/locales/fr/renew-ita.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"cancel-btn": "Cancel",
"save-btn": "Save",
"sin": "Social Insurance Number (SIN)",
"date-of-birth": "Date of birth",
"year-of-birth": "Year of birth",
"single-legal-name": "If your spouse or common-law partner has a single legal name",
"name-instructions": "If using a single legal name, please enter that name in BOTH the first name and last name fields.",
"confirm-checkbox": "I confirm that my spouse or common-law partner is aware and has agreed to share their personal information.",
Expand All @@ -47,14 +47,7 @@
"marital-status-required": "Select marital status",
"marital-status-no-partner-information": "If you are married or in a common-law relationship you must enter their information on the next page. Select your marital status and press 'Save'.",
"confirm-required": "Checkbox must be selected",
"date-of-birth-day-number": "Day must be a number",
"date-of-birth-day-required": "Date of birth must include a day",
"date-of-birth-is-past": "Date of birth must be in the past",
"date-of-birth-is-past-valid": "Date of birth too far in the past",
"date-of-birth-month-required": "Date of birth must include a month",
"date-of-birth-valid": "Day must be valid for the given month and year",
"date-of-birth-year-number": "Year must be a number, for example 1950",
"date-of-birth-year-required": "Date of birth must include a year",
"date-of-birth-year-required": "Year of birth is required",
"sin-required": "Enter 9-digit SIN, for example 123 456 789",
"sin-valid": "Must be a valid SIN",
"sin-unique": "The Social Insurance Number (SIN) must be unique",
Expand Down Expand Up @@ -213,6 +206,7 @@
"full-name-change": "Change full name",
"marital-title": "Marital status",
"marital-change": "Change marital status",
"year-of-birth": "Year of birth",
"spouse-title": "Spouse or common-law partner information",
"spouse-consent": {
"label": "Consent",
Expand Down Expand Up @@ -266,6 +260,7 @@
"register-msca-text": "(FR) Register for a My Service Canada (MSCA) account to view letters sent to you from the Government of Canada about your Canadian Dental Care Plan membership.",
"applicant-summary": "(FR) Summary of updates",
"applicant-title": "(FR) Applicant",
"year-of-birth": "(FR) Year of birth",
"member-info": "(FR) Member information",
"spouse-info": "(FR) Spouse or common-law partner information",
"contact-info": "(FR) Contact information",
Expand Down