1
0
mirror of https://github.com/ascribe/onion.git synced 2025-01-03 10:25:08 +01:00

Merge pull request #68 from ascribe/PR-hotfixes

PR hotfixes
This commit is contained in:
Brett Sun 2015-12-14 16:57:51 +01:00
commit 8aae923388
13 changed files with 213 additions and 171 deletions

View File

@ -85,6 +85,7 @@ let PieceContainer = React.createClass({
// 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(); UserActions.fetchCurrentUser();
}, },
@ -92,7 +93,7 @@ let PieceContainer = React.createClass({
componentDidUpdate() { componentDidUpdate() {
const { pieceError } = this.state; const { pieceError } = this.state;
if(pieceError && pieceError.status === 404) { if (pieceError && pieceError.status === 404) {
this.throws(new ResourceNotFoundError(getLangText("Oops, the piece you're looking for doesn't exist."))); this.throws(new ResourceNotFoundError(getLangText("Oops, the piece you're looking for doesn't exist.")));
} }
}, },

View File

@ -182,7 +182,7 @@ let Form = React.createClass({
delete formData.password; delete formData.password;
} }
console.logGlobal(err, false, formData); console.logGlobal(err, formData);
if(this.props.isInline) { if(this.props.isInline) {
let notification = new GlobalNotificationModel(getLangText('Something went wrong, please try again later'), 'danger'); let notification = new GlobalNotificationModel(getLangText('Something went wrong, please try again later'), 'danger');

View File

@ -93,7 +93,6 @@ let LoginForm = React.createClass({
<input <input
type="email" type="email"
placeholder={getLangText('Enter your email')} placeholder={getLangText('Enter your email')}
name="email"
defaultValue={email} defaultValue={email}
required/> required/>
</Property> </Property>
@ -103,7 +102,6 @@ let LoginForm = React.createClass({
<input <input
type="password" type="password"
placeholder={getLangText('Enter your password')} placeholder={getLangText('Enter your password')}
name="password"
required/> required/>
</Property> </Property>
</Form> </Form>

View File

@ -71,17 +71,9 @@ export default function UploadButton({ className = 'btn btn-default btn-sm' } =
handleOnClick() { handleOnClick() {
if(!this.state.disabled) { if(!this.state.disabled) {
let evt; let evt;
const uploadingFiles = this.getUploadingFiles();
const uploadedFile = this.getUploadedFile();
this.clearSelection(); // First, remove any currently uploading or uploaded items
if(uploadingFiles.length) { this.onClickRemove();
this.props.handleCancelFile(uploadingFiles[0].id);
} else if(uploadedFile && !uploadedFile.s3UrlSafe) {
this.props.handleCancelFile(uploadedFile.id);
} else if(uploadedFile && uploadedFile.s3UrlSafe) {
this.props.handleDeleteFile(uploadedFile.id);
}
try { try {
evt = new MouseEvent('click', { evt = new MouseEvent('click', {
@ -99,18 +91,19 @@ export default function UploadButton({ className = 'btn btn-default btn-sm' } =
} }
}, },
onClickCancel() {
this.clearSelection();
const uploadingFile = this.getUploadingFiles()[0];
this.props.handleCancelFile(uploadingFile.id);
},
onClickRemove() { onClickRemove() {
this.clearSelection(); const uploadingFiles = this.getUploadingFiles();
const uploadedFile = this.getUploadedFile(); const uploadedFile = this.getUploadedFile();
this.props.handleDeleteFile(uploadedFile.id);
},
this.clearSelection();
if(uploadingFiles.length) {
this.props.handleCancelFile(uploadingFiles[0].id);
} else if(uploadedFile && !uploadedFile.s3UrlSafe) {
this.props.handleCancelFile(uploadedFile.id);
} else if(uploadedFile && uploadedFile.s3UrlSafe) {
this.props.handleDeleteFile(uploadedFile.id);
}
},
getButtonLabel() { getButtonLabel() {
let { filesToUpload, fileClassToUpload } = this.props; let { filesToUpload, fileClassToUpload } = this.props;
@ -133,7 +126,7 @@ export default function UploadButton({ className = 'btn btn-default btn-sm' } =
return ( return (
<span> <span>
{' ' + truncateTextAtCharIndex(uploadingFiles[0].name, 40) + ' '} {' ' + truncateTextAtCharIndex(uploadingFiles[0].name, 40) + ' '}
[<a onClick={this.onClickCancel}>{getLangText('cancel upload')}</a>] [<a onClick={this.onClickRemove}>{getLangText('cancel upload')}</a>]
</span> </span>
); );
} else if(uploadedFile) { } else if(uploadedFile) {
@ -193,4 +186,4 @@ export default function UploadButton({ className = 'btn btn-default btn-sm' } =
); );
} }
}); });
} }

View File

@ -344,6 +344,7 @@ const ReactS3FineUploader = React.createClass({
// still we warn the user of this component // still we warn the user of this component
console.warn('createBlobRoutine was not defined for ReactS3FineUploader. Continuing without creating the blob on the server.'); console.warn('createBlobRoutine was not defined for ReactS3FineUploader. Continuing without creating the blob on the server.');
resolve(); resolve();
return;
} }
window.fetch(createBlobRoutine.url, { window.fetch(createBlobRoutine.url, {
@ -439,7 +440,7 @@ const ReactS3FineUploader = React.createClass({
onComplete(id, name, res, xhr) { onComplete(id, name, res, xhr) {
// There has been an issue with the server's connection // There has been an issue with the server's connection
if (xhr && xhr.status === 0 && res.success) { if (xhr && xhr.status === 0 && res.success) {
console.logGlobal(new Error('Upload succeeded with a status code 0'), false, { console.logGlobal(new Error('Upload succeeded with a status code 0'), {
files: this.state.filesToUpload, files: this.state.filesToUpload,
chunks: this.state.chunks, chunks: this.state.chunks,
xhr: this.getXhrErrorComment(xhr) xhr: this.getXhrErrorComment(xhr)
@ -497,7 +498,7 @@ const ReactS3FineUploader = React.createClass({
}, },
onError(id, name, errorReason, xhr) { onError(id, name, errorReason, xhr) {
console.logGlobal(errorReason, false, { console.logGlobal(errorReason, {
files: this.state.filesToUpload, files: this.state.filesToUpload,
chunks: this.state.chunks, chunks: this.state.chunks,
xhr: this.getXhrErrorComment(xhr) xhr: this.getXhrErrorComment(xhr)

View File

@ -16,12 +16,13 @@ import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
import AclProxy from './acl_proxy'; import AclProxy from './acl_proxy';
import EventActions from '../actions/event_actions';
import UserActions from '../actions/user_actions'; import UserActions from '../actions/user_actions';
import UserStore from '../stores/user_store'; import UserStore from '../stores/user_store';
import WhitelabelActions from '../actions/whitelabel_actions'; import WhitelabelActions from '../actions/whitelabel_actions';
import WhitelabelStore from '../stores/whitelabel_store'; import WhitelabelStore from '../stores/whitelabel_store';
import EventActions from '../actions/event_actions';
import HeaderNotifications from './header_notification'; import HeaderNotifications from './header_notification';
@ -58,6 +59,19 @@ let Header = React.createClass({
// close the mobile expanded navigation after a click by itself. // close the mobile expanded navigation after a click by itself.
// To get rid of this, we set the state of the component ourselves. // To get rid of this, we set the state of the component ourselves.
history.listen(this.onRouteChange); history.listen(this.onRouteChange);
if (this.state.currentUser && this.state.currentUser.email) {
EventActions.profileDidLoad.defer(this.state.currentUser);
}
},
componentWillUpdate(nextProps, nextState) {
const { currentUser: { email: curEmail } = {} } = this.state;
const { currentUser: { email: nextEmail } = {} } = nextState;
if (nextEmail && curEmail !== nextEmail) {
EventActions.profileDidLoad.defer(nextState.currentUser);
}
}, },
componentWillUnmount() { componentWillUnmount() {
@ -105,10 +119,6 @@ let Header = React.createClass({
onChange(state) { onChange(state) {
this.setState(state); this.setState(state);
if(this.state.currentUser && this.state.currentUser.email) {
EventActions.profileDidLoad.defer(this.state.currentUser);
}
}, },
onMenuItemClick() { onMenuItemClick() {

View File

@ -75,7 +75,7 @@ const PRRegisterPieceForm = React.createClass({
const additionalDataFormData = additionalDataForm.getFormData(); const additionalDataFormData = additionalDataForm.getFormData();
// composing data for piece registration // composing data for piece registration
let registerPieceFormData = registerPieceForm.getFormData(); const registerPieceFormData = registerPieceForm.getFormData();
registerPieceFormData.digital_work_key = digitalWorkKey.state.value; registerPieceFormData.digital_work_key = digitalWorkKey.state.value;
registerPieceFormData.thumbnail_file = thumbnailKey.state.value; registerPieceFormData.thumbnail_file = thumbnailKey.state.value;
registerPieceFormData.terms = true; registerPieceFormData.terms = true;
@ -83,33 +83,33 @@ const PRRegisterPieceForm = React.createClass({
// submitting the piece // submitting the piece
requests requests
.post(ApiUrls.pieces_list, { body: registerPieceFormData }) .post(ApiUrls.pieces_list, { body: registerPieceFormData })
.then(({ success, piece, notification }) => { .then(({ piece, notification }) => {
if(success) { this.setState({piece}, () => {
this.setState({ supportingMaterials.refs.input.createBlobRoutine();
piece proofOfPayment.refs.input.createBlobRoutine();
}, () => { });
supportingMaterials.refs.input.createBlobRoutine();
proofOfPayment.refs.input.createBlobRoutine();
});
setCookie(currentUser.email, piece.id); setCookie(currentUser.email, piece.id);
return requests.post(ApiUrls.piece_extradata, { return requests
.post(ApiUrls.piece_extradata, {
body: { body: {
extradata: additionalDataFormData, extradata: additionalDataFormData,
piece_id: piece.id piece_id: piece.id
}, },
piece_id: piece.id piece_id: piece.id
})
.then(() => {
const notificationMessage = new GlobalNotificationModel(notification || getLangText('You have successfully submitted "%s" to Portfolio Review 2015', piece.title), 'success', 5000);
GlobalNotificationActions.appendGlobalNotification(notificationMessage);
}); });
} else {
const notificationMessage = new GlobalNotificationModel(notification, 'danger', 5000);
GlobalNotificationActions.appendGlobalNotification(notificationMessage);
}
}) })
.then(() => this.history.pushState(null, `/pieces/${this.state.piece.id}`)) .then(() => this.history.pushState(null, `/pieces/${this.state.piece.id}`))
.catch(() => { .catch((err) => {
const notificationMessage = new GlobalNotificationModel(getLangText("Ups! We weren't able to send your submission. Contact: support@ascribe.io"), 'danger', 5000); const notificationMessage = new GlobalNotificationModel(getLangText("Oops! We weren't able to send your submission. Contact: support@ascribe.io"), 'danger', 5000);
GlobalNotificationActions.appendGlobalNotification(notificationMessage); GlobalNotificationActions.appendGlobalNotification(notificationMessage);
console.logGlobal(new Error('Portfolio Review piece registration failed'), err);
}); });
}, },
@ -167,7 +167,7 @@ const PRRegisterPieceForm = React.createClass({
} else { } else {
return ( return (
<button <button
type="submit" type="button"
className="btn btn-default btn-wide" className="btn btn-default btn-wide"
disabled={!(digitalWorkKeyReady && thumbnailKeyReady && proofOfPaymentReady && supportingMaterialsReady)} disabled={!(digitalWorkKeyReady && thumbnailKeyReady && proofOfPaymentReady && supportingMaterialsReady)}
onClick={this.submit}> onClick={this.submit}>
@ -191,7 +191,7 @@ const PRRegisterPieceForm = React.createClass({
label={getLangText('Full name')}> label={getLangText('Full name')}>
<input <input
type="text" type="text"
placeholder="(e.g. Andy Warhol)" placeholder={getLangText('(e.g. Andy Warhol)')}
required/> required/>
</Property> </Property>
<Property <Property
@ -199,7 +199,7 @@ const PRRegisterPieceForm = React.createClass({
label={getLangText('Title of the Work')}> label={getLangText('Title of the Work')}>
<input <input
type="text" type="text"
placeholder="(e.g. 32 Campbell's Soup Cans)" placeholder={getLangText("(e.g. 32 Campbell's Soup Cans)")}
required/> required/>
</Property> </Property>
<Property <Property
@ -207,7 +207,7 @@ const PRRegisterPieceForm = React.createClass({
label={getLangText('Year of creation')}> label={getLangText('Year of creation')}>
<input <input
type="number" type="number"
placeholder="(e.g. 1962)" placeholder={getLangText('(e.g. 1962)')}
min={1} min={1}
required/> required/>
</Property> </Property>
@ -224,25 +224,51 @@ const PRRegisterPieceForm = React.createClass({
className="ascribe-form-bordered" className="ascribe-form-bordered"
ref="additionalDataForm"> ref="additionalDataForm">
<Property <Property
name='artist_bio' name='1-date_of_birth'
label={getLangText('Date of Birth')}>
<input
type="number"
placeholder={getLangText('(e.g. 1962)')}
min={1900}
required/>
</Property>
<Property
name='2-artist_bio'
label={getLangText('Biography')}> label={getLangText('Biography')}>
<InputTextAreaToggable <InputTextAreaToggable
rows={1} rows={1}
placeholder={getLangText('Enter your biography')}/> placeholder={getLangText('Enter your biography')}/>
</Property> </Property>
<Property <Property
name='exhibition' name='3-exhibition'
label={getLangText('Exhibition / Publication history (optional)')}> label={getLangText('Exhibition / Publication history (optional)')}>
<InputTextAreaToggable <InputTextAreaToggable
rows={1} rows={1}
placeholder={getLangText('Enter exhibitions and publication history')}/> placeholder={getLangText('Enter exhibitions and publication history')}/>
</Property> </Property>
<Property <Property
name='contact_information' name='4-phone_number'
label={getLangText('Contact information')}> label={getLangText('Phone Number')}>
<InputTextAreaToggable <input
rows={1} type="tel"
placeholder={getLangText('Enter your contact information (phone/website)')}/> placeholder={getLangText('Enter your phone number')}
required/>
</Property>
<Property
name='5-email'
label={getLangText('Email Address')}>
<input
type="email"
placeholder={getLangText('Enter your email')}
required/>
</Property>
<Property
name='6-website'
label={getLangText('Website')}>
<input
type="url"
placeholder={getLangText('Enter your website')}
required/>
</Property> </Property>
</Form> </Form>
<Form <Form
@ -311,7 +337,7 @@ const PRRegisterPieceForm = React.createClass({
createBlobRoutine={this.getCreateBlobRoutine()} createBlobRoutine={this.getCreateBlobRoutine()}
keyRoutine={{ keyRoutine={{
url: AppConstants.serverUrl + 's3/key/', url: AppConstants.serverUrl + 's3/key/',
fileClass: 'other_data' fileClass: 'otherdata'
}} }}
validation={{ validation={{
itemLimit: AppConstants.fineUploader.validation.registerWork.itemLimit, itemLimit: AppConstants.fineUploader.validation.registerWork.itemLimit,
@ -333,7 +359,7 @@ const PRRegisterPieceForm = React.createClass({
createBlobRoutine={this.getCreateBlobRoutine()} createBlobRoutine={this.getCreateBlobRoutine()}
keyRoutine={{ keyRoutine={{
url: AppConstants.serverUrl + 's3/key/', url: AppConstants.serverUrl + 's3/key/',
fileClass: 'other_data' fileClass: 'otherdata'
}} }}
validation={{ validation={{
itemLimit: AppConstants.fineUploader.validation.registerWork.itemLimit, itemLimit: AppConstants.fineUploader.validation.registerWork.itemLimit,
@ -372,4 +398,4 @@ const PRRegisterPieceForm = React.createClass({
} }
}); });
export default PRRegisterPieceForm; export default PRRegisterPieceForm;

View File

@ -5,32 +5,18 @@ import { Link } from 'react-router';
import Glyphicon from 'react-bootstrap/lib/Glyphicon'; import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import UserStore from '../../../../../stores/user_store';
import UserActions from '../../../../../actions/user_actions';
import { getLangText } from '../../../../../utils/lang_utils'; import { getLangText } from '../../../../../utils/lang_utils';
const PRHero = React.createClass({ const PRHero = React.createClass({
getInitialState() { propTypes: {
return UserStore.getState(); currentUser: React.PropTypes.shape({
}, email: React.PropTypes.object
})
componentDidMount() {
UserStore.listen(this.onChange);
UserActions.fetchCurrentUser.defer();
},
componentWillUnmount() {
UserStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
}, },
render() { render() {
const { currentUser } = this.state; const { currentUser } = this.props;
return ( return (
<div className="piece--hero"> <div className="piece--hero">

View File

@ -6,6 +6,8 @@ import GlobalNotification from '../../../global_notification';
import Hero from './components/pr_hero'; import Hero from './components/pr_hero';
import Header from '../../../header'; import Header from '../../../header';
import EventActions from '../../../../actions/event_actions';
import UserStore from '../../../../stores/user_store'; import UserStore from '../../../../stores/user_store';
import UserActions from '../../../../actions/user_actions'; import UserActions from '../../../../actions/user_actions';
@ -30,6 +32,19 @@ let PRApp = React.createClass({
componentDidMount() { componentDidMount() {
UserStore.listen(this.onChange); UserStore.listen(this.onChange);
UserActions.fetchCurrentUser(); UserActions.fetchCurrentUser();
if (this.state.currentUser && this.state.currentUser.email) {
EventActions.profileDidLoad.defer(this.state.currentUser);
}
},
componentWillUpdate(nextProps, nextState) {
const { currentUser: { email: curEmail } = {} } = this.state;
const { currentUser: { email: nextEmail } = {} } = nextState;
if (nextEmail && curEmail !== nextEmail) {
EventActions.profileDidLoad.defer(nextState.currentUser);
}
}, },
componentWillUnmount() { componentWillUnmount() {
@ -49,7 +64,7 @@ let PRApp = React.createClass({
if (currentUser && currentUser.email && history.isActive(`/pieces/${getCookie(currentUser.email)}`)) { if (currentUser && currentUser.email && history.isActive(`/pieces/${getCookie(currentUser.email)}`)) {
header = <Hero />; header = <Hero currentUser={currentUser} />;
style = { paddingTop: '0 !important' }; style = { paddingTop: '0 !important' };
} else if(currentUser && (currentUser.is_admin || currentUser.is_jury || currentUser.is_judge)) { } else if(currentUser && (currentUser.is_admin || currentUser.is_jury || currentUser.is_judge)) {
header = <Header routes={routes} />; header = <Header routes={routes} />;

View File

@ -6,6 +6,9 @@ import Moment from 'moment';
import StarRating from 'react-star-rating'; import StarRating from 'react-star-rating';
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,6 +57,8 @@ let PieceContainer = React.createClass({
params: React.PropTypes.object params: React.PropTypes.object
}, },
mixins: [ReactError],
getInitialState() { getInitialState() {
return mergeOptions( return mergeOptions(
PieceStore.getState(), PieceStore.getState(),
@ -63,14 +68,15 @@ let PieceContainer = React.createClass({
componentDidMount() { componentDidMount() {
PieceStore.listen(this.onChange); PieceStore.listen(this.onChange);
PieceActions.fetchOne(this.props.params.pieceId);
UserStore.listen(this.onChange); UserStore.listen(this.onChange);
UserActions.fetchCurrentUser();
// 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({});
PieceActions.fetchOne(this.props.params.pieceId);
UserActions.fetchCurrentUser();
}, },
// This is done to update the container when the user clicks on the prev or next // This is done to update the container when the user clicks on the prev or next
@ -82,6 +88,14 @@ let PieceContainer = React.createClass({
} }
}, },
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() {
PieceStore.unlisten(this.onChange); PieceStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange); UserStore.unlisten(this.onChange);
@ -92,10 +106,6 @@ let PieceContainer = React.createClass({
this.setState(state); this.setState(state);
}, },
loadPiece() {
PieceActions.fetchOne(this.props.params.pieceId);
},
getActions() { getActions() {
if (this.state.piece && if (this.state.piece &&
this.state.piece.notifications && this.state.piece.notifications &&
@ -112,7 +122,7 @@ let PieceContainer = React.createClass({
render() { render() {
if(this.state.piece && this.state.piece.id) { if(this.state.piece && this.state.piece.id) {
/* /*
This really needs a refactor! This really needs a refactor!
- Tim - Tim
@ -122,7 +132,7 @@ let PieceContainer = React.createClass({
let artistName = ((this.state.currentUser.is_jury && !this.state.currentUser.is_judge) || let artistName = ((this.state.currentUser.is_jury && !this.state.currentUser.is_judge) ||
(this.state.currentUser.is_judge && !this.state.piece.selected )) ? (this.state.currentUser.is_judge && !this.state.piece.selected )) ?
null : this.state.piece.artist_name; null : this.state.piece.artist_name;
// Only show the artist email if you are a judge and the piece is shortlisted // Only show the artist email if you are a judge and the piece is shortlisted
let artistEmail = (this.state.currentUser.is_judge && this.state.piece.selected ) ? let artistEmail = (this.state.currentUser.is_judge && this.state.piece.selected ) ?
<DetailProperty label={getLangText('REGISTREE')} value={ this.state.piece.user_registered } /> : null; <DetailProperty label={getLangText('REGISTREE')} value={ this.state.piece.user_registered } /> : null;
@ -146,7 +156,7 @@ let PieceContainer = React.createClass({
<NavigationHeader <NavigationHeader
piece={this.state.piece} piece={this.state.piece}
currentUser={this.state.currentUser}/> currentUser={this.state.currentUser}/>
<h1 className="ascribe-detail-title">{this.state.piece.title}</h1> <h1 className="ascribe-detail-title">{this.state.piece.title}</h1>
<DetailProperty label={getLangText('BY')} value={artistName} /> <DetailProperty label={getLangText('BY')} value={artistName} />
<DetailProperty label={getLangText('DATE')} value={Moment(this.state.piece.date_created, 'YYYY-MM-DD').year()} /> <DetailProperty label={getLangText('DATE')} value={Moment(this.state.piece.date_created, 'YYYY-MM-DD').year()} />
@ -429,18 +439,21 @@ let PrizePieceDetails = React.createClass({
}, },
render() { render() {
if (this.props.piece const { piece } = this.props;
&& this.props.piece.prize
&& this.props.piece.prize.name if (piece &&
&& Object.keys(this.props.piece.extra_data).length !== 0){ piece.prize &&
piece.prize.name &&
Object.keys(piece.extra_data).length !== 0) {
return ( return (
<CollapsibleParagraph <CollapsibleParagraph
title={getLangText('Prize Details')} title={getLangText('Prize Details')}
defaultExpanded={true}> defaultExpanded={true}>
<Form ref='form'> <Form ref='form'>
{Object.keys(this.props.piece.extra_data).map((data) => { {Object.keys(piece.extra_data).sort().map((data) => {
let label = data.replace('_', ' '); // Remove leading number (for sorting), if any, and underscores with spaces
const value = this.props.piece.extra_data[data] || 'N/A'; let label = data.replace(/^\d-/, '').replace(/_/g, ' ');
const value = piece.extra_data[data] || 'N/A';
return ( return (
<Property <Property
@ -460,8 +473,8 @@ let PrizePieceDetails = React.createClass({
isReadyForFormSubmission={() => {}} isReadyForFormSubmission={() => {}}
editable={false} editable={false}
overrideForm={true} overrideForm={true}
pieceId={this.props.piece.id} pieceId={piece.id}
otherData={this.props.piece.other_data} otherData={piece.other_data}
multiple={true} /> multiple={true} />
</Form> </Form>
</CollapsibleParagraph> </CollapsibleParagraph>

View File

@ -13,8 +13,7 @@ import AppConstants from '../constants/application_constants';
* @param {boolean} ignoreSentry Defines whether or not the error should be submitted to Sentry * @param {boolean} ignoreSentry Defines whether or not the error should be submitted to Sentry
* @param {string} comment Will also be submitted to Sentry, but will not be logged * @param {string} comment Will also be submitted to Sentry, but will not be logged
*/ */
function logGlobal(error, ignoreSentry = AppConstants.errorMessagesToIgnore.indexOf(error.message) > -1, function logGlobal(error, comment, ignoreSentry = AppConstants.errorMessagesToIgnore.indexOf(error.message) > -1) {
comment) {
console.error(error); console.error(error);
if(!ignoreSentry) { if(!ignoreSentry) {
@ -24,7 +23,6 @@ function logGlobal(error, ignoreSentry = AppConstants.errorMessagesToIgnore.inde
Raven.captureException(error); Raven.captureException(error);
} }
} }
} }
export function initLogging() { export function initLogging() {
@ -36,4 +34,4 @@ export function initLogging() {
window.onerror = Raven.process; window.onerror = Raven.process;
console.logGlobal = logGlobal; console.logGlobal = logGlobal;
} }

View File

@ -10,71 +10,67 @@ import { argsToQueryParams } from '../utils/url_utils';
class Requests { class Requests {
unpackResponse(response) { unpackResponse(url) {
if (response.status >= 500) { return (response) => {
let err = new Error(response.status + ' - ' + response.statusText + ' - on URL:' + response.url); if (response == null) {
return response
.text()
.then((resText) => {
const resJson = JSON.parse(resText);
err = new Error(resJson.errors.pop());
// ES6 promises don't have a .finally() clause so
// we fake that here by forcing the .catch() clause
// to run
return Promise.reject();
})
.catch(() => { throw err; });
}
return Q.Promise((resolve, reject) => {
response.text()
.then((responseText) => {
// If the responses' body does not contain any data,
// fetch will resolve responseText to the string 'None'.
// If this is the case, we can not try to parse it as JSON.
if(responseText !== 'None') {
let body = JSON.parse(responseText);
if(body && body.errors) {
let error = new Error('Form Error');
error.json = body;
reject(error);
} else if(body && body.detail) {
reject(new Error(body.detail));
} else if('success' in body && !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 {
resolve(body);
}
} else {
if(response.status >= 400) {
reject(new Error(response.status + ' - ' + response.statusText + ' - on URL:' + response.url));
} else {
resolve({});
}
}
}).catch(reject);
});
}
handleError(url) {
return (err) => {
if (err instanceof TypeError) {
throw new Error('For: ' + url + ' - Server did not respond to the request. (Not even displayed a 500)'); throw new Error('For: ' + url + ' - Server did not respond to the request. (Not even displayed a 500)');
} else {
throw err;
} }
};
if (response.status >= 500) {
let err = new Error(response.status + ' - ' + response.statusText + ' - on URL:' + response.url);
return response
.text()
.then((resText) => {
const resJson = JSON.parse(resText);
err = new Error(resJson.errors.pop());
// ES6 promises don't have a .finally() clause so
// we fake that here by forcing the .catch() clause
// to run
return Promise.reject();
})
.catch(() => { throw err; });
}
return Q.Promise((resolve, reject) => {
response.text()
.then((responseText) => {
// If the responses' body does not contain any data,
// fetch will resolve responseText to the string 'None'.
// If this is the case, we can not try to parse it as JSON.
if(responseText !== 'None') {
let body = JSON.parse(responseText);
if(body && body.errors) {
let error = new Error('Form Error');
error.json = body;
reject(error);
} else if(body && body.detail) {
reject(new Error(body.detail));
} else if('success' in body && !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 {
resolve(body);
}
} else {
if(response.status >= 400) {
reject(new Error(response.status + ' - ' + response.statusText + ' - on URL:' + response.url));
} else {
resolve({});
}
}
}).catch(reject);
});
}
} }
getUrl(url) { getUrl(url) {
@ -128,8 +124,7 @@ class Requests {
} }
merged.method = verb; merged.method = verb;
return fetch(url, merged) return fetch(url, merged)
.then(this.unpackResponse) .then(this.unpackResponse(url));
.catch(this.handleError(url));
} }
get(url, params) { get(url, params) {

View File

@ -145,4 +145,10 @@ $pr--button-color: $pr--nav-fg-prim-color;
text-transform: capitalize; text-transform: capitalize;
} }
} }
}
// intercom
#intercom-container .intercom-launcher-button {
background-color: $pr--button-color !important;
border-color: $pr--button-color !important;
}
}