Skip to content

Commit

Permalink
Demographics question8 and9 (#564)
Browse files Browse the repository at this point in the history
* added question 7 to page demographics part2

* added question 8 and 9 to demographics part2

* code reformat after PR review
  • Loading branch information
olivierroyESDC authored Mar 1, 2024
1 parent 71ec0b3 commit cae5782
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 12 deletions.
3 changes: 3 additions & 0 deletions frontend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,11 @@ LOOKUP_SVC_ALLDISABILITYTYPES_CACHE_TTL_MILLISECONDS=3600000
LOOKUP_SVC_ALLSEXATBIRTHTYPES_CACHE_TTL_MILLISECONDS=3600000
LOOKUP_SVC_MARITALSTATUSES_CACHE_TTL_MILLISECONDS=3600000
LOOKUP_SVC_ALLMOUTHPAINTYPES_CACHE_TTL_MILLISECONDS=3600000
LOOKUP_SVC_LASTTIMEDENTISTVISITTYPES_CACHE_TTL_MILLISECONDS=3600000
LOOKUP_SVC_AVOIDEDDENTALCOSTTYPES_CACHE_TTL_MILLISECONDS=3600000

GET_ALL_LETTER_TYPES_CACHE_TTL_SECONDS=0

# id for communication method of 'digital'
COMMUNICATION_METHOD_DIGITAL_ID='digital'

71 changes: 69 additions & 2 deletions frontend/app/mocks/demographics-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,73 @@ const demographicDB = factory({
nameEn: String,
nameFr: String,
},

lastTimeDentistVisitType: {
id: primaryKey(faker.string.uuid),
nameEn: String,
nameFr: String,
},

avoidedDentalCostType: {
id: primaryKey(faker.string.uuid),
nameEn: String,
nameFr: String,
},
});

demographicDB.avoidedDentalCostType.create({
nameEn: 'Yes',
nameFr: 'Oui',
});

demographicDB.avoidedDentalCostType.create({
nameEn: 'No',
nameFr: 'Non',
});

demographicDB.avoidedDentalCostType.create({
nameEn: "Don't know",
nameFr: 'Ne sais pas',
});

demographicDB.avoidedDentalCostType.create({
nameEn: 'Prefer not to answer',
nameFr: '(FR) Prefer not to answer',
});

demographicDB.lastTimeDentistVisitType.create({
nameEn: 'Less than a year ago',
nameFr: '(FR) Less than a year ago',
});

demographicDB.lastTimeDentistVisitType.create({
nameEn: '1 year to less than 3 years ago',
nameFr: '(FR) 1 year to less than 3 years ago',
});

demographicDB.lastTimeDentistVisitType.create({
nameEn: '3 years ago, or more',
nameFr: '(FR) 3 years ago, or more',
});

demographicDB.lastTimeDentistVisitType.create({
nameEn: 'Rarely',
nameFr: '(FR) Rarely',
});

demographicDB.lastTimeDentistVisitType.create({
nameEn: 'Never seen an oral health professional',
nameFr: '(FR) Never seen an oral health professional',
});

demographicDB.lastTimeDentistVisitType.create({
nameEn: "Don't know",
nameFr: 'Ne sais pas',
});

demographicDB.lastTimeDentistVisitType.create({
nameEn: 'Prefer not to answer',
nameFr: '(FR) Prefer not to answer',
});

