Skip to content

Commit

Permalink
Add Error Boundary
Browse files Browse the repository at this point in the history
  • Loading branch information
consindo committed Sep 21, 2019
1 parent a200743 commit a6cee2c
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 37 deletions.
37 changes: 21 additions & 16 deletions js/views/reusable/LinkButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,45 +13,52 @@ class LinkButton extends React.Component {
onClick: PropTypes.func,
color: PropTypes.string,
size: PropTypes.string,
target: PropTypes.string,
}

static defaultProps = {
target: '_blank',
}

triggerLink = () => {
if (this.props.href.split(':')[0] === 'mailto') {
window.location = this.props.href
const { href } = this.props
if (href.split(':')[0] === 'mailto') {
window.location = href
} else {
window.open(this.props.href)
window.open(href)
}
}

render() {
const { href, target, size, color, label, onClick } = this.props
let wrapperStyle = null
let textStyle = null
if (this.props.size === 'small') {
if (size === 'small') {
wrapperStyle =
this.props.color === 'secondary'
color === 'secondary'
? [styles.wrapper, styles.wrapperSecondary, styles.wrapperSmall]
: [styles.wrapper, styles.wrapperSmall]
textStyle =
this.props.color === 'secondary'
color === 'secondary'
? [styles.text, styles.textSecondary, styles.textSmall]
: [styles.text, styles.textSmall]
} else {
wrapperStyle =
this.props.color === 'secondary'
color === 'secondary'
? [styles.wrapper, styles.wrapperSecondary]
: styles.wrapper
textStyle =
this.props.color === 'secondary'
color === 'secondary'
? [styles.text, styles.textSecondary]
: styles.text
}

const inner = (
<View style={wrapperStyle}>
<Text style={textStyle}>{this.props.label}</Text>
<Text style={textStyle}>{label}</Text>
</View>
)
if (this.props.href && iOS.detect()) {
if (href && iOS.detect()) {
return (
<TouchableOpacity
iOSHacks
Expand All @@ -62,21 +69,19 @@ class LinkButton extends React.Component {
</TouchableOpacity>
)
}
if (this.props.href) {
if (href) {
return (
<TouchableOpacity
activeOpacity={75}
target="_blank"
target={target}
accessibilityRole="link"
href={this.props.href}
href={href}
>
{inner}
</TouchableOpacity>
)
}
return (
<TouchableOpacity onClick={this.props.onClick}>{inner}</TouchableOpacity>
)
return <TouchableOpacity onClick={onClick}>{inner}</TouchableOpacity>
}
}
styles = StyleSheet.create({
Expand Down
56 changes: 35 additions & 21 deletions js/views/shell/Content.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { View, StyleSheet } from 'react-native'
import { withRouter, Route } from 'react-router-dom'

import Switch from './Switch.jsx'
import { ErrorBoundary } from './ErrorBoundary.jsx'

import Events from '../../stores/Events'
import Station from '../station/Station.jsx'
Expand Down Expand Up @@ -75,27 +76,40 @@ class Content extends React.Component {
}
onLayout={this.triggerLayout}
>
<Switch location={location} key="switch" timeout={400}>
<Route path="/" exact render={wrapFn(rootComponent)} />
<Route path="/s/:region/:station" exact render={wrapFn(Station)} />
<Route path="/s/:region/:station/save" exact render={wrapFn(Save)} />
<Route path="/l/:region" exact render={wrapFn(LineList)} />
<Route path="/l/:region/all" exact render={wrapFn(AllLines)} />
<Route
path="/l/:region/:agency_id/:route_short_name"
exact
render={wrapFn(Line)}
/>
<Route
path="/l/:region/:agency_id/:route_short_name/picker"
exact
render={wrapFn(LinePicker)}
/>
<Route path="/sponsor" exact render={wrapFn(Sponsor)} />
<Route path="/region" exact render={wrapFn(Region)} />
<Route path="/settings" exact render={wrapFn(Settings)} />
<Route render={wrapFn(NoMatch)} />
</Switch>
<ErrorBoundary>
<Switch location={location} key="switch" timeout={400}>
<Route path="/" exact render={wrapFn(rootComponent)} />
<Route
path="/fail"
exact
render={() => {
throw new Error('Intentional error')
}}
/>
<Route path="/s/:region/:station" exact render={wrapFn(Station)} />
<Route
path="/s/:region/:station/save"
exact
render={wrapFn(Save)}
/>
<Route path="/l/:region" exact render={wrapFn(LineList)} />
<Route path="/l/:region/all" exact render={wrapFn(AllLines)} />
<Route
path="/l/:region/:agency_id/:route_short_name"
exact
render={wrapFn(Line)}
/>
<Route
path="/l/:region/:agency_id/:route_short_name/picker"
exact
render={wrapFn(LinePicker)}
/>
<Route path="/sponsor" exact render={wrapFn(Sponsor)} />
<Route path="/region" exact render={wrapFn(Region)} />
<Route path="/settings" exact render={wrapFn(Settings)} />
<Route render={wrapFn(NoMatch)} />
</Switch>
</ErrorBoundary>
</View>
)
}
Expand Down
74 changes: 74 additions & 0 deletions js/views/shell/ErrorBoundary.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { Component } from 'react'
import { View, Text, StyleSheet } from 'react-native'

import { vars } from '../../styles.js'
import Wrapper from './Wrapper.jsx'
import Header from '../reusable/Header.jsx'
import LinkButton from '../reusable/LinkButton.jsx'

let styles

export class ErrorBoundary extends Component {
constructor(props) {
super(props)
this.state = { hasError: false }
}

static getDerivedStateFromError() {
return { hasError: true }
}

componentDidCatch(error, errorInfo) {
// TODO: Log error to an error reporting service
console.error(error, errorInfo)
}

render() {
const { hasError } = this.state
if (hasError) {
// You can render any custom fallback UI
return (
<Wrapper>
<View style={styles.wrapper}>
<Header title="Error!" hideClose />
<View style={styles.error}>
<Text style={styles.errorMessage}>
There was an unexpected error. You can either try reload this
page, or return home.
</Text>
<LinkButton
href={window.location.toString()}
target="_self"
label="Reload Page"
/>
<LinkButton
color="secondary"
href="/"
label="Return Home"
target="_self"
/>
</View>
</View>
</Wrapper>
)
}

const { children } = this.props
return children
}
}

const { padding, defaultFontSize, fontFamily } = vars
styles = StyleSheet.create({
wrapper: {
flex: 1,
},
error: {
padding,
},
errorMessage: {
fontSize: defaultFontSize,
fontFamily,
marginBottom: padding,
},
})

0 comments on commit a6cee2c

Please sign in to comment.