-
Notifications
You must be signed in to change notification settings - Fork 3k
/
Copy pathListBoundaryLoader.tsx
115 lines (99 loc) · 4.37 KB
/
ListBoundaryLoader.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import React, {useEffect} from 'react';
import {ActivityIndicator, View} from 'react-native';
import type {ValueOf} from 'type-fest';
import Button from '@components/Button';
import ReportActionsSkeletonView from '@components/ReportActionsSkeletonView';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';
type ListBoundaryLoaderProps = {
/** type of rendered loader. Can be 'header' or 'footer' */
type: ValueOf<typeof CONST.LIST_COMPONENTS>;
/** Shows if we call fetching older report action */
isLoadingOlderReportActions?: boolean;
/** Shows if we call initial loading of report action */
isLoadingInitialReportActions?: boolean;
/** Shows if we call fetching newer report action */
isLoadingNewerReportActions?: boolean;
/** Name of the last report action */
lastReportActionName?: string;
/** Shows if there was an error when loading report actions */
hasError?: boolean;
/** Function to retry if there was an error */
onRetry?: () => void;
};
function ListBoundaryLoader({
type,
isLoadingOlderReportActions = false,
isLoadingInitialReportActions = false,
lastReportActionName = '',
isLoadingNewerReportActions = false,
hasError = false,
onRetry,
}: ListBoundaryLoaderProps) {
const theme = useTheme();
const styles = useThemeStyles();
const {isOffline} = useNetwork();
const {translate} = useLocalize();
// When retrying we want to show the loading state in the retry button so we
// have this separate state to handle that.
const [isRetrying, setIsRetrying] = React.useState(false);
const retry = () => {
setIsRetrying(true);
onRetry?.();
};
// Reset the retrying state once loading is done.
useEffect(() => {
if (isLoadingNewerReportActions || isLoadingOlderReportActions) {
return;
}
setIsRetrying(false);
}, [isLoadingNewerReportActions, isLoadingOlderReportActions]);
if (hasError || isRetrying) {
return (
<View style={[styles.alignItemsCenter, styles.justifyContentCenter, styles.listBoundaryError]}>
<Text style={styles.listBoundaryErrorText}>{translate('listBoundary.errorMessage')}</Text>
{!isOffline && (
<Button
small
onPress={retry}
text={translate('listBoundary.tryAgain')}
isLoading={isRetrying}
/>
)}
</View>
);
}
// We use two different loading components for the header and footer
// to reduce the jumping effect when the user is scrolling to the newer report actions
if (type === CONST.LIST_COMPONENTS.FOOTER) {
/*
Ensure that the report chat is not loaded until the beginning.
This is to avoid displaying the skeleton view above the "created" action in a newly generated optimistic chat or one with not that many comments.
Additionally, if we are offline and the report is not loaded until the beginning, we assume there are more actions to load;
Therefore, show the skeleton view even though the actions are not actually loading.
*/
const isReportLoadedUntilBeginning = lastReportActionName === CONST.REPORT.ACTIONS.TYPE.CREATED;
const mayLoadMoreActions = !isReportLoadedUntilBeginning && (isLoadingInitialReportActions || isOffline);
if (isLoadingOlderReportActions || mayLoadMoreActions) {
return <ReportActionsSkeletonView />;
}
}
if (type === CONST.LIST_COMPONENTS.HEADER && isLoadingNewerReportActions) {
// applied for a header of the list, i.e. when you scroll to the bottom of the list
// the styles for android and the rest components are different that's why we use two different components
return (
<View style={[styles.alignItemsCenter, styles.justifyContentCenter, styles.listBoundaryLoader]}>
<ActivityIndicator
color={theme.spinner}
size="small"
/>
</View>
);
}
}
ListBoundaryLoader.displayName = 'ListBoundaryLoader';
export default ListBoundaryLoader;