Skip to content

Commit 2b927ff

Browse files
committed
add initial fully-featured building editor
1 parent 7404460 commit 2b927ff

File tree

8 files changed

+604
-106
lines changed

8 files changed

+604
-106
lines changed

source/navigation.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import JobDetailView from './views/sis/student-work/detail'
1717
import {
1818
BuildingHoursView,
1919
BuildingHoursDetailView,
20+
BuildingHoursProblemReportView,
21+
BuildingHoursScheduleEditorView,
2022
} from './views/building-hours'
2123
import TransportationView from './views/transportation'
2224
import SettingsView from './views/settings'
@@ -34,6 +36,8 @@ export const AppNavigator = StackNavigator(
3436
HomeView: {screen: HomeView},
3537
BuildingHoursDetailView: {screen: BuildingHoursDetailView},
3638
BuildingHoursView: {screen: BuildingHoursView},
39+
BuildingHoursProblemReportView: {screen: BuildingHoursProblemReportView},
40+
BuildingHoursScheduleEditorView: {screen: BuildingHoursScheduleEditorView},
3741
CalendarView: {screen: CalendarView},
3842
ContactsView: {screen: ContactsView},
3943
CreditsView: {screen: CreditsView},

source/views/building-hours/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@
22

33
export {BuildingHoursView} from './stateful-list'
44
export {BuildingHoursDetailView} from './detail'
5+
export {
6+
BuildingHoursProblemReportView,
7+
BuildingHoursScheduleEditorView,
8+
} from './report'
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// @flow
2+
3+
export const blankSchedule = () => ({days: [], from: '9:00am', to: '5:00pm'})

source/views/building-hours/lib/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ export {formatBuildingTimes} from './format-times'
77
export {summarizeDays} from './summarize-days'
88
export {isScheduleOpenAtMoment} from './is-schedule-open'
99
export {getDayOfWeek} from './get-day-of-week'
10+
export {parseHours} from './parse-hours'
11+
export {blankSchedule} from './blank-schedule'
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
/**
2+
* @flow
3+
*
4+
* An editor for individual building schedules.
5+
*/
6+
7+
import React from 'react'
8+
import xor from 'lodash/xor'
9+
import fromPairs from 'lodash/fromPairs'
10+
import {ScrollView, Text, StyleSheet} from 'react-native'
11+
import moment from 'moment-timezone'
12+
import {TableView, Section, Cell} from 'react-native-tableview-simple'
13+
import type {SingleBuildingScheduleType, DayOfWeekEnumType} from '../types'
14+
import {Row} from '../../components/layout'
15+
import type {TopLevelViewPropsType} from '../../types'
16+
import {parseHours, blankSchedule} from '../lib'
17+
import * as c from '../../components/colors'
18+
import DatePicker from 'react-native-datepicker'
19+
import {Touchable} from '../../components/touchable'
20+
import {DeleteButtonCell} from '../../components/cells/delete-button'
21+
22+
export class BuildingHoursScheduleEditorView extends React.PureComponent {
23+
static navigationOptions = {
24+
title: 'Edit Schedule',
25+
}
26+
27+
state: {
28+
set: ?SingleBuildingScheduleType,
29+
} = {
30+
set: this.props.navigation.state.params.initialSet,
31+
}
32+
33+
props: TopLevelViewPropsType & {
34+
navigation: {
35+
state: {
36+
params: {
37+
set: SingleBuildingScheduleType,
38+
onEditSet: (set: SingleBuildingScheduleType) => any,
39+
onDeleteSet: () => any,
40+
},
41+
},
42+
},
43+
}
44+
45+
delete = () => {
46+
this.props.navigation.state.params.onDeleteSet()
47+
}
48+
49+
onChangeDays = (newDays: DayOfWeekEnumType[]) => {
50+
this.setState(
51+
state => ({...state, set: {...state.set, days: newDays}}),
52+
() => this.props.navigation.state.params.onEditSet(this.state.set),
53+
)
54+
}
55+
56+
onChangeOpen = (newDate: moment) => {
57+
this.setState(
58+
state => ({...state, set: {...state.set, from: newDate.format('h:mma')}}),
59+
() => this.props.navigation.state.params.onEditSet(this.state.set),
60+
)
61+
}
62+
63+
onChangeClose = (newDate: moment) => {
64+
this.setState(
65+
state => ({...state, set: {...state.set, to: newDate.format('h:mma')}}),
66+
() => this.props.navigation.state.params.onEditSet(this.state.set),
67+
)
68+
}
69+
70+
render() {
71+
const set = this.state.set || blankSchedule()
72+
73+
const {open, close} = parseHours(set, moment())
74+
75+
return (
76+
<ScrollView>
77+
<TableView>
78+
<Section header="DAYS">
79+
<WeekToggles days={set.days} onChangeDays={this.onChangeDays} />
80+
</Section>
81+
82+
<Section header="TIMES">
83+
<DatePickerCell
84+
title="Open"
85+
date={open}
86+
onChange={this.onChangeOpen}
87+
/>
88+
<DatePickerCell
89+
title="Close"
90+
date={close}
91+
onChange={this.onChangeClose}
92+
/>
93+
</Section>
94+
95+
<Section>
96+
<DeleteButtonCell title="Delete Hours" onPress={this.delete} />
97+
</Section>
98+
</TableView>
99+
</ScrollView>
100+
)
101+
}
102+
}
103+
104+
class WeekToggles extends React.PureComponent {
105+
props: {days: DayOfWeekEnumType[], onChangeDays: (DayOfWeekEnumType[]) => any}
106+
107+
toggleDay = day => {
108+
this.props.onChangeDays(xor(this.props.days, [day]))
109+
}
110+
111+
render() {
112+
const allDays = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']
113+
114+
return (
115+
<Row justifyContent="center">
116+
{allDays.map((day, i) =>
117+
<ToggleButton
118+
key={day}
119+
text={day}
120+
active={this.props.days.includes(day)}
121+
onPress={this.toggleDay}
122+
style={i === allDays.length - 1 && styles.finalCell}
123+
/>,
124+
)}
125+
</Row>
126+
)
127+
}
128+
}
129+
130+
class ToggleButton extends React.PureComponent {
131+
props: {
132+
active: boolean,
133+
text: string,
134+
onPress: (newState: string) => any,
135+
style?: any,
136+
}
137+
138+
onPress = () => this.props.onPress(this.props.text)
139+
140+
render() {
141+
const {text, style, active} = this.props
142+
return (
143+
<Touchable
144+
highlight={false}
145+
containerStyle={[style, styles.dayWrapper, active && styles.activeDay]}
146+
onPress={this.onPress}
147+
>
148+
<Text style={[styles.dayText, active && styles.activeDayText]}>
149+
{text}
150+
</Text>
151+
</Touchable>
152+
)
153+
}
154+
}
155+
156+
class DatePickerCell extends React.PureComponent {
157+
props: {
158+
date: moment,
159+
title: string,
160+
onChange?: (date: moment) => any,
161+
_ref?: (ref: any) => any,
162+
}
163+
164+
_picker: any
165+
openPicker = () => {} //this._picker.onPressDate()
166+
167+
setRef = (ref: any) => {
168+
this._picker = ref
169+
this.props._ref && this.props._ref(ref)
170+
}
171+
172+
onChange = (newDate: moment) => {
173+
console.log(newDate)
174+
this.props.onChange && this.props.onChange(newDate)
175+
}
176+
177+
render() {
178+
const {date, title} = this.props
179+
const accessory = (
180+
<Date ref={this.setRef} date={date.toDate()} onChange={this.onChange} />
181+
)
182+
183+
return (
184+
<Cell
185+
title={title}
186+
cellStyle="RightDetail"
187+
cellAccessoryView={accessory}
188+
onPress={this.openPicker}
189+
/>
190+
)
191+
}
192+
}
193+
194+
const Date = ({date, onChange}) => {
195+
const format = 'h:mma'
196+
197+
const callback = (newDateString: string) => {
198+
const oldMoment = moment(date)
199+
const newMoment = moment(newDateString, format)
200+
201+
oldMoment.hours(newMoment.hours())
202+
oldMoment.minutes(newMoment.minutes())
203+
204+
onChange(oldMoment)
205+
}
206+
207+
return (
208+
<DatePicker
209+
date={date}
210+
style={styles.datePicker}
211+
mode="time"
212+
format={format}
213+
is24Hour={false}
214+
confirmBtnText="Confirm"
215+
cancelBtnText="Cancel"
216+
showIcon={false}
217+
onDateChange={callback}
218+
customStyles={{
219+
dateInput: styles.datePickerInput,
220+
dateText: styles.datePickerText,
221+
}}
222+
/>
223+
)
224+
}
225+
226+
const styles = StyleSheet.create({
227+
dayWrapper: {
228+
flex: 1,
229+
alignItems: 'center',
230+
paddingVertical: 10,
231+
paddingHorizontal: 2,
232+
backgroundColor: c.white,
233+
borderRightWidth: StyleSheet.hairlineWidth,
234+
borderRightColor: c.iosSeparator,
235+
},
236+
finalCell: {
237+
borderRightWidth: 0,
238+
},
239+
activeDay: {
240+
backgroundColor: c.brickRed,
241+
},
242+
dayText: {
243+
fontSize: 16,
244+
},
245+
activeDayText: {
246+
color: c.white,
247+
},
248+
datePicker: {
249+
width: null,
250+
},
251+
datePickerInput: {
252+
flex: 0,
253+
borderWidth: 0,
254+
},
255+
datePickerText: {
256+
color: c.iosDisabledText,
257+
fontSize: 16,
258+
},
259+
})

0 commit comments

Comments
 (0)