Skip to content

Commit

Permalink
[cases] error handling and feedback improvements (#91)
Browse files Browse the repository at this point in the history
* [feat] add loading feedback to qr code scanner button.

* [feat] add loading feedback to AddCase screen button.

* [feat] add loading feedback to confirm eligibility button.

* [feat] loading feedback for ineligibility and opt out actions.

* [feat] add loading feedback to file claim action.

* [fix] restructure CaseScreen and CaseContext to prevent unnecessary reloads.

* [refactor] integrate getCaseStatus with case context.

* [refactor] case status -> claim status.

* [feat] create basic loading spinner component.

* [feat] replace loading text with spinner on all screens.

* [feat] add light grey background as image placeholder.

* [refactor] loading screen component.

* [refactor] move add/remove case to case context.

* [cleanup] add ios/ to gitignore.

* [cleanup] use case context function for fetching context data.

* [cleanup] remove unused import.

* [wip][feat] configure timeout behavior for poor network connection settings.

* [refactor] move resetAndPushToRoute to auth queries; cleanup.

* [feat] create resetAndPushToHome that navigates to the home screen (relative to whether they're logged in or not).

* [feat] create wip full stop error function; refactor screen loading component.

* [cleanup] misc cleanup; update screen loading text for clarity.

* [cleanup] update doc strings.

* [feat] begin integrating error handler for case fetching functions.

* [wip] continue adding error handling to case related screens.

* [feat] add error handler to all case related screens.

* [fix] case context code performance and clarity improvements.

* [cleanup] misc refactoring and adding comments.

* [fix] resolve missing caseData on FileClaim screen.
  • Loading branch information
ronniebeggs authored Jun 19, 2024
1 parent d37a573 commit 3154f46
Show file tree
Hide file tree
Showing 28 changed files with 567 additions and 307 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ node_modules/
.expo/
dist/
web-build/
ios/

# Native
*.orig.*
Expand Down
83 changes: 83 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"react-native-elements": "^3.4.3",
"react-native-gesture-handler": "~2.16.1",
"react-native-otp-textinput": "^1.1.5",
"react-native-paper": "^5.12.3",
"react-native-safe-area-context": "4.10.1",
"react-native-screens": "3.31.1",
"react-native-svg": "15.2.0",
Expand Down
1 change: 1 addition & 0 deletions src/Components/CaseSummaryCard/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export default StyleSheet.create({
justifyContent: 'space-between',
borderTopRightRadius: 4,
borderTopLeftRadius: 4,
backgroundColor: colors.lightGrey,
},
infoContainer: {
flexDirection: 'column',
Expand Down
1 change: 1 addition & 0 deletions src/Components/CaseSummaryContent/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default StyleSheet.create({
borderRadius: 5,
marginTop: 30,
marginBottom: 20,
backgroundColor: colors.lightGrey,
},
summaryContainer: {
width: '100%',
Expand Down
10 changes: 3 additions & 7 deletions src/Components/FormsCard/FormsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,9 @@ export default function FormsCard(caseData: Case) {
const [featuredForm, setFeaturedForm] = useState<Form>();

const getForm = async () => {
const formData = await getFeaturedForm(
caseData.id,
caseData.featuredFormName,
);
if (formData) {
setFeaturedForm(formData);
}
await getFeaturedForm(caseData.id, caseData.featuredFormName)
.then(formData => setFeaturedForm(formData))
.catch(response => console.warn(response));
};

useEffect(() => {
Expand Down
42 changes: 42 additions & 0 deletions src/Components/ScreenLoadingComponent/ScreenLoadingComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useEffect, useState } from 'react';
import { View, Text } from 'react-native';
import { ActivityIndicator } from 'react-native-paper';

import styles from './styles';
import { colors } from '../../styles/colors';
import { fonts } from '../../styles/fonts';

export default function ScreenLoadingComponent() {
const [loadingPromptExists, setLoadingPromptExists] =
useState<boolean>(false);
const [timeoutReached, setTimeoutReached] = useState<boolean>(false);

useEffect(() => {
setTimeout(() => {
setLoadingPromptExists(true);
setTimeout(() => {
setTimeoutReached(true);
}, 10000);
}, 5000);
}, []);

return (
<View style={styles.container}>
<ActivityIndicator size="small" color={colors.midRed} />
{loadingPromptExists && (
<View>
{!timeoutReached ? (
<Text style={fonts.body}>This is taking longer than usual...</Text>
) : (
<Text style={fonts.body}>
There seems to be an issue connecting with Impact Fund servers...{' '}
{'\n'}
{'\n'}
Please check your internet connection or try again later.
</Text>
)}
</View>
)}
</View>
);
}
10 changes: 10 additions & 0 deletions src/Components/ScreenLoadingComponent/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { StyleSheet } from 'react-native';

export default StyleSheet.create({
container: {
width: 300,
alignItems: 'center',
marginTop: 20,
rowGap: 20,
},
});
59 changes: 26 additions & 33 deletions src/app/(BottomTabNavigation)/AllCases/CaseScreen/[caseUid].tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useLocalSearchParams, useNavigation } from 'expo-router';
import { useLocalSearchParams } from 'expo-router';
import React, { useEffect, useState } from 'react';
import { View, ScrollView, Text } from 'react-native';

Expand All @@ -9,50 +9,45 @@ import ClaimStatusBar from '../../../../Components/ClaimStatusBar/ClaimStatusBar
import EducationalBar from '../../../../Components/EducationalBar/EducationalBar';
import EligibilityCard from '../../../../Components/EligibilityCard/EligibilityCard';
import FormsCard from '../../../../Components/FormsCard/FormsCard';
import ScreenLoadingComponent from '../../../../Components/ScreenLoadingComponent/ScreenLoadingComponent';
import StatusUpdatesBar from '../../../../Components/StatusUpdatesBar/StatusUpdatesBar';
import { useCaseContext } from '../../../../context/CaseContext';
import { fonts } from '../../../../styles/fonts';
import { device } from '../../../../styles/global';
import { getCaseStatus, getCaseById } from '../../../../supabase/queries/cases';
import { Case, Eligibility } from '../../../../types/types';
import { fullStopErrorHandler } from '../../../../supabase/queries/auth';
import { getCaseById } from '../../../../supabase/queries/cases';
import { Case, ClaimStatus } from '../../../../types/types';

function CaseScreen() {
export default function CaseScreen() {
const { caseUid } = useLocalSearchParams<{ caseUid: string }>();
const [status, setStatus] = useState<Eligibility>();
const [status, setStatus] = useState<ClaimStatus>();
const [caseData, setCaseData] = useState<Case>();
const [isLoading, setIsLoading] = useState<boolean>(true);
const navigation = useNavigation();

const getCase = async (uid: string) => {
const caseData = await getCaseById(uid);
setCaseData(caseData);
setIsLoading(false);
const { getClaimStatus } = useCaseContext();

const getCase = async (caseUid: string) => {
await getCaseById(caseUid)
.then(caseData => setCaseData(caseData))
.catch(response => fullStopErrorHandler(response));
};

const getStatus = async (uid: string) => {
const caseStatus = await getCaseStatus(uid);
setStatus(caseStatus);
const getStatus = async (caseUid: string) => {
await getClaimStatus(caseUid)
.then(claimStatus => setStatus(claimStatus))
.catch(response => fullStopErrorHandler(response));
};

useEffect(() => {
if (caseUid !== undefined) {
if (caseUid) {
getCase(caseUid);
getStatus(caseUid);
}
}, []);

useEffect(() => {
navigation.addListener('focus', async () => {
setIsLoading(true);
if (caseUid !== undefined) {
await getStatus(caseUid);
}
setIsLoading(false);
});
}, [navigation]);

return (
<View style={device.safeArea}>
{isLoading || caseData === undefined ? (
<Text>Loading...</Text>
{!caseData || !status ? (
<ScreenLoadingComponent />
) : (
<ScrollView
style={styles.outerScroll}
Expand All @@ -65,18 +60,18 @@ function CaseScreen() {
</Text>
</View>

{status === Eligibility.ELIGIBLE && (
{status === ClaimStatus.ELIGIBLE && (
<EligibilityCard caseUid={caseData.id} />
)}

{status === Eligibility.CLAIM_FILED && (
{status === ClaimStatus.CLAIM_FILED && (
<ClaimStatusBar status="Claim Filed" />
)}

<CaseSummaryCard {...caseData} />

{(status === Eligibility.INELIGIBLE ||
status === Eligibility.UNDETERMINED) && (
{(status === ClaimStatus.INELIGIBLE ||
status === ClaimStatus.UNDETERMINED) && (
<CheckEligibilityButton caseUid={caseData.id} />
)}
<StatusUpdatesBar
Expand All @@ -90,5 +85,3 @@ function CaseScreen() {
</View>
);
}

export default CaseScreen;
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { useLocalSearchParams } from 'expo-router';
import React, { useState, useEffect } from 'react';
import { View, Text } from 'react-native';
import { View } from 'react-native';

import styles from './styles';
import CaseSummaryContent from '../../../../Components/CaseSummaryContent/CaseSummaryContent';
import ExternalSiteLink from '../../../../Components/ExternalSiteLink/ExternalSiteLink';
import ScreenLoadingComponent from '../../../../Components/ScreenLoadingComponent/ScreenLoadingComponent';
import { device } from '../../../../styles/global';
import { fullStopErrorHandler } from '../../../../supabase/queries/auth';
import { getCaseById } from '../../../../supabase/queries/cases';
import { Case } from '../../../../types/types';

Expand All @@ -14,20 +16,21 @@ export default function CaseSummaryScreen() {
const [caseData, setCaseData] = useState<Case>();

const getCase = async (uid: string) => {
const caseData = await getCaseById(uid);
setCaseData(caseData);
await getCaseById(uid)
.then(caseData => setCaseData(caseData))
.catch(response => fullStopErrorHandler(response));
};

useEffect(() => {
if (caseUid !== undefined) {
if (caseUid) {
getCase(caseUid);
}
}, []);

return (
<View style={device.safeArea}>
{caseData === undefined ? (
<Text>Loading...</Text>
<ScreenLoadingComponent />
) : (
<>
<CaseSummaryContent {...caseData} />
Expand Down
Loading

0 comments on commit 3154f46

Please sign in to comment.