66import React from 'react'
77import { View , Text , StyleSheet } from 'react-native'
88import { Badge } from '../components/badge'
9+ import isEqual from 'lodash/isEqual'
910import type momentT from 'moment'
1011import type { BuildingType } from './types'
1112import * as c from '../components/colors'
12- import { Row , Column } from '../components/layout'
13+ import { Row } from '../components/layout'
1314import { ListRow , Detail , Title } from '../components/list'
1415import { getDetailedBuildingStatus , getShortBuildingStatus } from './lib'
1516
@@ -42,68 +43,128 @@ const styles = StyleSheet.create({
4243 } ,
4344} )
4445
45- export class BuildingRow extends React . PureComponent {
46- props : {
47- info : BuildingType ,
48- name : string ,
49- now : momentT ,
50- onPress : BuildingType => any ,
46+ const BG_COLORS = {
47+ Open : c . moneyGreen ,
48+ Closed : c . salmon ,
49+ }
50+
51+ const FG_COLORS = {
52+ Open : c . hollyGreen ,
53+ Closed : c . brickRed ,
54+ }
55+
56+ type Props = {
57+ info : BuildingType ,
58+ name : string ,
59+ now : momentT ,
60+ onPress : BuildingType => any ,
61+ }
62+
63+ type State = {
64+ openStatus : string ,
65+ hours : Array < any > ,
66+ accentBg : string ,
67+ accentText : string ,
68+ }
69+
70+ export class BuildingRow extends React . Component < void , Props , State > {
71+ state = {
72+ openStatus : 'Unknown' ,
73+ hours : [ ] ,
74+ firstUpdate : true ,
75+
76+ // when changing these, make sure to change the fallbacks in setStateFromProps
77+ accentBg : c . goldenrod ,
78+ accentText : 'rgb(130, 82, 45)' ,
5179 }
5280
53- onPress = ( ) => {
54- this . props . onPress ( this . props . info )
81+ componentWillMount ( ) {
82+ this . setStateFromProps ( this . props )
5583 }
5684
57- render ( ) {
58- const { info, name, now} = this . props
85+ componentWillReceiveProps ( nextProps : Props ) {
86+ this . setStateFromProps ( nextProps )
87+ }
5988
60- const bgColors = {
61- Open : c . moneyGreen ,
62- Closed : c . salmon ,
63- }
64- const foregroundColors = {
65- Open : c . hollyGreen ,
66- Closed : c . brickRed ,
89+ shouldComponentUpdate ( nextProps : Props , nextState : State ) {
90+ // We won't check the time in shouldComponentUpdate, because we really
91+ // only care if the building status has changed, and this is called after
92+ // setStateFromProps runs.
93+ return (
94+ this . props . name !== nextProps . name ||
95+ this . props . info !== nextProps . info ||
96+ this . props . onPress !== nextProps . onPress ||
97+ this . state . openStatus !== nextState . openStatus ||
98+ ! isEqual ( this . state . hours , nextState . hours )
99+ )
100+ }
101+
102+ setStateFromProps = ( nextProps : Props ) => {
103+ // we check the time in setStateFromProps, because shouldComponentUpdate
104+ // runs _after_ setStateFromProps.
105+ if (
106+ this . props . now . isSame ( nextProps . now , 'minute' ) &&
107+ ! this . state . firstUpdate
108+ ) {
109+ return
67110 }
68111
112+ const { info, now} = nextProps
113+
69114 const openStatus = getShortBuildingStatus ( info , now )
70115 const hours = getDetailedBuildingStatus ( info , now )
71116
72- const accent = bgColors [ openStatus ] || c . goldenrod
73- const textaccent = foregroundColors [ openStatus ] || 'rgb(130, 82, 45)'
117+ // when changing these, make sure to change the initial values in `state`
118+ const accentBg = BG_COLORS [ openStatus ] || c . goldenrod
119+ const accentText = FG_COLORS [ openStatus ] || 'rgb(130, 82, 45)'
120+
121+ this . setState ( ( ) => ( {
122+ openStatus,
123+ hours,
124+ accentBg,
125+ accentText,
126+ firstUpdate : false ,
127+ } ) )
128+ }
129+
130+ onPress = ( ) = > {
131+ this . props . onPress ( this . props . info )
132+ }
133+
134+ render ( ) {
135+ const { info , name } = this . props
136+ const { openStatus , hours , accentBg , accentText } = this . state
74137
75138 return (
76139 < ListRow onPress = { this . onPress } arrowPosition = "center" style = { styles . row } >
77- < Column >
78- < Row style = { styles . title } >
79- < Title lines = { 1 } style = { styles . titleText } >
80- < Text > { name } </ Text >
81- { info . abbreviation ? < Text > ({ info . abbreviation } )</ Text > : null }
82- { info . subtitle
83- ? < Text style = { styles . subtitleText } > { info . subtitle } </ Text >
84- : null }
85- </ Title >
86-
87- < Badge
88- text = { openStatus }
89- accentColor = { accent }
90- textColor = { textaccent }
91- style = { styles . accessoryBadge }
92- />
93- </ Row >
94-
95- < View style = { styles . detailWrapper } >
96- { hours . map ( ( { isActive, label, status} , i ) =>
97- < Detail key = { i } style = { styles . detailRow } >
98- < BuildingTimeSlot
99- highlight = { hours . length > 1 && isActive }
100- label = { label }
101- status = { status }
102- />
103- </ Detail > ,
104- ) }
105- </ View >
106- </ Column >
140+ < Row style = { styles . title } >
141+ < Title lines = { 1 } style = { styles . titleText } >
142+ < Text > { name } </ Text >
143+ { info . abbreviation ? < Text > ({ info . abbreviation } )</ Text > : null }
144+ { info . subtitle
145+ ? < Text style = { styles . subtitleText } > { info . subtitle } </ Text >
146+ : null }
147+ </ Title >
148+
149+ < Badge
150+ text = { openStatus }
151+ accentColor = { accentBg }
152+ textColor = { accentText }
153+ style = { styles . accessoryBadge }
154+ />
155+ </ Row >
156+
157+ < View style = { styles . detailWrapper } >
158+ { hours . map ( ( { isActive, label, status} , i ) =>
159+ < Detail key = { i } style = { styles . detailRow } >
160+ < BuildingTimeSlot
161+ highlight = { hours . length > 1 && isActive }
162+ label = { label }
163+ status = { status }
164+ />
165+ </ Detail > ,
166+ ) }
167+ </ View >
107168 </ ListRow >
108169 )
109170 }
@@ -119,7 +180,7 @@ const BuildingTimeSlot = ({
119180 highlight : boolean ,
120181} ) => {
121182 // we don't want to show the 'Hours' label, since almost every row has it
122- const showLabel = label !== 'Hours'
183+ const showLabel = label && label !== 'Hours'
123184
124185 return (
125186 < Text >
0 commit comments