11// @flow
22/**
33 * All About Olaf
4- * Building Hours list page
4+ * Building Hours view. This component loads data from either GitHub or
5+ * the local copy as a fallback, and renders the list of buildings.
56 */
67
78import React from 'react'
8- import { ListView , RefreshControl , StyleSheet , Platform } from 'react-native'
9- import { BuildingRow } from './row'
9+ import { NoticeView } from '../components/notice'
1010import { tracker } from '../../analytics'
11+ import { BuildingHoursList } from './list'
1112
13+ import type momentT from 'moment'
1214import type { TopLevelViewPropsType } from '../types'
1315import type { BuildingType } from './types'
14- import delay from 'delay'
15- import { data as buildingHours } from '../../docs/building-hours'
16+ import { data as fallbackBuildingHours } from '../../docs/building-hours'
1617import groupBy from 'lodash/groupBy'
1718
18- import * as c from '../components/colors'
19- import { ListSeparator , ListSectionHeader } from '../components/list'
2019import moment from 'moment-timezone'
2120const CENTRAL_TZ = 'America/Winnipeg'
2221
2322export { BuildingHoursDetailView } from './detail'
2423
25- const styles = StyleSheet . create ( {
26- container : {
27- backgroundColor : c . white ,
28- } ,
29- } )
24+ const githubBaseUrl = 'https://stodevx.github.io/AAO-React-Native'
25+
26+ const groupBuildings = ( buildings : BuildingType [ ] ) => groupBy ( buildings , b => b . category || 'Other' )
27+
3028
3129export class BuildingHoursView extends React . Component {
32- state = {
33- dataSource : this . getDataSource ( ) ,
34- intervalId : 0 ,
30+ state : {
31+ error : ?Error ,
32+ loading : boolean ,
33+ now : momentT ,
34+ buildings : { [ key : string ] : BuildingType [ ] } ,
35+ intervalId : number ,
36+ } = {
37+ error : null ,
38+ loading : true ,
3539 // now: moment.tz('Wed 7:25pm', 'ddd h:mma', null, CENTRAL_TZ),
3640 now : moment . tz ( CENTRAL_TZ ) ,
37- refreshing : false ,
41+ buildings : groupBuildings ( fallbackBuildingHours ) ,
42+ intervalId : 0 ,
3843 }
3944
4045 componentWillMount ( ) {
46+ this . fetchData ( )
47+
4148 // This updates the screen every ten seconds, so that the building
4249 // info statuses are updated without needing to leave and come back.
4350 this . setState ( { intervalId : setInterval ( this . updateTime , 10000 ) } )
@@ -49,77 +56,48 @@ export class BuildingHoursView extends React.Component {
4956
5057 props: TopLevelViewPropsType ;
5158
52- getDataSource ( ) {
53- return new ListView . DataSource ( {
54- rowHasChanged : ( r1 : BuildingType , r2 : BuildingType ) => r1 !== r2 ,
55- sectionHeaderHasChanged : ( r1 : any , r2 : any ) => r1 !== r2 ,
56- } ) . cloneWithRowsAndSections ( groupBy ( buildingHours , b => b . category || 'Other' ) )
57- }
58-
5959 updateTime = ( ) => {
60- this . setState ( {
61- now : moment . tz ( CENTRAL_TZ ) ,
62- dataSource : this . getDataSource ( ) ,
63- } )
64- }
65-
66- onPressRow = ( data : BuildingType ) => {
67- tracker . trackEvent ( 'building-hours' , data . name )
68- this . props . navigator . push ( {
69- id : 'BuildingHoursDetailView' ,
70- index : this . props . route . index + 1 ,
71- title : data . name ,
72- backButtonTitle : 'Hours' ,
73- props : data ,
74- sceneConfig : Platform . OS === 'android' ? 'fromBottom' : undefined ,
75- } )
60+ this . setState ( { now : moment . tz ( CENTRAL_TZ ) } )
7661 }
7762
78- renderRow = ( data : BuildingType ) => {
79- return (
80- < BuildingRow
81- name = { data . name }
82- info = { data }
83- now = { this . state . now }
84- onPress = { ( ) => this . onPressRow ( data ) }
85- />
86- )
87- }
63+ fetchData = async ( ) => {
64+ this . setState ( { loading : true } )
8865
89- renderSectionHeader = ( data : any , id : string ) => {
90- return < ListSectionHeader style = { styles . rowSectionHeader } title = { id } />
91- }
66+ let buildings : BuildingType [ ] = [ ]
67+ try {
68+ let container = await fetchJson ( `${ githubBaseUrl } /building-hours.json` )
69+ let data = container . data
70+ buildings = data
71+ } catch ( err ) {
72+ tracker . trackException ( err . message )
73+ console . warn ( err )
74+ buildings = fallbackBuildingHours
75+ }
9276
93- renderSeparator = ( sectionID : any , rowID : any ) => {
94- return < ListSeparator key = { ` ${ sectionID } - ${ rowID } ` } />
95- }
77+ if ( __DEV__ ) {
78+ buildings = fallbackBuildingHours
79+ }
9680
97- refresh = async ( ) => {
98- this . setState ( { refreshing : true } )
99- await delay ( 500 )
10081 this . setState ( {
82+ loading : false ,
83+ buildings : groupBuildings ( buildings ) ,
10184 now : moment . tz ( CENTRAL_TZ ) ,
102- refreshing : false ,
103- dataSource : this . getDataSource ( ) ,
10485 } )
10586 }
10687
107- // Render a given scene
10888 render ( ) {
89+ if ( this . state . error ) {
90+ return < NoticeView text = { 'Error: ' + this . state . error . message } />
91+ }
92+
10993 return (
110- < ListView
111- dataSource = { this . state . dataSource }
112- renderRow = { this . renderRow }
113- renderSectionHeader = { this . renderSectionHeader }
114- renderSeparator = { this . renderSeparator }
115- contentContainerStyle = { styles . container }
116- removeClippedSubviews = { false } // remove after https://github.com/facebook/react-native/issues/8607#issuecomment-241715202
117- refreshControl = {
118- < RefreshControl
119- refreshing = { this . state . refreshing }
120- onRefresh = { this . refresh }
121- />
122- }
94+ < BuildingHoursList
95+ route = { this . props . route }
96+ navigator = { this . props . navigator }
97+ buildings = { this . state . buildings }
98+ now = { this . state . now }
99+ onRefresh = { this . fetchData }
100+ loading = { this . state . loading }
123101 />
124102 )
125103 }
0 commit comments