1
0
mirror of https://github.com/ascribe/onion.git synced 2024-06-28 08:37:59 +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 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 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() {
let linkData;
@ -150,8 +162,9 @@ let AccordionListItem = React.createClass({
</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}
</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() {
let shouldDisplay = this.props.availableAcls.indexOf(this.props.action) > -1;
let aclProps = this.actionProperties();
@ -121,18 +135,6 @@ let AclButton = React.createClass({
{ aclProps.form }
</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 DeleteButton from '../ascribe_buttons/delete_button';
import CreateEditionButton from '../ascribe_buttons/create_editions_button';
let AclButtonList = React.createClass({
propTypes: {
className: React.PropTypes.string,
editions: React.PropTypes.object,
editions: React.PropTypes.oneOfType([
React.PropTypes.object,
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() {
@ -69,8 +75,7 @@ let AclButtonList = React.createClass({
handleSuccess={this.props.handleSuccess} />
<DeleteButton
editions={this.props.editions}/>
<CreateEditionButton
piece={this.props.editions}/>
{this.props.children}
</div>
);
}

View File

@ -1,42 +1,82 @@
'use strict';
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 PieceListActions from '../../actions/piece_list_actions';
import { getAvailableAcls } from '../../utils/acl_utils';
let CreateEditionsButton = React.createClass({
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 () {
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;
}
let availableAcls = getAvailableAcls([this.props.piece]);
if (availableAcls.indexOf('editions') === -1){
return null;
if(piece.num_editions === 0) {
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 Col from 'react-bootstrap/lib/Col';
import Button from 'react-bootstrap/lib/Button';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import UserActions from '../../actions/user_actions';
@ -22,7 +21,6 @@ import Property from './../ascribe_forms/property';
import EditionDetailProperty from './detail_property';
import InputTextAreaToggable from './../ascribe_forms/input_textarea_toggable';
import EditionHeader from './header';
import EditionFurtherDetails from './further_details';
//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 AppConstants from '../../constants/application_constants';
import { getCookie } from '../../utils/fetch_api_utils';
import { getLangText } from '../../utils/lang_utils';
let Link = Router.Link;
@ -76,7 +73,12 @@ let Edition = React.createClass({
content={this.props.edition}/>
</Col>
<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
currentUser={this.state.currentUser}
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 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 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 { mergeOptions } from '../../utils/general_utils';
/**
* This is the component that implements display-specific functionality
@ -41,7 +34,12 @@ let Piece = React.createClass({
},
getInitialState() {
return UserStore.getState();
return mergeOptions(
UserStore.getState(),
{
showCreateEditionsDialog: false
}
);
},
componentDidMount() {
@ -57,8 +55,28 @@ let Piece = React.createClass({
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 (
<Row>
<Col md={6}>
@ -66,12 +84,29 @@ let Piece = React.createClass({
content={this.props.piece}/>
</Col>
<Col md={6} className="ascribe-edition-details">
<Header
content={this.props.piece}/>
<PieceSummary
currentUser={this.state.currentUser}
piece={this.props.piece}
handleSuccess={this.props.loadPiece}/>
<div className="ascribe-detail-header">
<EditionDetailProperty label="TITLE" value={<div className="ascribe-detail-title">{this.props.piece.title}</div>} />
<EditionDetailProperty label="BY" value={this.props.piece.artist_name} />
<EditionDetailProperty label="DATE" value={ this.props.piece.date_created.slice(0, 4) } />
{this.props.piece.num_editions > 0 ? <EditionDetailProperty label="NUMBER OF EDITIONS" value={ this.props.piece.num_editions } /> : null}
<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
title="Further Details"
show={this.props.piece.acl.indexOf('edit') > -1
@ -85,42 +120,10 @@ let Piece = React.createClass({
otherData={this.props.piece.other_data}
handleSuccess={this.props.loadPiece}/>
</CollapsibleParagraph>
</Col>
</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;

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',
'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.',
'REGISTREE': 'REGISTREE',
},
'de': {
'ID': 'ID',
@ -420,6 +421,7 @@ const languages = {
'I agree to the Terms of Service': 'I agree to the Terms of Service',
'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.',
'REGISTREE': 'REGISTREE',
},
'fr': {
'ID': 'ID',
@ -630,6 +632,7 @@ const languages = {
'I agree to the Terms of Service': 'I agree to the Terms of Service',
'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.',
'REGISTREE': 'REGISTREE',
}
};