Application Android et IOS pour l'amicale des élèves https://play.google.com/store/apps/details?id=fr.amicaleinsat.application
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RequestScreen.tsx 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import React, { useEffect, useRef } from 'react';
  2. import ErrorView from './ErrorView';
  3. import { useRequestLogic } from '../../utils/customHooks';
  4. import {
  5. useFocusEffect,
  6. useNavigation,
  7. useRoute,
  8. } from '@react-navigation/native';
  9. import BasicLoadingScreen from './BasicLoadingScreen';
  10. import i18n from 'i18n-js';
  11. import { API_REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
  12. import { StackNavigationProp } from '@react-navigation/stack';
  13. import { MainRoutes } from '../../navigation/MainNavigator';
  14. import { useLogout } from '../../utils/logout';
  15. export type RequestScreenProps<T> = {
  16. request: () => Promise<T>;
  17. render: (
  18. data: T | undefined,
  19. loading: boolean,
  20. lastRefreshDate: Date | undefined,
  21. refreshData: (newRequest?: () => Promise<T>) => void,
  22. status: REQUEST_STATUS,
  23. code?: API_REQUEST_CODES
  24. ) => React.ReactElement;
  25. cache?: T;
  26. onCacheUpdate?: (newCache: T) => void;
  27. onMajorError?: (status: number, code?: number) => void;
  28. showLoading?: boolean;
  29. showError?: boolean;
  30. refreshOnFocus?: boolean;
  31. autoRefreshTime?: number;
  32. refresh?: boolean;
  33. onFinish?: () => void;
  34. };
  35. export type RequestProps = {
  36. refreshData: () => void;
  37. loading: boolean;
  38. };
  39. type Props<T> = RequestScreenProps<T>;
  40. const MIN_REFRESH_TIME = 3 * 1000;
  41. export default function RequestScreen<T>(props: Props<T>) {
  42. const onLogout = useLogout();
  43. const navigation = useNavigation<StackNavigationProp<any>>();
  44. const route = useRoute();
  45. const refreshInterval = useRef<number>();
  46. const [loading, lastRefreshDate, status, code, data, refreshData] =
  47. useRequestLogic<T>(
  48. props.request,
  49. props.cache,
  50. props.onCacheUpdate,
  51. props.refreshOnFocus,
  52. MIN_REFRESH_TIME
  53. );
  54. // Store last refresh prop value
  55. const lastRefresh = useRef<boolean>(false);
  56. useEffect(() => {
  57. // Refresh data if refresh prop changed and we are not loading
  58. if (props.refresh && !lastRefresh.current && !loading) {
  59. refreshData();
  60. // Call finish callback if refresh prop was set and we finished loading
  61. } else if (lastRefresh.current && !loading && props.onFinish) {
  62. props.onFinish();
  63. }
  64. // Update stored refresh prop value
  65. if (props.refresh !== lastRefresh.current) {
  66. lastRefresh.current = props.refresh === true;
  67. }
  68. }, [props, loading, refreshData]);
  69. useFocusEffect(
  70. React.useCallback(() => {
  71. if (!props.cache && props.refreshOnFocus !== false) {
  72. refreshData();
  73. }
  74. if (props.autoRefreshTime && props.autoRefreshTime > 0) {
  75. refreshInterval.current = setInterval(
  76. refreshData,
  77. props.autoRefreshTime
  78. );
  79. }
  80. return () => {
  81. if (refreshInterval.current) {
  82. clearInterval(refreshInterval.current);
  83. }
  84. };
  85. }, [props.cache, props.refreshOnFocus, props.autoRefreshTime, refreshData])
  86. );
  87. const isErrorCritical = (e: API_REQUEST_CODES | undefined) => {
  88. return e === API_REQUEST_CODES.BAD_TOKEN;
  89. };
  90. useEffect(() => {
  91. if (isErrorCritical(code)) {
  92. onLogout();
  93. navigation.replace(MainRoutes.Login, { nextScreen: route.name });
  94. }
  95. }, [code, navigation, route, onLogout]);
  96. if (data === undefined && loading && props.showLoading !== false) {
  97. return <BasicLoadingScreen />;
  98. } else if (
  99. data === undefined &&
  100. (status !== REQUEST_STATUS.SUCCESS ||
  101. (status === REQUEST_STATUS.SUCCESS && code !== undefined)) &&
  102. props.showError !== false
  103. ) {
  104. return (
  105. <ErrorView
  106. status={status}
  107. code={code}
  108. loading={loading}
  109. button={
  110. isErrorCritical(code)
  111. ? undefined
  112. : {
  113. icon: 'refresh',
  114. text: i18n.t('general.retry'),
  115. onPress: () => refreshData(),
  116. }
  117. }
  118. />
  119. );
  120. } else {
  121. return props.render(
  122. data,
  123. loading,
  124. lastRefreshDate,
  125. refreshData,
  126. status,
  127. code
  128. );
  129. }
  130. }