Skip to content

Commit

Permalink
feat: render demographics
Browse files Browse the repository at this point in the history
  • Loading branch information
mgramigna committed Dec 22, 2023
1 parent 5fd1d8c commit c1b7613
Show file tree
Hide file tree
Showing 17 changed files with 396 additions and 25 deletions.
5 changes: 5 additions & 0 deletions apps/expo/src/app/(app)/appointments/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ const Appointments = () => {
</TouchableOpacity>
</View>
{slotsLoading && <ActivityIndicator />}
{slots?.total === 0 && (
<Text italic className="text-center text-xl">
No available appointments
</Text>
)}
<FlatList
showsVerticalScrollIndicator={false}
className="pb-20"
Expand Down
9 changes: 8 additions & 1 deletion apps/expo/src/app/(app)/home/allergy.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react';
import { ScrollView } from 'react-native';
import { ScrollView, View } from 'react-native';
import { router } from 'expo-router';
import { Button } from '@/components/atoms/Button';
import { Text } from '@/components/atoms/Text';
import { ScreenView } from '@/components/molecules/ScreenView';
import { useAuth } from '@/context/AuthContext';
Expand All @@ -13,6 +15,11 @@ const Allergy = () => {
<Text className="mt-8 text-xl">
To update your allergies, please reach out to your care team
</Text>
<View className="mt-8 flex flex-row gap-8">
<View className="flex-1">
<Button text="Close" variant="secondary" onPress={() => router.push('..')} />
</View>
</View>
</ScrollView>
</ScreenView>
) : null;
Expand Down
2 changes: 1 addition & 1 deletion apps/expo/src/app/(app)/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ const Home = () => {
)}
<Button
text="Find Vaccines"
className="mt-4"
className="mb-24 mt-4"
onPress={() => Linking.openURL('https://www.vaccines.gov')}
/>
</View>
Expand Down
104 changes: 93 additions & 11 deletions apps/expo/src/app/(app)/profile/about.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,50 @@
import React from 'react';
import { ActivityIndicator, ScrollView, View } from 'react-native';
import React, { useCallback, useState } from 'react';
import { ActivityIndicator, Alert, View } from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import { Button } from '@/components/atoms/Button';
import { Skeleton } from '@/components/atoms/Skeleton';
import { Text } from '@/components/atoms/Text';
import { AddEditDemographicsModal } from '@/components/molecules/AddEditDemographicsModal';
import { AddGoalModal } from '@/components/molecules/AddGoalModal';
import { ScreenView } from '@/components/molecules/ScreenView';
import { type DemographicsFormType } from '@/components/organisms/DemographicsForm';
import { DemographicsInfo } from '@/components/organisms/DemographicsInfo';
import { usePatient } from '@/context/PatientContext';

// import { getEthnicities, getRaces } from '@/fhirpath/patient';
import { getCodeFromConcept } from '@/fhirpath/utils';
import { palette } from '@/theme/colors';
import { api } from '@/utils/api';
import { MaterialCommunityIcons } from '@expo/vector-icons';

