Skip to content

Commit

Permalink
Add allergy management features including data fetching and UI compon…
Browse files Browse the repository at this point in the history
…ents
  • Loading branch information
stephenBarrs committed Nov 27, 2024
1 parent e4832b5 commit e2a96bc
Show file tree
Hide file tree
Showing 10 changed files with 371 additions and 116 deletions.
2 changes: 1 addition & 1 deletion VAMobile/src/api/allergies/getAllergies.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { allergyKeys } from './queryKeys'
* Fetch user Allergies
*/
const getAllergies = (): Promise<AllergyListPayload | undefined> => {
return get<AllergyListPayload>('/v1/health/immunizations', {
return get<AllergyListPayload>('/v0/health/allergy-intolerances', {
'page[number]': '1',
'page[size]': LARGE_PAGE_SIZE.toString(),
sort: 'date',
Expand Down
50 changes: 19 additions & 31 deletions VAMobile/src/api/types/AllergyData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,38 +22,26 @@ export type Allergy = {
id?: string | null
type?: string | null
attributes?: {
cvxCode?: number | null
date?: string | null
doseNumber?: number | string | null
doseSeries?: number | string | null
groupName?: string | null
manufacturer?: string | null
note?: string | null
shortDescription?: string | null
reaction?: string | null
}
relationships?: {
location?: {
data?: {
id?: string | null
type?: string | null
} | null
}
code?: {
text?: string | null
} | null
category?: string | null
recordedDate?: string | null
notes?: Array<NoteText> | null
recorder?: {
display?: string | null
} | null
reactions?: Array<Reaction> | null
}
}

export type AllergyLocationPayload = {
data: {
type?: string | null
id?: string | null
attributes: {
name?: string | null
address: {
street?: string | null
city?: string | null
state?: string | null
zipCode?: string | null
} | null
}
}
export type Reaction = {
manifestation: Array<ManifestationText> | null
}
export type ManifestationText = {
text: string
}

export type NoteText = {
text: string
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { StackScreenProps } from '@react-navigation/stack'

import { every } from 'underscore'

import { useAllergies } from 'api/allergies/getAllergies'
import { useAllergyLocation } from 'api/allergies/getAllergyLocation'
import { Box, FeatureLandingTemplate, LoadingComponent, TextArea, TextView } from 'components'
import { Events } from 'constants/analytics'
Expand All @@ -25,12 +26,13 @@ type AllergyDetailsScreenProps = StackScreenProps<HealthStackParamList, 'Allergy
*/
function AllergyDetailsScreen({ route, navigation }: AllergyDetailsScreenProps) {
const { allergy } = route.params
const { data: location, isLoading: detailsLoading } = useAllergyLocation(
allergy.relationships?.location?.data?.id || '',
{
enabled: !!allergy.relationships?.location?.data?.id && screenContentAllowed('WG_VaccineDetails'),
},
)
// const { data: location, isLoading: detailsLoading } = useAllergyLocation(
// allergy.relationships?.location?.data?.id || '',
// {
// enabled: !!allergy.relationships?.location?.data?.id && screenContentAllowed('WG_VaccineDetails'),
// },
// )
const { isLoading: detailsLoading } = useAllergies({ enabled: screenContentAllowed('WG_VaccineDetails') })

const theme = useTheme()
const { t } = useTranslation(NAMESPACE.COMMON)
Expand All @@ -39,45 +41,45 @@ function AllergyDetailsScreen({ route, navigation }: AllergyDetailsScreenProps)

const placeHolder = t('noneNoted')

useEffect(() => {
logAnalyticsEvent(Events.vama_vaccine_details(allergy?.attributes?.groupName || ''))
}, [dispatch, allergy])
// analtyics
// useEffect(() => {
// logAnalyticsEvent(Events.vama_vaccine_details(allergy?.attributes?.groupName || ''))
// }, [dispatch, allergy])

if (!allergy) {
return <></>
}

const displayDate = allergy.attributes?.date ? formatDateMMMMDDYYYY(allergy.attributes.date) : placeHolder

const displayName = allergy.attributes?.groupName
? t('vaccines.vaccineName', { name: allergy.attributes.groupName })
const displayDate = allergy.attributes?.recordedDate
? formatDateMMMMDDYYYY(allergy.attributes.recordedDate)
: placeHolder

const hasSeries = allergy.attributes?.doseNumber && allergy.attributes?.doseSeries
const displaySeries = hasSeries
? t('vaccines.details.series.display', {
doseNumber: allergy.attributes?.doseNumber,
seriesDoses: allergy.attributes?.doseSeries,
})
const displayName = allergy.attributes?.code?.text
? t('allergies.allergyName', { name: allergy.attributes?.code?.text })
: placeHolder

const optionalFields = [hasSeries, allergy.attributes?.note, location?.data, allergy.attributes?.reaction]
const isPartialData = !every(optionalFields)
const hasType = allergy.attributes?.category
// const displayType = hasType ? allergy.attributes?.category : placeHolder

// Only show the manufacturer label if the vaccine is COVID-19, any other type should not be displayed
const isCovidVaccine = allergy.attributes?.groupName?.toUpperCase()?.includes(COVID19)
const optionalFields = [
hasType,
allergy.attributes?.notes,
// allergy.attributes?.reaction,
allergy.attributes?.recorder,
]
const isPartialData = !every(optionalFields)

return (
<FeatureLandingTemplate
backLabel={t('vaVaccines')}
backLabelA11y={a11yLabelVA(t('vaVaccines'))}
backLabel={t('vaAllergies')}
backLabelA11y={a11yLabelVA(t('vaAllergies'))}
backLabelOnPress={navigation.goBack}
title={t('details')}
backLabelTestID="allergiesDetailsBackID">
{detailsLoading ? (
// <LoadingComponent text={t('vaccines.details.loading')} />
<LoadingComponent text="Loading your allergy record" />
<LoadingComponent text={t('allergies.details.loading')} />
) : (
// <LoadingComponent text="Loading your allergy record" />
<Box mb={contentMarginBottom}>
<TextArea>
<TextView variant="MobileBody" mb={standardMarginBetween}>
Expand All @@ -87,70 +89,68 @@ function AllergyDetailsScreen({ route, navigation }: AllergyDetailsScreenProps)
<TextView variant="MobileBodyBold">{displayName}</TextView>
</Box>
<TextView variant="MobileBodyBold" selectable={true}>
{t('vaccines.details.typeAndDosage')}
{'Type'}
</TextView>

<TextView
variant="MobileBody"
selectable={true}
mb={standardMarginBetween}
testID={'Type And Dosage ' + allergy.attributes?.shortDescription || placeHolder}>
{allergy.attributes?.shortDescription || placeHolder}
</TextView>
{isCovidVaccine && (
<>
<TextView variant="MobileBodyBold">{t('vaccines.details.manufacturer')}</TextView>
<TextView
variant="MobileBody"
selectable={true}
mb={standardMarginBetween}
testID={'Manufacturer ' + allergy.attributes?.manufacturer || placeHolder}>
{allergy.attributes?.manufacturer || placeHolder}
</TextView>
</>
)}
<TextView variant="MobileBodyBold">{t('vaccines.details.series')}</TextView>
<TextView variant="MobileBody" selectable={true} testID={'Series status' + displaySeries}>
{displaySeries}
testID={'Type ' + allergy.attributes?.category || placeHolder}>
{allergy.attributes?.category || placeHolder}
</TextView>

<Box mt={theme.dimensions.standardMarginBetween}>
<TextView variant="MobileBodyBold">{t('vaccines.details.provider')}</TextView>
{location && (
<>
<TextView variant="MobileBody" selectable={true}>
{location.data.attributes.name}
</TextView>
<TextView variant="MobileBody" selectable={true}>
{location.data.attributes.address?.street}
</TextView>
<TextView variant="MobileBody" selectable={true}>
{t('vaccines.details.address', {
city: location.data.attributes.address?.city,
state: location.data.attributes.address?.state,
zip: location.data.attributes.address?.zipCode,
})}
</TextView>
</>
)}
{!location && (
<TextView variant="MobileBody" selectable={true}>
{placeHolder}
</TextView>
)}
<TextView variant="MobileBody" selectable={true} testID={'Series status'}>
{allergy.attributes?.recorder?.display || placeHolder}
</TextView>
</Box>

<Box mt={theme.dimensions.standardMarginBetween}>
<Box>
<TextView variant="MobileBodyBold">{t('vaccines.details.reaction')}</TextView>
<TextView variant="MobileBody" selectable={true} mb={standardMarginBetween}>
{allergy.attributes?.reaction || placeHolder}
</TextView>
{allergy?.attributes?.reactions?.length ? (
allergy.attributes?.reactions?.map((reaction, index) => {
return reaction.manifestation?.map((manifestation, i) => (
<TextView
key={i}
variant="MobileBody"
selectable={true}
testID={'Reaction ' + manifestation.text || placeHolder}>
{manifestation.text || placeHolder}
</TextView>
))
})
) : (
<TextView variant="MobileBody" selectable={true} testID={'Reaction ' + placeHolder}>
{placeHolder}{' '}
</TextView>
)}
</Box>
<Box mt={theme.dimensions.standardMarginBetween}>
<TextView variant="MobileBodyBold">{t('vaccines.details.notes')}</TextView>
{console.log(JSON.stringify(allergy.attributes?.notes, null, 2))}
{allergy?.attributes?.notes?.length ? (
allergy.attributes?.notes?.map((note, index) => {
console.log('NOTE: ' + JSON.stringify(note, null, 2))
console.log('NOTE TEXT: ' + note.text)
return (
<TextView
key={index}
variant="MobileBody"
selectable={true}
testID={'Note ' + note.text || placeHolder}>
{note.text || placeHolder}
</TextView>
)
})
) : (
<TextView variant="MobileBody" selectable={true} testID={'Note ' + placeHolder}>
{placeHolder}{' '}
</TextView>
)}
</Box>
<TextView variant="MobileBodyBold">{t('vaccines.details.notes')}</TextView>
<TextView
variant="MobileBody"
selectable={true}
testID={'Notes ' + allergy.attributes?.note || 'None noted'}>
{allergy.attributes?.note || placeHolder}
</TextView>
</Box>
</TextArea>
{isPartialData && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ function AllergyListScreen({ navigation }: AllergyListScreenProps) {
error: vaccineError,
refetch: refetchVaccines,
} = useAllergies({ enabled: screenContentAllowed('WG_VaccineList') && !vaccinesInDowntime })

// console.log(JSON.stringify(allergies, null, 3))

const theme = useTheme()
const { t } = useTranslation(NAMESPACE.COMMON)
const navigateTo = useRouteNavigation()
Expand All @@ -64,8 +67,8 @@ function AllergyListScreen({ navigation }: AllergyListScreenProps) {

const allergyButtons: Array<DefaultListItemObj> = map(AllergiesToShow, (allergy, index) => {
const textLines: Array<TextLine> = [
{ text: t('vaccines.vaccineName', { name: allergy.attributes?.groupName }), variant: 'MobileBodyBold' },
{ text: formatDateMMMMDDYYYY(allergy.attributes?.date || '') },
{ text: allergy.attributes?.code?.text ?? '', variant: 'MobileBodyBold' },
{ text: formatDateMMMMDDYYYY(allergy.attributes?.recordedDate || '') },
]

const allergyButton: DefaultListItemObj = {
Expand Down Expand Up @@ -113,10 +116,10 @@ function AllergyListScreen({ navigation }: AllergyListScreenProps) {
backLabel={t('health.title')}
backLabelOnPress={navigation.goBack}
title="Allergies"
titleA11y={a11yLabelVA(t('vaVaccines'))}
titleA11y={a11yLabelVA(t('vaAllergies'))}
scrollViewProps={scrollViewProps}>
{loading ? (
<LoadingComponent text={t('vaccines.loading')} />
<LoadingComponent text={t('allergies.loading')} />
) : vaccineError || vaccinesInDowntime ? (
<ErrorComponent
screenID={ScreenIDTypesConstants.VACCINE_LIST_SCREEN_ID}
Expand Down
6 changes: 5 additions & 1 deletion VAMobile/src/screens/HealthScreen/HealthScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,11 @@ export function HealthScreen({}: HealthScreenProps) {
onPress={() => navigateTo('VaccineList')}
testID="toVaccineListID"
/>
<LargeNavButton title="Allergies" onPress={() => navigateTo('AllergyList')} testID="toAllergyListID" />
<LargeNavButton
title={t('vaAllergies.buttonTitle')}
onPress={() => navigateTo('AllergyList')}
testID="toAllergyListID"
/>
{showAlert && <CategoryLandingAlert text={alertMessage} isError={activityError} />}
</Box>
{cernerExist && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ function VaccineListScreen({ navigation }: VaccineListScreenProps) {
error: vaccineError,
refetch: refetchVaccines,
} = useVaccines({ enabled: screenContentAllowed('WG_VaccineList') && !vaccinesInDowntime })

console.log(JSON.stringify(vaccines, null, 3))

const theme = useTheme()
const { t } = useTranslation(NAMESPACE.COMMON)
const navigateTo = useRouteNavigation()
Expand Down
27 changes: 27 additions & 0 deletions VAMobile/src/store/api/demo/allergies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { AllergyListPayload } from 'api/types/AllergyData'

import { Params } from '..'
import { DemoStore } from './store'

type AllergyPageNumber = '1'

/**
* Type denoting the demo data store
*/
export type AllergyList = {
'/v1/health/allergy-intolerances': {
'1': AllergyListPayload
}
}

export type AllergyDemoStore = AllergyList

/**
* Type to define the mock returns to keep type safety
*/
export type AllergyDemoReturnTypes = undefined | AllergyListPayload

export const getAllergyList = (store: DemoStore, params: Params, endpoint: string): AllergyListPayload => {
const page = params['page[number]']
return store[endpoint as keyof AllergyList][page as AllergyPageNumber] as AllergyListPayload
}
Loading

0 comments on commit e2a96bc

Please sign in to comment.