Skip to content
This repository has been archived by the owner on Nov 10, 2023. It is now read-only.

Commit

Permalink
feat: Add specific error boundary for safe apps (#3932)
Browse files Browse the repository at this point in the history
* Add specific error boundary for safe apps

* Use render props for the error boundary UI
  • Loading branch information
yagopv authored Jun 8, 2022
1 parent 35494d6 commit a38298f
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { ReactNode, ErrorInfo } from 'react'

type SafeAppsErrorBoundaryProps = {
children?: ReactNode
render: () => ReactNode
}

type SafeAppsErrorBoundaryState = {
hasError: boolean
error?: Error
}

class SafeAppsErrorBoundary extends React.Component<SafeAppsErrorBoundaryProps, SafeAppsErrorBoundaryState> {
public state: SafeAppsErrorBoundaryState = {
hasError: false,
}

constructor(props: SafeAppsErrorBoundaryProps) {
super(props)
this.state = { hasError: false }
}

public componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
console.error('Uncaught error:', error, errorInfo)
}

public static getDerivedStateFromError(error: Error): SafeAppsErrorBoundaryState {
return { hasError: true, error }
}

public render(): React.ReactNode {
if (this.state.hasError) {
return this.props.render()
}

return this.props.children
}
}

export default SafeAppsErrorBoundary
78 changes: 78 additions & 0 deletions src/routes/safe/components/Apps/components/SafeAppsLoadError.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { useSelector } from 'react-redux'
import { useHistory } from 'react-router-dom'
import { currentSession } from 'src/logic/currentSession/store/selectors'
import styled from 'styled-components'
import { Text, Link, Icon, FixedIcon, Title } from '@gnosis.pm/safe-react-components'
import { generateSafeRoute, SAFE_ROUTES } from 'src/routes/routes'

const SafeAppsLoadError = (): React.ReactElement => {
const history = useHistory()
const { currentShortName, currentSafeAddress } = useSelector(currentSession)
const handleGoBack = () => {
history.push(
generateSafeRoute(SAFE_ROUTES.APPS, {
safeAddress: currentSafeAddress,
shortName: currentShortName,
}),
)
}

return (
<Wrapper>
<Content>
<Title size="md">Safe App could not be loaded.</Title>
<FixedIcon type="networkError" />

<div>
<Text size="xl" as="span">
In case the problem persists, please reach out to us via{' '}
</Text>
<LinkWrapper>
<a target="_blank" href="https://chat.gnosis-safe.io" rel="noopener noreferrer">
<Text color="primary" size="lg" as="span">
Discord
</Text>
</a>
<Icon type="externalLink" color="primary" size="sm" />
</LinkWrapper>
</div>

<Link size="lg" color="primary" onClick={handleGoBack}>
Go back to the Safe Apps list
</Link>
</Content>
</Wrapper>
)
}

const Wrapper = styled.div`
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
`

const Content = styled.div`
width: 400px;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
> * {
margin-top: 10px;
}
`

const LinkWrapper = styled.div`
display: inline-flex;
margin-bottom: 10px;
> :first-of-type {
margin-right: 5px;
}
`

export default SafeAppsLoadError
9 changes: 7 additions & 2 deletions src/routes/safe/components/Apps/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useHistory } from 'react-router-dom'

import { useSafeAppUrl } from 'src/logic/hooks/useSafeAppUrl'
import AppFrame from 'src/routes/safe/components/Apps/components/AppFrame'
import AppsList from 'src/routes/safe/components/Apps/components/AppsList'
import LegalDisclaimer from 'src/routes/safe/components/Apps/components/LegalDisclaimer'
import { useLegalConsent } from 'src/routes/safe/components/Apps/hooks/useLegalConsent'
import SafeAppsErrorBoundary from './components/SafeAppsErrorBoundary'
import SafeAppsLoadError from './components/SafeAppsLoadError'

const Apps = (): React.ReactElement => {
const history = useHistory()
Expand All @@ -19,7 +20,11 @@ const Apps = (): React.ReactElement => {
return <LegalDisclaimer onCancel={goBack} onConfirm={onConsentReceipt} />
}

return <AppFrame appUrl={url} />
return (
<SafeAppsErrorBoundary render={() => <SafeAppsLoadError />}>
<AppFrame appUrl={url} />
</SafeAppsErrorBoundary>
)
} else {
return <AppsList />
}
Expand Down

0 comments on commit a38298f

Please sign in to comment.