const About = () => {
const [goalModalOpen, setGoalModalOpen] = useState(false);
const [demographicsModalOpen, setDemographicsModalOpen] = useState(false);

const { patient, isLoading } = usePatient();

const { data: goalBundle, isLoading: goalsLoading } = api.goal.search.useQuery(
{
patient: patient!.id,
},
{
enabled: patient != null,
},
);

const utils = api.useUtils();
const updatePatientMutation = api.patient.update.useMutation({
onSuccess: async () => {
await utils.patient.get.invalidate();
setDemographicsModalOpen(false);
},
onError: () => {
Alert.alert('Something went wrong');
},
});

const handleDemographicsSave = useCallback((_form: DemographicsFormType) => {
Alert.alert('TODO: update patient resource');
}, []);

if (isLoading) {
return (
<ScreenView>
Expand All @@ -20,13 +56,59 @@ const About = () => {
}

return patient ? (
<ScreenView>
<ScrollView className="h-full" showsVerticalScrollIndicator={false}>
<Text className="text-2xl" weight="bold">
About Me
</Text>
</ScrollView>
</ScreenView>
<>
<ScreenView>
<KeyboardAwareScrollView className="h-full" showsVerticalScrollIndicator={false}>
<View>
<Text className="text-3xl" weight="bold">
Healthcare Goals
</Text>
<View>
{goalsLoading && <Skeleton className="bg-coolGray-200 h-10 w-full" />}
{!goalsLoading &&
goalBundle?.entry
?.filter(
({ resource }) => getCodeFromConcept(resource.achievementStatus) !== 'achieved',
)
.map(({ resource: goal }) => (
<View key={goal.id} className="flex flex-row">
<MaterialCommunityIcons
name="format-quote-open"
size={36}
color={palette.cyan[300]}
/>
<View className="self-end">
<Text className="text-lg">{goal.description.text}</Text>
</View>
</View>
))}
<View className="mt-8">
<Button text="Add Goal" onPress={() => setGoalModalOpen(true)} />
</View>
</View>
</View>
<View className="mt-8 pb-24">
<Text className="text-3xl" weight="bold">
Demographics
</Text>
<View className="mt-4">
<DemographicsInfo patient={patient} />
<View className="mt-8">
<Button text="Update Demographics" onPress={() => setDemographicsModalOpen(true)} />
</View>
</View>
</View>
</KeyboardAwareScrollView>
</ScreenView>
<AddGoalModal isOpen={goalModalOpen} onClose={() => setGoalModalOpen(false)} />
<AddEditDemographicsModal
isOpen={demographicsModalOpen}
onClose={() => setDemographicsModalOpen(false)}
onSubmit={handleDemographicsSave}
patient={patient}
isMutating={updatePatientMutation.isPending}
/>
</>
) : null;
};

Expand Down
19 changes: 11 additions & 8 deletions apps/expo/src/app/(app)/profile/billing.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { Fragment, useCallback, useState } from 'react';
import { ScrollView, View } from 'react-native';
import { Button } from '@/components/atoms/Button';
import { Skeleton } from '@/components/atoms/Skeleton';
import { Text } from '@/components/atoms/Text';
import { AddEditInsuranceModal } from '@/components/molecules/AddEditInsuranceModal';
import { ScreenView } from '@/components/molecules/ScreenView';
Expand All @@ -16,7 +17,7 @@ const Billing = () => {
const { patientId } = useAuth();
const [insuranceModalOpen, setInsuranceModalOpen] = useState(false);

const { data: coverageBundle } = api.coverage.search.useQuery(
const { data: coverageBundle, isLoading: coverageLoading } = api.coverage.search.useQuery(
{
patient: patientId!,
},
Expand Down Expand Up @@ -65,13 +66,15 @@ const Billing = () => {
</Text>
</View>
<View className="mt-8 flex gap-4">
{coverageBundle?.entry
?.filter(({ resource }) => resource.status === 'active')
.map(({ resource }) => (
<Fragment key={resource.id}>
<CoverageDetail coverage={resource} patientId={patientId} />
</Fragment>
))}
{coverageLoading && <Skeleton className="bg-coolGray-200 h-52 w-full" />}
{!coverageLoading &&
coverageBundle?.entry
?.filter(({ resource }) => resource.status === 'active')
.map(({ resource }) => (
<Fragment key={resource.id}>
<CoverageDetail coverage={resource} patientId={patientId} />
</Fragment>
))}
</View>
<View className="mt-8">
<Button text="Add New Insurance" onPress={() => setInsuranceModalOpen(true)} />
Expand Down
2 changes: 1 addition & 1 deletion apps/expo/src/app/(app)/profile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const Profile = () => {
/>
</TouchableOpacity>
</View>
<View className="mt-24">
<View className="mt-12">
<Button onPress={signOut} variant="secondary" text="Log Out" />
</View>
</ScrollView>
Expand Down
11 changes: 11 additions & 0 deletions apps/expo/src/components/atoms/Chip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { View } from 'react-native';

import { Text } from './Text';

export const Chip = ({ text }: { text?: string }) => {
return (
<View className="rounded-full bg-cyan-200 p-4">
<Text className="text-coolGray-700 text-xl">{text}</Text>
</View>
);
};
41 changes: 41 additions & 0 deletions apps/expo/src/components/molecules/AddEditDemographicsModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Modal } from 'react-native';
import { AutocompleteDropdownContextProvider } from 'react-native-autocomplete-dropdown';

import { type Patient } from '@careforge/canvas';

import { ScreenView } from '../molecules/ScreenView';
import { DemographicsForm, type DemographicsFormType } from '../organisms/DemographicsForm';

export const AddEditDemographicsModal = ({
isOpen,
onSubmit,
onClose,
patient,
isMutating,
}: {
patient: Patient;
isOpen: boolean;
onClose: () => void;
onSubmit: (form: DemographicsFormType) => void;
isMutating?: boolean;
}) => {
return (
<Modal
animationType="slide"
visible={isOpen}
presentationStyle="pageSheet"
onRequestClose={onClose}
>
<AutocompleteDropdownContextProvider>
<ScreenView>
<DemographicsForm
onCancel={onClose}
onSubmit={onSubmit}
isMutating={isMutating}
patient={patient}
/>
</ScreenView>
</AutocompleteDropdownContextProvider>
</Modal>
);
};
32 changes: 32 additions & 0 deletions apps/expo/src/components/molecules/AddGoalModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Modal, ScrollView, View } from 'react-native';
import { AutocompleteDropdownContextProvider } from 'react-native-autocomplete-dropdown';

import { Button } from '../atoms/Button';
import { Text } from '../atoms/Text';
import { ScreenView } from '../molecules/ScreenView';

export const AddGoalModal = ({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) => {
return (
<Modal
animationType="slide"
visible={isOpen}
presentationStyle="pageSheet"
onRequestClose={onClose}
>
<AutocompleteDropdownContextProvider>
<ScreenView>
<ScrollView className="h-full">
<Text className="mt-8 text-xl">
To update your health goals, please reach out to your care team
</Text>
<View className="mt-8 flex flex-row gap-8">
<View className="flex-1">
<Button text="Close" variant="secondary" onPress={onClose} />
</View>
</View>
</ScrollView>
</ScreenView>
</AutocompleteDropdownContextProvider>
</Modal>
);
};
4 changes: 2 additions & 2 deletions apps/expo/src/components/molecules/DetailCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ export const DetailCard = ({
<View className="bg-coolGray-700 border-coolGray-300 flex flex-row items-center justify-between rounded-md border px-4 py-8">
<View className="flex flex-row items-center">
{leftIcon}
<View className="pl-2">
<View className="pl-2 pr-2">
<Text className="text-lg">{text}</Text>
</View>
{rightIcon}
</View>
{rightIcon}
</View>
</TouchableOpacity>
);
Expand Down
2 changes: 1 addition & 1 deletion apps/expo/src/components/organisms/ConsentDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const ConsentDetail = ({ consent }: { consent: Consent }) => {
text={`${getConsentName(consent)} (${
consent.status === 'active' ? 'Accepted' : 'Rejected'
})`}
rightIcon={<Ionicons name="document" size={24} color={palette.cyan[700]} />}
leftIcon={<Ionicons name="document" size={24} color={palette.cyan[700]} />}
onPress={() => setIsOpen(true)}
/>
<Modal
Expand Down
59 changes: 59 additions & 0 deletions apps/expo/src/components/organisms/DemographicsForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';
import { View } from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { z } from 'zod';

import { type Patient } from '@careforge/canvas';

import { Button } from '../atoms/Button';
import { Text } from '../atoms/Text';

const DemographicsFormSchema = z.object({});

export type DemographicsFormType = z.infer<typeof DemographicsFormSchema>;

export const DemographicsForm = ({
patient: _patient,
onSubmit,
onCancel,
isMutating,
}: {
patient: Patient;
onSubmit: (form: DemographicsFormType) => void;
onCancel: () => void;
isMutating?: boolean;
}) => {
const {
formState: { isValid },
handleSubmit,
} = useForm<DemographicsFormType>({
resolver: zodResolver(DemographicsFormSchema),
defaultValues: {},
});

return (
<KeyboardAwareScrollView showsVerticalScrollIndicator={false} className="h-full">
<Text className="text-3xl" weight="bold">
Edit Demographics
</Text>
<View className="mt-8 flex gap-8">
<Text>TODO</Text>
</View>
<View className="mt-8 flex flex-row gap-8">
<View className="flex-1">
<Button text="Cancel" variant="secondary" onPress={onCancel} />
</View>
<View className="flex-1">
<Button
disabled={!isValid}
text="Save"
onPress={handleSubmit(onSubmit)}
isLoading={isMutating}
/>
</View>
</View>
</KeyboardAwareScrollView>
);
};
Loading

0 comments on commit c1b7613

Please sign in to comment.