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

Browser navigation and saving results for results page #1115

Merged
merged 4 commits into from
Nov 19, 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
29 changes: 26 additions & 3 deletions client-state/Form.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import Joi from 'joi'
import { getWebTranslations, WebTranslations } from '../i18n/web'
import { BenefitHandler } from '../utils/api/benefitHandler'
import { FieldsHandler } from '../utils/api/fieldsHandler'
import { Language, ValidationErrors } from '../utils/api/definitions/enums'
import {
FieldConfig,
fieldDefinitions,
FieldKey,
FieldType,
} from '../utils/api/definitions/fields'
import { VisibleFieldsObject } from '../utils/web/types'
import { ResponseError, ResponseSuccess } from '../utils/api/definitions/types'
import { FieldsHandler } from '../utils/api/fieldsHandler'
import MainHandler from '../utils/api/mainHandler'
import { VisibleFieldsObject } from '../utils/web/types'
import { FormField } from './FormField'
import { InputHelper } from './InputHelper'

export class Form {
public readonly allFieldConfigs: FieldConfig[]
public readonly fields: FormField[]

private results: ResponseSuccess | ResponseError
private localInputs: InputHelper

constructor(
private readonly language: Language,
inputHelper: InputHelper,
Expand All @@ -31,6 +34,9 @@ export class Form {

update(inputs: InputHelper) {
const data = new MainHandler(inputs.asObjectWithLanguage).results
this.results = data
this.localInputs = inputs

this.clearAllErrors()

// set visibility of fields
Expand Down Expand Up @@ -86,6 +92,23 @@ export class Form {
}
}

writeToSessionStorage(): void {
try {
if (this.results && this.localInputs) {
sessionStorage.setItem(
'calculationResults',
JSON.stringify(this.results)
)
sessionStorage.setItem(
'resultPageInputs',
JSON.stringify(this.localInputs)
)
}
} catch (error) {
console.error('Error writing to sessionStorage:', error)
}
}

get visibleFields(): FormField[] {
return this.fields.filter((value) => value.visible)
}
Expand Down
5 changes: 2 additions & 3 deletions components/ResultsPage/YourAnswers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export const YourAnswers: React.VFC<{
})
return initialState
})
const [_activeStep, setActiveStep] = useSessionStorage('step')

