1
0
mirror of https://github.com/ascribe/onion.git synced 2024-06-30 13:41:57 +02:00

separate create edition form logic

This commit is contained in:
Tim Daubenschütz 2015-07-13 17:09:44 +02:00
parent ad6dd40867
commit e71c2f9fe0
10 changed files with 216 additions and 175 deletions

View File

@ -8,7 +8,7 @@ import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
import Tooltip from 'react-bootstrap/lib/Tooltip'; import Tooltip from 'react-bootstrap/lib/Tooltip';
import AccordionListItemEditionWidget from './accordion_list_item_edition_widget'; import AccordionListItemEditionWidget from './accordion_list_item_edition_widget';
import AccordionListItemCreateEditions from './accordion_list_item_create_editions'; import CreateEditionsForm from '../ascribe_forms/create_editions_form';
import PieceListActions from '../../actions/piece_list_actions'; import PieceListActions from '../../actions/piece_list_actions';
import EditionListActions from '../../actions/edition_list_actions'; import EditionListActions from '../../actions/edition_list_actions';
@ -101,6 +101,18 @@ let AccordionListItem = React.createClass({
}); });
}, },
getCreateEditionsDialog() {
if(this.props.content.num_editions < 1 && this.state.showCreateEditionsDialog) {
return (
<div className="ascribe-accordion-list-item-table col-xs-12 col-sm-10 col-md-8 col-lg-8 col-sm-offset-1 col-md-offset-2 col-lg-offset-2">
<CreateEditionsForm
pieceId={this.props.content.id}
handleSuccess={this.handleEditionCreationSuccess} />
</div>
);
}
},
render() { render() {
let linkData; let linkData;
@ -150,8 +162,9 @@ let AccordionListItem = React.createClass({
</div> </div>
</div> </div>
</div> </div>
{this.props.content.num_editions < 1 && this.state.showCreateEditionsDialog ? <AccordionListItemCreateEditions pieceId={this.props.content.id} handleSuccess={this.handleEditionCreationSuccess}/> : null}
{this.getCreateEditionsDialog()}
{/* this.props.children is AccordionListItemTableEditions */} {/* this.props.children is AccordionListItemTableEditions */}
{this.props.children} {this.props.children}
</div> </div>

View File

@ -1,51 +0,0 @@
'use strict';
import React from 'react';
import Form from '../ascribe_forms/form';
import Property from '../ascribe_forms/property';
import apiUrls from '../../constants/api_urls';
import { getLangText } from '../../utils/lang_utils';
let AccordionListItemCreateEditions = React.createClass({
propTypes: {
pieceId: React.PropTypes.number,
handleSuccess: React.PropTypes.func
},
getFormData(){
return {
piece_id: parseInt(this.props.pieceId, 10)
};
},
render() {
return (
<div className="ascribe-accordion-list-item-table col-xs-12 col-sm-10 col-md-8 col-lg-8 col-sm-offset-1 col-md-offset-2 col-lg-offset-2">
<Form
ref='form'
url={apiUrls.editions}
getFormData={this.getFormData}
handleSuccess={this.props.handleSuccess}
spinner={
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
</button>
}>
<Property
name='num_editions'
label={getLangText('Number of editions')}>
<input
type="number"
placeholder="(e.g. 32)"
min={0}/>
</Property>
</Form>
</div>
);
}
});
export default AccordionListItemCreateEditions;

View File

@ -105,6 +105,20 @@ let AclButton = React.createClass({
} }
}, },
getShareMessage(){
return (
`
${getLangText('Hi')},
${getLangText('I am sharing')}:
${this.getTitlesString()} ${getLangText('with you')}.
${getLangText('Truly yours')},
${this.props.currentUser.username}
`
);
},
render() { render() {
let shouldDisplay = this.props.availableAcls.indexOf(this.props.action) > -1; let shouldDisplay = this.props.availableAcls.indexOf(this.props.action) > -1;
let aclProps = this.actionProperties(); let aclProps = this.actionProperties();
@ -121,18 +135,6 @@ let AclButton = React.createClass({
{ aclProps.form } { aclProps.form }
</ModalWrapper> </ModalWrapper>
); );
},
getShareMessage(){
return (
`${getLangText('Hi')},
${getLangText('I am sharing')} :
${this.getTitlesString()}${getLangText('with you')}.
${getLangText('Truly yours')},
${this.props.currentUser.username}`
);
} }
}); });

View File

