<commit_before>// @flow
/**
 * All About Olaf
 * Calendar page
 */

import React from 'react'
import {EventList} from './event-list'
import {tracker} from '../../analytics'
import type {PresenceEventType, EventType} from './types'
import moment from 'moment-timezone'
import delay from 'delay'
import LoadingView from '../components/loading'
const TIMEZONE = 'America/Winnipeg'

export class PresenceCalendarView extends React.Component {
  state: {
    events: EventType[],
    loaded: boolean,
    refreshing: boolean,
    error: ?Error,
    now: moment,
  } = {
    events: [],
    loaded: false,
    refreshing: true,
    error: null,
    now: moment.tz(TIMEZONE),
  };

  componentWillMount() {
    this.refresh()
  }

  props: {
    url: string,
  };

  convertEvents(data: PresenceEventType[], now: moment): EventType[] {
    return data
      .map(event => {
        const startTime = moment(event.startDateTimeUtc)
        const endTime = moment(event.endDateTimeUtc)
        return {
          startTime,
          endTime,
          summary: event.eventName,
          location: `Where: ${event.location}\nOrg: ${event.organizationName}`,
          isOngoing: startTime.isBefore(now, 'day'),
          extra: {type: 'presence', data: event},
        }
      })
      .filter(event => event.endTime.isSameOrAfter(now))
  }

  getEvents = async (now: moment = moment.tz(TIMEZONE)) => {
    let url = this.props.url

    let data: PresenceEventType[] = []
    try {
      data = await fetchJson(url)
    } catch (error) {
      tracker.trackException(error.message)
      this.setState({error: error.message})
      console.warn(error)
    }

    this.setState({
      now,
      loaded: true,
      events: this.convertEvents(data, now),
    })
  };

  refresh = async () => {
    let start = Date.now()
    this.setState({refreshing: true})

    await this.getEvents()

    // wait 0.5 seconds – if we let it go at normal speed, it feels broken.
    let elapsed = start - Date.now()
    if (elapsed < 500) {
      await delay(500 - elapsed)
    }

    this.setState({refreshing: false})
  };

  render() {
    if (!this.state.loaded) {
      return <LoadingView />
    }

    return (
      <EventList
        events={this.state.events}
        refreshing={this.state.refreshing}
        onRefresh={this.refresh}
        now={this.state.now}
        message={this.state.error ? this.state.error.message : null}
      />
    )
  }
}
<commit_msg>sort presence events by starttime (#869)<commit_after>// @flow
/**
 * All About Olaf
 * Calendar page
 */

import React from 'react'
import {EventList} from './event-list'
import {tracker} from '../../analytics'
import type {PresenceEventType, EventType} from './types'
import moment from 'moment-timezone'
import delay from 'delay'
import sortBy from 'lodash/sortBy'
import LoadingView from '../components/loading'
const TIMEZONE = 'America/Winnipeg'

export class PresenceCalendarView extends React.Component {
  state: {
    events: EventType[],
    loaded: boolean,
    refreshing: boolean,
    error: ?Error,
    now: moment,
  } = {
    events: [],
    loaded: false,
    refreshing: true,
    error: null,
    now: moment.tz(TIMEZONE),
  };

  componentWillMount() {
    this.refresh()
  }

  props: {
    url: string,
  };

  convertEvents(data: PresenceEventType[], now: moment): EventType[] {
    const events = data
      .map(event => {
        const startTime = moment(event.startDateTimeUtc)
        const endTime = moment(event.endDateTimeUtc)
        return {
          startTime,
          endTime,
          summary: event.eventName,
          location: `Where: ${event.location}\nOrg: ${event.organizationName}`,
          isOngoing: startTime.isBefore(now, 'day'),
          extra: {type: 'presence', data: event},
        }
      })
      .filter(event => event.endTime.isSameOrAfter(now))

    return sortBy(events, event => event.startTime.toISOString())
  }

  getEvents = async (now: moment = moment.tz(TIMEZONE)) => {
    let url = this.props.url

    let data: PresenceEventType[] = []
    try {
      data = await fetchJson(url)
    } catch (error) {
      tracker.trackException(error.message)
      this.setState({error: error.message})
      console.warn(error)
    }

    this.setState({
      now,
      loaded: true,
      events: this.convertEvents(data, now),
    })
  };

  refresh = async () => {
    let start = Date.now()
    this.setState({refreshing: true})

    await this.getEvents()

    // wait 0.5 seconds – if we let it go at normal speed, it feels broken.
    let elapsed = start - Date.now()
    if (elapsed < 500) {
      await delay(500 - elapsed)
    }

    this.setState({refreshing: false})
  };

  render() {
    if (!this.state.loaded) {
      return <LoadingView />
    }

    return (
      <EventList
        events={this.state.events}
        refreshing={this.state.refreshing}
        onRefresh={this.refresh}
        now={this.state.now}
        message={this.state.error ? this.state.error.message : null}
      />
    )
  }
}

{'fraction_non_alphanumeric': 0.13518334985133795, 'fraction_numerical': 0.0037661050545094153, 'mean_word_length': 2.501734906315059, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '516327', 'n_tokens_mistral': 1611, 'n_tokens_neox': 1579, 'n_words': 376}