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

Refactor MarketSubmitButton to pull the piece as necessary rather than always fetching it in MarketAdditionalDataForm

This commit is contained in:
Brett Sun 2016-01-15 14:22:28 +01:00
parent c6071d8ab4
commit 50129b9d0c
9 changed files with 194 additions and 159 deletions

View File

@ -5,15 +5,14 @@ import React from 'react';
import Row from 'react-bootstrap/lib/Row'; import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col'; import Col from 'react-bootstrap/lib/Col';
import Form from './../ascribe_forms/form';
import PieceExtraDataForm from './../ascribe_forms/form_piece_extradata';
import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions'; import GlobalNotificationActions from '../../actions/global_notification_actions';
import FurtherDetailsFileuploader from './further_details_fileuploader'; import FurtherDetailsFileuploader from './further_details_fileuploader';
import Form from './../ascribe_forms/form';
import PieceExtraDataForm from './../ascribe_forms/form_piece_extradata';
import { formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils'; import { formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils';

View File

@ -30,7 +30,7 @@ let MarketAclButtonList = React.createClass({
componentDidMount() { componentDidMount() {
UserStore.listen(this.onChange); UserStore.listen(this.onChange);
UserActions.fetchCurrentUser(); UserActions.fetchCurrentUser.defer();
}, },
componentWillUnmount() { componentWillUnmount() {

View File

@ -3,6 +3,11 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import PieceActions from '../../../../../../actions/piece_actions';
import PieceStore from '../../../../../../stores/piece_store';
import WhitelabelActions from '../../../../../../actions/whitelabel_actions';
import WhitelabelStore from '../../../../../../stores/whitelabel_store';
import MarketAdditionalDataForm from '../market_forms/market_additional_data_form'; import MarketAdditionalDataForm from '../market_forms/market_additional_data_form';
import AclFormFactory from '../../../../../ascribe_forms/acl_form_factory'; import AclFormFactory from '../../../../../ascribe_forms/acl_form_factory';
@ -11,15 +16,14 @@ import ConsignForm from '../../../../../ascribe_forms/form_consign';
import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper'; import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper';
import AclProxy from '../../../../../acl_proxy'; import AclProxy from '../../../../../acl_proxy';
import AscribeSpinner from '../../../../../ascribe_spinner';
import PieceActions from '../../../../../../actions/piece_actions';
import WhitelabelActions from '../../../../../../actions/whitelabel_actions';
import WhitelabelStore from '../../../../../../stores/whitelabel_store';
import ApiUrls from '../../../../../../constants/api_urls'; import ApiUrls from '../../../../../../constants/api_urls';
import { getAclFormMessage, getAclFormDataId } from '../../../../../../utils/form_utils'; import { getAclFormMessage, getAclFormDataId } from '../../../../../../utils/form_utils';
import { mergeOptions } from '../../../../../../utils/general_utils';
import { getLangText } from '../../../../../../utils/lang_utils'; import { getLangText } from '../../../../../../utils/lang_utils';
import { onChangeOnce } from '../../../../../../utils/store_utils';
let MarketSubmitButton = React.createClass({ let MarketSubmitButton = React.createClass({
propTypes: { propTypes: {
@ -27,11 +31,19 @@ let MarketSubmitButton = React.createClass({
currentUser: React.PropTypes.object, currentUser: React.PropTypes.object,
editions: React.PropTypes.array.isRequired, editions: React.PropTypes.array.isRequired,
handleSuccess: React.PropTypes.func.isRequired, handleSuccess: React.PropTypes.func.isRequired,
className: React.PropTypes.string,
className: React.PropTypes.string
}, },
// This component may eventually need to use the
// PieceStore, but we don't need it initially
getInitialState() { getInitialState() {
return WhitelabelStore.getState(); return mergeOptions(
WhitelabelStore.getState(),
{
piece: {}
}
);
}, },
componentDidMount() { componentDidMount() {
@ -41,6 +53,7 @@ let MarketSubmitButton = React.createClass({
}, },
componentWillUnmount() { componentWillUnmount() {
PieceStore.unlisten(this.onChange);
WhitelabelStore.unlisten(this.onChange); WhitelabelStore.unlisten(this.onChange);
}, },
@ -62,8 +75,24 @@ let MarketSubmitButton = React.createClass({
return false; return false;
}, },
getFormDataId() { getAdditionalDataForm() {
return getAclFormDataId(false, this.props.editions); const { piece } = this.state;
if (piece.id) {
return (
<MarketAdditionalDataForm
extraData={piece.extra_data}
otherData={piece.other_data}
pieceId={piece.id}
submitLabel={getLangText('Continue to consignment')} />
);
} else {
return (
<div className="fullpage-spinner">
<AscribeSpinner color='dark-blue' size='lg'/>
</div>
);
}
}, },
getAggregateEditionDetails() { getAggregateEditionDetails() {
@ -82,6 +111,10 @@ let MarketSubmitButton = React.createClass({
}); });
}, },
getFormDataId() {
return getAclFormDataId(false, this.props.editions);
},
handleAdditionalDataSuccess(pieceId) { handleAdditionalDataSuccess(pieceId) {
// Fetch newly updated piece to update the views // Fetch newly updated piece to update the views
PieceActions.fetchPiece(pieceId); PieceActions.fetchPiece(pieceId);
@ -89,6 +122,19 @@ let MarketSubmitButton = React.createClass({
this.refs.consignModal.show(); this.refs.consignModal.show();
}, },
loadPieceIfNeeded(neededPieceId) {
if (neededPieceId) {
const pieceStore = PieceStore.getState();
if (pieceStore.piece.id === neededPieceId) {
this.setState(pieceStore);
} else {
onChangeOnce(this, PieceStore);
PieceActions.fetchPiece(neededPieceId);
}
}
},
render() { render() {
const { availableAcls, currentUser, className, editions, handleSuccess } = this.props; const { availableAcls, currentUser, className, editions, handleSuccess } = this.props;
const { whitelabel: { name: whitelabelName = 'Market', user: whitelabelAdminEmail } } = this.state; const { whitelabel: { name: whitelabelName = 'Market', user: whitelabelAdminEmail } } = this.state;
@ -102,7 +148,9 @@ let MarketSubmitButton = React.createClass({
}); });
const triggerButton = ( const triggerButton = (
<button className={classNames('btn', 'btn-default', 'btn-sm', className)}> <button
className={classNames('btn', 'btn-default', 'btn-sm', className)}
onClick={solePieceId && !canSubmit ? () => this.loadPieceIfNeeded(solePieceId) : () => {}}>
{getLangText('CONSIGN TO %s', whitelabelName.toUpperCase())} {getLangText('CONSIGN TO %s', whitelabelName.toUpperCase())}
</button> </button>
); );
@ -128,9 +176,7 @@ let MarketSubmitButton = React.createClass({
trigger={triggerButton} trigger={triggerButton}
handleSuccess={() => this.handleAdditionalDataSuccess(solePieceId)} handleSuccess={() => this.handleAdditionalDataSuccess(solePieceId)}
title={getLangText('Add additional information')}> title={getLangText('Add additional information')}>
<MarketAdditionalDataForm {this.getAdditionalDataForm()}
pieceId={solePieceId}
submitLabel={getLangText('Continue to consignment')} />
</ModalWrapper> </ModalWrapper>
<ModalWrapper <ModalWrapper

View File

@ -6,8 +6,12 @@ import MarketAdditionalDataForm from '../market_forms/market_additional_data_for
let MarketFurtherDetails = React.createClass({ let MarketFurtherDetails = React.createClass({
propTypes: { propTypes: {
pieceId: React.PropTypes.number, pieceId: React.PropTypes.number.isRequired,
editable: React.PropTypes.bool,
extraData: React.PropTypes.object,
handleSuccess: React.PropTypes.func, handleSuccess: React.PropTypes.func,
otherData: React.PropTypes.arrayOf(React.PropTypes.object)
}, },
render() { render() {

View File

@ -2,21 +2,18 @@
import React from 'react'; import React from 'react';
import Form from '../../../../../ascribe_forms/form';
import Property from '../../../../../ascribe_forms/property';
import InputTextAreaToggable from '../../../../../ascribe_forms/input_textarea_toggable';
import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_details_fileuploader';
import AscribeSpinner from '../../../../../ascribe_spinner';
import GlobalNotificationModel from '../../../../../../models/global_notification_model'; import GlobalNotificationModel from '../../../../../../models/global_notification_model';
import GlobalNotificationActions from '../../../../../../actions/global_notification_actions'; import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_details_fileuploader';
import InputTextAreaToggable from '../../../../../ascribe_forms/input_textarea_toggable';
import Form from '../../../../../ascribe_forms/form';
import Property from '../../../../../ascribe_forms/property';
import { formSubmissionValidation } from '../../../../../ascribe_uploader/react_s3_fine_uploader_utils'; import { formSubmissionValidation } from '../../../../../ascribe_uploader/react_s3_fine_uploader_utils';
import PieceActions from '../../../../../../actions/piece_actions'; import AscribeSpinner from '../../../../../ascribe_spinner';
import PieceStore from '../../../../../../stores/piece_store';
import ApiUrls from '../../../../../../constants/api_urls'; import ApiUrls from '../../../../../../constants/api_urls';
import AppConstants from '../../../../../../constants/application_constants'; import AppConstants from '../../../../../../constants/application_constants';
@ -28,13 +25,16 @@ import { getLangText } from '../../../../../../utils/lang_utils';
let MarketAdditionalDataForm = React.createClass({ let MarketAdditionalDataForm = React.createClass({
propTypes: { propTypes: {
pieceId: React.PropTypes.number, pieceId: React.PropTypes.number.isRequired,
editable: React.PropTypes.bool, editable: React.PropTypes.bool,
extraData: React.PropTypes.object,
handleSuccess: React.PropTypes.func,
isInline: React.PropTypes.bool, isInline: React.PropTypes.bool,
otherData: React.PropTypes.arrayOf(React.PropTypes.object),
showHeading: React.PropTypes.bool, showHeading: React.PropTypes.bool,
showNotification: React.PropTypes.bool, showNotification: React.PropTypes.bool,
submitLabel: React.PropTypes.string, submitLabel: React.PropTypes.string
handleSuccess: React.PropTypes.func
}, },
getDefaultProps() { getDefaultProps() {
@ -45,33 +45,18 @@ let MarketAdditionalDataForm = React.createClass({
}, },
getInitialState() { getInitialState() {
const pieceStore = PieceStore.getState(); return {
return mergeOptions(
pieceStore,
{
// Allow the form to be submitted if there's already an additional image uploaded // Allow the form to be submitted if there's already an additional image uploaded
isUploadReady: this.isUploadReadyOnChange(pieceStore.piece), isUploadReady: this.isUploadReadyOnChange(),
forceUpdateKey: 0 forceUpdateKey: 0
});
},
componentDidMount() {
PieceStore.listen(this.onChange);
if (this.props.pieceId) {
PieceActions.fetchPiece(this.props.pieceId);
} }
}, },
componentWillUnmount() { componentWillReceiveProps(nextProps) {
PieceStore.unlisten(this.onChange); if (this.props.extraData !== nextProps.extraData || this.props.otherData !== nextProps.otherData) {
}, this.setState({
// Allow the form to be submitted if the updated piece has an additional image uploaded
onChange(state) { isUploadReady: this.isUploadReadyOnChange(),
Object.assign({}, state, {
// Allow the form to be submitted if the updated piece already has an additional image uploaded
isUploadReady: this.isUploadReadyOnChange(state.piece),
/** /**
* Increment the forceUpdateKey to force the form to rerender on each change * Increment the forceUpdateKey to force the form to rerender on each change
@ -82,13 +67,12 @@ let MarketAdditionalDataForm = React.createClass({
*/ */
forceUpdateKey: this.state.forceUpdateKey + 1 forceUpdateKey: this.state.forceUpdateKey + 1
}); });
}
this.setState(state);
}, },
getFormData() { getFormData() {
let extradata = {}; const extradata = {};
let formRefs = this.refs.form.refs; const formRefs = this.refs.form.refs;
// Put additional fields in extra data object // Put additional fields in extra data object
Object Object
@ -99,12 +83,12 @@ let MarketAdditionalDataForm = React.createClass({
return { return {
extradata: extradata, extradata: extradata,
piece_id: this.state.piece.id piece_id: this.props.pieceId
}; };
}, },
isUploadReadyOnChange(piece) { isUploadReadyOnChange() {
return piece && piece.other_data && piece.other_data.length > 0; return this.props.otherData && this.props.otherData.length;
}, },
handleSuccessWithNotification() { handleSuccessWithNotification() {
@ -123,10 +107,18 @@ let MarketAdditionalDataForm = React.createClass({
}, },
render() { render() {
const { editable, isInline, handleSuccess, showHeading, showNotification, submitLabel } = this.props; const {
const { piece } = this.state; editable,
let buttons, heading; extraData,
isInline,
handleSuccess,
otherData,
pieceId,
showHeading,
showNotification,
submitLabel } = this.props;
let buttons, heading;
let spinner = <AscribeSpinner color='dark-blue' size='lg' />; let spinner = <AscribeSpinner color='dark-blue' size='lg' />;
if (!isInline) { if (!isInline) {
@ -156,76 +148,68 @@ let MarketAdditionalDataForm = React.createClass({
) : null; ) : null;
} }
if (piece.id) {
return ( return (
<Form <Form
className="ascribe-form-bordered" className="ascribe-form-bordered"
ref='form' ref='form'
key={this.state.forceUpdateKey} key={this.state.forceUpdateKey}
url={requests.prepareUrl(ApiUrls.piece_extradata, {piece_id: piece.id})} url={requests.prepareUrl(ApiUrls.piece_extradata, {piece_id: pieceId})}
handleSuccess={showNotification ? this.handleSuccessWithNotification : handleSuccess} handleSuccess={showNotification ? this.handleSuccessWithNotification : handleSuccess}
getFormData={this.getFormData} getFormData={this.getFormData}
buttons={buttons} buttons={buttons}
spinner={spinner} spinner={spinner}
disabled={!this.props.editable || !piece.acl.acl_edit}> disabled={!this.props.editable}>
{heading} {heading}
<FurtherDetailsFileuploader <FurtherDetailsFileuploader
label={getLangText('Marketplace Thumbnail Image')} label={getLangText('Marketplace Thumbnail Image')}
submitFile={function () {}} submitFile={function () {}}
setIsUploadReady={this.setIsUploadReady} setIsUploadReady={this.setIsUploadReady}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile} isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
pieceId={piece.id} pieceId={pieceId}
otherData={piece.other_data} otherData={otherData}
editable={editable} /> editable={editable} />
<Property <Property
name='artist_bio' name='artist_bio'
label={getLangText('Artist Bio')} label={getLangText('Artist Bio')}
expanded={editable || !!piece.extra_data.artist_bio}> expanded={editable || !!extraData.artist_bio}>
<InputTextAreaToggable <InputTextAreaToggable
rows={1} rows={1}
defaultValue={piece.extra_data.artist_bio} defaultValue={extraData.artist_bio}
placeholder={getLangText('Enter a biography of the artist...')} placeholder={getLangText('Enter a biography of the artist...')}
required /> required />
</Property> </Property>
<Property <Property
name='work_description' name='work_description'
label={getLangText('Work Description')} label={getLangText('Work Description')}
expanded={editable || !!piece.extra_data.work_description}> expanded={editable || !!extraData.work_description}>
<InputTextAreaToggable <InputTextAreaToggable
rows={1} rows={1}
defaultValue={piece.extra_data.work_description} defaultValue={extraData.work_description}
placeholder={getLangText('Enter a description of the work...')} placeholder={getLangText('Enter a description of the work...')}
required /> required />
</Property> </Property>
<Property <Property
name='technology_details' name='technology_details'
label={getLangText('Technology Details')} label={getLangText('Technology Details')}
expanded={editable || !!piece.extra_data.technology_details}> expanded={editable || !!extraData.technology_details}>
<InputTextAreaToggable <InputTextAreaToggable
rows={1} rows={1}
defaultValue={piece.extra_data.technology_details} defaultValue={extraData.technology_details}
placeholder={getLangText('Enter technological details about the work...')} placeholder={getLangText('Enter technological details about the work...')}
required /> required />
</Property> </Property>
<Property <Property
name='display_instructions' name='display_instructions'
label={getLangText('Display Instructions')} label={getLangText('Display Instructions')}
expanded={editable || !!piece.extra_data.display_instructions}> expanded={editable || !!extraData.display_instructions}>
<InputTextAreaToggable <InputTextAreaToggable
rows={1} rows={1}
defaultValue={piece.extra_data.display_instructions} defaultValue={extraData.display_instructions}
placeholder={getLangText('Enter instructions on how to best display the work...')} placeholder={getLangText('Enter instructions on how to best display the work...')}
required /> required />
</Property> </Property>
</Form> </Form>
); );
} else {
return (
<div className="ascribe-loading-position">
{spinner}
</div>
);
}
} }
}); });

View File

@ -6,11 +6,6 @@ import { History } from 'react-router';
import Col from 'react-bootstrap/lib/Col'; import Col from 'react-bootstrap/lib/Col';
import Row from 'react-bootstrap/lib/Row'; import Row from 'react-bootstrap/lib/Row';
import MarketAdditionalDataForm from './market_forms/market_additional_data_form';
import Property from '../../../../ascribe_forms/property';
import RegisterPieceForm from '../../../../ascribe_forms/form_register_piece';
import PieceActions from '../../../../../actions/piece_actions'; import PieceActions from '../../../../../actions/piece_actions';
import PieceListStore from '../../../../../stores/piece_list_store'; import PieceListStore from '../../../../../stores/piece_list_store';
import PieceListActions from '../../../../../actions/piece_list_actions'; import PieceListActions from '../../../../../actions/piece_list_actions';
@ -19,6 +14,11 @@ import UserActions from '../../../../../actions/user_actions';
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 MarketAdditionalDataForm from './market_forms/market_additional_data_form';
import Property from '../../../../ascribe_forms/property';
import RegisterPieceForm from '../../../../ascribe_forms/form_register_piece';
import SlidesContainer from '../../../../ascribe_slides_container/slides_container'; import SlidesContainer from '../../../../ascribe_slides_container/slides_container';
import { getLangText } from '../../../../../utils/lang_utils'; import { getLangText } from '../../../../../utils/lang_utils';

View File

@ -7,8 +7,8 @@ import PieceActions from '../actions/piece_actions';
const PieceSource = { const PieceSource = {
lookupPiece: { lookupPiece: {
remote(state) { remote(state, pieceId) {
return requests.get('piece', { piece_id: state.pieceMeta.idToFetch }); return requests.get('piece', { piece_id: pieceId });
}, },
success: PieceActions.successFetchPiece, success: PieceActions.successFetchPiece,

View File

@ -21,8 +21,7 @@ class PieceStore {
getInitialState() { getInitialState() {
this.piece = {}; this.piece = {};
this.pieceMeta = { this.pieceMeta = {
err: null, err: null
idToFetch: null
}; };
return { return {
@ -31,10 +30,12 @@ class PieceStore {
} }
} }
onFetchPiece(idToFetch) { onFetchPiece(pieceId) {
this.pieceMeta.idToFetch = idToFetch; this.getInstance().lookupPiece(pieceId);
this.getInstance().lookupPiece(); // Prevent alt from sending an empty change event when a request is sent
// off to the source
this.preventDefault();
} }
onSuccessFetchPiece({ piece }) { onSuccessFetchPiece({ piece }) {
@ -42,10 +43,12 @@ class PieceStore {
this.onUpdatePiece(piece); this.onUpdatePiece(piece);
} else { } else {
this.pieceMeta.err = new Error('Problem fetching the piece'); this.pieceMeta.err = new Error('Problem fetching the piece');
console.logGlobal(this.pieceMeta.err);
} }
} }
onErrorPiece(err) { onErrorPiece(err) {
console.logGlobal(err);
this.pieceMeta.err = err; this.pieceMeta.err = err;
} }
@ -56,7 +59,6 @@ class PieceStore {
onUpdatePiece(piece) { onUpdatePiece(piece) {
this.piece = piece; this.piece = piece;
this.pieceMeta.err = null; this.pieceMeta.err = null;
this.pieceMeta.idToFetch = null;
} }
onUpdateProperty({ key, value }) { onUpdateProperty({ key, value }) {

View File

@ -238,7 +238,7 @@ $vivi23--highlight-color: #de2600;
&.active:hover{ &.active:hover{
background-color: $vivi23--highlight-color; background-color: $vivi23--highlight-color;
border-color: $vivi23--highlight-color; border-color: $vivi23--highlight-color;
color: $vivi23--highlight-color; color: $vivi23--bg-color;
} }
} }