Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

NavigateSectionList.js 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // @flow
  2. import React, { Component } from 'react';
  3. // TODO: Maybe try to make all NavigateSectionList components to work for both
  4. // mobile and web, and move them to NavigateSectionList component.
  5. import {
  6. NavigateSectionListEmptyComponent,
  7. NavigateSectionListItem,
  8. NavigateSectionListSectionHeader,
  9. SectionList
  10. } from './_';
  11. import type { Section } from '../Types';
  12. type Props = {
  13. /**
  14. * Indicates if the list is disabled or not.
  15. */
  16. disabled: boolean,
  17. /**
  18. * Function to be invoked when an item is pressed. The item's URL is passed.
  19. */
  20. onPress: Function,
  21. /**
  22. * Function to be invoked when pull-to-refresh is performed.
  23. */
  24. onRefresh: Function,
  25. /**
  26. * Function to be invoked when a secondary action is performed on an item.
  27. * The item's ID is passed.
  28. */
  29. onSecondaryAction: Function,
  30. /**
  31. * Function to override the rendered default empty list component.
  32. */
  33. renderListEmptyComponent: Function,
  34. /**
  35. * An array of sections
  36. */
  37. sections: Array<Section>,
  38. /**
  39. * Optional array of on-slide actions this list should support. For details
  40. * see https://github.com/dancormier/react-native-swipeout.
  41. */
  42. slideActions?: Array<Object>
  43. };
  44. /**
  45. * Implements a general section list to display items that have a URL property
  46. * and navigates to (probably) meetings, such as the recent list or the meeting
  47. * list components.
  48. */
  49. class NavigateSectionList extends Component<Props> {
  50. /**
  51. * Creates an empty section object.
  52. *
  53. * @param {string} title - The title of the section.
  54. * @param {string} key - The key of the section. It must be unique.
  55. * @private
  56. * @returns {Object}
  57. */
  58. static createSection(title: string, key: string) {
  59. return {
  60. data: [],
  61. key,
  62. title
  63. };
  64. }
  65. /**
  66. * Constructor of the NavigateSectionList component.
  67. *
  68. * @inheritdoc
  69. */
  70. constructor(props: Props) {
  71. super(props);
  72. this._getItemKey = this._getItemKey.bind(this);
  73. this._onPress = this._onPress.bind(this);
  74. this._onRefresh = this._onRefresh.bind(this);
  75. this._renderItem = this._renderItem.bind(this);
  76. this._renderListEmptyComponent
  77. = this._renderListEmptyComponent.bind(this);
  78. this._renderSectionHeader = this._renderSectionHeader.bind(this);
  79. }
  80. /**
  81. * Implements React's {@code Component.render}.
  82. * Note: We don't use the refreshing value yet, because refreshing of these
  83. * lists is super quick, no need to complicate the code - yet.
  84. *
  85. * @inheritdoc
  86. */
  87. render() {
  88. const {
  89. renderListEmptyComponent = this._renderListEmptyComponent(),
  90. sections
  91. } = this.props;
  92. return (
  93. <SectionList
  94. ListEmptyComponent = { renderListEmptyComponent }
  95. keyExtractor = { this._getItemKey }
  96. onItemClick = { this.props.onPress }
  97. onRefresh = { this._onRefresh }
  98. refreshing = { false }
  99. renderItem = { this._renderItem }
  100. renderSectionHeader = { this._renderSectionHeader }
  101. sections = { sections } />
  102. );
  103. }
  104. _getItemKey: (Object, number) => string;
  105. /**
  106. * Generates a unique id to every item.
  107. *
  108. * @param {Object} item - The item.
  109. * @param {number} index - The item index.
  110. * @private
  111. * @returns {string}
  112. */
  113. _getItemKey(item, index) {
  114. return `${index}-${item.key}`;
  115. }
  116. _onPress: string => Function;
  117. /**
  118. * Returns a function that is used in the onPress callback of the items.
  119. *
  120. * @param {string} url - The URL of the item to navigate to.
  121. * @private
  122. * @returns {Function}
  123. */
  124. _onPress(url) {
  125. const { disabled, onPress } = this.props;
  126. if (!disabled && url && typeof onPress === 'function') {
  127. return () => onPress(url);
  128. }
  129. return null;
  130. }
  131. _onRefresh: () => void;
  132. /**
  133. * Invokes the onRefresh callback if present.
  134. *
  135. * @private
  136. * @returns {void}
  137. */
  138. _onRefresh() {
  139. const { onRefresh } = this.props;
  140. if (typeof onRefresh === 'function') {
  141. onRefresh();
  142. }
  143. }
  144. _onSecondaryAction: Object => Function;
  145. /**
  146. * Returns a function that is used in the secondaryAction callback of the
  147. * items.
  148. *
  149. * @param {string} id - The id of the item that secondary action was
  150. * performed on.
  151. * @private
  152. * @returns {Function}
  153. */
  154. _onSecondaryAction(id) {
  155. return () => {
  156. this.props.onSecondaryAction(id);
  157. };
  158. }
  159. _renderItem: Object => Object;
  160. /**
  161. * Renders a single item in the list.
  162. *
  163. * @param {Object} listItem - The item to render.
  164. * @param {string} key - The item needed for rendering using map on web.
  165. * @private
  166. * @returns {Component}
  167. */
  168. _renderItem(listItem, key: string = '') {
  169. const { item } = listItem;
  170. const { id, url } = item;
  171. // XXX The value of title cannot be undefined; otherwise, react-native
  172. // will throw a TypeError: Cannot read property of undefined. While it's
  173. // difficult to get an undefined title and very likely requires the
  174. // execution of incorrect source code, it is undesirable to break the
  175. // whole app because of an undefined string.
  176. if (typeof item.title === 'undefined') {
  177. return null;
  178. }
  179. return (
  180. <NavigateSectionListItem
  181. item = { item }
  182. key = { key }
  183. onPress = { url ? this._onPress(url) : undefined }
  184. secondaryAction = {
  185. url ? undefined : this._onSecondaryAction(id) }
  186. slideActions = { this.props.slideActions } />
  187. );
  188. }
  189. _renderListEmptyComponent: () => Object;
  190. /**
  191. * Renders a component to display when the list is empty.
  192. *
  193. * @param {Object} section - The section being rendered.
  194. * @private
  195. * @returns {React$Node}
  196. */
  197. _renderListEmptyComponent() {
  198. const { onRefresh } = this.props;
  199. if (typeof onRefresh === 'function') {
  200. return (
  201. <NavigateSectionListEmptyComponent />
  202. );
  203. }
  204. return null;
  205. }
  206. _renderSectionHeader: Object => Object;
  207. /**
  208. * Renders a section header.
  209. *
  210. * @param {Object} section - The section being rendered.
  211. * @private
  212. * @returns {React$Node}
  213. */
  214. _renderSectionHeader(section) {
  215. return (
  216. <NavigateSectionListSectionHeader
  217. section = { section } />
  218. );
  219. }
  220. }
  221. export default NavigateSectionList;