1
0
mirror of https://github.com/ascribe/onion.git synced 2024-12-23 01:39:36 +01:00

Merge pull request #1 from ascribe/AD-1177-display-404-on-pieces-and-editio

AD-1177 display 404 on pieces and editio
This commit is contained in:
Tim Daubenschütz 2015-12-07 11:49:39 +01:00
commit 2b6b78310c
10 changed files with 116 additions and 9 deletions

View File

@ -7,7 +7,8 @@ import EditionFetcher from '../fetchers/edition_fetcher';
class EditionActions { class EditionActions {
constructor() { constructor() {
this.generateActions( this.generateActions(
'updateEdition' 'updateEdition',
'editionFailed'
); );
} }
@ -18,6 +19,7 @@ class EditionActions {
}) })
.catch((err) => { .catch((err) => {
console.logGlobal(err); console.logGlobal(err);
this.actions.editionFailed(err.json);
}); });
} }
} }

View File

@ -8,7 +8,8 @@ class PieceActions {
constructor() { constructor() {
this.generateActions( this.generateActions(
'updatePiece', 'updatePiece',
'updateProperty' 'updateProperty',
'pieceFailed'
); );
} }
@ -19,6 +20,7 @@ class PieceActions {
}) })
.catch((err) => { .catch((err) => {
console.logGlobal(err); console.logGlobal(err);
this.actions.pieceFailed(err.json);
}); });
} }
} }

View File