@ -7,14 +7,20 @@ import UserStore from '../../stores/user_store';
import AclButton from '../ascribe_buttons/acl_button'; import AclButton from '../ascribe_buttons/acl_button';
import DeleteButton from '../ascribe_buttons/delete_button'; import DeleteButton from '../ascribe_buttons/delete_button';
import CreateEditionButton from '../ascribe_buttons/create_editions_button';
let AclButtonList = React.createClass({ let AclButtonList = React.createClass({
propTypes: { propTypes: {
className: React.PropTypes.string, className: React.PropTypes.string,
editions: React.PropTypes.object, editions: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
]),
availableAcls: React.PropTypes.array, availableAcls: React.PropTypes.array,
handleSuccess: React.PropTypes.func handleSuccess: React.PropTypes.func,
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
])
}, },
getInitialState() { getInitialState() {
@ -69,8 +75,7 @@ let AclButtonList = React.createClass({
handleSuccess={this.props.handleSuccess} /> handleSuccess={this.props.handleSuccess} />
<DeleteButton <DeleteButton
editions={this.props.editions}/> editions={this.props.editions}/>
<CreateEditionButton {this.props.children}
piece={this.props.editions}/>
</div> </div>
); );
} }

View File

@ -1,42 +1,82 @@
'use strict'; 'use strict';
import React from 'react'; import React from 'react';
import Router from 'react-router';
import Button from 'react-bootstrap/lib/Button';
import EditionDeleteForm from '../ascribe_forms/form_delete_edition';
import EditionRemoveFromCollectionForm from '../ascribe_forms/form_remove_editions_from_collection';
import ModalWrapper from '../ascribe_modal/modal_wrapper';
import AccordionListItemCreateEditions from './../ascribe_accordion_list/accordion_list_item_create_editions';
import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions';
import { getAvailableAcls } from '../../utils/acl_utils';
import { getLangText } from '../../utils/lang_utils.js'
import EditionListActions from '../../actions/edition_list_actions'; import EditionListActions from '../../actions/edition_list_actions';
import PieceListActions from '../../actions/piece_list_actions';
import { getAvailableAcls } from '../../utils/acl_utils';
let CreateEditionsButton = React.createClass({ let CreateEditionsButton = React.createClass({
propTypes: { propTypes: {
piece: React.PropTypes.object.isRequired piece: React.PropTypes.object.isRequired,
toggleCreateEditionsDialog: React.PropTypes.func.isRequired
}, },
mixins: [Router.Navigation], getInitialState() {
return {};
},
componentDidUpdate() {
if(this.props.piece.num_editions === 0 && typeof this.state.pollingIntervalIndex === 'undefined') {
this.startPolling();
}
},
componentWillUnmount() {
clearInterval(this.state.pollingIntervalIndex);
},
startPolling() {
// start polling until editions are defined
let pollingIntervalIndex = setInterval(() => {
EditionListActions.fetchEditionList(this.props.piece.id)
.then((res) => {
clearInterval(this.state.pollingIntervalIndex);
PieceListActions.updatePropertyForPiece({
pieceId: this.props.piece.id,
key: 'num_editions',
value: res.editions[0].num_editions
});
EditionListActions.toggleEditionList(this.props.piece.id);
})
.catch(() => {
/* Ignore and keep going */
});
}, 5000);
this.setState({
pollingIntervalIndex
});
},
render: function () { render: function () {
if (this.props.piece.constructor === Array){ let piece = this.props.piece;
let availableAcls = getAvailableAcls(piece);
if (availableAcls.indexOf('editions') < -1 || piece.num_editions > 0){
return null; return null;
} }
let availableAcls = getAvailableAcls([this.props.piece]);
if (availableAcls.indexOf('editions') === -1){ if(piece.num_editions === 0) {
return null; return (
<button disabled className="btn btn-default btn-sm">
CREATING EDITIONS <span className="glyph-ascribe-spool-chunked spin"/>
</button>
);
} else {
return (
<button
className="btn btn-default btn-sm"
onClick={this.props.toggleCreateEditionsDialog}>
CREATE EDITIONS
</button>
);
} }
return (
<button className="btn btn-default btn-sm">
CREATE EDITIONS
</button>
);
} }
}); });

View File

