1
0
mirror of https://github.com/ascribe/onion.git synced 2024-12-23 01:39:36 +01: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 {
return (
<div className={this.props.className + ' ascribe-accordion-list-loading'}>
<div className={this.props.className + ' ascribe-loading-position'}>
{this.props.loadingElement}
</div>
);

View File

@ -11,7 +11,6 @@ let Navigation = Router.Navigation;
let SlidesContainer = React.createClass({
propTypes: {
breadcrumbs: React.PropTypes.arrayOf(React.PropTypes.string),
children: React.PropTypes.arrayOf(React.PropTypes.element),
forwardProcess: React.PropTypes.bool.isRequired
},
@ -22,15 +21,22 @@ let SlidesContainer = React.createClass({
// handle queryParameters
let queryParams = this.getQuery();
let slideNum = -1;
let startFrom = -1;
if(queryParams && 'slide_num' in queryParams) {
slideNum = parseInt(queryParams.slide_num, 10);
}
// 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 {
slideNum,
startFrom,
containerWidth: 0,
slideNum: slideNum,
historyLength: window.history.length
};
},
@ -55,9 +61,23 @@ let SlidesContainer = React.createClass({
window.addEventListener('resize', this.handleContainerResize);
},
componentDidUpdate() {
// check if slide_num was defined, and if not then default to 0
componentWillReceiveProps() {
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);
},
@ -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,
// though only if the slideNum is actually in the range of our children-list.
setSlideNum(slideNum) {
@ -102,7 +128,7 @@ let SlidesContainer = React.createClass({
// if slideNum is within the range of slides and none of the previous cases
// 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) {
// Bootstrapping the component, getInitialState is called once to save
@ -135,15 +161,45 @@ let SlidesContainer = React.createClass({
}
},
renderBreadCrumbs() {
if (this.props.breadcrumbs) {
let numSlides = this.props.breadcrumbs.length;
extractBreadcrumbs() {
let breadcrumbs = [];
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);
return (
<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="no-margin row ascribe-breadcrumb-container">
{this.props.breadcrumbs.map((breadcrumb, i) => {
{breadcrumbs.map((breadcrumb, i) => {
return (
<Col
className="no-padding"
@ -151,7 +207,7 @@ let SlidesContainer = React.createClass({
key={i}>
<div className="ascribe-breadcrumb">
<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>
</a>
@ -163,14 +219,19 @@ let SlidesContainer = React.createClass({
</div>
</div>
);
}
} else {
return null;
}
},
// Since we need to give the slides a width, we need to call ReactAddons.addons.cloneWithProps
// Also, a key is nice to have!
renderChildren() {
return ReactAddons.Children.map(this.props.children, (child, i) => {
// since the default parameter of startFrom is -1, we do not need to check
// if its actually present in the url bar, as it will just not match
if(i >= this.state.startFrom) {
return ReactAddons.addons.cloneWithProps(child, {
className: 'ascribe-slide',
style: {
@ -178,6 +239,10 @@ let SlidesContainer = React.createClass({
},
key: i
});
} else {
// Abortions are bad mkay
return null;
}
});
},
@ -186,11 +251,11 @@ let SlidesContainer = React.createClass({
<div
className="container ascribe-sliding-container-wrapper"
ref="containerWrapper">
{this.renderBreadCrumbs()}
{this.renderBreadcrumbs()}
<div
className="container ascribe-sliding-container"
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)'
}}>
<div className="row">

View File

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

View File

@ -3,18 +3,12 @@
import React from 'react';
import classNames from 'classnames';
import Moment from 'moment';
import ButtonLink from 'react-router-bootstrap/lib/ButtonLink';
import WhitelabelActions from '../../../../../../actions/whitelabel_actions';
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 { getAclFormMessage } from '../../../../../../utils/form_utils';
let CylandSubmitButton = React.createClass({
propTypes: {
@ -41,36 +35,25 @@ let CylandSubmitButton = React.createClass({
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 (
<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)}>
{getLangText('Submit to Cyland')}
</button>
);
},
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>
</ButtonLink>
);
}
});

View File

@ -20,11 +20,8 @@ import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_de
import DetailProperty from '../../../../../ascribe_detail/detail_property';
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({
getInitialState() {
return mergeOptions(
@ -106,10 +103,11 @@ let CylandPieceDetails = React.createClass({
show={true}
defaultExpanded={true}>
<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('_', ' ');
return (
<Property
key={i}
name={data}
label={label}
editable={false}>

View File

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

View File

@ -65,7 +65,7 @@ $ascribe-accordion-list-font: 'Source Sans Pro';
overflow: hidden;
text-overflow: ellipsis;
}
a {
a:not(.btn) {
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 {
display: block;
margin: auto;

View File

@ -428,3 +428,9 @@ hr {
color: #000;
}
}
.ascribe-loading-position {
padding-top: 30%;
padding-bottom: 30%;
text-align: center;
}