@ -1,6 +1,10 @@
'use strict'; 'use strict';
import React from 'react'; import React from 'react';
import { History } from 'react-router';
import ReactError from '../../mixins/react_error';
import { ResourceNotFoundError } from '../../models/errors';
import EditionActions from '../../actions/edition_actions'; import EditionActions from '../../actions/edition_actions';
import EditionStore from '../../stores/edition_store'; import EditionStore from '../../stores/edition_store';
@ -9,6 +13,7 @@ import Edition from './edition';
import AscribeSpinner from '../ascribe_spinner'; import AscribeSpinner from '../ascribe_spinner';
import { getLangText } from '../../utils/lang_utils';
import { setDocumentTitle } from '../../utils/dom_utils'; import { setDocumentTitle } from '../../utils/dom_utils';
@ -22,6 +27,8 @@ let EditionContainer = React.createClass({
params: React.PropTypes.object params: React.PropTypes.object
}, },
mixins: [History, ReactError],
getInitialState() { getInitialState() {
return EditionStore.getState(); return EditionStore.getState();
}, },
@ -29,11 +36,11 @@ let EditionContainer = React.createClass({
componentDidMount() { componentDidMount() {
EditionStore.listen(this.onChange); EditionStore.listen(this.onChange);
// Every time we enter the edition detail page, just reset the edition // Every time we're entering the edition detail page,
// store as it will otherwise display wrong/old data once the user loads // just reset the edition that is saved in the edition store
// as it will otherwise display wrong/old data once the user loads
// the edition detail a second time // the edition detail a second time
EditionActions.updateEdition({}); EditionActions.updateEdition({});
this.loadEdition(); this.loadEdition();
}, },
@ -46,6 +53,14 @@ let EditionContainer = React.createClass({
} }
}, },
componentDidUpdate() {
const { editionError } = this.state;
if(editionError && editionError.status === 404) {
this.throws(new ResourceNotFoundError(getLangText("Oops, the edition you're looking for doesn't exist.")));
}
},
componentWillUnmount() { componentWillUnmount() {
window.clearInterval(this.state.timerId); window.clearInterval(this.state.timerId);
EditionStore.unlisten(this.onChange); EditionStore.unlisten(this.onChange);

View File

@ -4,6 +4,9 @@ import React from 'react';
import { History } from 'react-router'; import { History } from 'react-router';
import Moment from 'moment'; import Moment from 'moment';
import ReactError from '../../mixins/react_error';
import { ResourceNotFoundError } from '../../models/errors';
import PieceActions from '../../actions/piece_actions'; import PieceActions from '../../actions/piece_actions';
import PieceStore from '../../stores/piece_store'; import PieceStore from '../../stores/piece_store';
@ -54,7 +57,7 @@ let PieceContainer = React.createClass({
params: React.PropTypes.object params: React.PropTypes.object
}, },
mixins: [History], mixins: [History, ReactError],
getDefaultProps() { getDefaultProps() {
return { return {
@ -76,15 +79,22 @@ let PieceContainer = React.createClass({
componentDidMount() { componentDidMount() {
UserStore.listen(this.onChange); UserStore.listen(this.onChange);
PieceListStore.listen(this.onChange); PieceListStore.listen(this.onChange);
UserActions.fetchCurrentUser();
PieceStore.listen(this.onChange); PieceStore.listen(this.onChange);
// Every time we enter the piece detail page, just reset the piece // Every time we enter the piece detail page, just reset the piece
// store as it will otherwise display wrong/old data once the user loads // store as it will otherwise display wrong/old data once the user loads
// the piece detail a second time // the piece detail a second time
PieceActions.updatePiece({}); PieceActions.updatePiece({});
this.loadPiece(); this.loadPiece();
UserActions.fetchCurrentUser();
},
componentDidUpdate() {
const { pieceError } = this.state;
if(pieceError && pieceError.status === 404) {
this.throws(new ResourceNotFoundError(getLangText("Oops, the piece you're looking for doesn't exist.")));
}
}, },
componentWillUnmount() { componentWillUnmount() {

View File

@ -6,6 +6,16 @@ import { getLangText } from '../utils/lang_utils';
let ErrorNotFoundPage = React.createClass({ let ErrorNotFoundPage = React.createClass({
propTypes: {
message: React.PropTypes.string
},
getDefaultProps() {
return {
message: getLangText("Oops, the page you are looking for doesn't exist.")
};
},
render() { render() {
return ( return (
<div className="row"> <div className="row">
@ -13,7 +23,7 @@ let ErrorNotFoundPage = React.createClass({
<div className="error-wrapper"> <div className="error-wrapper">
<h1>404</h1> <h1>404</h1>
<p> <p>
{getLangText('Ups, the page you are looking for does not exist.')} {this.props.message}
</p> </p>
</div> </div>
</div> </div>

16
js/mixins/react_error.js Normal file
View File

@ -0,0 +1,16 @@
'use strict';
import invariant from 'invariant';
const ReactError = {
throws(err) {
if(!err.handler) {
invariant(err.handler, 'Error thrown to ReactError did not have a `handler` function');
console.logGlobal('Error thrown to ReactError did not have a `handler` function');
} else {
err.handler(this, err);
}
}
};
export default ReactError;

31
js/models/errors.js Normal file
View File

@ -0,0 +1,31 @@
'use strict';
import React from 'react';
import ErrorNotFoundPage from '../components/error_not_found_page';
export class ResourceNotFoundError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
this.message = message;
// `captureStackTrace` might not be available in IE:
// - http://stackoverflow.com/a/8460753/1263876
if(Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor.name);
}
}
handler(component, err) {
const monkeyPatchedKey = `_${this.name}MonkeyPatched`;
if(!component.state[monkeyPatchedKey]) {
component.render = () => <ErrorNotFoundPage message={err.message} />;
component.setState({
[monkeyPatchedKey]: true
});
}
}
}

View File

@ -7,11 +7,17 @@ import EditionActions from '../actions/edition_actions';
class EditionStore { class EditionStore {
constructor() { constructor() {
this.edition = {}; this.edition = {};
this.editionError = null;
this.bindActions(EditionActions); this.bindActions(EditionActions);
} }
onUpdateEdition(edition) { onUpdateEdition(edition) {
this.edition = edition; this.edition = edition;
this.editionError = null;
}
onEditionFailed(error) {
this.editionError = error;
} }
} }

View File

@ -7,11 +7,13 @@ import PieceActions from '../actions/piece_actions';
class PieceStore { class PieceStore {
constructor() { constructor() {
this.piece = {}; this.piece = {};
this.pieceError = null;
this.bindActions(PieceActions); this.bindActions(PieceActions);
} }
onUpdatePiece(piece) { onUpdatePiece(piece) {
this.piece = piece; this.piece = piece;
this.pieceError = null;
} }
onUpdateProperty({key, value}) { onUpdateProperty({key, value}) {
@ -21,6 +23,10 @@ class PieceStore {
throw new Error('There is no piece defined in PieceStore or the piece object does not have the property you\'re looking for.'); throw new Error('There is no piece defined in PieceStore or the piece object does not have the property you\'re looking for.');
} }
} }
onPieceFailed(err) {
this.pieceError = err;
}
} }
export default alt.createStore(PieceStore, 'PieceStore'); export default alt.createStore(PieceStore, 'PieceStore');

View File

@ -30,6 +30,15 @@ class Requests {
reject(error); reject(error);
} else if(body && body.detail) { } else if(body && body.detail) {
reject(new Error(body.detail)); reject(new Error(body.detail));
} else if(!body.success) {
let error = new Error('Client Request Error');
error.json = {
status: response.status,
statusText: response.statusText,
type: response.type,
url: response.url
};
reject(error);
} else { } else {
resolve(body); resolve(body);
} }