demographicDB.bornType.create({
Expand Down Expand Up @@ -105,7 +172,7 @@ demographicDB.mouthPainType.create({
});

demographicDB.mouthPainType.create({
nameEn: 'Prefer not to say',
nameFr: '(FR) Prefer not to say',
nameEn: 'Prefer not to answer',
nameFr: '(FR) Prefer not to answer',
});
export { demographicDB };
27 changes: 27 additions & 0 deletions frontend/app/mocks/lookup-api.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,33 @@ export function getLookupApiMockHandlers() {
return HttpResponse.json(sexAtBirthTypes);
}),

//
// Handler for GET request to retrieve all mouth pain types
//
http.get('https://api.example.com/lookups/last-time-visited-dentist-types', ({ request }) => {
log.debug('Handling request for [%s]', request.url);
const lastTimeDentistVisitTypes = demographicDB.lastTimeDentistVisitType.getAll();
return HttpResponse.json(lastTimeDentistVisitTypes);
}),

//
// Handler for GET request to retrieve all mouth pain types
//
http.get('https://api.example.com/lookups/avoided-dental-cost-types', ({ request }) => {
log.debug('Handling request for [%s]', request.url);
const avoidedDentalCostTypes = demographicDB.avoidedDentalCostType.getAll();
return HttpResponse.json(avoidedDentalCostTypes);
}),

//
// Handler for GET request to retrieve all mouth pain types
//
http.get('https://api.example.com/lookups/mouth-pain-types', ({ request }) => {
log.debug('Handling request for [%s]', request.url);
const mouthPainTypes = demographicDB.mouthPainType.getAll();
return HttpResponse.json(mouthPainTypes);
}),

//
// Handler for GET request to retrieve all mouth pain types
//
Expand Down
39 changes: 35 additions & 4 deletions frontend/app/routes/_public+/intake+/$id+/demographics-part2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,19 @@ export const handle = {
export async function loader({ request, params }: LoaderFunctionArgs) {
const sexAtBirthTypes = await getLookupService().getAllSexAtBirthTypes();
const mouthPainTypes = await getLookupService().getAllMouthPaintTypes();
const lastTimeDentistVisitTypes = await getLookupService().getAllLastTimeDentistVisitTypes();
const avoidedDentalCostTypes = await getLookupService().getAllAvoidedDentalCostTypes();
const intakeFlow = getIntakeFlow();
const { id, state } = await intakeFlow.loadState({ request, params });
return json({ sexAtBirthTypes, mouthPainTypes, id, state });
return json({ sexAtBirthTypes, mouthPainTypes, lastTimeDentistVisitTypes, avoidedDentalCostTypes, id, state });
}

export async function action({ request }: ActionFunctionArgs) {
return json('');
}

export default function DemographicsPart2() {
const { sexAtBirthTypes, mouthPainTypes, id } = useLoaderData<typeof loader>();
const { sexAtBirthTypes, mouthPainTypes, lastTimeDentistVisitTypes, avoidedDentalCostTypes, id } = useLoaderData<typeof loader>();
const { i18n, t } = useTranslation(i18nNamespaces);

return (
Expand All @@ -42,7 +44,7 @@ export default function DemographicsPart2() {
<InputRadios
id="born-type"
name="bornType"
legend={t('demographics-oral-health-questions:part2.question6')}
legend={t('demographics-oral-health-questions:part2.question-sex-at-birth')}
options={sexAtBirthTypes.map((sexAtBirthType) => ({
children: getNameByLanguage(i18n.language, sexAtBirthType),
value: sexAtBirthType.id,
Expand All @@ -57,7 +59,7 @@ export default function DemographicsPart2() {
<InputRadios
id="mouth-pain-type"
name="mouthPainType"
legend={t('demographics-oral-health-questions:part2.question7')}
legend={t('demographics-oral-health-questions:part2.question-mouth-pain')}
options={mouthPainTypes.map((mouthPainType) => ({
children: getNameByLanguage(i18n.language, mouthPainType),
value: mouthPainType.id,
Expand All @@ -67,6 +69,35 @@ export default function DemographicsPart2() {
</div>
)}

{lastTimeDentistVisitTypes.length > 0 && (
<div className="my-6">
<InputRadios
id="last-time-dentist-visit-type"
name="lastTimeDentistVisitType"
legend={t('demographics-oral-health-questions:part2.question-last-dental-visit')}
options={lastTimeDentistVisitTypes.map((lastTimeDentistVisitType) => ({
children: getNameByLanguage(i18n.language, lastTimeDentistVisitType),
value: lastTimeDentistVisitType.id,
}))}
required
/>
</div>
)}

{avoidedDentalCostTypes.length > 0 && (
<div className="my-6">
<InputRadios
id="avoided-dental-cost-type"
name="avoidedDentalCostType"
legend={t('demographics-oral-health-questions:part2.question-avoided-dental-cost')}
options={avoidedDentalCostTypes.map((avoidedDentalCostType) => ({
children: getNameByLanguage(i18n.language, avoidedDentalCostType),
value: avoidedDentalCostType.id,
}))}
required
/>
</div>
)}
<div className="flex flex-wrap items-center gap-3">
<ButtonLink id="cancel-button" to={`/intake/${id}/demographics-part1`}>
{t('demographics-oral-health-questions:part2.button-back')}
Expand Down
62 changes: 60 additions & 2 deletions frontend/app/services/lookup-service.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ const sexAtBirthTypeSchema = z.object({
nameFr: z.string().optional(),
});

const lastTimeDentistVisitTypeSchema = z.object({
id: z.string(),
nameEn: z.string().optional(),
nameFr: z.string().optional(),
});

const avoidedDentalCostTypeSchema = z.object({
id: z.string(),
nameEn: z.string().optional(),
nameFr: z.string().optional(),
});

const maritalStatusSchema = z.object({
id: z.string(),
code: z.string(),
Expand Down Expand Up @@ -82,6 +94,8 @@ function createLookupService() {
LOOKUP_SVC_ALLSEXATBIRTHTYPES_CACHE_TTL_MILLISECONDS,
LOOKUP_SVC_MARITALSTATUSES_CACHE_TTL_MILLISECONDS,
LOOKUP_SVC_ALLMOUTHPAINTYPES_CACHE_TTL_MILLISECONDS,
LOOKUP_SVC_LASTTIMEDENTISTVISITTYPES_CACHE_TTL_MILLISECONDS,
LOOKUP_SVC_AVOIDEDDENTALCOSTTYPES_CACHE_TTL_MILLISECONDS,
} = getEnv();

async function getAllPreferredLanguages() {
Expand All @@ -105,6 +119,48 @@ function createLookupService() {
throw new Error(`Failed to fetch data. Status: ${response.status}, Status Text: ${response.statusText}`);
}

async function getAllAvoidedDentalCostTypes() {
const url = `${INTEROP_API_BASE_URI}/lookups/avoided-dental-cost-types/`;
const response = await fetch(url);

const avoidedDentalCostTypeSchemaList = z.array(avoidedDentalCostTypeSchema);

if (response.ok) {
return avoidedDentalCostTypeSchemaList.parse(await response.json());
}

log.error('%j', {
message: 'Failed to fetch data',
status: response.status,
statusText: response.statusText,
url: url,
responseBody: await response.text(),
});

throw new Error(`Failed to fetch data. Status: ${response.status}, Status Text: ${response.statusText}`);
}

async function getAllLastTimeDentistVisitTypes() {
const url = `${INTEROP_API_BASE_URI}/lookups/last-time-visited-dentist-types/`;
const response = await fetch(url);

const lastTimeDentistVisitTypeSchemaList = z.array(lastTimeDentistVisitTypeSchema);

if (response.ok) {
return lastTimeDentistVisitTypeSchemaList.parse(await response.json());
}

log.error('%j', {
message: 'Failed to fetch data',
status: response.status,
statusText: response.statusText,
url: url,
responseBody: await response.text(),
});

throw new Error(`Failed to fetch data. Status: ${response.status}, Status Text: ${response.statusText}`);
}

async function getAllSexAtBirthTypes() {
const url = `${INTEROP_API_BASE_URI}/lookups/sex-at-birth-types/`;
const response = await fetch(url);
Expand Down Expand Up @@ -315,8 +371,10 @@ function createLookupService() {
getAllRegions: moize(getAllRegions, { maxAge: LOOKUP_SVC_ALLREGIONS_CACHE_TTL_MILLISECONDS, onCacheAdd: () => log.info('Creating new AllRegions memo') }),
getAllBornTypes: moize(getAllBornTypes, { maxAge: LOOKUP_SVC_ALLBORNTYPES_CACHE_TTL_MILLISECONDS, onCacheAdd: () => log.info('Creating new AllBornTypes memo') }),
getAllDisabilityTypes: moize(getAllDisabilityTypes, { maxAge: LOOKUP_SVC_ALLDISABILITYTYPES_CACHE_TTL_MILLISECONDS, onCacheAdd: () => log.info('Creating new AllDisabilityTypes memo') }),
getAllSexAtBirthTypes: moize(getAllSexAtBirthTypes, { maxAge: LOOKUP_SVC_ALLSEXATBIRTHTYPES_CACHE_TTL_MILLISECONDS, onCacheAdd: () => log.info('Creating new AllDisabilityTypes memo') }),
getAllSexAtBirthTypes: moize(getAllSexAtBirthTypes, { maxAge: LOOKUP_SVC_ALLSEXATBIRTHTYPES_CACHE_TTL_MILLISECONDS, onCacheAdd: () => log.info('Creating new AllSexAtBirthTypes memo') }),
getAllMaritalStatuses: moize(getAllMaritalStatuses, { maxAge: LOOKUP_SVC_MARITALSTATUSES_CACHE_TTL_MILLISECONDS, onCacheAdd: () => log.info('Creating new AllMaritalStatuses memo') }),
getAllMouthPaintTypes: moize(getAllMouthPainTypes, { maxAge: LOOKUP_SVC_ALLMOUTHPAINTYPES_CACHE_TTL_MILLISECONDS, onCacheAdd: () => log.info('Creating new AllDisabilityTypes memo') }),
getAllMouthPaintTypes: moize(getAllMouthPainTypes, { maxAge: LOOKUP_SVC_ALLMOUTHPAINTYPES_CACHE_TTL_MILLISECONDS, onCacheAdd: () => log.info('Creating new AllMouthPaintTypes memo') }),
getAllAvoidedDentalCostTypes: moize(getAllAvoidedDentalCostTypes, { maxAge: LOOKUP_SVC_AVOIDEDDENTALCOSTTYPES_CACHE_TTL_MILLISECONDS, onCacheAdd: () => log.info('Creating new AllAvoidedDentalCostTypes memo') }),
getAllLastTimeDentistVisitTypes: moize(getAllLastTimeDentistVisitTypes, { maxAge: LOOKUP_SVC_LASTTIMEDENTISTVISITTYPES_CACHE_TTL_MILLISECONDS, onCacheAdd: () => log.info('Creating new AllLastTimeDentistVisitTypes memo') }),
};
}
2 changes: 2 additions & 0 deletions frontend/app/utils/env.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ const serverEnv = z.object({
LOOKUP_SVC_ALLDISABILITYTYPES_CACHE_TTL_MILLISECONDS: z.coerce.number().default(60 * 60 * 1000),
LOOKUP_SVC_ALLSEXATBIRTHTYPES_CACHE_TTL_MILLISECONDS: z.coerce.number().default(60 * 60 * 1000),
LOOKUP_SVC_ALLMOUTHPAINTYPES_CACHE_TTL_MILLISECONDS: z.coerce.number().default(60 * 60 * 1000),
LOOKUP_SVC_LASTTIMEDENTISTVISITTYPES_CACHE_TTL_MILLISECONDS: z.coerce.number().default(60 * 60 * 1000),
LOOKUP_SVC_AVOIDEDDENTALCOSTTYPES_CACHE_TTL_MILLISECONDS: z.coerce.number().default(60 * 60 * 1000),
GET_ALL_LETTER_TYPES_CACHE_TTL_SECONDS: z.coerce.number().default(24 * 60 * 60),

// OpenTelemetry/Dynatrace settings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
"part2": {
"page-title": "Voluntary demographic and oral health questions part 2 of 2",

"question6": "What was your sex at birth? Sex refers to sex assigned at birth.",
"question7": "In the past 12 months, how often have you had any persistent or on-going mouth pain? Mouth pain includes pain in teeth, gums, tongue, jaw, jaw joints.",
"question-sex-at-birth": "6. What was your sex at birth? Sex refers to sex assigned at birth.",
"question-mouth-pain": "7. In the past 12 months, how often have you had any persistent or on-going mouth pain? Mouth pain includes pain in teeth, gums, tongue, jaw, jaw joints.",
"question-last-dental-visit": "8. When was the last time you saw a dentist, denturist, dental hygienist or any other dental specialist? Services may have been provided in any setting where the oral health professional is licensed to practice",
"question-avoided-dental-cost": "9. In the past 12 months, have you avoided going to a dental professional for dental care due to the cost of care?",

"button-back": "Back < ",
"button-continue": "Continue > "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
"part2": {
"page-title": "(FR) Voluntary demographic and oral health questions part 2 of 2",

"question6": "(FR) What was your sex at birth? Sex refers to sex assigned at birth.",
"question7": "(FR) In the past 12 months, how often have you had any persistent or on-going mouth pain? Mouth pain includes pain in teeth, gums, tongue, jaw, jaw joints.",
"question-sex-at-birth": "6.(FR) What was your sex at birth? Sex refers to sex assigned at birth.",
"question-mouth-pain": "7.(FR) In the past 12 months, how often have you had any persistent or on-going mouth pain? Mouth pain includes pain in teeth, gums, tongue, jaw, jaw joints.",
"question-last-dental-visit": "8. (FR) When was the last time you saw a dentist, denturist, dental hygienist or any other dental specialist? Services may have been provided in any setting where the oral health professional is licensed to practice",
"question-avoided-dental-cost": "9. (FR) In the past 12 months, have you avoided going to a dental professional for dental care due to the cost of care?",

"button-back": "(FR) Back < ",
"button-continue": "(FR) Continue > "
Expand Down

0 comments on commit cae5782

Please sign in to comment.