const toggleAccordion = (category) => {
setAccordionStates((prevStates) => ({
Expand All @@ -61,8 +60,8 @@ export const YourAnswers: React.VFC<{

const handlePageChange = (key: string) => (e) => {
e.preventDefault()
setActiveStep(keyToStepMap[key] || 0)
router.push(`/questions#${key}`)
const category = fieldDefinitions[key]?.category?.key
router.push(`/questions?step=${category}#${key}`)
}

/**
Expand Down
2 changes: 0 additions & 2 deletions components/ResultsPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ const ResultsPage: React.VFC<{
const ref = useRef<HTMLDivElement>()
const tsln = useTranslation<WebTranslations>()
const router = useRouter()
const [_activeStep, setActiveStep] = useSessionStorage('step')

const isPartnered =
inputs.find((input) => input.key === FieldKey.MARITAL_STATUS)['value'] ===
Expand Down Expand Up @@ -155,7 +154,6 @@ const ResultsPage: React.VFC<{
custom="mt-6 justify-center md:w-[fit-content]"
onClick={(e) => {
e.preventDefault()
setActiveStep(1)
router.push('/questions')
}}
/>
Expand Down
6 changes: 6 additions & 0 deletions components/Stepper/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/* eslint-disable jsx-a11y/anchor-is-valid */
// import PropTypes from "prop-types";
import React from 'react'
import { WebTranslations } from '../../i18n/web'
import { Button } from '../Forms/Button'
import { useTranslation } from '../Hooks'

// Stepper props
export interface StepperProps {
Expand All @@ -24,6 +26,7 @@ export interface StepperProps {
}

export function Stepper(props: StepperProps) {
const tsln = useTranslation<WebTranslations>()
return (
<div className="pt-3 pb-6 sm:pb-40">
<div>
Expand Down Expand Up @@ -61,6 +64,9 @@ export function Stepper(props: StepperProps) {
</div>
)}
</div>
{props.activeStep === 1 && (
<p className="mt-[24px]">{tsln.stepper.navWarning}</p>
)}
</div>
</div>
)
Expand Down
32 changes: 30 additions & 2 deletions components/StepperPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,29 @@ interface StepperPageProps {
setPageTitle: (title: string) => void
}

const defaultStep = 'marital'
const formSteps = ['marital', 'age', 'income', 'residence']

const StepperPage: React.FC<StepperPageProps> = ({ setPageTitle }) => {
const router = useRouter()
const langx = useRouter().locale as Language
const language =
langx === Language.EN || langx === Language.FR ? langx : Language.EN
const tsln = useTranslation<WebTranslations>()

const { step } = router.query

useEffect(() => {
// Redirect to the default step if no step is specified or the step is invalid
if (
!step ||
typeof step !== 'string' ||
!Object.values(formSteps).includes(step)
) {
router.replace(`/questions?step=${defaultStep}`)
}
}, [])

const allFieldConfigs: FieldConfig[] = FieldsHandler.getAllFieldData(language)
const [inputs, setInputs]: [
FieldInputsObject,
Expand Down Expand Up @@ -111,7 +127,9 @@ const StepperPage: React.FC<StepperPageProps> = ({ setPageTitle }) => {

const [steps, setSteps] = useState(getSteps(tsln))
const totalSteps = Object.keys(steps).length
const [activeStep, setActiveStep] = useSessionStorage('step', 1)
const [activeStep, setActiveStep] = useState(
formSteps.indexOf(step as string) + 1
)
const [isLastStep, setIsLastStep] = useState(false)

const [stepTitle, setStepTitle] = useState('')
Expand Down Expand Up @@ -154,6 +172,10 @@ const StepperPage: React.FC<StepperPageProps> = ({ setPageTitle }) => {
setFieldsMetaData(getFieldsMetaData(activeStep))
}, [ageDate])

useEffect(() => {
setActiveStep(formSteps.indexOf(step as string) + 1)
}, [step])

useEffect(() => {
const topElement = document.getElementById('topOfPageFocus')
if (topElement) {
Expand Down Expand Up @@ -382,6 +404,7 @@ const StepperPage: React.FC<StepperPageProps> = ({ setPageTitle }) => {

function submitForm() {
if (form.isValid) {
form.writeToSessionStorage()
language === 'en' ? router.push('/results') : router.push('/resultats')
}
}
Expand All @@ -403,6 +426,8 @@ const StepperPage: React.FC<StepperPageProps> = ({ setPageTitle }) => {
if (isLastStep) {
submitForm()
} else {
const nextStep = formSteps[activeStep]
router.push(`/questions?step=${nextStep}`)
setActiveStep(activeStep + 1)
}
} else {
Expand Down Expand Up @@ -430,7 +455,10 @@ const StepperPage: React.FC<StepperPageProps> = ({ setPageTitle }) => {
id: 'previous',
text: tsln.stepper.previousStep,
onClick: () => {
setActiveStep(Math.max(activeStep - 1, 1))
if (activeStep > 1) {
router.push(`/questions?step=${formSteps[activeStep - 2]}`)
setActiveStep(Math.max(activeStep - 1, 1))
}
},
}}
nextProps={{
Expand Down
1 change: 1 addition & 0 deletions i18n/web/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ const en: WebTranslations = {
previousStep: 'Previous',
nextStep: 'Next',
getEstimate: 'Estimate my benefits',
navWarning: `Note: Please navigate using the "Previous" and "Next" buttons. Using your browser's navigation buttons is not recommended.`,
},
datePicker: {
month: 'Month',
Expand Down
1 change: 1 addition & 0 deletions i18n/web/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ const fr: WebTranslations = {
nextStep: 'Suivant',
previousStep: 'Précédent',
getEstimate: 'Estimer mes prestations',
navWarning: `Note: Veuillez naviguer en utilisant les boutons «Précédent» et «Suivant». Il n’est pas recommandé d’utiliser les boutons de votre navigateur.`,
},
datePicker: {
month: 'Mois',
Expand Down
1 change: 1 addition & 0 deletions i18n/web/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ export type WebTranslations = {
nextStep: string
previousStep: string
getEstimate: string
navWarning: string
}
//Date Picker
datePicker: {
Expand Down
1 change: 0 additions & 1 deletion pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ const Home: NextPage<{ adobeAnalyticsUrl: string }> = ({
text={tsln.startBenefitsEstimator}
style="primary"
onClick={(e) => {
sessionStorage.setItem('step', '1')
router.push('/questions')
}}
custom="w-auto justify-center mb-4"
Expand Down
15 changes: 15 additions & 0 deletions pages/questions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { useRouter } from 'next/router'
import StepperPage from '../../components/StepperPage'
import React from 'react'

const defaultStep = 'marital'
const steps = ['marital', 'age', 'income', 'residence']

const Stepper: NextPage<{ adobeAnalyticsUrl: string }> = ({
adobeAnalyticsUrl,
}) => {
Expand All @@ -23,6 +26,18 @@ const Stepper: NextPage<{ adobeAnalyticsUrl: string }> = ({
}
}, []) // eslint-disable-line react-hooks/exhaustive-deps

const { step } = router.query

useEffect(() => {
if (!step || typeof step !== 'string' || !steps.includes(step)) {
router.replace(`/questions?step=${defaultStep}`)
}
}, [step, router])

if (!step || typeof step !== 'string' || !steps.includes(step)) {
return null
}

return (
<>
<Head>
Expand Down
15 changes: 11 additions & 4 deletions pages/results/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,16 @@ const Results: NextPage<{ adobeAnalyticsUrl: string }> = ({
const language =
langx === Language.EN || langx === Language.FR ? langx : Language.EN

const inputHelper = new InputHelper(inputs, setInputs, language)
const mainHandler = new MainHandler(inputHelper.asObjectWithLanguage)
const response: ResponseSuccess | ResponseError = mainHandler.results
const response: ResponseSuccess | ResponseError = JSON.parse(
sessionStorage.getItem('calculationResults') || '{}'
)

const savedInputs = JSON.parse(
sessionStorage.getItem('resultPageInputs') || '{}'
)

const inputHelper = new InputHelper(savedInputs.inputs, setInputs, language)

const tsln = useTranslation<WebTranslations>()

useEffect(() => {
Expand All @@ -60,7 +67,7 @@ const Results: NextPage<{ adobeAnalyticsUrl: string }> = ({
</Head>

<Layout title={tsln.resultPageTitle}>
{'results' in response ? (
{'results' in response && inputHelper.asArray.length !== 0 ? (
<ResultsPage
inputs={inputHelper.asArray}
results={response.results}
Expand Down
Loading