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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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 [
  47. loading,
  48. lastRefreshDate,
  49. status,
  50. code,
  51. data,
  52. refreshData,
  53. ] = useRequestLogic<T>(
  54. props.request,
  55. props.cache,
  56. props.onCacheUpdate,
  57. props.refreshOnFocus,
  58. MIN_REFRESH_TIME
  59. );
  60. // Store last refresh prop value
  61. const lastRefresh = useRef<boolean>(false);
  62. useEffect(() => {
  63. // Refresh data if refresh prop changed and we are not loading
  64. if (props.refresh && !lastRefresh.current && !loading) {
  65. refreshData();
  66. // Call finish callback if refresh prop was set and we finished loading
  67. } else if (lastRefresh.current && !loading && props.onFinish) {
  68. props.onFinish();
  69. }
  70. // Update stored refresh prop value
  71. if (props.refresh !== lastRefresh.current) {
  72. lastRefresh.current = props.refresh === true;
  73. }
  74. }, [props, loading, refreshData]);
  75. useFocusEffect(
  76. React.useCallback(() => {
  77. if (!props.cache && props.refreshOnFocus !== false) {
  78. refreshData();
  79. }
  80. if (props.autoRefreshTime && props.autoRefreshTime > 0) {
  81. refreshInterval.current = setInterval(
  82. refreshData,
  83. props.autoRefreshTime
  84. );
  85. }
  86. return () => {
  87. if (refreshInterval.current) {
  88. clearInterval(refreshInterval.current);
  89. }
  90. };
  91. }, [props.cache, props.refreshOnFocus, props.autoRefreshTime, refreshData])
  92. );
  93. const isErrorCritical = (e: API_REQUEST_CODES | undefined) => {
  94. return e === API_REQUEST_CODES.BAD_TOKEN;
  95. };
  96. useEffect(() => {
  97. if (isErrorCritical(code)) {
  98. onLogout();
  99. navigation.replace(MainRoutes.Login, { nextScreen: route.name });
  100. }
  101. }, [code, navigation, route, onLogout]);
  102. if (data === undefined && loading && props.showLoading !== false) {
  103. return <BasicLoadingScreen />;
  104. } else if (
  105. data === undefined &&
  106. (status !== REQUEST_STATUS.SUCCESS ||
  107. (status === REQUEST_STATUS.SUCCESS && code !== undefined)) &&
  108. props.showError !== false
  109. ) {
  110. return (
  111. <ErrorView
  112. status={status}
  113. code={code}
  114. loading={loading}
  115. button={
  116. isErrorCritical(code)
  117. ? undefined
  118. : {
  119. icon: 'refresh',
  120. text: i18n.t('general.retry'),
  121. onPress: () => refreshData(),
  122. }
  123. }
  124. />
  125. );
  126. } else {
  127. return props.render(
  128. data,
  129. loading,
  130. lastRefreshDate,
  131. refreshData,
  132. status,
  133. code
  134. );
  135. }
  136. }