@ -5,7 +5,6 @@ import Router from 'react-router';
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 Button from 'react-bootstrap/lib/Button';
import Glyphicon from 'react-bootstrap/lib/Glyphicon'; import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import UserActions from '../../actions/user_actions'; import UserActions from '../../actions/user_actions';
@ -22,7 +21,6 @@ import Property from './../ascribe_forms/property';
import EditionDetailProperty from './detail_property'; import EditionDetailProperty from './detail_property';
import InputTextAreaToggable from './../ascribe_forms/input_textarea_toggable'; import InputTextAreaToggable from './../ascribe_forms/input_textarea_toggable';
import EditionHeader from './header';
import EditionFurtherDetails from './further_details'; import EditionFurtherDetails from './further_details';
//import PieceExtraDataForm from './../ascribe_forms/form_piece_extradata'; //import PieceExtraDataForm from './../ascribe_forms/form_piece_extradata';
@ -38,7 +36,6 @@ import GlobalNotificationActions from '../../actions/global_notification_actions
import apiUrls from '../../constants/api_urls'; import apiUrls from '../../constants/api_urls';
import AppConstants from '../../constants/application_constants'; import AppConstants from '../../constants/application_constants';
import { getCookie } from '../../utils/fetch_api_utils';
import { getLangText } from '../../utils/lang_utils'; import { getLangText } from '../../utils/lang_utils';
let Link = Router.Link; let Link = Router.Link;
@ -76,7 +73,12 @@ let Edition = React.createClass({
content={this.props.edition}/> content={this.props.edition}/>
</Col> </Col>
<Col md={6} className="ascribe-edition-details"> <Col md={6} className="ascribe-edition-details">
<EditionHeader content={this.props.edition}/> <div className="ascribe-detail-header">
<EditionDetailProperty label="TITLE" value={<div className="ascribe-detail-title">{this.props.edition.title}</div>} />
<EditionDetailProperty label="BY" value={this.props.edition.artist_name} />
<EditionDetailProperty label="DATE" value={ this.props.edition.date_created.slice(0, 4) } />
<hr/>
</div>
<EditionSummary <EditionSummary
currentUser={this.state.currentUser} currentUser={this.state.currentUser}
edition={this.props.edition} /> edition={this.props.edition} />

View File

@ -1,26 +0,0 @@
'use strict';
import React from 'react';
import EditionDetailProperty from './detail_property';
let Header = React.createClass({
propTypes: {
content: React.PropTypes.object
},
render() {
var titleHtml = <div className="ascribe-detail-title">{this.props.content.title}</div>;
return (
<div className="ascribe-detail-header">
<EditionDetailProperty label="TITLE" value={titleHtml} />
<EditionDetailProperty label="BY" value={this.props.content.artist_name} />
<EditionDetailProperty label="DATE" value={ this.props.content.date_created.slice(0, 4) } />
<hr/>
</div>
);
}
});
export default Header;

View File

@ -15,21 +15,14 @@ import UserStore from '../../stores/user_store';
import MediaContainer from './media_container'; import MediaContainer from './media_container';
import Header from './header'; import EditionDetailProperty from './detail_property';
import Form from './../ascribe_forms/form';
import Property from './../ascribe_forms/property';
import RequestActionForm from './../ascribe_forms/form_request_action';
import EditionActions from '../../actions/edition_actions';
import AclButtonList from './../ascribe_buttons/acl_button_list'; import AclButtonList from './../ascribe_buttons/acl_button_list';
import CreateEditionsForm from '../ascribe_forms/create_editions_form';
import CreateEditionsButton from '../ascribe_buttons/create_editions_button';
import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions';
import apiUrls from '../../constants/api_urls';
import { getLangText } from '../../utils/lang_utils'; import { getLangText } from '../../utils/lang_utils';
import { mergeOptions } from '../../utils/general_utils';
/** /**
* This is the component that implements display-specific functionality * This is the component that implements display-specific functionality
@ -41,7 +34,12 @@ let Piece = React.createClass({
}, },
getInitialState() { getInitialState() {
return UserStore.getState(); return mergeOptions(
UserStore.getState(),
{
showCreateEditionsDialog: false
}
);
}, },
componentDidMount() { componentDidMount() {
@ -57,8 +55,28 @@ let Piece = React.createClass({
this.setState(state); this.setState(state);
}, },
render() { toggleCreateEditionsDialog() {
this.setState({
showCreateEditionsDialog: !this.state.showCreateEditionsDialog
});
},
getCreateEditionsDialog() {
if(this.props.piece.num_editions < 1 && this.state.showCreateEditionsDialog) {
return (
<div style={{marginTop: '1em'}}>
<CreateEditionsForm
pieceId={this.props.piece.id}
handleSuccess={this.handleEditionCreationSuccess} />
<hr/>
</div>
);
} else {
return (<hr/>);
}
},
render() {
return ( return (
<Row> <Row>
<Col md={6}> <Col md={6}>
@ -66,12 +84,29 @@ let Piece = React.createClass({
content={this.props.piece}/> content={this.props.piece}/>
</Col> </Col>
<Col md={6} className="ascribe-edition-details"> <Col md={6} className="ascribe-edition-details">
<Header <div className="ascribe-detail-header">
content={this.props.piece}/> <EditionDetailProperty label="TITLE" value={<div className="ascribe-detail-title">{this.props.piece.title}</div>} />
<PieceSummary <EditionDetailProperty label="BY" value={this.props.piece.artist_name} />
currentUser={this.state.currentUser} <EditionDetailProperty label="DATE" value={ this.props.piece.date_created.slice(0, 4) } />
piece={this.props.piece} {this.props.piece.num_editions > 0 ? <EditionDetailProperty label="NUMBER OF EDITIONS" value={ this.props.piece.num_editions } /> : null}
handleSuccess={this.props.loadPiece}/> <hr/>
</div>
<div className="ascribe-detail-header">
<DetailProperty label={getLangText('REGISTREE')} value={ this.props.piece.user_registered } />
</div>
<AclButtonList
className="text-center ascribe-button-list"
availableAcls={this.props.piece.acl}
editions={this.props.piece}
handleSuccess={this.props.handleSuccess}>
<CreateEditionsButton
piece={this.props.piece}
toggleCreateEditionsDialog={this.toggleCreateEditionsDialog}/>
</AclButtonList>
{this.getCreateEditionsDialog()}
<CollapsibleParagraph <CollapsibleParagraph
title="Further Details" title="Further Details"
show={this.props.piece.acl.indexOf('edit') > -1 show={this.props.piece.acl.indexOf('edit') > -1
@ -85,42 +120,10 @@ let Piece = React.createClass({
otherData={this.props.piece.other_data} otherData={this.props.piece.other_data}
handleSuccess={this.props.loadPiece}/> handleSuccess={this.props.loadPiece}/>
</CollapsibleParagraph> </CollapsibleParagraph>
</Col> </Col>
</Row> </Row>
); );
} }
}); });
let PieceSummary = React.createClass({
propTypes: {
piece: React.PropTypes.object
},
getActions(){
let actions = (
<Row>
<Col md={12}>
<AclButtonList
className="text-center ascribe-button-list"
availableAcls={this.props.piece.acl}
editions={this.props.piece}
handleSuccess={this.props.handleSuccess} />
</Col>
</Row>);
return actions;
//return null;
},
render() {
return (
<div className="ascribe-detail-header">
<DetailProperty label={getLangText('REGISTREE')} value={ this.props.piece.user_registered } />
{this.getActions()}
<hr/>
</div>
);
}
});
export default Piece; export default Piece;

View File

@ -0,0 +1,50 @@
'use strict';
import React from 'react';
import Form from '../ascribe_forms/form';
import Property from '../ascribe_forms/property';
import apiUrls from '../../constants/api_urls';
import { getLangText } from '../../utils/lang_utils';
let CreateEditionsForm = React.createClass({
propTypes: {
handleSuccess: React.PropTypes.func,
pieceId: React.PropTypes.number
},
getFormData(){
return {
piece_id: parseInt(this.props.pieceId, 10)
};
},
render() {
return (
<Form
ref='form'
url={apiUrls.editions}
getFormData={this.getFormData}
handleSuccess={this.props.handleSuccess}
spinner={
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
</button>
}>
<Property
name='num_editions'
label={getLangText('Number of editions')}>
<input
type="number"
placeholder="(e.g. 32)"
min={0}/>
</Property>
</Form>
);
}
});
export default CreateEditionsForm;

View File

@ -210,6 +210,7 @@ const languages = {
'I agree to the Terms of Service': 'I agree to the Terms of Service', 'I agree to the Terms of Service': 'I agree to the Terms of Service',
'read': 'read', 'read': 'read',
'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'If your email address exists in our database, you will receive a password recovery link in a few minutes.', 'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'If your email address exists in our database, you will receive a password recovery link in a few minutes.',
'REGISTREE': 'REGISTREE',
}, },
'de': { 'de': {
'ID': 'ID', 'ID': 'ID',
@ -420,6 +421,7 @@ const languages = {
'I agree to the Terms of Service': 'I agree to the Terms of Service', 'I agree to the Terms of Service': 'I agree to the Terms of Service',
'read': 'read', 'read': 'read',
'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'If your email address exists in our database, you will receive a password recovery link in a few minutes.', 'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'If your email address exists in our database, you will receive a password recovery link in a few minutes.',
'REGISTREE': 'REGISTREE',
}, },
'fr': { 'fr': {
'ID': 'ID', 'ID': 'ID',
@ -630,6 +632,7 @@ const languages = {
'I agree to the Terms of Service': 'I agree to the Terms of Service', 'I agree to the Terms of Service': 'I agree to the Terms of Service',
'read': 'read', 'read': 'read',
'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'Si votre adresse électronique existe dans notre base de données, vous recevrez un lien de récupération de mot de passe dans quelques minutes.', 'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'Si votre adresse électronique existe dans notre base de données, vous recevrez un lien de récupération de mot de passe dans quelques minutes.',
'REGISTREE': 'REGISTREE',
} }
}; };