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.

WebSectionList.tsx 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * Copyright (c) 2019 - 2020 Arnaud Vergnet.
  3. *
  4. * This file is part of Campus INSAT.
  5. *
  6. * Campus INSAT is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Campus INSAT is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. import React, { useState } from 'react';
  20. import i18n from 'i18n-js';
  21. import { Snackbar } from 'react-native-paper';
  22. import {
  23. RefreshControl,
  24. SectionListData,
  25. SectionListProps,
  26. StyleSheet,
  27. View,
  28. } from 'react-native';
  29. import ErrorView from './ErrorView';
  30. import { TAB_BAR_HEIGHT } from '../Tabbar/CustomTabBar';
  31. import CollapsibleSectionList from '../Collapsible/CollapsibleSectionList';
  32. import GENERAL_STYLES from '../../constants/Styles';
  33. import RequestScreen, { RequestScreenProps } from './RequestScreen';
  34. import { CollapsibleComponentPropsType } from '../Collapsible/CollapsibleComponent';
  35. import { REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
  36. export type SectionListDataType<ItemT> = Array<{
  37. title: string;
  38. icon?: string;
  39. data: Array<ItemT>;
  40. keyExtractor?: (data: ItemT) => string;
  41. }>;
  42. type Props<ItemT, RawData> = Omit<
  43. CollapsibleComponentPropsType,
  44. 'children' | 'paddedProps'
  45. > &
  46. Omit<
  47. RequestScreenProps<RawData>,
  48. | 'render'
  49. | 'showLoading'
  50. | 'showError'
  51. | 'refresh'
  52. | 'onFinish'
  53. | 'onMajorError'
  54. > &
  55. Omit<
  56. SectionListProps<ItemT>,
  57. 'sections' | 'getItemLayout' | 'ListHeaderComponent' | 'ListEmptyComponent'
  58. > & {
  59. createDataset: (
  60. data: RawData | undefined,
  61. isLoading: boolean
  62. ) => SectionListDataType<ItemT>;
  63. renderListHeaderComponent?: (
  64. data?: RawData
  65. ) => React.ComponentType<any> | React.ReactElement | null;
  66. renderSectionHeader?: (
  67. data: { section: SectionListData<ItemT> },
  68. isLoading: boolean
  69. ) => React.ReactElement | null;
  70. itemHeight?: number | null;
  71. };
  72. const styles = StyleSheet.create({
  73. container: {
  74. minHeight: '100%',
  75. },
  76. });
  77. /**
  78. * Component used to render a SectionList with data fetched from the web
  79. * To force the component to update, change the value of updateData.
  80. */
  81. function WebSectionList<ItemT, RawData>(props: Props<ItemT, RawData>) {
  82. const [snackbarVisible, setSnackbarVisible] = useState(false);
  83. const showSnackBar = () => setSnackbarVisible(true);
  84. const hideSnackBar = () => setSnackbarVisible(false);
  85. const getItemLayout = (
  86. height: number,
  87. _data: Array<SectionListData<ItemT>> | null,
  88. index: number
  89. ): { length: number; offset: number; index: number } => {
  90. return {
  91. length: height,
  92. offset: height * index,
  93. index,
  94. };
  95. };
  96. const render = (
  97. data: RawData | undefined,
  98. loading: boolean,
  99. refreshData: (newRequest?: () => Promise<RawData>) => void,
  100. status: REQUEST_STATUS,
  101. code?: REQUEST_CODES
  102. ) => {
  103. const { itemHeight } = props;
  104. const dataset = props.createDataset(data, loading);
  105. if (!data && !loading) {
  106. showSnackBar();
  107. }
  108. return (
  109. <CollapsibleSectionList
  110. {...props}
  111. sections={dataset}
  112. paddedProps={(paddingTop) => ({
  113. refreshControl: (
  114. <RefreshControl
  115. progressViewOffset={paddingTop}
  116. refreshing={loading}
  117. onRefresh={refreshData}
  118. />
  119. ),
  120. })}
  121. renderItem={props.renderItem}
  122. style={styles.container}
  123. ListHeaderComponent={
  124. props.renderListHeaderComponent != null
  125. ? props.renderListHeaderComponent(data)
  126. : null
  127. }
  128. ListEmptyComponent={
  129. loading ? undefined : (
  130. <ErrorView
  131. status={status}
  132. code={code}
  133. button={{
  134. icon: 'refresh',
  135. text: i18n.t('general.retry'),
  136. onPress: refreshData,
  137. }}
  138. />
  139. )
  140. }
  141. getItemLayout={
  142. itemHeight ? (d, i) => getItemLayout(itemHeight, d, i) : undefined
  143. }
  144. />
  145. );
  146. };
  147. return (
  148. <View style={GENERAL_STYLES.flex}>
  149. <RequestScreen<RawData>
  150. request={props.request}
  151. render={render}
  152. showError={false}
  153. showLoading={false}
  154. autoRefreshTime={props.autoRefreshTime}
  155. refreshOnFocus={props.refreshOnFocus}
  156. cache={props.cache}
  157. onCacheUpdate={props.onCacheUpdate}
  158. />
  159. <Snackbar
  160. visible={snackbarVisible}
  161. onDismiss={hideSnackBar}
  162. action={{
  163. label: 'OK',
  164. onPress: hideSnackBar,
  165. }}
  166. duration={4000}
  167. style={{
  168. bottom: TAB_BAR_HEIGHT,
  169. }}
  170. >
  171. {i18n.t('general.listUpdateFail')}
  172. </Snackbar>
  173. </View>
  174. );
  175. }
  176. export default WebSectionList;