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.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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 from 'react';
  20. import i18n from 'i18n-js';
  21. import {
  22. RefreshControl,
  23. SectionListData,
  24. SectionListProps,
  25. StyleSheet,
  26. } from 'react-native';
  27. import ErrorView from './ErrorView';
  28. import CollapsibleSectionList from '../Collapsible/CollapsibleSectionList';
  29. import RequestScreen, { RequestScreenProps } from './RequestScreen';
  30. import { CollapsibleComponentPropsType } from '../Collapsible/CollapsibleComponent';
  31. import { API_REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
  32. export type SectionListDataType<ItemT> = Array<{
  33. title: string;
  34. icon?: string;
  35. data: Array<ItemT>;
  36. keyExtractor?: (data: ItemT) => string;
  37. }>;
  38. type Props<ItemT, RawData> = Omit<
  39. CollapsibleComponentPropsType,
  40. 'children' | 'paddedProps'
  41. > &
  42. Omit<
  43. RequestScreenProps<RawData>,
  44. 'render' | 'showLoading' | 'showError' | 'onMajorError'
  45. > &
  46. Omit<
  47. SectionListProps<ItemT>,
  48. 'sections' | 'getItemLayout' | 'ListHeaderComponent' | 'ListEmptyComponent'
  49. > & {
  50. createDataset: (
  51. data: RawData | undefined,
  52. loading: boolean,
  53. lastRefreshDate: Date | undefined,
  54. refreshData: (newRequest?: () => Promise<RawData>) => void,
  55. status: REQUEST_STATUS,
  56. code?: API_REQUEST_CODES
  57. ) => SectionListDataType<ItemT>;
  58. renderListHeaderComponent?: (
  59. data: RawData | undefined,
  60. loading: boolean,
  61. lastRefreshDate: Date | undefined,
  62. refreshData: (newRequest?: () => Promise<RawData>) => void,
  63. status: REQUEST_STATUS,
  64. code?: API_REQUEST_CODES
  65. ) => React.ComponentType<any> | React.ReactElement | null;
  66. itemHeight?: number | null;
  67. };
  68. const styles = StyleSheet.create({
  69. container: {
  70. minHeight: '100%',
  71. },
  72. });
  73. /**
  74. * Component used to render a SectionList with data fetched from the web
  75. * To force the component to update, change the value of updateData.
  76. */
  77. function WebSectionList<ItemT, RawData>(props: Props<ItemT, RawData>) {
  78. const getItemLayout = (
  79. height: number,
  80. _data: Array<SectionListData<ItemT>> | null,
  81. index: number
  82. ): { length: number; offset: number; index: number } => {
  83. return {
  84. length: height,
  85. offset: height * index,
  86. index,
  87. };
  88. };
  89. const render = (
  90. data: RawData | undefined,
  91. loading: boolean,
  92. lastRefreshDate: Date | undefined,
  93. refreshData: (newRequest?: () => Promise<RawData>) => void,
  94. status: REQUEST_STATUS,
  95. code?: API_REQUEST_CODES
  96. ) => {
  97. const { itemHeight } = props;
  98. const dataset = props.createDataset(
  99. data,
  100. loading,
  101. lastRefreshDate,
  102. refreshData,
  103. status,
  104. code
  105. );
  106. return (
  107. <CollapsibleSectionList
  108. {...props}
  109. sections={dataset}
  110. paddedProps={(paddingTop) => ({
  111. refreshControl: (
  112. <RefreshControl
  113. progressViewOffset={paddingTop}
  114. refreshing={loading}
  115. onRefresh={refreshData}
  116. />
  117. ),
  118. })}
  119. renderItem={props.renderItem}
  120. style={styles.container}
  121. ListHeaderComponent={
  122. props.renderListHeaderComponent != null
  123. ? props.renderListHeaderComponent(
  124. data,
  125. loading,
  126. lastRefreshDate,
  127. refreshData,
  128. status,
  129. code
  130. )
  131. : null
  132. }
  133. ListEmptyComponent={
  134. loading ? undefined : (
  135. <ErrorView
  136. status={status}
  137. code={code}
  138. button={
  139. code !== API_REQUEST_CODES.BAD_TOKEN
  140. ? {
  141. icon: 'refresh',
  142. text: i18n.t('general.retry'),
  143. onPress: () => refreshData(),
  144. }
  145. : undefined
  146. }
  147. />
  148. )
  149. }
  150. getItemLayout={
  151. itemHeight ? (d, i) => getItemLayout(itemHeight, d, i) : undefined
  152. }
  153. />
  154. );
  155. };
  156. return (
  157. <RequestScreen<RawData>
  158. request={props.request}
  159. render={render}
  160. showError={false}
  161. showLoading={false}
  162. autoRefreshTime={props.autoRefreshTime}
  163. refreshOnFocus={props.refreshOnFocus}
  164. cache={props.cache}
  165. onCacheUpdate={props.onCacheUpdate}
  166. refresh={props.refresh}
  167. onFinish={props.onFinish}
  168. />
  169. );
  170. }
  171. export default WebSectionList;