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

Merge branch 'AD-613-cyland-white-label-page' of bitbucket.org:ascribe/onion into AD-613-cyland-white-label-page

This commit is contained in:
diminator 2015-08-19 16:45:53 +02:00
commit 7458bdcb92
9 changed files with 144 additions and 82 deletions

View File

@ -28,7 +28,7 @@ let AccordionList = React.createClass({
); );
} else { } else {
return ( return (
<div className={this.props.className + ' ascribe-accordion-list-loading'}> <div className={this.props.className + ' ascribe-loading-position'}>
{this.props.loadingElement} {this.props.loadingElement}
</div> </div>
); );

View File

@ -11,7 +11,6 @@ let Navigation = Router.Navigation;
let SlidesContainer = React.createClass({ let SlidesContainer = React.createClass({
propTypes: { propTypes: {
breadcrumbs: React.PropTypes.arrayOf(React.PropTypes.string),
children: React.PropTypes.arrayOf(React.PropTypes.element), children: React.PropTypes.arrayOf(React.PropTypes.element),
forwardProcess: React.PropTypes.bool.isRequired forwardProcess: React.PropTypes.bool.isRequired
}, },
@ -22,15 +21,22 @@ let SlidesContainer = React.createClass({
// handle queryParameters // handle queryParameters
let queryParams = this.getQuery(); let queryParams = this.getQuery();
let slideNum = -1; let slideNum = -1;
let startFrom = -1;
if(queryParams && 'slide_num' in queryParams) { if(queryParams && 'slide_num' in queryParams) {
slideNum = parseInt(queryParams.slide_num, 10); slideNum = parseInt(queryParams.slide_num, 10);
} }
// if slide_num is not set, this will be done in componentDidMount // if slide_num is not set, this will be done in componentDidMount
// the query param 'start_from' removes all slide children before the respective number
if(queryParams && 'start_from' in queryParams) {
startFrom = parseInt(queryParams.start_from, 10);
}
return { return {
slideNum,
startFrom,
containerWidth: 0, containerWidth: 0,
slideNum: slideNum,
historyLength: window.history.length historyLength: window.history.length
}; };
}, },
@ -55,9 +61,23 @@ let SlidesContainer = React.createClass({
window.addEventListener('resize', this.handleContainerResize); window.addEventListener('resize', this.handleContainerResize);
}, },
componentDidUpdate() { componentWillReceiveProps() {
// check if slide_num was defined, and if not then default to 0
let queryParams = this.getQuery(); let queryParams = this.getQuery();
// also check if start_from was updated
// This applies for example when the user tries to submit a already existing piece
// (starting from slide 1 for example) and then clicking on + NEW WORK
if(queryParams && !('start_from' in queryParams)) {
this.setState({
startFrom: -1
});
}
},
componentDidUpdate() {
let queryParams = this.getQuery();
// check if slide_num was defined, and if not then default to 0
this.setSlideNum(queryParams.slide_num); this.setSlideNum(queryParams.slide_num);
}, },
@ -72,6 +92,12 @@ let SlidesContainer = React.createClass({
}); });
}, },
// When the start_from parameter is used, this.setSlideNum can not simply be used anymore.
nextSlide() {
let nextSlide = this.state.slideNum + 1;
this.setSlideNum(nextSlide);
},
// We let every one from the outsite set the page number of the slider, // We let every one from the outsite set the page number of the slider,
// though only if the slideNum is actually in the range of our children-list. // though only if the slideNum is actually in the range of our children-list.
setSlideNum(slideNum) { setSlideNum(slideNum) {
@ -102,7 +128,7 @@ let SlidesContainer = React.createClass({
// if slideNum is within the range of slides and none of the previous cases // if slideNum is within the range of slides and none of the previous cases
// where matched, we can actually do transitions // where matched, we can actually do transitions
} else if(slideNum >= 0 || slideNum < React.Children.count(this.props.children)) { } else if(slideNum >= 0 || slideNum < this.customChildrenCount()) {
if(slideNum !== this.state.slideNum - 1) { if(slideNum !== this.state.slideNum - 1) {
// Bootstrapping the component, getInitialState is called once to save // Bootstrapping the component, getInitialState is called once to save
@ -135,15 +161,45 @@ let SlidesContainer = React.createClass({
} }
}, },
renderBreadCrumbs() { extractBreadcrumbs() {
if (this.props.breadcrumbs) { let breadcrumbs = [];
let numSlides = this.props.breadcrumbs.length;
ReactAddons.Children.map(this.props.children, (child, i) => {
if(i >= this.state.startFrom) {
breadcrumbs.push(child.props['data-slide-title']);
}
});
return breadcrumbs;
},
customChildrenCount() {
let count = 0;
React.Children.forEach(this.props.children, (child, i) => {
if(i >= this.state.startFrom) {
count++;
}
});
return count;
},
renderBreadcrumbs() {
let breadcrumbs = this.extractBreadcrumbs();
let numOfChildren = this.customChildrenCount();
// check if every child/slide has a title,
// otherwise do not display the breadcrumbs at all
// Also, if there is only one child, do not display the breadcrumbs
if(breadcrumbs.length === numOfChildren && breadcrumbs.length > 1 && numOfChildren > 1) {
let numSlides = breadcrumbs.length;
let columnWidth = Math.floor(12 / numSlides); let columnWidth = Math.floor(12 / numSlides);
return ( return (
<div className="row" style={{width: this.state.containerWidth}}> <div className="row" style={{width: this.state.containerWidth}}>
<div className="col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1 col-xs-12"> <div className="col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1 col-xs-12">
<div className="no-margin row ascribe-breadcrumb-container"> <div className="no-margin row ascribe-breadcrumb-container">
{this.props.breadcrumbs.map((breadcrumb, i) => { {breadcrumbs.map((breadcrumb, i) => {
return ( return (
<Col <Col
className="no-padding" className="no-padding"
@ -151,7 +207,7 @@ let SlidesContainer = React.createClass({
key={i}> key={i}>
<div className="ascribe-breadcrumb"> <div className="ascribe-breadcrumb">
<a className={this.state.slideNum === i ? 'active' : ''}> <a className={this.state.slideNum === i ? 'active' : ''}>
{this.props.breadcrumbs[i]} {breadcrumb}
<span className={i === numSlides - 1 ? 'invisible' : '' + 'pull-right glyphicon glyphicon-chevron-right'}> <span className={i === numSlides - 1 ? 'invisible' : '' + 'pull-right glyphicon glyphicon-chevron-right'}>
</span> </span>
</a> </a>
@ -163,21 +219,30 @@ let SlidesContainer = React.createClass({
</div> </div>
</div> </div>
); );
} else {
return null;
} }
return null;
}, },
// Since we need to give the slides a width, we need to call ReactAddons.addons.cloneWithProps // Since we need to give the slides a width, we need to call ReactAddons.addons.cloneWithProps
// Also, a key is nice to have! // Also, a key is nice to have!
renderChildren() { renderChildren() {
return ReactAddons.Children.map(this.props.children, (child, i) => { return ReactAddons.Children.map(this.props.children, (child, i) => {
return ReactAddons.addons.cloneWithProps(child, { // since the default parameter of startFrom is -1, we do not need to check
className: 'ascribe-slide', // if its actually present in the url bar, as it will just not match
style: {
width: this.state.containerWidth if(i >= this.state.startFrom) {
}, return ReactAddons.addons.cloneWithProps(child, {
key: i className: 'ascribe-slide',
}); style: {
width: this.state.containerWidth
},
key: i
});
} else {
// Abortions are bad mkay
return null;
}
}); });
}, },
@ -186,11 +251,11 @@ let SlidesContainer = React.createClass({
<div <div
className="container ascribe-sliding-container-wrapper" className="container ascribe-sliding-container-wrapper"
ref="containerWrapper"> ref="containerWrapper">
{this.renderBreadCrumbs()} {this.renderBreadcrumbs()}
<div <div
className="container ascribe-sliding-container" className="container ascribe-sliding-container"
style={{ style={{
width: this.state.containerWidth * React.Children.count(this.props.children), width: this.state.containerWidth * this.customChildrenCount(),
transform: 'translateX(' + (-1) * this.state.containerWidth * this.state.slideNum + 'px)' transform: 'translateX(' + (-1) * this.state.containerWidth * this.state.slideNum + 'px)'
}}> }}>
<div className="row"> <div className="row">

View File

@ -138,7 +138,7 @@ let PieceList = React.createClass({
this.transitionTo(this.getPathname(), {page: 1}); this.transitionTo(this.getPathname(), {page: 1});
}, },
applyOrderBy(orderBy, orderAsc) { applyOrderBy(orderBy) {
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
orderBy, this.state.orderAsc, this.state.filterBy); orderBy, this.state.orderAsc, this.state.filterBy);
}, },

View File

@ -3,18 +3,12 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import Moment from 'moment'; import ButtonLink from 'react-router-bootstrap/lib/ButtonLink';
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 ModalWrapper from '../../../../../ascribe_modal/modal_wrapper';
import LoanForm from '../../../../../ascribe_forms/form_loan';
import ApiUrls from '../../../../../../constants/api_urls';
import { getLangText } from '../../../../../../utils/lang_utils'; import { getLangText } from '../../../../../../utils/lang_utils';
import { getAclFormMessage } from '../../../../../../utils/form_utils';
let CylandSubmitButton = React.createClass({ let CylandSubmitButton = React.createClass({
propTypes: { propTypes: {
@ -41,36 +35,25 @@ let CylandSubmitButton = React.createClass({
this.setState(state); this.setState(state);
}, },
getSubmitButton() { render() {
let piece = this.props.piece;
let startFrom = 1;
if(piece && piece.extra_data && Object.keys(piece.extra_data).length > 0) {
startFrom = 2;
}
return ( return (
<button <ButtonLink
to="register_piece"
query={{
'slide_num': 0,
'start_from': startFrom,
'piece_id': this.props.piece.id
}}
className={classNames('btn', 'btn-default', 'btn-xs', this.props.className)}> className={classNames('btn', 'btn-default', 'btn-xs', this.props.className)}>
{getLangText('Submit to Cyland')} {getLangText('Submit to Cyland')}
</button> </ButtonLink>
);
},
render() {
let today = new Moment();
let loanEndDate = new Moment();
loanEndDate.add(1000, 'years');
return (
<ModalWrapper
trigger={this.getSubmitButton()}
handleSuccess={this.props.handleSuccess}
title={getLangText('Submit to Cyland')}>
<LoanForm
message={getAclFormMessage('acl_loan', '\"' + this.props.piece.title + '\"', this.props.username)}
id={{piece_id: this.props.piece.id}}
url={ApiUrls.ownership_loans_pieces}
email={this.state.whitelabel.user}
gallery="Cyland Archive"
startdate={today}
enddate={loanEndDate}
showPersonalMessage={false}
handleSuccess={this.props.handleSuccess}/>
</ModalWrapper>
); );
} }
}); });

View File

@ -20,11 +20,8 @@ import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_de
import DetailProperty from '../../../../../ascribe_detail/detail_property'; import DetailProperty from '../../../../../ascribe_detail/detail_property';
import { mergeOptions } from '../../../../../../utils/general_utils'; import { mergeOptions } from '../../../../../../utils/general_utils';
import { getLangText } from '../../../../../../utils/lang_utils';
/**
* This is the component that implements resource/data specific functionality
*/
let CylandPieceContainer = React.createClass({ let CylandPieceContainer = React.createClass({
getInitialState() { getInitialState() {
return mergeOptions( return mergeOptions(
@ -106,10 +103,11 @@ let CylandPieceDetails = React.createClass({
show={true} show={true}
defaultExpanded={true}> defaultExpanded={true}>
<Form ref='form'> <Form ref='form'>
{Object.keys(this.props.piece.extra_data).map((data) => { {Object.keys(this.props.piece.extra_data).map((data, i) => {
let label = data.replace('_', ' '); let label = data.replace('_', ' ');
return ( return (
<Property <Property
key={i}
name={data} name={data}
label={label} label={label}
editable={false}> editable={false}>

View File

@ -24,7 +24,7 @@ let CylandAdditionalDataForm = React.createClass({
getInitialState() { getInitialState() {
return { return {
isUploadReady: false isUploadReady: true
}; };
}, },
@ -119,7 +119,11 @@ let CylandAdditionalDataForm = React.createClass({
</Form> </Form>
); );
} else { } else {
return <span>First register the piece.</span>; return (
<div className="ascribe-loading-position">
<img src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} />
</div>
);
} }
} }
}); });

View File

@ -40,9 +40,10 @@ import { getLangText } from '../../../../../utils/lang_utils';
import { mergeOptions } from '../../../../../utils/general_utils'; import { mergeOptions } from '../../../../../utils/general_utils';
import { getAclFormMessage } from '../../../../../utils/form_utils'; import { getAclFormMessage } from '../../../../../utils/form_utils';
let CylandRegisterPiece = React.createClass({ let CylandRegisterPiece = React.createClass({
mixins: [Router.Navigation], mixins: [Router.Navigation, Router.State],
getInitialState(){ getInitialState(){
return mergeOptions( return mergeOptions(
@ -63,6 +64,12 @@ let CylandRegisterPiece = React.createClass({
WhitelabelStore.listen(this.onChange); WhitelabelStore.listen(this.onChange);
UserActions.fetchCurrentUser(); UserActions.fetchCurrentUser();
WhitelabelActions.fetchWhitelabel(); WhitelabelActions.fetchWhitelabel();
let queryParams = this.getQuery();
if(queryParams && 'piece_id' in queryParams) {
PieceActions.fetchOne(queryParams.piece_id);
}
}, },
componentWillUnmount() { componentWillUnmount() {
@ -85,24 +92,32 @@ let CylandRegisterPiece = React.createClass({
handleRegisterSuccess(response){ handleRegisterSuccess(response){
this.refreshPieceList();
// also start loading the piece for the next step // also start loading the piece for the next step
if(response && response.piece) { if(response && response.piece) {
PieceActions.updatePiece(response.piece); PieceActions.updatePiece(response.piece);
} }
this.refs.slidesContainer.setSlideNum(1); this.refs.slidesContainer.nextSlide();
}, },
handleAdditionalDataSuccess() { handleAdditionalDataSuccess() {
this.refs.slidesContainer.setSlideNum(2); this.refreshPieceList();
this.refs.slidesContainer.nextSlide();
}, },
handleLoanSuccess(response) { handleLoanSuccess(response) {
let notification = new GlobalNotificationModel(response.notification, 'success', 10000); let notification = new GlobalNotificationModel(response.notification, 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification); GlobalNotificationActions.appendGlobalNotification(notification);
// once the user was able to register + loan a piece successfully, we need to make sure to keep this.refreshPieceList();
// the piece list up to date
PieceActions.fetchOne(this.state.piece.id);
this.transitionTo('piece', {pieceId: this.state.piece.id});
},
refreshPieceList() {
PieceListActions.fetchPieceList( PieceListActions.fetchPieceList(
this.state.page, this.state.page,
this.state.pageSize, this.state.pageSize,
@ -111,9 +126,6 @@ let CylandRegisterPiece = React.createClass({
this.state.orderAsc, this.state.orderAsc,
this.state.filterBy this.state.filterBy
); );
PieceActions.fetchOne(this.state.piece.id);
this.transitionTo('piece', {pieceId: this.state.piece.id});
}, },
changeSlide() { changeSlide() {
@ -138,9 +150,8 @@ let CylandRegisterPiece = React.createClass({
return ( return (
<SlidesContainer <SlidesContainer
ref="slidesContainer" ref="slidesContainer"
breadcrumbs={['Register work', 'Additional details', 'Loan']}
forwardProcess={true}> forwardProcess={true}>
<div> <div data-slide-title="Register work">
<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}>
<RegisterPieceForm <RegisterPieceForm
@ -167,7 +178,7 @@ let CylandRegisterPiece = React.createClass({
</Col> </Col>
</Row> </Row>
</div> </div>
<div> <div data-slide-title="Additional details">
<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}>
<CylandAdditionalDataForm <CylandAdditionalDataForm
@ -176,7 +187,7 @@ let CylandRegisterPiece = React.createClass({
</Col> </Col>
</Row> </Row>
</div> </div>
<div> <div data-slide-title="Loan">
<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}>
<LoanForm <LoanForm

View File

@ -65,7 +65,7 @@ $ascribe-accordion-list-font: 'Source Sans Pro';
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
a { a:not(.btn) {
color: #666; color: #666;
} }
} }
@ -79,11 +79,6 @@ $ascribe-accordion-list-font: 'Source Sans Pro';
} }
} }
.ascribe-accordion-list-loading {
padding-top: 30%;
padding-bottom: 30%;
}
.ascribe-accordion-list-loading img { .ascribe-accordion-list-loading img {
display: block; display: block;
margin: auto; margin: auto;

View File

@ -427,4 +427,10 @@ hr {
&:hover { &:hover {
color: #000; color: #000;
} }
} }
.ascribe-loading-position {
padding-top: 30%;
padding-bottom: 30%;
text-align: center;
}