mirror of
https://github.com/ascribe/onion.git
synced 2025-02-14 21:10:27 +01:00
Merge branch 'AD-419-decouple-piece-registration-from-' into AD-565-add-landing-page-for-sluice
This commit is contained in:
commit
3f0cdbad06
@ -7,7 +7,8 @@ import PieceFetcher from '../fetchers/piece_fetcher';
|
|||||||
class PieceActions {
|
class PieceActions {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.generateActions(
|
this.generateActions(
|
||||||
'updatePiece'
|
'updatePiece',
|
||||||
|
'updateProperty'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,21 @@ class PieceListActions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fetchPieceList(page, pageSize, search, orderBy, orderAsc) {
|
fetchPieceList(page, pageSize, search, orderBy, orderAsc) {
|
||||||
|
// To prevent flickering on a pagination request,
|
||||||
|
// we overwrite the piecelist with an empty list before
|
||||||
|
// pieceListCount === -1 defines the loading state
|
||||||
|
this.actions.updatePieceList({
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
search,
|
||||||
|
orderBy,
|
||||||
|
orderAsc,
|
||||||
|
'pieceList': [],
|
||||||
|
'pieceListCount': -1
|
||||||
|
});
|
||||||
|
|
||||||
|
// afterwards, we can load the list
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
PieceListFetcher
|
PieceListFetcher
|
||||||
.fetch(page, pageSize, search, orderBy, orderAsc)
|
.fetch(page, pageSize, search, orderBy, orderAsc)
|
||||||
|
@ -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';
|
||||||
@ -35,20 +35,6 @@ let AccordionListItem = React.createClass({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
if(this.props.content.num_editions === 0 && typeof this.state.pollingIntervalIndex === 'undefined') {
|
|
||||||
this.startPolling();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
clearInterval(this.state.pollingIntervalIndex);
|
|
||||||
},
|
|
||||||
|
|
||||||
onChange(state) {
|
|
||||||
this.setState(state);
|
|
||||||
},
|
|
||||||
|
|
||||||
getGlyphicon(){
|
getGlyphicon(){
|
||||||
if (this.props.content.requestAction){
|
if (this.props.content.requestAction){
|
||||||
return (
|
return (
|
||||||
@ -66,39 +52,32 @@ let AccordionListItem = React.createClass({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
handleEditionCreationSuccess(response) {
|
handleEditionCreationSuccess() {
|
||||||
let notification = new GlobalNotificationModel(response.notification, 'success', 10000);
|
|
||||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
|
||||||
PieceListActions.updatePropertyForPiece({pieceId: this.props.content.id, key: 'num_editions', value: 0});
|
PieceListActions.updatePropertyForPiece({pieceId: this.props.content.id, key: 'num_editions', value: 0});
|
||||||
|
|
||||||
this.toggleCreateEditionsDialog();
|
this.toggleCreateEditionsDialog();
|
||||||
},
|
},
|
||||||
|
|
||||||
startPolling() {
|
onPollingSuccess(pieceId, numEditions) {
|
||||||
// start polling until editions are defined
|
|
||||||
let pollingIntervalIndex = setInterval(() => {
|
|
||||||
EditionListActions.fetchEditionList(this.props.content.id)
|
|
||||||
.then((res) => {
|
|
||||||
|
|
||||||
clearInterval(this.state.pollingIntervalIndex);
|
|
||||||
|
|
||||||
PieceListActions.updatePropertyForPiece({
|
PieceListActions.updatePropertyForPiece({
|
||||||
pieceId: this.props.content.id,
|
pieceId,
|
||||||
key: 'num_editions',
|
key: 'num_editions',
|
||||||
value: res.editions[0].num_editions
|
value: numEditions
|
||||||
});
|
});
|
||||||
|
|
||||||
EditionListActions.toggleEditionList(this.props.content.id);
|
EditionListActions.toggleEditionList(pieceId);
|
||||||
|
},
|
||||||
|
|
||||||
})
|
getCreateEditionsDialog() {
|
||||||
.catch(() => {
|
if(this.props.content.num_editions < 1 && this.state.showCreateEditionsDialog) {
|
||||||
/* Ignore and keep going */
|
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">
|
||||||
}, 5000);
|
<CreateEditionsForm
|
||||||
|
pieceId={this.props.content.id}
|
||||||
this.setState({
|
handleSuccess={this.handleEditionCreationSuccess} />
|
||||||
pollingIntervalIndex
|
</div>
|
||||||
});
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -141,7 +120,8 @@ let AccordionListItem = React.createClass({
|
|||||||
<AccordionListItemEditionWidget
|
<AccordionListItemEditionWidget
|
||||||
className="pull-right"
|
className="pull-right"
|
||||||
piece={this.props.content}
|
piece={this.props.content}
|
||||||
toggleCreateEditionsDialog={this.toggleCreateEditionsDialog}/>
|
toggleCreateEditionsDialog={this.toggleCreateEditionsDialog}
|
||||||
|
onPollingSuccess={this.onPollingSuccess}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span style={{'clear': 'both'}}></span>
|
<span style={{'clear': 'both'}}></span>
|
||||||
@ -150,7 +130,8 @@ 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}
|
||||||
|
@ -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;
|
|
@ -6,13 +6,16 @@ import classNames from 'classnames';
|
|||||||
import EditionListActions from '../../actions/edition_list_actions';
|
import EditionListActions from '../../actions/edition_list_actions';
|
||||||
import EditionListStore from '../../stores/edition_list_store';
|
import EditionListStore from '../../stores/edition_list_store';
|
||||||
|
|
||||||
|
import CreateEditionsButton from '../ascribe_buttons/create_editions_button';
|
||||||
|
|
||||||
import { getLangText } from '../../utils/lang_utils';
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
|
|
||||||
let AccordionListItemEditionWidget = React.createClass({
|
let AccordionListItemEditionWidget = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
className: React.PropTypes.string,
|
className: React.PropTypes.string,
|
||||||
piece: React.PropTypes.object.isRequired,
|
piece: React.PropTypes.object.isRequired,
|
||||||
toggleCreateEditionsDialog: React.PropTypes.func.isRequired
|
toggleCreateEditionsDialog: React.PropTypes.func.isRequired,
|
||||||
|
onPollingSuccess: React.PropTypes.func
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
@ -55,16 +58,9 @@ let AccordionListItemEditionWidget = React.createClass({
|
|||||||
let isEditionListOpen = this.state.isEditionListOpenForPieceId[pieceId] ? this.state.isEditionListOpenForPieceId[pieceId].show : false;
|
let isEditionListOpen = this.state.isEditionListOpenForPieceId[pieceId] ? this.state.isEditionListOpenForPieceId[pieceId].show : false;
|
||||||
|
|
||||||
if(isEditionListOpen) {
|
if(isEditionListOpen) {
|
||||||
if(typeof this.state.editionList[pieceId] === 'undefined') {
|
|
||||||
return (
|
|
||||||
<span className="glyph-ascribe-spool-chunked spin"/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
return (
|
||||||
<span className="glyphicon glyphicon-menu-up" aria-hidden="true" style={{top: 2}}></span>
|
<span className="glyphicon glyphicon-menu-up" aria-hidden="true" style={{top: 2}}></span>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<span className="glyphicon glyphicon-menu-down" aria-hidden="true" style={{top: 2}}></span>
|
<span className="glyphicon glyphicon-menu-down" aria-hidden="true" style={{top: 2}}></span>
|
||||||
@ -76,23 +72,16 @@ let AccordionListItemEditionWidget = React.createClass({
|
|||||||
let piece = this.props.piece;
|
let piece = this.props.piece;
|
||||||
let numEditions = piece.num_editions;
|
let numEditions = piece.num_editions;
|
||||||
|
|
||||||
if(numEditions === -1) {
|
if(numEditions <= 0) {
|
||||||
return (
|
return (
|
||||||
<button
|
<CreateEditionsButton
|
||||||
onClick={this.props.toggleCreateEditionsDialog}
|
label={getLangText('Create editions')}
|
||||||
className={classNames('btn', 'btn-default', 'btn-xs', 'ascribe-accordion-list-item-edition-widget', this.props.className)}>
|
className="btn-xs pull-right"
|
||||||
+ Editions
|
piece={piece}
|
||||||
</button>
|
toggleCreateEditionsDialog={this.props.toggleCreateEditionsDialog}
|
||||||
|
onPollingSuccess={this.props.onPollingSuccess}/>
|
||||||
);
|
);
|
||||||
}
|
} else if(numEditions === 1) {
|
||||||
else if(numEditions === 0) {
|
|
||||||
return (
|
|
||||||
<button disabled className={classNames('btn', 'btn-default', 'btn-xs', this.props.className)}>
|
|
||||||
Creating Editions <span className="glyph-ascribe-spool-chunked spin"/>
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if(numEditions === 1) {
|
|
||||||
let editionMapping = piece && piece.first_edition ? piece.first_edition.edition_number + '/' + piece.num_editions : '';
|
let editionMapping = piece && piece.first_edition ? piece.first_edition.edition_number + '/' + piece.num_editions : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -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}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,93 @@
|
|||||||
'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 EditionListStore from '../../stores/edition_list_store';
|
||||||
|
|
||||||
|
import { getAvailableAcls } from '../../utils/acl_utils';
|
||||||
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
let CreateEditionsButton = React.createClass({
|
let CreateEditionsButton = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
piece: React.PropTypes.object.isRequired
|
label: React.PropTypes.string,
|
||||||
|
className: React.PropTypes.string,
|
||||||
|
piece: React.PropTypes.object.isRequired,
|
||||||
|
toggleCreateEditionsDialog: React.PropTypes.func.isRequired,
|
||||||
|
onPollingSuccess: React.PropTypes.func
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation],
|
getInitialState() {
|
||||||
|
return EditionListStore.getState();
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
EditionListStore.listen(this.onChange);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
EditionListStore.unlisten(this.onChange);
|
||||||
|
clearInterval(this.state.pollingIntervalIndex);
|
||||||
|
},
|
||||||
|
|
||||||
|
onChange(state) {
|
||||||
|
this.setState(state);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
if(this.props.piece.num_editions === 0 && typeof this.state.pollingIntervalIndex === 'undefined') {
|
||||||
|
this.startPolling();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
startPolling() {
|
||||||
|
// start polling until editions are defined
|
||||||
|
let pollingIntervalIndex = setInterval(() => {
|
||||||
|
EditionListActions.fetchEditionList(this.props.piece.id)
|
||||||
|
.then((res) => {
|
||||||
|
|
||||||
|
clearInterval(this.state.pollingIntervalIndex);
|
||||||
|
this.props.onPollingSuccess(this.props.piece.id, res.editions[0].num_editions);
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
/* Ignore and keep going */
|
||||||
|
});
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
pollingIntervalIndex
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
render: function () {
|
render: function () {
|
||||||
if (this.props.piece.constructor === Array){
|
let piece = this.props.piece;
|
||||||
return null;
|
|
||||||
}
|
let availableAcls = getAvailableAcls(piece);
|
||||||
let availableAcls = getAvailableAcls([this.props.piece]);
|
|
||||||
if (availableAcls.indexOf('editions') === -1){
|
if (availableAcls.indexOf('editions') < -1 || piece.num_editions > 0){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(piece.num_editions === 0 && typeof this.state.editionList[piece.id] === 'undefined') {
|
||||||
return (
|
return (
|
||||||
<button className="btn btn-default btn-sm">
|
<button
|
||||||
CREATE EDITIONS
|
disabled
|
||||||
|
className={classNames('btn', 'btn-default', this.props.className)}>
|
||||||
|
{getLangText('Creating editions')} <span className="glyph-ascribe-spool-chunked spin"/>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className={classNames('btn', 'btn-default', this.props.className)}
|
||||||
|
onClick={this.props.toggleCreateEditionsDialog}>
|
||||||
|
{this.props.label}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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} />
|
||||||
|
@ -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;
|
|
@ -10,26 +10,22 @@ import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph
|
|||||||
import DetailProperty from './detail_property';
|
import DetailProperty from './detail_property';
|
||||||
|
|
||||||
import FurtherDetails from './further_details';
|
import FurtherDetails from './further_details';
|
||||||
|
|
||||||
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 PieceActions from '../../actions/piece_actions';
|
||||||
|
|
||||||
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 +37,12 @@ let Piece = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return UserStore.getState();
|
return mergeOptions(
|
||||||
|
UserStore.getState(),
|
||||||
|
{
|
||||||
|
showCreateEditionsDialog: false
|
||||||
|
}
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -57,8 +58,40 @@ let Piece = React.createClass({
|
|||||||
this.setState(state);
|
this.setState(state);
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
toggleCreateEditionsDialog() {
|
||||||
|
this.setState({
|
||||||
|
showCreateEditionsDialog: !this.state.showCreateEditionsDialog
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
handleEditionCreationSuccess() {
|
||||||
|
PieceActions.updateProperty({key: 'num_editions', value: 0});
|
||||||
|
this.toggleCreateEditionsDialog();
|
||||||
|
},
|
||||||
|
|
||||||
|
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/>);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handlePollingSuccess(pieceId, numEditions) {
|
||||||
|
PieceActions.updateProperty({
|
||||||
|
key: 'num_editions',
|
||||||
|
value: numEditions
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
return (
|
return (
|
||||||
<Row>
|
<Row>
|
||||||
<Col md={6}>
|
<Col md={6}>
|
||||||
@ -66,12 +99,31 @@ 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) } />
|
||||||
|
{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}>
|
||||||
|
<CreateEditionsButton
|
||||||
|
label={getLangText('CREATE EDITIONS')}
|
||||||
|
className="btn-sm"
|
||||||
piece={this.props.piece}
|
piece={this.props.piece}
|
||||||
handleSuccess={this.props.loadPiece}/>
|
toggleCreateEditionsDialog={this.toggleCreateEditionsDialog}
|
||||||
|
onPollingSuccess={this.handlePollingSuccess}/>
|
||||||
|
</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 +137,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;
|
||||||
|
62
js/components/ascribe_forms/create_editions_form.js
Normal file
62
js/components/ascribe_forms/create_editions_form.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Form from '../ascribe_forms/form';
|
||||||
|
import Property from '../ascribe_forms/property';
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
let CreateEditionsForm = React.createClass({
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
handleSuccess: React.PropTypes.func,
|
||||||
|
pieceId: React.PropTypes.number
|
||||||
|
},
|
||||||
|
|
||||||
|
getFormData(){
|
||||||
|
return {
|
||||||
|
piece_id: parseInt(this.props.pieceId, 10)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSuccess(response) {
|
||||||
|
let notification = new GlobalNotificationModel(response.notification, 'success', 10000);
|
||||||
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
|
|
||||||
|
if(this.props.handleSuccess) {
|
||||||
|
this.props.handleSuccess(response);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Form
|
||||||
|
ref='form'
|
||||||
|
url={apiUrls.editions}
|
||||||
|
getFormData={this.getFormData}
|
||||||
|
handleSuccess={this.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;
|
@ -97,9 +97,9 @@ let LoginForm = React.createClass({
|
|||||||
{getLangText(this.props.submitMessage)}
|
{getLangText(this.props.submitMessage)}
|
||||||
</button>}
|
</button>}
|
||||||
spinner={
|
spinner={
|
||||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
<span 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" />
|
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||||
</button>
|
</span>
|
||||||
}>
|
}>
|
||||||
<FormPropertyHeader>
|
<FormPropertyHeader>
|
||||||
<h3>{getLangText(this.props.headerMessage)}</h3>
|
<h3>{getLangText(this.props.headerMessage)}</h3>
|
||||||
|
165
js/components/ascribe_forms/form_register_piece.js
Normal file
165
js/components/ascribe_forms/form_register_piece.js
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import AppConstants from '../../constants/application_constants';
|
||||||
|
|
||||||
|
import Form from './form';
|
||||||
|
import Property from './property';
|
||||||
|
import FormPropertyHeader from './form_property_header';
|
||||||
|
|
||||||
|
import apiUrls from '../../constants/api_urls';
|
||||||
|
|
||||||
|
import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader';
|
||||||
|
|
||||||
|
import { getCookie } from '../../utils/fetch_api_utils';
|
||||||
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
|
|
||||||
|
|
||||||
|
let RegisterPieceForm = React.createClass({
|
||||||
|
getInitialState(){
|
||||||
|
return {
|
||||||
|
digitalWorkKey: null,
|
||||||
|
isUploadReady: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
getFormData(){
|
||||||
|
return {
|
||||||
|
digital_work_key: this.state.digitalWorkKey
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
submitKey(key){
|
||||||
|
this.setState({
|
||||||
|
digitalWorkKey: key
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setIsUploadReady(isReady) {
|
||||||
|
this.setState({
|
||||||
|
isUploadReady: isReady
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
isReadyForFormSubmission(files) {
|
||||||
|
files = files.filter((file) => file.status !== 'deleted' && file.status !== 'canceled');
|
||||||
|
if (files.length > 0 && files[0].status === 'upload successful') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Form
|
||||||
|
className="ascribe-form-bordered"
|
||||||
|
ref='form'
|
||||||
|
url={apiUrls.pieces_list}
|
||||||
|
getFormData={this.getFormData}
|
||||||
|
handleSuccess={this.props.handleSuccess}
|
||||||
|
buttons={<button
|
||||||
|
type="submit"
|
||||||
|
className="btn ascribe-btn ascribe-btn-login"
|
||||||
|
disabled={!this.state.isUploadReady}>
|
||||||
|
{getLangText('Register work')}
|
||||||
|
</button>}
|
||||||
|
spinner={
|
||||||
|
<span 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" />
|
||||||
|
</span>
|
||||||
|
}>
|
||||||
|
<FormPropertyHeader>
|
||||||
|
<h3>{getLangText('Register your work')}</h3>
|
||||||
|
</FormPropertyHeader>
|
||||||
|
<Property
|
||||||
|
ignoreFocus={true}>
|
||||||
|
<FileUploader
|
||||||
|
submitKey={this.submitKey}
|
||||||
|
setIsUploadReady={this.setIsUploadReady}
|
||||||
|
isReadyForFormSubmission={this.isReadyForFormSubmission}
|
||||||
|
editable={this.props.isFineUploaderEditable}/>
|
||||||
|
</Property>
|
||||||
|
<Property
|
||||||
|
name='artist_name'
|
||||||
|
label={getLangText('Artist Name')}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="(e.g. Andy Warhol)"
|
||||||
|
required/>
|
||||||
|
</Property>
|
||||||
|
<Property
|
||||||
|
name='title'
|
||||||
|
label={getLangText('Title')}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="(e.g. 32 Campbell's Soup Cans)"
|
||||||
|
required/>
|
||||||
|
</Property>
|
||||||
|
<Property
|
||||||
|
name='date_created'
|
||||||
|
label={getLangText('Year Created')}>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="(e.g. 1962)"
|
||||||
|
min={0}
|
||||||
|
required/>
|
||||||
|
</Property>
|
||||||
|
{this.props.children}
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let FileUploader = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
setIsUploadReady: React.PropTypes.func,
|
||||||
|
submitKey: React.PropTypes.func,
|
||||||
|
isReadyForFormSubmission: React.PropTypes.func,
|
||||||
|
onClick: React.PropTypes.func,
|
||||||
|
// editable is used to lock react fine uploader in case
|
||||||
|
// a user is actually not logged in already to prevent him from droping files
|
||||||
|
// before login in
|
||||||
|
editable: React.PropTypes.bool
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<ReactS3FineUploader
|
||||||
|
onClick={this.props.onClick}
|
||||||
|
keyRoutine={{
|
||||||
|
url: AppConstants.serverUrl + 's3/key/',
|
||||||
|
fileClass: 'digitalwork'
|
||||||
|
}}
|
||||||
|
createBlobRoutine={{
|
||||||
|
url: apiUrls.blob_digitalworks
|
||||||
|
}}
|
||||||
|
submitKey={this.props.submitKey}
|
||||||
|
validation={{
|
||||||
|
itemLimit: 100000,
|
||||||
|
sizeLimit: '25000000000'
|
||||||
|
}}
|
||||||
|
setIsUploadReady={this.props.setIsUploadReady}
|
||||||
|
isReadyForFormSubmission={this.props.isReadyForFormSubmission}
|
||||||
|
areAssetsDownloadable={false}
|
||||||
|
areAssetsEditable={this.props.editable}
|
||||||
|
signature={{
|
||||||
|
endpoint: AppConstants.serverUrl + 's3/signature/',
|
||||||
|
customHeaders: {
|
||||||
|
'X-CSRFToken': getCookie('csrftoken')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
deleteFile={{
|
||||||
|
enabled: true,
|
||||||
|
method: 'DELETE',
|
||||||
|
endpoint: AppConstants.serverUrl + 's3/delete',
|
||||||
|
customHeaders: {
|
||||||
|
'X-CSRFToken': getCookie('csrftoken')
|
||||||
|
}
|
||||||
|
}}/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default RegisterPieceForm;
|
@ -84,9 +84,9 @@ let SignupForm = React.createClass({
|
|||||||
{getLangText(this.props.submitMessage)}
|
{getLangText(this.props.submitMessage)}
|
||||||
</button>}
|
</button>}
|
||||||
spinner={
|
spinner={
|
||||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
<span 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" />
|
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||||
</button>
|
</span>
|
||||||
}>
|
}>
|
||||||
<FormPropertyHeader>
|
<FormPropertyHeader>
|
||||||
<h3>{getLangText(this.props.headerMessage)}</h3>
|
<h3>{getLangText(this.props.headerMessage)}</h3>
|
||||||
|
@ -68,9 +68,9 @@ let CoaVerifyForm = React.createClass({
|
|||||||
{getLangText('Verify your Certificate of Authenticity')}
|
{getLangText('Verify your Certificate of Authenticity')}
|
||||||
</button>}
|
</button>}
|
||||||
spinner={
|
spinner={
|
||||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
<span 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" />
|
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||||
</button>
|
</span>
|
||||||
}>
|
}>
|
||||||
<Property
|
<Property
|
||||||
name='message'
|
name='message'
|
||||||
|
@ -12,12 +12,16 @@ let Link = Router.Link;
|
|||||||
|
|
||||||
let LoginContainer = React.createClass({
|
let LoginContainer = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
message: React.PropTypes.string
|
message: React.PropTypes.string,
|
||||||
|
redirectOnLoggedIn: React.PropTypes.bool,
|
||||||
|
redirectOnLoginSuccess: React.PropTypes.bool
|
||||||
},
|
},
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
return {
|
return {
|
||||||
message: getLangText('Enter') + ' ascribe'
|
message: getLangText('Enter') + ' ascribe',
|
||||||
|
redirectOnLoggedIn: true,
|
||||||
|
redirectOnLoginSuccess: true
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -25,6 +29,8 @@ let LoginContainer = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div className="ascribe-login-wrapper">
|
<div className="ascribe-login-wrapper">
|
||||||
<LoginForm
|
<LoginForm
|
||||||
|
redirectOnLoggedIn={this.props.redirectOnLoggedIn}
|
||||||
|
redirectOnLoginSuccess={this.props.redirectOnLoginSuccess}
|
||||||
message={this.props.message} />
|
message={this.props.message} />
|
||||||
<div className="ascribe-login-text">
|
<div className="ascribe-login-text">
|
||||||
{getLangText('Not an ascribe user')}? <Link to="signup">{getLangText('Sign up')}...</Link><br/>
|
{getLangText('Not an ascribe user')}? <Link to="signup">{getLangText('Sign up')}...</Link><br/>
|
||||||
|
@ -82,9 +82,9 @@ let PasswordRequestResetForm = React.createClass({
|
|||||||
{getLangText('Reset your password')}
|
{getLangText('Reset your password')}
|
||||||
</button>}
|
</button>}
|
||||||
spinner={
|
spinner={
|
||||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
<span 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" />
|
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||||
</button>
|
</span>
|
||||||
}>
|
}>
|
||||||
<Property
|
<Property
|
||||||
name='email'
|
name='email'
|
||||||
@ -129,9 +129,9 @@ let PasswordResetForm = React.createClass({
|
|||||||
{getLangText('Reset your password')}
|
{getLangText('Reset your password')}
|
||||||
</button>}
|
</button>}
|
||||||
spinner={
|
spinner={
|
||||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
<span 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" />
|
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||||
</button>
|
</span>
|
||||||
}>
|
}>
|
||||||
<Property
|
<Property
|
||||||
name='password'
|
name='password'
|
||||||
|
@ -2,14 +2,10 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import DatePicker from 'react-datepicker/dist/react-datepicker';
|
|
||||||
|
|
||||||
import Router from 'react-router';
|
import Router 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 AppConstants from '../constants/application_constants';
|
|
||||||
|
|
||||||
import LicenseActions from '../actions/license_actions';
|
import LicenseActions from '../actions/license_actions';
|
||||||
import LicenseStore from '../stores/license_store';
|
import LicenseStore from '../stores/license_store';
|
||||||
|
|
||||||
@ -21,17 +17,14 @@ import UserStore from '../stores/user_store';
|
|||||||
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 Form from './ascribe_forms/form';
|
|
||||||
import Property from './ascribe_forms/property';
|
import Property from './ascribe_forms/property';
|
||||||
import PropertyCollapsible from './ascribe_forms/property_collapsible';
|
import PropertyCollapsible from './ascribe_forms/property_collapsible';
|
||||||
import FormPropertyHeader from './ascribe_forms/form_property_header';
|
import RegisterPieceForm from './ascribe_forms/form_register_piece';
|
||||||
|
//import FormPropertyHeader from './ascribe_forms/form_property_header';
|
||||||
|
|
||||||
import LoginContainer from './login_container';
|
import LoginContainer from './login_container';
|
||||||
import SlidesContainer from './ascribe_slides_container/slides_container';
|
import SlidesContainer from './ascribe_slides_container/slides_container';
|
||||||
|
|
||||||
import apiUrls from '../constants/api_urls';
|
|
||||||
|
|
||||||
import ReactS3FineUploader from './ascribe_uploader/react_s3_fine_uploader';
|
|
||||||
|
|
||||||
import { mergeOptions } from '../utils/general_utils';
|
import { mergeOptions } from '../utils/general_utils';
|
||||||
import { getCookie } from '../utils/fetch_api_utils';
|
import { getCookie } from '../utils/fetch_api_utils';
|
||||||
@ -46,8 +39,6 @@ let RegisterPiece = React.createClass( {
|
|||||||
UserStore.getState(),
|
UserStore.getState(),
|
||||||
PieceListStore.getState(),
|
PieceListStore.getState(),
|
||||||
{
|
{
|
||||||
digitalWorkKey: null,
|
|
||||||
uploadStatus: false,
|
|
||||||
selectedLicense: 0,
|
selectedLicense: 0,
|
||||||
isFineUploaderEditable: false
|
isFineUploaderEditable: false
|
||||||
});
|
});
|
||||||
@ -97,32 +88,6 @@ let RegisterPiece = React.createClass( {
|
|||||||
this.transitionTo('piece', {pieceId: response.piece.id});
|
this.transitionTo('piece', {pieceId: response.piece.id});
|
||||||
},
|
},
|
||||||
|
|
||||||
getFormData(){
|
|
||||||
return {
|
|
||||||
digital_work_key: this.state.digitalWorkKey
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
submitKey(key){
|
|
||||||
this.setState({
|
|
||||||
digitalWorkKey: key
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
setIsUploadReady(isReady) {
|
|
||||||
this.setState({
|
|
||||||
isUploadReady: isReady
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
isReadyForFormSubmission(files) {
|
|
||||||
files = files.filter((file) => file.status !== 'deleted' && file.status !== 'canceled');
|
|
||||||
if (files.length > 0 && files[0].status === 'upload successful') {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onLicenseChange(event){
|
onLicenseChange(event){
|
||||||
//console.log(this.state.licenses[event.target.selectedIndex].url);
|
//console.log(this.state.licenses[event.target.selectedIndex].url);
|
||||||
this.setState({selectedLicense: event.target.selectedIndex});
|
this.setState({selectedLicense: event.target.selectedIndex});
|
||||||
@ -170,59 +135,9 @@ let RegisterPiece = React.createClass( {
|
|||||||
onFocus={this.changeSlide}>
|
onFocus={this.changeSlide}>
|
||||||
<Row className="no-margin">
|
<Row className="no-margin">
|
||||||
<Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}>
|
<Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}>
|
||||||
<Form
|
<RegisterPieceForm
|
||||||
className="ascribe-form-bordered"
|
isFineUploaderEditable={this.state.isFineUploaderEditable}
|
||||||
ref='form'
|
handleSuccess={this.handleSuccess}>
|
||||||
url={apiUrls.pieces_list}
|
|
||||||
getFormData={this.getFormData}
|
|
||||||
handleSuccess={this.handleSuccess}
|
|
||||||
buttons={<button
|
|
||||||
type="submit"
|
|
||||||
className="btn ascribe-btn ascribe-btn-login"
|
|
||||||
disabled={!this.state.isUploadReady}>
|
|
||||||
{getLangText('Register work')}
|
|
||||||
</button>}
|
|
||||||
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>
|
|
||||||
}>
|
|
||||||
<FormPropertyHeader>
|
|
||||||
<h3>{getLangText('Register your work')}</h3>
|
|
||||||
</FormPropertyHeader>
|
|
||||||
<Property
|
|
||||||
ignoreFocus={true}>
|
|
||||||
<FileUploader
|
|
||||||
submitKey={this.submitKey}
|
|
||||||
setIsUploadReady={this.setIsUploadReady}
|
|
||||||
isReadyForFormSubmission={this.isReadyForFormSubmission}
|
|
||||||
editable={this.state.isFineUploaderEditable}/>
|
|
||||||
</Property>
|
|
||||||
<Property
|
|
||||||
name='artist_name'
|
|
||||||
label={getLangText('Artist Name')}>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="(e.g. Andy Warhol)"
|
|
||||||
required/>
|
|
||||||
</Property>
|
|
||||||
<Property
|
|
||||||
name='title'
|
|
||||||
label={getLangText('Title')}>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="(e.g. 32 Campbell's Soup Cans)"
|
|
||||||
required/>
|
|
||||||
</Property>
|
|
||||||
<Property
|
|
||||||
name='date_created'
|
|
||||||
label={getLangText('Year Created')}>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
placeholder="(e.g. 1962)"
|
|
||||||
min={0}
|
|
||||||
required/>
|
|
||||||
</Property>
|
|
||||||
<PropertyCollapsible
|
<PropertyCollapsible
|
||||||
checkboxLabel={getLangText('Specify editions')}>
|
checkboxLabel={getLangText('Specify editions')}>
|
||||||
<span>{getLangText('Editions')}</span>
|
<span>{getLangText('Editions')}</span>
|
||||||
@ -232,7 +147,7 @@ let RegisterPiece = React.createClass( {
|
|||||||
min={0}/>
|
min={0}/>
|
||||||
</PropertyCollapsible>
|
</PropertyCollapsible>
|
||||||
{this.getLicenses()}
|
{this.getLicenses()}
|
||||||
</Form>
|
</RegisterPieceForm>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
@ -248,54 +163,4 @@ let RegisterPiece = React.createClass( {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
let FileUploader = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
setIsUploadReady: React.PropTypes.func,
|
|
||||||
submitKey: React.PropTypes.func,
|
|
||||||
isReadyForFormSubmission: React.PropTypes.func,
|
|
||||||
onClick: React.PropTypes.func,
|
|
||||||
// editable is used to lock react fine uploader in case
|
|
||||||
// a user is actually not logged in already to prevent him from droping files
|
|
||||||
// before login in
|
|
||||||
editable: React.PropTypes.bool
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<ReactS3FineUploader
|
|
||||||
onClick={this.props.onClick}
|
|
||||||
keyRoutine={{
|
|
||||||
url: AppConstants.serverUrl + 's3/key/',
|
|
||||||
fileClass: 'digitalwork'
|
|
||||||
}}
|
|
||||||
createBlobRoutine={{
|
|
||||||
url: apiUrls.blob_digitalworks
|
|
||||||
}}
|
|
||||||
submitKey={this.props.submitKey}
|
|
||||||
validation={{
|
|
||||||
itemLimit: 100000,
|
|
||||||
sizeLimit: '25000000000'
|
|
||||||
}}
|
|
||||||
setIsUploadReady={this.props.setIsUploadReady}
|
|
||||||
isReadyForFormSubmission={this.props.isReadyForFormSubmission}
|
|
||||||
areAssetsDownloadable={false}
|
|
||||||
areAssetsEditable={this.props.editable}
|
|
||||||
signature={{
|
|
||||||
endpoint: AppConstants.serverUrl + 's3/signature/',
|
|
||||||
customHeaders: {
|
|
||||||
'X-CSRFToken': getCookie('csrftoken')
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
deleteFile={{
|
|
||||||
enabled: true,
|
|
||||||
method: 'DELETE',
|
|
||||||
endpoint: AppConstants.serverUrl + 's3/delete',
|
|
||||||
customHeaders: {
|
|
||||||
'X-CSRFToken': getCookie('csrftoken')
|
|
||||||
}
|
|
||||||
}}/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default RegisterPiece;
|
export default RegisterPiece;
|
||||||
|
@ -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',
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ class PieceListStore {
|
|||||||
* the number of items the resource actually - without pagination - provides.
|
* the number of items the resource actually - without pagination - provides.
|
||||||
*/
|
*/
|
||||||
this.pieceList = [];
|
this.pieceList = [];
|
||||||
|
// -1 specifies that the store is currently loading
|
||||||
this.pieceListCount = -1;
|
this.pieceListCount = -1;
|
||||||
this.page = 1;
|
this.page = 1;
|
||||||
this.pageSize = 10;
|
this.pageSize = 10;
|
||||||
|
@ -13,6 +13,14 @@ class PieceStore {
|
|||||||
onUpdatePiece(piece) {
|
onUpdatePiece(piece) {
|
||||||
this.piece = piece;
|
this.piece = piece;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onUpdateProperty({key, value}) {
|
||||||
|
if(this.piece && key in this.piece) {
|
||||||
|
this.piece[key] = value;
|
||||||
|
} else {
|
||||||
|
throw new Error('There is no piece defined in PieceStore or the piece object does not have the property you\'re looking for.');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default alt.createStore(PieceStore, 'PieceStore');
|
export default alt.createStore(PieceStore, 'PieceStore');
|
||||||
|
Loading…
Reference in New Issue
Block a user