Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

CalendarListContent.native.tsx 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. import React, { Component } from 'react';
  2. import { WithTranslation } from 'react-i18next';
  3. import { connect } from 'react-redux';
  4. import { createCalendarClickedEvent, createCalendarSelectedEvent } from '../../analytics/AnalyticsEvents';
  5. import { sendAnalytics } from '../../analytics/functions';
  6. import { appNavigate } from '../../app/actions.native';
  7. import { IReduxState } from '../../app/types';
  8. import { getLocalizedDateFormatter } from '../../base/i18n/dateUtil';
  9. import { translate } from '../../base/i18n/functions';
  10. import NavigateSectionList from '../../base/react/components/native/NavigateSectionList';
  11. import { openUpdateCalendarEventDialog, refreshCalendar } from '../actions.native';
  12. /**
  13. * The type of the React {@code Component} props of
  14. * {@link CalendarListContent}.
  15. */
  16. interface IProps extends WithTranslation {
  17. /**
  18. * The calendar event list.
  19. */
  20. _eventList: Array<any>;
  21. /**
  22. * Indicates if the list is disabled or not.
  23. */
  24. disabled: boolean;
  25. /**
  26. * The Redux dispatch function.
  27. */
  28. dispatch: Function;
  29. /**
  30. *
  31. */
  32. listEmptyComponent: React.ReactElement<any>;
  33. }
  34. /**
  35. * Component to display a list of events from a connected calendar.
  36. */
  37. class CalendarListContent extends Component<IProps> {
  38. /**
  39. * Default values for the component's props.
  40. */
  41. static defaultProps = {
  42. _eventList: []
  43. };
  44. /**
  45. * Initializes a new {@code CalendarListContent} instance.
  46. *
  47. * @inheritdoc
  48. */
  49. constructor(props: IProps) {
  50. super(props);
  51. // Bind event handlers so they are only bound once per instance.
  52. this._onPress = this._onPress.bind(this);
  53. this._onRefresh = this._onRefresh.bind(this);
  54. this._onSecondaryAction = this._onSecondaryAction.bind(this);
  55. this._toDateString = this._toDateString.bind(this);
  56. this._toDisplayableItem = this._toDisplayableItem.bind(this);
  57. this._toDisplayableList = this._toDisplayableList.bind(this);
  58. this._toTimeString = this._toTimeString.bind(this);
  59. }
  60. /**
  61. * Implements React's {@link Component#componentDidMount()}. Invoked
  62. * immediately after this component is mounted.
  63. *
  64. * @inheritdoc
  65. * @returns {void}
  66. */
  67. componentDidMount() {
  68. sendAnalytics(createCalendarSelectedEvent());
  69. }
  70. /**
  71. * Implements React's {@link Component#render}.
  72. *
  73. * @inheritdoc
  74. */
  75. render() {
  76. const { disabled, listEmptyComponent } = this.props;
  77. return (
  78. <NavigateSectionList
  79. disabled = { disabled }
  80. onPress = { this._onPress }
  81. onRefresh = { this._onRefresh }
  82. onSecondaryAction = { this._onSecondaryAction }
  83. renderListEmptyComponent
  84. = { listEmptyComponent }
  85. sections = { this._toDisplayableList() } />
  86. );
  87. }
  88. /**
  89. * Handles the list's navigate action.
  90. *
  91. * @private
  92. * @param {string} url - The url string to navigate to.
  93. * @param {string} analyticsEventName - Тhe name of the analytics event
  94. * associated with this action.
  95. * @returns {void}
  96. */
  97. _onPress(url: string, analyticsEventName = 'meeting.tile') {
  98. sendAnalytics(createCalendarClickedEvent(analyticsEventName));
  99. this.props.dispatch(appNavigate(url));
  100. }
  101. /**
  102. * Callback to execute when the list is doing a pull-to-refresh.
  103. *
  104. * @private
  105. * @returns {void}
  106. */
  107. _onRefresh() {
  108. this.props.dispatch(refreshCalendar(true));
  109. }
  110. /**
  111. * Handles the list's secondary action.
  112. *
  113. * @private
  114. * @param {string} id - The ID of the item on which the secondary action was
  115. * performed.
  116. * @returns {void}
  117. */
  118. _onSecondaryAction(id: string) {
  119. this.props.dispatch(openUpdateCalendarEventDialog(id));
  120. }
  121. /**
  122. * Generates a date string for a given event.
  123. *
  124. * @param {Object} event - The event.
  125. * @private
  126. * @returns {string}
  127. */
  128. _toDateString(event: any) {
  129. const startDateTime
  130. = getLocalizedDateFormatter(event.startDate).format('MMM Do, YYYY');
  131. return `${startDateTime}`;
  132. }
  133. /**
  134. * Creates a displayable object from an event.
  135. *
  136. * @param {Object} event - The calendar event.
  137. * @private
  138. * @returns {Object}
  139. */
  140. _toDisplayableItem(event: any) {
  141. return {
  142. id: event.id,
  143. key: `${event.id}-${event.startDate}`,
  144. lines: [
  145. event.url,
  146. this._toTimeString(event)
  147. ],
  148. title: event.title,
  149. url: event.url
  150. };
  151. }
  152. /**
  153. * Transforms the event list to a displayable list with sections.
  154. *
  155. * @private
  156. * @returns {Array<Object>}
  157. */
  158. _toDisplayableList() {
  159. const { _eventList, t } = this.props;
  160. const now = new Date();
  161. const { createSection } = NavigateSectionList;
  162. const TODAY_SECTION = 'today';
  163. const sectionMap = new Map();
  164. for (const event of _eventList) {
  165. const displayableEvent = this._toDisplayableItem(event);
  166. const startDate = new Date(event.startDate).getDate();
  167. if (startDate === now.getDate()) {
  168. let todaySection = sectionMap.get(TODAY_SECTION);
  169. if (!todaySection) {
  170. todaySection
  171. = createSection(t('calendarSync.today'), TODAY_SECTION);
  172. sectionMap.set(TODAY_SECTION, todaySection);
  173. }
  174. todaySection.data.push(displayableEvent);
  175. } else if (sectionMap.has(startDate)) {
  176. const section = sectionMap.get(startDate);
  177. if (section) {
  178. section.data.push(displayableEvent);
  179. }
  180. } else {
  181. const newSection
  182. = createSection(this._toDateString(event), startDate);
  183. sectionMap.set(startDate, newSection);
  184. newSection.data.push(displayableEvent);
  185. }
  186. }
  187. return Array.from(sectionMap.values());
  188. }
  189. /**
  190. * Generates a time (interval) string for a given event.
  191. *
  192. * @param {Object} event - The event.
  193. * @private
  194. * @returns {string}
  195. */
  196. _toTimeString(event: any) {
  197. const startDateTime
  198. = getLocalizedDateFormatter(event.startDate).format('lll');
  199. const endTime
  200. = getLocalizedDateFormatter(event.endDate).format('LT');
  201. return `${startDateTime} - ${endTime}`;
  202. }
  203. }
  204. /**
  205. * Maps redux state to component props.
  206. *
  207. * @param {Object} state - The redux state.
  208. * @returns {IProps}
  209. */
  210. function _mapStateToProps(state: IReduxState) {
  211. return {
  212. _eventList: state['features/calendar-sync'].events
  213. };
  214. }
  215. export default translate(connect(_mapStateToProps)(CalendarListContent));