Show error message when column fetch fails

This commit is contained in:
Bruno Lemos
2018-12-04 20:00:28 -02:00
parent 930f2f4dfc
commit 707490f1f0
6 changed files with 118 additions and 25 deletions

View File

@@ -1,5 +1,11 @@
import React from 'react'
import { ActivityIndicator, Text, View } from 'react-native'
import {
ActivityIndicator,
Text,
TextStyle,
View,
ViewStyle,
} from 'react-native'
import { LoadState } from '@devhub/core/src/types'
import { contentPadding } from '../../styles/variables'
@@ -33,14 +39,64 @@ const clearMessage = getRandomClearMessage()
const emoji = getRandomEmoji()
export interface EmptyCardsProps {
errorMessage?: string
fetchNextPage: ((params?: { perPage?: number }) => void) | undefined
loadState: LoadState
refresh: (() => void | Promise<void>) | undefined
}
export function EmptyCards(props: EmptyCardsProps) {
const theme = useTheme()
const { fetchNextPage, loadState } = props
const { errorMessage, fetchNextPage, loadState, refresh } = props
const hasError = errorMessage || loadState === 'error'
const renderContent = () => {
if (loadState === 'loading_first') {
return <ActivityIndicator color={theme.foregroundColor} />
}
const containerStyle: ViewStyle = { width: '100%', padding: contentPadding }
const textStyle: TextStyle = {
lineHeight: 20,
fontSize: 14,
color: theme.foregroundColorMuted50,
textAlign: 'center',
}
if (hasError) {
return (
<View style={containerStyle}>
<Text style={textStyle}>
{`⚠️\nSomething went wrong`}
{!!errorMessage && (
<Text style={{ fontSize: 13 }}>{`\nError: ${errorMessage}`}</Text>
)}
</Text>
{!!refresh && (
<View style={{ padding: contentPadding }}>
<Button
children="Try again"
disabled={loadState !== 'error'}
loading={loadState === 'loading'}
onPress={() => refresh()}
/>
</View>
)}
</View>
)
}
return (
<View style={containerStyle}>
<Text style={textStyle}>
{clearMessage} {emoji}
</Text>
</View>
)
}
return (
<TransparentTextOverlay
@@ -58,17 +114,11 @@ export function EmptyCards(props: EmptyCardsProps) {
padding: contentPadding,
}}
>
{loadState === 'loading_first' ? (
<ActivityIndicator color={theme.foregroundColor} />
) : (
<Text style={{ color: theme.foregroundColorMuted50 }}>
{clearMessage} {emoji}
</Text>
)}
{renderContent()}
</View>
<View style={{ minHeight: 40 + 2 * contentPadding }}>
{!!fetchNextPage && loadState !== 'loading_first' && (
{!!fetchNextPage && !hasError && loadState !== 'loading_first' && (
<View style={{ padding: contentPadding }}>
<Button
children="Load more"

View File

@@ -7,15 +7,17 @@ import { contentPadding } from '../../styles/variables'
import { Button } from '../common/Button'
import { TransparentTextOverlay } from '../common/TransparentTextOverlay'
import { useTheme } from '../context/ThemeContext'
import { EmptyCards } from './EmptyCards'
import { EmptyCards, EmptyCardsProps } from './EmptyCards'
import { EventCard } from './EventCard'
import { CardItemSeparator } from './partials/CardItemSeparator'
import { SwipeableEventCard } from './SwipeableEventCard'
export interface EventCardsProps {
errorMessage: EmptyCardsProps['errorMessage']
events: EnhancedGitHubEvent[]
fetchNextPage: ((params?: { perPage?: number }) => void) | undefined
loadState: LoadState
refresh: EmptyCardsProps['refresh']
repoIsKnown?: boolean
swipeable?: boolean
}
@@ -23,10 +25,17 @@ export interface EventCardsProps {
export const EventCards = React.memo((props: EventCardsProps) => {
const theme = useTheme()
const { events, fetchNextPage, loadState } = props
const { errorMessage, events, fetchNextPage, loadState, refresh } = props
if (!(events && events.length))
return <EmptyCards fetchNextPage={fetchNextPage} loadState={loadState} />
return (
<EmptyCards
errorMessage={errorMessage}
fetchNextPage={fetchNextPage}
loadState={loadState}
refresh={refresh}
/>
)
function keyExtractor(event: EnhancedGitHubEvent) {
return `event-card-${event.id}`
@@ -54,10 +63,10 @@ export const EventCards = React.memo((props: EventCardsProps) => {
<CardItemSeparator />
<View style={{ padding: contentPadding }}>
<Button
children={loadState === 'error' ? 'Oops. Try again' : 'Load more'}
disabled={loadState !== 'loaded'}
loading={loadState === 'loading_more'}
onPress={() => fetchNextPage()}
children="Load more"
/>
</View>
</>

View File

@@ -7,26 +7,41 @@ import { contentPadding } from '../../styles/variables'
import { Button } from '../common/Button'
import { TransparentTextOverlay } from '../common/TransparentTextOverlay'
import { useTheme } from '../context/ThemeContext'
import { EmptyCards } from './EmptyCards'
import { EmptyCards, EmptyCardsProps } from './EmptyCards'
import { NotificationCard } from './NotificationCard'
import { CardItemSeparator } from './partials/CardItemSeparator'
import { SwipeableNotificationCard } from './SwipeableNotificationCard'
export interface NotificationCardsProps {
errorMessage: EmptyCardsProps['errorMessage']
fetchNextPage: ((params?: { perPage?: number }) => void) | undefined
notifications: EnhancedGitHubNotification[]
repoIsKnown?: boolean
loadState: LoadState
notifications: EnhancedGitHubNotification[]
refresh: EmptyCardsProps['refresh']
repoIsKnown?: boolean
swipeable?: boolean
}
export function NotificationCards(props: NotificationCardsProps) {
const theme = useTheme()
const { fetchNextPage, loadState, notifications } = props
const {
errorMessage,
fetchNextPage,
loadState,
notifications,
refresh,
} = props
if (!(notifications && notifications.length))
return <EmptyCards fetchNextPage={fetchNextPage} loadState={loadState} />
return (
<EmptyCards
errorMessage={errorMessage}
fetchNextPage={fetchNextPage}
loadState={loadState}
refresh={refresh}
/>
)
function keyExtractor(notification: EnhancedGitHubNotification) {
return `notification-card-${notification.id}`
@@ -64,7 +79,7 @@ export function NotificationCards(props: NotificationCardsProps) {
<CardItemSeparator />
<View style={{ padding: contentPadding }}>
<Button
children="Load more"
children={loadState === 'error' ? 'Oops. Try again' : 'Load more'}
disabled={loadState !== 'loaded'}
loading={loadState === 'loading_more'}
onPress={() => fetchNextPage()}

View File

@@ -16,7 +16,7 @@ import { getFilteredEvents } from '../utils/helpers/filters'
export type EventCardsContainerProps = Omit<
EventCardsProps,
'events' | 'fetchNextPage' | 'loadState'
'errorMessage' | 'events' | 'fetchNextPage' | 'loadState' | 'refresh'
> & {
column: Column
subscriptions: ColumnSubscription[]
@@ -38,6 +38,11 @@ export const EventCardsContainer = React.memo(
const [loadState, setLoadState] = useState<LoadState>('loading_first')
const [pagination, setPagination] = useState({ page: 1, perPage: 10 })
const [error, setError] = useState<{
[key: string]: any
message: string
} | null>(null)
useEffect(() => {
fetchData()
}, [])
@@ -135,9 +140,11 @@ export const EventCardsContainer = React.memo(
setPagination(prevPagination => ({ ...prevPagination, page }))
setCanFetchMore(false)
}
setError(null)
} catch (error) {
console.error('Failed to load GitHub activity', error)
setLoadState('loaded')
setLoadState('error')
setError(error)
}
}
@@ -150,9 +157,11 @@ export const EventCardsContainer = React.memo(
<EventCards
{...props}
key={`event-cards-${column.id}`}
errorMessage={(error && error.message) || ''}
events={filteredEvents}
fetchNextPage={canFetchMore ? fetchNextPage : undefined}
loadState={loadState}
refresh={() => fetchData()}
/>
)
},

View File

@@ -23,7 +23,7 @@ import { getFilteredNotifications } from '../utils/helpers/filters'
export type NotificationCardsContainerProps = Omit<
NotificationCardsProps,
'notifications' | 'fetchNextPage' | 'loadState'
'errorMessage' | 'notifications' | 'fetchNextPage' | 'loadState' | 'refresh'
> & {
column: Column
subscriptions: ColumnSubscription[]
@@ -49,6 +49,11 @@ export const NotificationCardsContainer = React.memo(
const [pagination, setPagination] = useState({ page: 1, perPage: 10 })
const githubToken = useReduxState(selectors.githubTokenSelector)!
const [error, setError] = useState<{
[key: string]: any
message: string
} | null>(null)
useEffect(() => {
fetchData()
}, [])
@@ -169,9 +174,11 @@ export const NotificationCardsContainer = React.memo(
setPagination(prevPagination => ({ ...prevPagination, page }))
setCanFetchMore(false)
}
setError(null)
} catch (error) {
console.error('Failed to load GitHub notifications', error)
setLoadState('loaded')
setLoadState('error')
setError(error)
}
}
@@ -184,9 +191,11 @@ export const NotificationCardsContainer = React.memo(
<NotificationCards
{...props}
key={`notification-cards-${column.id}`}
notifications={filteredNotifications}
errorMessage={(error && error.message) || ''}
fetchNextPage={canFetchMore ? fetchNextPage : undefined}
loadState={loadState}
notifications={filteredNotifications}
refresh={() => fetchData()}
/>
)
},

View File

@@ -178,6 +178,7 @@ export type ModalPayload =
}
export type LoadState =
| 'error'
| 'loaded'
| 'loading'
| 'loading_first'