Skip to content
Snippets Groups Projects
Commit ab6afe95 authored by Todd Dembrey's avatar Todd Dembrey
Browse files

GH-877: handle error message when fetching with existing data

parent e675f4a6
No related branches found
No related tags found
No related merge requests found
...@@ -35,22 +35,25 @@ export default class Listing extends React.Component { ...@@ -35,22 +35,25 @@ export default class Listing extends React.Component {
listRef, listRef,
} = this.props; } = this.props;
if (isLoading && !items) { if ( items.length === 0 ) {
return ( if (isLoading) {
<div className="listing__list"> return (
<LoadingPanel /> <div className="listing__list">
</div> <LoadingPanel />
); </div>
} else if (isError) { );
return this.renderError(); } else if (isError) {
} else if (items.length === 0) { return this.renderError();
return <EmptyPanel column={this.props.column} />; } else {
return <EmptyPanel column={this.props.column} />;
}
} }
return ( return (
<> <>
{ isLoading && <InlineLoading /> } { isLoading && <InlineLoading /> }
<ul className={`listing__list listing__list--${column}`} ref={listRef}> <ul className={`listing__list listing__list--${column}`} ref={listRef}>
{ isError && this.renderErrorItem() }
<TransitionGroup component={null} > <TransitionGroup component={null} >
{items.map(v => renderItem(v))} {items.map(v => renderItem(v))}
</TransitionGroup> </TransitionGroup>
...@@ -59,9 +62,24 @@ export default class Listing extends React.Component { ...@@ -59,9 +62,24 @@ export default class Listing extends React.Component {
); );
} }
retryButton = (handleRetry) => {
return <a className="listing__help-link" onClick={handleRetry}>Refresh</a>;
}
renderErrorItem = () => {
const { handleRetry, error } = this.props;
return (
<li className={`listing__item listing__item--error`}>
<h5>Something went wrong!</h5>
<p>{ error }</p>
{ !navigator.onLine && <p>You appear to be offline.</p>}
{ handleRetry && this.retryButton(handleRetry) }
</li>
)
}
renderError = () => { renderError = () => {
const { handleRetry, error, column } = this.props; const { handleRetry, error, column } = this.props;
const retryButton = <a className="listing__help-link" onClick={handleRetry}>Refresh</a>;
return ( return (
<div className={`listing__list listing__list--${column} is-blank`}> <div className={`listing__list listing__list--${column} is-blank`}>
...@@ -71,14 +89,14 @@ export default class Listing extends React.Component { ...@@ -71,14 +89,14 @@ export default class Listing extends React.Component {
<p>Something went wrong!</p> <p>Something went wrong!</p>
} }
{handleRetry && retryButton && {handleRetry &&
<> <>
<div className="listing__blank-icon"> <div className="listing__blank-icon">
<SadNoteIcon /> <SadNoteIcon />
</div> </div>
<p className="listing__help-text listing__help-text--standout">Something went wrong!</p> <p className="listing__help-text listing__help-text--standout">Something went wrong!</p>
<p className="listing__help-text">Sorry we couldn&apos;t load the notes</p> <p className="listing__help-text">Sorry we couldn&apos;t load the notes</p>
{retryButton} { this.handleRetry(handleRetry) }
</> </>
} }
</div> </div>
......
...@@ -53,6 +53,14 @@ ...@@ -53,6 +53,14 @@
&__item { &__item {
@include submission-list-item; @include submission-list-item;
&--error {
padding: 5px 20px 5px;
p {
margin: 5px 0px;
}
}
&.is-active { &.is-active {
@include target-edge { @include target-edge {
margin-left: 8px; margin-left: 8px;
...@@ -71,6 +79,7 @@ ...@@ -71,6 +79,7 @@
} }
} }
// <a> tags // <a> tags
&__link { &__link {
display: block; display: block;
......
...@@ -8,6 +8,7 @@ import Listing from '@components/Listing'; ...@@ -8,6 +8,7 @@ import Listing from '@components/Listing';
import Note from '@containers/Note'; import Note from '@containers/Note';
import { import {
getNotesErrorState, getNotesErrorState,
getNotesErrorMessage,
getNoteIDsForSubmissionOfID, getNoteIDsForSubmissionOfID,
getNotesFetchState, getNotesFetchState,
} from '@selectors/notes'; } from '@selectors/notes';
...@@ -19,6 +20,7 @@ class NoteListing extends React.Component { ...@@ -19,6 +20,7 @@ class NoteListing extends React.Component {
submissionID: PropTypes.number, submissionID: PropTypes.number,
noteIDs: PropTypes.array, noteIDs: PropTypes.array,
isErrored: PropTypes.bool, isErrored: PropTypes.bool,
errorMessage: PropTypes.string,
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
}; };
...@@ -63,16 +65,17 @@ class NoteListing extends React.Component { ...@@ -63,16 +65,17 @@ class NoteListing extends React.Component {
} }
render() { render() {
const { noteIDs } = this.props; const { noteIDs, isLoading, isErrored, errorMessage } = this.props;
const passProps = {
isLoading: this.props.isLoading,
isError: this.props.isErrored,
handleRetry: this.handleRetry,
renderItem: this.renderItem,
items: noteIDs,
};
return ( return (
<Listing {...passProps} column="notes" /> <Listing
isLoading={ isLoading }
isError={ isErrored }
error={ errorMessage }
handleRetry={ this.handleRetry }
renderItem={ this.renderItem }
items={ noteIDs }
column="notes"
/>
); );
} }
} }
...@@ -85,6 +88,7 @@ const mapStateToProps = (state, ownProps) => ({ ...@@ -85,6 +88,7 @@ const mapStateToProps = (state, ownProps) => ({
noteIDs: getNoteIDsForSubmissionOfID(ownProps.submissionID)(state), noteIDs: getNoteIDsForSubmissionOfID(ownProps.submissionID)(state),
isLoading: getNotesFetchState(state), isLoading: getNotesFetchState(state),
isErrored: getNotesErrorState(state), isErrored: getNotesErrorState(state),
errorMessage: getNotesErrorMessage(state),
}); });
export default connect(mapStateToProps, mapDispatchToProps)(NoteListing); export default connect(mapStateToProps, mapDispatchToProps)(NoteListing);
...@@ -21,13 +21,20 @@ function notesFetching(state = false, action) { ...@@ -21,13 +21,20 @@ function notesFetching(state = false, action) {
} }
} }
function notesErrored(state = false, action) { function notesErrored(state = {errored: false, message: null}, action) {
switch (action.type) { switch (action.type) {
case UPDATE_NOTES: case UPDATE_NOTES:
case START_FETCHING_NOTES: case START_FETCHING_NOTES:
return false; return {
...state,
errored: false,
};
case FAIL_FETCHING_NOTES: case FAIL_FETCHING_NOTES:
return true; return {
...state,
message: action.error,
errored: true,
};
default: default:
return state; return state;
} }
...@@ -110,7 +117,7 @@ function notesByID(state = {}, action) { ...@@ -110,7 +117,7 @@ function notesByID(state = {}, action) {
export default combineReducers({ export default combineReducers({
byID: notesByID, byID: notesByID,
isFetching: notesFetching, isFetching: notesFetching,
isErrored: notesErrored, error: notesErrored,
createError: notesFailedCreating, createError: notesFailedCreating,
isCreating: notesCreating, isCreating: notesCreating,
}); });
...@@ -10,7 +10,9 @@ export const getNoteOfID = (noteID) => createSelector( ...@@ -10,7 +10,9 @@ export const getNoteOfID = (noteID) => createSelector(
export const getNotesFetchState = state => state.notes.isFetching === true; export const getNotesFetchState = state => state.notes.isFetching === true;
export const getNotesErrorState = state => state.notes.isErrored === true; export const getNotesErrorState = state => state.notes.error.errored === true;
export const getNotesErrorMessage = state => state.notes.error.message;
export const getNoteIDsForSubmissionOfID = submissionID => createSelector( export const getNoteIDsForSubmissionOfID = submissionID => createSelector(
[getSubmissionOfID(submissionID)], [getSubmissionOfID(submissionID)],
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment