diff --git a/components/Button.tsx b/components/Button.tsx index ef62835e6..82e97def4 100644 --- a/components/Button.tsx +++ b/components/Button.tsx @@ -10,7 +10,7 @@ interface ButtonProps { iconEnd?: boolean href?: string type?: 'submit' | 'reset' | 'button' - onClick: MouseEventHandler + onClick?: MouseEventHandler disabled?: boolean className?: string attributes?: { [key: string]: string } @@ -27,7 +27,7 @@ const Button = ({ iconEnd, href = 'no ref', type, - onClick, + onClick = () => {}, disabled, className, attributes, diff --git a/graphql/mappers/decision-reviews.ts b/graphql/mappers/decision-reviews.ts index d6982bf2e..e2bfdeec1 100644 --- a/graphql/mappers/decision-reviews.ts +++ b/graphql/mappers/decision-reviews.ts @@ -49,7 +49,7 @@ const getCachedContent = () => { cache, getFreshValue: async () => { const response = await fetch( - `${process.env.AEM_GRAPHQL_ENDPOINT}getSchDecisionReviewsV1` + `${process.env.AEM_GRAPHQL_ENDPOINT}getSchDecisionReviewsV1`, ) if (!response.ok) return null return (await response.json()) as GetSchDecisionReviewsV1 @@ -58,17 +58,17 @@ const getCachedContent = () => { }) } -export async function getDecisionReviewsContent() { +export async function getDecisionReviewsContent(): Promise { const response = await getCachedContent() const askFragment = findFragmentByScId( response, - 'decision-review-ask-service-canada' + 'decision-review-ask-service-canada', ) const appealFragment = findFragmentByScId( response, - 'decision-review-appeal-to-sst' + 'decision-review-appeal-to-sst', ) const mappedDecisionReviews = { @@ -82,7 +82,7 @@ export async function getDecisionReviewsContent() { text: level.scTitleEn, id: level.scId, } - } + }, ), pageName: response?.data.schPageV1ByPath.item.scPageNameEn, heading: response?.data.schPageV1ByPath.item.scTitleEn, @@ -95,7 +95,7 @@ export async function getDecisionReviewsContent() { areaLabel: askFragment?.scFragments[0].scLinkTextAssistiveEn, link: buildLink( askFragment?.scFragments[0].schURLType, - askFragment?.scFragments[0].scDestinationURLEn + askFragment?.scFragments[0].scDestinationURLEn, ), betaPopUp: askFragment?.scFragments[0].schBetaPopUp, }, @@ -108,7 +108,7 @@ export async function getDecisionReviewsContent() { areaLabel: appealFragment?.scFragments[0].scLinkTextAssistiveEn, link: buildLink( appealFragment?.scFragments[0].schURLType, - appealFragment?.scFragments[0].scDestinationURLEn + appealFragment?.scFragments[0].scDestinationURLEn, ), betaPopUp: appealFragment?.scFragments[0].schBetaPopUp, }, @@ -125,7 +125,7 @@ export async function getDecisionReviewsContent() { text: level.scTitleFr, id: level.scId, } - } + }, ), pageName: response?.data.schPageV1ByPath.item.scPageNameFr, heading: response?.data.schPageV1ByPath.item.scTitleFr, @@ -138,7 +138,7 @@ export async function getDecisionReviewsContent() { areaLabel: askFragment?.scFragments[0].scLinkTextAssistiveFr, link: buildLink( askFragment?.scFragments[0].schURLType, - askFragment?.scFragments[0].scDestinationURLFr + askFragment?.scFragments[0].scDestinationURLFr, ), betaPopUp: askFragment?.scFragments[0].schBetaPopUp, }, @@ -151,7 +151,7 @@ export async function getDecisionReviewsContent() { areaLabel: appealFragment?.scFragments[0].scLinkTextAssistiveFr, link: buildLink( appealFragment?.scFragments[0].schURLType, - appealFragment?.scFragments[0].scDestinationURLFr + appealFragment?.scFragments[0].scDestinationURLFr, ), betaPopUp: appealFragment?.scFragments[0].schBetaPopUp, }, @@ -164,11 +164,48 @@ export async function getDecisionReviewsContent() { const findFragmentByScId = ( res: GetSchDecisionReviewsV1 | null, - id: string + id: string, ) => { return ( res?.data.schPageV1ByPath.item.scFragments.find( - ({ scId }) => scId === id + ({ scId }) => scId === id, ) ?? null ) } + +// TODO: Figure out which of these actually need to be optional +export interface DecisionReviewContent { + err?: string + en?: { + id: string + breadcrumb: { link: string; text: string; id: string }[] | undefined + pageName: string | undefined + heading: string | undefined + content: { + content: string | undefined + button: { + id: string | undefined + text: string | undefined + areaLabel: string | undefined + link: string | undefined + betaPopUp: boolean | undefined + } + }[] + } + fr?: { + id: string + breadcrumb: { link: string; text: string; id: string }[] | undefined + pageName: string | undefined + heading: string | undefined + content: { + content: string | undefined + button: { + id: string | undefined + text: string | undefined + areaLabel: string | undefined + link: string | undefined + betaPopUp: boolean | undefined + } + }[] + } +} diff --git a/graphql/mappers/security-settings.ts b/graphql/mappers/security-settings.ts index 82a2a3e47..231b9f237 100644 --- a/graphql/mappers/security-settings.ts +++ b/graphql/mappers/security-settings.ts @@ -96,7 +96,7 @@ const getCachedContent = () => { cache, getFreshValue: async () => { const response = await fetch( - `${process.env.AEM_GRAPHQL_ENDPOINT}getSchSecuritySettingsV1` + `${process.env.AEM_GRAPHQL_ENDPOINT}getSchSecuritySettingsV1`, ) if (!response.ok) return null return (await response.json()) as GetSchSecuritySettingsV1 @@ -105,7 +105,7 @@ const getCachedContent = () => { }) } -export async function getSecuritySettingsContent() { +export async function getSecuritySettingsContent(): Promise { const response = await getCachedContent() const enLookingForFragment = @@ -124,7 +124,7 @@ export async function getSecuritySettingsContent() { const securityQuestions = findFragmentByScId( response, - 'security-settings-main-content' + 'security-settings-main-content', )?.scFragments?.find(({ scId }) => scId === 'security-questions') ?? null const mappedSecurity = { @@ -136,7 +136,7 @@ export async function getSecuritySettingsContent() { link: level.scPageNameEn, text: level.scTitleEn, } - } + }, ), pageName: response?.data.schPageV1ByPath.item.scPageNameEn, heading: response?.data.schPageV1ByPath.item.scTitleEn, @@ -144,7 +144,7 @@ export async function getSecuritySettingsContent() { lookingFor: { title: enLookingForFragment?.json[0].content[0].value, subText: enLookingForFragment?.json[1].content.map( - ({ value }) => value ?? null + ({ value }) => value ?? null, ), link: '/profile', id: 'profile', @@ -154,7 +154,7 @@ export async function getSecuritySettingsContent() { text: securityQuestions?.scLinkTextEn, link: buildLink( securityQuestions?.schURLType, - securityQuestions?.scDestinationURLEn + securityQuestions?.scDestinationURLEn, ), }, subTitle: securityQuestions?.scDescriptionEn.json[0].content[0].value, @@ -168,7 +168,7 @@ export async function getSecuritySettingsContent() { link: level.scPageNameFr, text: level.scTitleFr, } - } + }, ), pageName: response?.data.schPageV1ByPath.item.scPageNameFr, heading: response?.data.schPageV1ByPath.item.scTitleFr, @@ -186,7 +186,7 @@ export async function getSecuritySettingsContent() { text: securityQuestions?.scLinkTextFr, link: buildLink( securityQuestions?.schURLType, - securityQuestions?.scDestinationURLFr + securityQuestions?.scDestinationURLFr, ), }, subTitle: securityQuestions?.scDescriptionFr.json[0].content[0].value, @@ -198,11 +198,48 @@ export async function getSecuritySettingsContent() { const findFragmentByScId = ( res: GetSchSecuritySettingsV1 | null, - id: string + id: string, ) => { return ( res?.data.schPageV1ByPath.item.scFragments.find( - ({ scId }) => scId === id + ({ scId }) => scId === id, ) ?? null ) } + +// TODO: Figure out which of these actually need to be optional +export interface SecuritySettingsContent { + err?: string + en?: { + breadcrumb: { link: string; text: string }[] | undefined + pageName: string | undefined + heading: string | undefined + subHeading: string | undefined + lookingFor: { + title: string | undefined + subText: (string | null)[] | undefined + link: string + id: string + } + securityQuestions: { + linkTitle: { text: string | undefined; link: string } + subTitle: string | undefined + } + } + fr?: { + breadcrumb: { link: string; text: string }[] | undefined + pageName: string | undefined + heading: string | undefined + subHeading: string | undefined + lookingFor: { + title: string | undefined + subText: (string | null)[] | undefined + link: string + id: string + } + securityQuestions: { + linkTitle: { text: string | undefined; link: string } + subTitle: string | undefined + } + } +} diff --git a/lib/acronym.js b/lib/acronym.ts similarity index 96% rename from lib/acronym.js rename to lib/acronym.ts index e0059f547..bfbd05e67 100644 --- a/lib/acronym.js +++ b/lib/acronym.ts @@ -1,7 +1,7 @@ // These acronyms are used to convert benefit categories into acronyms for AA. // For logistical reasons, acronyms should only be returned in English, regardless of language. -export const acronym = (longText) => { +export const acronym = (longText: string) => { switch (longText.toLowerCase()) { case 'assurance emploi': return 'EI' diff --git a/pages/decision-reviews.js b/pages/decision-reviews.tsx similarity index 74% rename from pages/decision-reviews.js rename to pages/decision-reviews.tsx index 1c28034c2..a27b7c77a 100644 --- a/pages/decision-reviews.js +++ b/pages/decision-reviews.tsx @@ -1,8 +1,9 @@ import PropTypes from 'prop-types' import Heading from '../components/Heading' -import en from '../locales/en' -import fr from '../locales/fr' -import { getDecisionReviewsContent } from '../graphql/mappers/decision-reviews' +import { + DecisionReviewContent, + getDecisionReviewsContent, +} from '../graphql/mappers/decision-reviews' import { getLogger } from '../logging/log-util' import { AuthIsDisabled, @@ -11,18 +12,41 @@ import { Redirect, getIdToken, } from '../lib/auth' -import { authOptions } from '../pages/api/auth/[...nextauth]' +import { authOptions } from './api/auth/[...nextauth]' import { getServerSession } from 'next-auth/next' -import { getAuthModalsContent } from '../graphql/mappers/auth-modals' +import { + AuthModalsContent, + getAuthModalsContent, +} from '../graphql/mappers/auth-modals' import Markdown from 'markdown-to-jsx' import ErrorPage from '../components/ErrorPage' import Button from '../components/Button' +import { GetServerSidePropsContext } from 'next' -export default function DecisionReviews(props) { - const t = props.locale === 'en' ? en : fr - +interface DecisionReviewProps { + locale: string | undefined + content: { + err?: '500' | '404' | '503' + heading: string + content: { + content: string + button: { + id: string + text: string + areaLabel: string | undefined + link: string + } + }[] + } + bannerContent?: { err?: '500' | '404' | '503' } + popupContent?: { err?: '500' | '404' | '503' } + popupContentNA?: { err?: '500' | '404' | '503' } + authModals?: { err?: '500' | '404' | '503' } + aaPrefix: string | undefined +} +export default function DecisionReviews(props: DecisionReviewProps) { const errorCode = - props.content?.err || + props.content.err || props.bannerContent?.err || props.popupContent?.err || props.popupContentNA?.err || @@ -114,7 +138,15 @@ export default function DecisionReviews(props) { ) } -export async function getServerSideProps({ req, res, locale }) { +export async function getServerSideProps({ + req, + res, + locale, +}: { + req: GetServerSidePropsContext['req'] + res: GetServerSidePropsContext['res'] + locale: string +}) { const session = await getServerSession(req, res, authOptions) if (!AuthIsDisabled() && !(await AuthIsValid(req, session))) @@ -154,25 +186,29 @@ export async function getServerSideProps({ req, res, locale }) { const logger = getLogger('decision-reviews') logger.level = 'error' - const content = await getDecisionReviewsContent().catch((error) => { - logger.error(error) - return { err: '500' } - }) + const content = await getDecisionReviewsContent().catch( + (error): DecisionReviewContent => { + logger.error(error) + return { err: '500' } + }, + ) - const authModals = await getAuthModalsContent().catch((error) => { - logger.error(error) - return { err: '500' } - }) + const authModals = await getAuthModalsContent().catch( + (error): AuthModalsContent => { + logger.error(error) + return { err: '500' } + }, + ) /* istanbul ignore next */ const langToggleLink = locale === 'en' ? '/fr/demande-revision' : '/en/decision-reviews' const breadCrumbItems = locale === 'en' - ? content.en.breadcrumb?.map(({ link, text }) => { + ? content.en?.breadcrumb?.map(({ link, text }) => { return { text, link: '/' + locale + '/' + link } }) - : content.fr.breadcrumb?.map(({ link, text }) => { + : content.fr?.breadcrumb?.map(({ link, text }) => { return { text, link: '/' + locale + '/' + link } }) /* Place-holder Meta Data Props */ @@ -202,7 +238,7 @@ export async function getServerSideProps({ req, res, locale }) { locale, langToggleLink, content: - content?.err !== undefined + content.err !== undefined ? content : locale === 'en' ? content.en @@ -210,23 +246,23 @@ export async function getServerSideProps({ req, res, locale }) { meta, breadCrumbItems, aaPrefix: - content?.err !== undefined + content.err !== undefined ? '' - : `ESDC-EDSC_MSCA-MSDC-SCH:${content.en?.heading || content.en?.title}`, + : `ESDC-EDSC_MSCA-MSDC-SCH:${content.en?.heading}`, aaMenuPrefix: - content?.err !== undefined ? '' : `ESDC-EDSC_MSCA-MSDC-SCH:Nav Menu`, + content.err !== undefined ? '' : `ESDC-EDSC_MSCA-MSDC-SCH:Nav Menu`, popupStaySignedIn: - authModals?.err !== undefined + authModals.err !== undefined ? authModals : locale === 'en' - ? authModals.mappedPopupStaySignedIn.en - : authModals.mappedPopupStaySignedIn.fr, + ? authModals.mappedPopupStaySignedIn?.en + : authModals.mappedPopupStaySignedIn?.fr, popupYouHaveBeenSignedout: - authModals?.err !== undefined + authModals.err !== undefined ? authModals : locale === 'en' - ? authModals.mappedPopupSignedOut.en - : authModals.mappedPopupSignedOut.fr, + ? authModals.mappedPopupSignedOut?.en + : authModals.mappedPopupSignedOut?.fr, }, } } diff --git a/pages/profile.tsx b/pages/profile.tsx index 74c28d61e..f9b49b0a3 100644 --- a/pages/profile.tsx +++ b/pages/profile.tsx @@ -177,15 +177,17 @@ export async function getServerSideProps({ const logger = getLogger('profile') logger.level = 'error' - const content = await getProfileContent().catch((error) => { + const content = await getProfileContent().catch((error): ProfileContent => { logger.error(error) - return { err: '500' } as ProfileContent + return { err: '500' } }) - const authModals = await getAuthModalsContent().catch((error) => { - logger.error(error) - return { err: '500' } as AuthModalsContent - }) + const authModals = await getAuthModalsContent().catch( + (error): AuthModalsContent => { + logger.error(error) + return { err: '500' } + }, + ) /* istanbul ignore next */ const langToggleLink = locale === 'en' ? '/fr/profil' : '/en/profile' diff --git a/pages/security-settings.js b/pages/security-settings.tsx similarity index 72% rename from pages/security-settings.js rename to pages/security-settings.tsx index 526b9f9c7..c6acf0c16 100644 --- a/pages/security-settings.js +++ b/pages/security-settings.tsx @@ -3,8 +3,14 @@ import Heading from '../components/Heading' import PageLink from '../components/PageLink' import en from '../locales/en' import fr from '../locales/fr' -import { getSecuritySettingsContent } from '../graphql/mappers/security-settings' -import { getAuthModalsContent } from '../graphql/mappers/auth-modals' +import { + getSecuritySettingsContent, + SecuritySettingsContent, +} from '../graphql/mappers/security-settings' +import { + AuthModalsContent, + getAuthModalsContent, +} from '../graphql/mappers/auth-modals' import { getLogger } from '../logging/log-util' import { AuthIsDisabled, @@ -13,16 +19,36 @@ import { Redirect, getIdToken, } from '../lib/auth' -import { authOptions } from '../pages/api/auth/[...nextauth]' +import { authOptions } from './api/auth/[...nextauth]' import { getServerSession } from 'next-auth/next' import ErrorPage from '../components/ErrorPage' import Button from '../components/Button' +import { GetServerSidePropsContext } from 'next' + +interface SecurtitySettingsProps { + locale: string | undefined + content: { + err?: '500' | '404' | '503' + heading: string + subHeading: string + securityQuestions: { + linkTitle: { link: string | undefined; text: string } + subTitle: string + } + lookingFor: { title: string; subText: string[]; link: string } + } + bannerContent?: { err?: '500' | '404' | '503' } + popupContent?: { err?: '500' | '404' | '503' } + popupContentNA?: { err?: '500' | '404' | '503' } + authModals?: { err?: '500' | '404' | '503' } + aaPrefix: string +} -export default function SecuritySettings(props) { +export default function SecuritySettings(props: SecurtitySettingsProps) { const t = props.locale === 'en' ? en : fr const errorCode = - props.content?.err || + props.content.err || props.bannerContent?.err || props.popupContent?.err || props.popupContentNA?.err || @@ -37,7 +63,7 @@ export default function SecuritySettings(props) { props.locale === 'en' ? 'en/my-dashboard' : 'fr/mon-tableau-de-bord' } accountPageLink={ - props?.locale === 'en' + props.locale === 'en' ? 'https://srv136.services.gc.ca/sc/msca-mdsc/portal-portail/pro/home-accueil?Lang=eng' : 'https://srv136.services.gc.ca/sc/msca-mdsc/portal-portail/pro/home-accueil?Lang=fra' } @@ -80,7 +106,15 @@ export default function SecuritySettings(props) { ) } -export async function getServerSideProps({ req, res, locale }) { +export async function getServerSideProps({ + req, + res, + locale, +}: { + req: GetServerSidePropsContext['req'] + res: GetServerSidePropsContext['res'] + locale: string +}) { const session = await getServerSession(req, res, authOptions) if (!AuthIsDisabled() && !(await AuthIsValid(req, session))) @@ -120,28 +154,30 @@ export async function getServerSideProps({ req, res, locale }) { const logger = getLogger('security-settings') logger.level = 'error' - const content = await getSecuritySettingsContent().catch((error) => { - logger.error(error) - return { err: '500' } - }) + const content = await getSecuritySettingsContent().catch( + (error): SecuritySettingsContent => { + logger.error(error) + return { err: '500' } + }, + ) - const authModals = await getAuthModalsContent().catch((error) => { - logger.error(error) - return { err: '500' } - }) + const authModals = await getAuthModalsContent().catch( + (error): AuthModalsContent => { + logger.error(error) + return { err: '500' } + }, + ) /* istanbul ignore next */ const langToggleLink = locale === 'en' ? '/fr/parametres-securite' : '/en/security-settings' - const t = locale === 'en' ? en : fr - const breadCrumbItems = locale === 'en' - ? content.en.breadcrumb?.map(({ link, text }) => { + ? content.en?.breadcrumb?.map(({ link, text }) => { return { text, link: '/' + locale + '/' + link } }) - : content.fr.breadcrumb?.map(({ link, text }) => { + : content.fr?.breadcrumb?.map(({ link, text }) => { return { text, link: '/' + locale + '/' + link } }) @@ -172,7 +208,7 @@ export async function getServerSideProps({ req, res, locale }) { locale, langToggleLink, content: - content?.err !== undefined + content.err !== undefined ? content : locale === 'en' ? content.en @@ -180,23 +216,23 @@ export async function getServerSideProps({ req, res, locale }) { meta, breadCrumbItems, aaPrefix: - content?.err !== undefined + content.err !== undefined ? '' - : `ESDC-EDSC_MSCA-MSDC-SCH:${content.en?.heading || content.en?.title}`, + : `ESDC-EDSC_MSCA-MSDC-SCH:${content.en?.heading}`, aaMenuPrefix: - content?.err !== undefined ? '' : `ESDC-EDSC_MSCA-MSDC-SCH:Nav Menu`, + content.err !== undefined ? '' : `ESDC-EDSC_MSCA-MSDC-SCH:Nav Menu`, popupStaySignedIn: - authModals?.err !== undefined + authModals.err !== undefined ? authModals : locale === 'en' - ? authModals.mappedPopupStaySignedIn.en - : authModals.mappedPopupStaySignedIn.fr, + ? authModals.mappedPopupStaySignedIn?.en + : authModals.mappedPopupStaySignedIn?.fr, popupYouHaveBeenSignedout: - authModals?.err !== undefined + authModals.err !== undefined ? authModals : locale === 'en' - ? authModals.mappedPopupSignedOut.en - : authModals.mappedPopupSignedOut.fr, + ? authModals.mappedPopupSignedOut?.en + : authModals.mappedPopupSignedOut?.fr, }, } }