mirror of
https://github.com/ascribe/onion.git
synced 2024-12-22 17:33:14 +01:00
Merge branch 'AD-456-ikonotv-branded-page-for-registra' into AD-957-custom-upload-button-for-contract
This commit is contained in:
commit
497a330e1a
@ -1,47 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import alt from '../alt';
|
|
||||||
import OwnershipFetcher from '../fetchers/ownership_fetcher';
|
|
||||||
|
|
||||||
|
|
||||||
class ContractActions {
|
|
||||||
constructor() {
|
|
||||||
this.generateActions(
|
|
||||||
'updateContract',
|
|
||||||
'flushContract'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchContract(email) {
|
|
||||||
if(email.match(/.+\@.+\..+/)) {
|
|
||||||
OwnershipFetcher.fetchContract(email)
|
|
||||||
.then((contracts) => {
|
|
||||||
if (contracts && contracts.length > 0) {
|
|
||||||
this.actions.updateContract({
|
|
||||||
contractKey: contracts[0].s3Key,
|
|
||||||
contractUrl: contracts[0].s3Url,
|
|
||||||
contractEmail: email
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.actions.updateContract({
|
|
||||||
contractKey: null,
|
|
||||||
contractUrl: null,
|
|
||||||
contractEmail: null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.logGlobal(err);
|
|
||||||
this.actions.updateContract({
|
|
||||||
contractKey: null,
|
|
||||||
contractUrl: null,
|
|
||||||
contractEmail: null
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default alt.createActions(ContractActions);
|
|
94
js/actions/contract_agreement_list_actions.js
Normal file
94
js/actions/contract_agreement_list_actions.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import alt from '../alt';
|
||||||
|
import Q from 'q';
|
||||||
|
|
||||||
|
import OwnershipFetcher from '../fetchers/ownership_fetcher';
|
||||||
|
import ContractListActions from './contract_list_actions';
|
||||||
|
|
||||||
|
class ContractAgreementListActions {
|
||||||
|
constructor() {
|
||||||
|
this.generateActions(
|
||||||
|
'updateContractAgreementList',
|
||||||
|
'flushContractAgreementList'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchContractAgreementList(issuer, accepted, pending) {
|
||||||
|
return Q.Promise((resolve, reject) => {
|
||||||
|
this.actions.updateContractAgreementList(null);
|
||||||
|
OwnershipFetcher.fetchContractAgreementList(issuer, accepted, pending)
|
||||||
|
.then((contractAgreementList) => {
|
||||||
|
if (contractAgreementList.count > 0) {
|
||||||
|
this.actions.updateContractAgreementList(contractAgreementList.results);
|
||||||
|
resolve(contractAgreementList.results);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.logGlobal(err);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchAvailableContractAgreementList(issuer){
|
||||||
|
return Q.Promise((resolve, reject) => {
|
||||||
|
this.actions.fetchContractAgreementList(issuer, true, null)
|
||||||
|
.then((contractAgreementListAccepted) => {
|
||||||
|
if (!contractAgreementListAccepted) {
|
||||||
|
// fetch pending agreements if no accepted ones
|
||||||
|
return this.actions.fetchContractAgreementList(issuer, null, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(contractAgreementListAccepted);
|
||||||
|
}
|
||||||
|
}).then((contractAgreementListPending) => {
|
||||||
|
resolve(contractAgreementListPending);
|
||||||
|
}).catch((err) => {
|
||||||
|
console.logGlobal(err);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createContractAgreementFromPublicContract(issuer){
|
||||||
|
ContractListActions.fetchContractList(null, null, issuer)
|
||||||
|
.then((publicContract) => {
|
||||||
|
// create an agreement with the public contract if there is one
|
||||||
|
if (publicContract && publicContract.length > 0) {
|
||||||
|
return this.actions.createContractAgreement(null, publicContract[0]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*
|
||||||
|
contractAgreementList in the store is already set to null;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}).then((publicContracAgreement) => {
|
||||||
|
if (publicContracAgreement) {
|
||||||
|
this.actions.updateContractAgreementList([publicContracAgreement]);
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
console.logGlobal(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createContractAgreement(issuer, contract){
|
||||||
|
return Q.Promise((resolve, reject) => {
|
||||||
|
OwnershipFetcher.createContractAgreement(issuer, contract).then(
|
||||||
|
(contractAgreement) => {
|
||||||
|
resolve(contractAgreement);
|
||||||
|
}
|
||||||
|
).catch((err) => {
|
||||||
|
console.logGlobal(err);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default alt.createActions(ContractAgreementListActions);
|
@ -12,15 +12,19 @@ class ContractListActions {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchContractList(isActive) {
|
fetchContractList(isActive, isPublic, issuer) {
|
||||||
OwnershipFetcher.fetchContractList(isActive)
|
return Q.Promise((resolve, reject) => {
|
||||||
.then((contracts) => {
|
OwnershipFetcher.fetchContractList(isActive, isPublic, issuer)
|
||||||
this.actions.updateContractList(contracts.results);
|
.then((contracts) => {
|
||||||
})
|
this.actions.updateContractList(contracts.results);
|
||||||
.catch((err) => {
|
resolve(contracts.results);
|
||||||
console.logGlobal(err);
|
})
|
||||||
this.actions.updateContractList([]);
|
.catch((err) => {
|
||||||
});
|
console.logGlobal(err);
|
||||||
|
this.actions.updateContractList([]);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,21 +20,28 @@ let AclProxy = React.createClass({
|
|||||||
show: React.PropTypes.bool
|
show: React.PropTypes.bool
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
getChildren() {
|
||||||
if(this.props.show) {
|
if (React.Children.count(this.props.children) > 1){
|
||||||
|
/*
|
||||||
|
This might ruin styles for header items in the navbar etc
|
||||||
|
*/
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
/* can only do this when there is only 1 child, but will preserve styles */
|
||||||
|
return this.props.children;
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if(this.props.show) {
|
||||||
|
return this.getChildren();
|
||||||
} else {
|
} else {
|
||||||
if(this.props.aclObject) {
|
if(this.props.aclObject) {
|
||||||
if(this.props.aclObject[this.props.aclName]) {
|
if(this.props.aclObject[this.props.aclName]) {
|
||||||
return (
|
return this.getChildren();
|
||||||
<span>
|
|
||||||
{this.props.children}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
/* if(typeof this.props.aclObject[this.props.aclName] === 'undefined') {
|
/* if(typeof this.props.aclObject[this.props.aclName] === 'undefined') {
|
||||||
console.warn('The aclName you\'re filtering for was not present (or undefined) in the aclObject.');
|
console.warn('The aclName you\'re filtering for was not present (or undefined) in the aclObject.');
|
||||||
|
@ -14,7 +14,7 @@ import CoaActions from '../../actions/coa_actions';
|
|||||||
import CoaStore from '../../stores/coa_store';
|
import CoaStore from '../../stores/coa_store';
|
||||||
import PieceListActions from '../../actions/piece_list_actions';
|
import PieceListActions from '../../actions/piece_list_actions';
|
||||||
import PieceListStore from '../../stores/piece_list_store';
|
import PieceListStore from '../../stores/piece_list_store';
|
||||||
import EditionListActions from '../../actions/edition_list_actions';;
|
import EditionListActions from '../../actions/edition_list_actions';
|
||||||
|
|
||||||
import HistoryIterator from './history_iterator';
|
import HistoryIterator from './history_iterator';
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ let ContractAgreementForm = React.createClass({
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
ContractListStore.listen(this.onChange);
|
ContractListStore.listen(this.onChange);
|
||||||
ContractListActions.fetchContractList({is_active: 'True'});
|
ContractListActions.fetchContractList({is_active: true});
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
@ -45,7 +45,7 @@ let CreateContractForm = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleCreateSuccess(response) {
|
handleCreateSuccess(response) {
|
||||||
ContractListActions.fetchContractList({is_active: 'True'});
|
ContractListActions.fetchContractList({is_active: true});
|
||||||
let notification = new GlobalNotificationModel(getLangText('Contract %s successfully created', response.name), 'success', 5000);
|
let notification = new GlobalNotificationModel(getLangText('Contract %s successfully created', response.name), 'success', 5000);
|
||||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
this.refs.form.reset();
|
this.refs.form.reset();
|
||||||
|
@ -12,11 +12,12 @@ import InputTextAreaToggable from './input_textarea_toggable';
|
|||||||
import InputDate from './input_date';
|
import InputDate from './input_date';
|
||||||
import InputCheckbox from './input_checkbox';
|
import InputCheckbox from './input_checkbox';
|
||||||
|
|
||||||
import ContractStore from '../../stores/contract_store';
|
import ContractAgreementListStore from '../../stores/contract_agreement_list_store';
|
||||||
import ContractActions from '../../actions/contract_actions';
|
import ContractAgreementListActions from '../../actions/contract_agreement_list_actions';
|
||||||
|
|
||||||
import AppConstants from '../../constants/application_constants';
|
import AppConstants from '../../constants/application_constants';
|
||||||
|
|
||||||
|
import { mergeOptions } from '../../utils/general_utils';
|
||||||
import { getLangText } from '../../utils/lang_utils';
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
|
|
||||||
|
|
||||||
@ -48,40 +49,74 @@ let LoanForm = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return ContractStore.getState();
|
return ContractAgreementListStore.getState();
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
ContractStore.listen(this.onChange);
|
ContractAgreementListStore.listen(this.onChange);
|
||||||
ContractActions.flushContract.defer();
|
this.getContractAgreementsOrCreatePublic(this.props.email);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
// however, it can also be that at the time the component is mounting,
|
||||||
|
// the email is not defined (because it's asynchronously fetched from the server).
|
||||||
|
// Then we need to update it as soon as it is included into LoanForm's props.
|
||||||
|
if(nextProps && nextProps.email) {
|
||||||
|
this.getContractAgreementsOrCreatePublic(nextProps.email);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
ContractStore.unlisten(this.onChange);
|
ContractAgreementListStore.unlisten(this.onChange);
|
||||||
},
|
},
|
||||||
|
|
||||||
onChange(state) {
|
onChange(state) {
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getContractAgreementsOrCreatePublic(email){
|
||||||
|
ContractAgreementListActions.flushContractAgreementList();
|
||||||
|
if (email) {
|
||||||
|
ContractAgreementListActions.fetchAvailableContractAgreementList(email).then(
|
||||||
|
(contractAgreementList) => {
|
||||||
|
if (!contractAgreementList) {
|
||||||
|
ContractAgreementListActions.createContractAgreementFromPublicContract(email);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
getFormData(){
|
getFormData(){
|
||||||
return this.props.id;
|
return mergeOptions(
|
||||||
|
this.props.id,
|
||||||
|
this.getContractAgreementId()
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleOnChange(event) {
|
handleOnChange(event) {
|
||||||
// event.target.value is the submitted email of the loanee
|
// event.target.value is the submitted email of the loanee
|
||||||
if(event && event.target && event.target.value && event.target.value.match(/.*@.*/)) {
|
if(event && event.target && event.target.value && event.target.value.match(/.*@.*\..*/)) {
|
||||||
ContractActions.fetchContract(event.target.value);
|
this.getContractAgreementsOrCreatePublic(event.target.value);
|
||||||
} else {
|
} else {
|
||||||
ContractActions.flushContract();
|
ContractAgreementListActions.flushContractAgreementList();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getContractAgreementId() {
|
||||||
|
if (this.state.contractAgreementList && this.state.contractAgreementList.length > 0) {
|
||||||
|
return {'contract_agreement_id': this.state.contractAgreementList[0].id};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
getContractCheckbox() {
|
getContractCheckbox() {
|
||||||
if(this.state.contractKey && this.state.contractUrl) {
|
if(this.state.contractAgreementList && this.state.contractAgreementList.length > 0) {
|
||||||
// we need to define a key on the InputCheckboxes as otherwise
|
// we need to define a key on the InputCheckboxes as otherwise
|
||||||
// react is not rerendering them on a store switch and is keeping
|
// react is not rerendering them on a store switch and is keeping
|
||||||
// the default value of the component (which is in that case true)
|
// the default value of the component (which is in that case true)
|
||||||
|
let contract = this.state.contractAgreementList[0].contract;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Property
|
<Property
|
||||||
name="terms"
|
name="terms"
|
||||||
@ -92,8 +127,8 @@ let LoanForm = React.createClass({
|
|||||||
defaultChecked={false}>
|
defaultChecked={false}>
|
||||||
<span>
|
<span>
|
||||||
{getLangText('I agree to the')}
|
{getLangText('I agree to the')}
|
||||||
<a href={this.state.contractUrl} target="_blank">
|
<a href={contract.blob.url_safe} target="_blank">
|
||||||
{getLangText('terms of')} {this.state.contractEmail}
|
{getLangText('terms of ')} {contract.issuer}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</InputCheckbox>
|
</InputCheckbox>
|
||||||
@ -157,8 +192,8 @@ let LoanForm = React.createClass({
|
|||||||
<Property
|
<Property
|
||||||
name='loanee'
|
name='loanee'
|
||||||
label={getLangText('Loanee Email')}
|
label={getLangText('Loanee Email')}
|
||||||
onChange={this.handleOnChange}
|
|
||||||
editable={!this.props.email}
|
editable={!this.props.email}
|
||||||
|
onBlur={this.handleOnChange}
|
||||||
overrideForm={!!this.props.email}>
|
overrideForm={!!this.props.email}>
|
||||||
<input
|
<input
|
||||||
value={this.props.email}
|
value={this.props.email}
|
||||||
|
@ -28,7 +28,7 @@ let ContractSettings = React.createClass({
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
ContractListStore.listen(this.onChange);
|
ContractListStore.listen(this.onChange);
|
||||||
ContractListActions.fetchContractList({is_active: 'True'});
|
ContractListActions.fetchContractList({is_active: true});
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@ -44,7 +44,7 @@ let ContractSettings = React.createClass({
|
|||||||
contract.is_public = true;
|
contract.is_public = true;
|
||||||
ContractListActions.changeContract(contract)
|
ContractListActions.changeContract(contract)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
ContractListActions.fetchContractList({is_active: 'True'});
|
ContractListActions.fetchContractList({is_active: true});
|
||||||
let notification = getLangText('Contract %s is now public', contract.name);
|
let notification = getLangText('Contract %s is now public', contract.name);
|
||||||
notification = new GlobalNotificationModel(notification, 'success', 4000);
|
notification = new GlobalNotificationModel(notification, 'success', 4000);
|
||||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
@ -60,7 +60,7 @@ let ContractSettings = React.createClass({
|
|||||||
return () => {
|
return () => {
|
||||||
ContractListActions.removeContract(contract.id)
|
ContractListActions.removeContract(contract.id)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
ContractListActions.fetchContractList({is_active: 'True'});
|
ContractListActions.fetchContractList({is_active: true});
|
||||||
let notification = new GlobalNotificationModel(response.notification, 'success', 4000);
|
let notification = new GlobalNotificationModel(response.notification, 'success', 4000);
|
||||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
})
|
})
|
||||||
|
@ -141,7 +141,7 @@ let Header = React.createClass({
|
|||||||
<MenuItemLink eventKey="3" to="logout">{getLangText('Log out')}</MenuItemLink>
|
<MenuItemLink eventKey="3" to="logout">{getLangText('Log out')}</MenuItemLink>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
);
|
);
|
||||||
navRoutesLinks = <NavRoutesLinks routes={this.props.routes} navbar right/>;
|
navRoutesLinks = <NavRoutesLinks routes={this.props.routes} userAcl={this.state.currentUser.acl} navbar right/>;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
account = <NavItemLink to="login">{getLangText('LOGIN')}</NavItemLink>;
|
account = <NavItemLink to="login">{getLangText('LOGIN')}</NavItemLink>;
|
||||||
|
@ -3,53 +3,80 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import Nav from 'react-bootstrap/lib/Nav';
|
import Nav from 'react-bootstrap/lib/Nav';
|
||||||
import DropdownButton from 'react-bootstrap/lib/DropdownButton';
|
|
||||||
import MenuItemLink from 'react-router-bootstrap/lib/MenuItemLink';
|
import NavRoutesLinksLink from './nav_routes_links_link';
|
||||||
import NavItemLink from 'react-router-bootstrap/lib/NavItemLink';
|
|
||||||
|
import AclProxy from './acl_proxy';
|
||||||
|
|
||||||
import { sanitizeList } from '../utils/general_utils';
|
import { sanitizeList } from '../utils/general_utils';
|
||||||
|
|
||||||
|
|
||||||
let NavRoutesLinks = React.createClass({
|
let NavRoutesLinks = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
routes: React.PropTypes.element
|
routes: React.PropTypes.element,
|
||||||
|
userAcl: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
extractLinksFromRoutes(node, i) {
|
/**
|
||||||
|
* This method generales a bunch of react-bootstrap specific links
|
||||||
|
* from the routes we defined in one of the specific routes.js file
|
||||||
|
*
|
||||||
|
* We can define a headerTitle as well as a aclName and according to that the
|
||||||
|
* link will be created for a specific user
|
||||||
|
* @param {ReactElement} node Starts at the very top of a routes files root
|
||||||
|
* @param {object} userAcl ACL object we use throughout the whole app
|
||||||
|
* @param {number} i Depth of the route in comparison to the root
|
||||||
|
* @return {Array} Array of ReactElements that can be displayed to the user
|
||||||
|
*/
|
||||||
|
extractLinksFromRoutes(node, userAcl, i) {
|
||||||
if(!node) {
|
if(!node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = node.props;
|
let links = node.props.children.map((child, j) => {
|
||||||
|
let childrenFn = null;
|
||||||
|
let { aclName, headerTitle, name, children } = child.props;
|
||||||
|
|
||||||
let links = node.children.map((child, j) => {
|
// If the node has children that could be rendered, then we want
|
||||||
|
// to execute this function again with the child as the root
|
||||||
|
//
|
||||||
|
// Otherwise we'll just pass childrenFn as false
|
||||||
|
if(child.props.children && child.props.children.length > 0) {
|
||||||
|
childrenFn = this.extractLinksFromRoutes(child, userAcl, i++);
|
||||||
|
}
|
||||||
|
|
||||||
// check if this a candidate for a link generation
|
// We validate if the user has set the title correctly,
|
||||||
if(child.props.headerTitle && typeof child.props.headerTitle === 'string') {
|
// otherwise we're not going to render his route
|
||||||
|
if(headerTitle && typeof headerTitle === 'string') {
|
||||||
// also check if it is a candidate for generating a dropdown menu
|
// if there is an aclName present on the route definition,
|
||||||
if(child.props.children && child.props.children.length > 0) {
|
// we evaluate it against the user's acl
|
||||||
|
if(aclName && typeof aclName !== 'undefined') {
|
||||||
return (
|
return (
|
||||||
<DropdownButton title={child.props.headerTitle} key={j}>
|
<AclProxy
|
||||||
{this.extractLinksFromRoutes(child, i++)}
|
key={j}
|
||||||
</DropdownButton>
|
aclName={aclName}
|
||||||
);
|
aclObject={this.props.userAcl}>
|
||||||
} else if(i === 1) {
|
<NavRoutesLinksLink
|
||||||
// if the node's child is actually a node of level one (a child of a node), we're
|
headerTitle={headerTitle}
|
||||||
// returning a DropdownButton matching MenuItemLink
|
routeName={name}
|
||||||
return (
|
depth={i}
|
||||||
<MenuItemLink to={child.props.name} key={j}>{child.props.headerTitle}</MenuItemLink>
|
children={childrenFn}/>
|
||||||
);
|
</AclProxy>
|
||||||
} else if(i === 0) {
|
|
||||||
return (
|
|
||||||
<NavItemLink to={child.props.name} key={j}>{child.props.headerTitle}</NavItemLink>
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return (
|
||||||
|
<NavRoutesLinksLink
|
||||||
|
key={j}
|
||||||
|
headerTitle={headerTitle}
|
||||||
|
routeName={name}
|
||||||
|
depth={i}
|
||||||
|
children={childrenFn}/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// remove all nulls from the list of generated links
|
// remove all nulls from the list of generated links
|
||||||
@ -57,9 +84,11 @@ let NavRoutesLinks = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
let {routes, userAcl} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Nav {...this.props}>
|
<Nav {...this.props}>
|
||||||
{this.extractLinksFromRoutes(this.props.routes, 0)}
|
{this.extractLinksFromRoutes(routes, userAcl, 0)}
|
||||||
</Nav>
|
</Nav>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
51
js/components/nav_routes_links_link.js
Normal file
51
js/components/nav_routes_links_link.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import DropdownButton from 'react-bootstrap/lib/DropdownButton';
|
||||||
|
import MenuItemLink from 'react-router-bootstrap/lib/MenuItemLink';
|
||||||
|
import NavItemLink from 'react-router-bootstrap/lib/NavItemLink';
|
||||||
|
|
||||||
|
let NavRoutesLinksLink = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
headerTitle: React.PropTypes.string,
|
||||||
|
routeName: React.PropTypes.string,
|
||||||
|
|
||||||
|
children: React.PropTypes.oneOfType([
|
||||||
|
React.PropTypes.arrayOf(React.PropTypes.element),
|
||||||
|
React.PropTypes.element
|
||||||
|
]),
|
||||||
|
|
||||||
|
depth: React.PropTypes.number
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { children, headerTitle, depth, routeName } = this.props;
|
||||||
|
|
||||||
|
// if the route has children, we're returning a DropdownButton that will get filled
|
||||||
|
// with MenuItemLinks
|
||||||
|
if(children) {
|
||||||
|
return (
|
||||||
|
<DropdownButton title={headerTitle}>
|
||||||
|
{children}
|
||||||
|
</DropdownButton>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if(depth === 1) {
|
||||||
|
// if the node's child is actually a node of level one (a child of a node), we're
|
||||||
|
// returning a DropdownButton matching MenuItemLink
|
||||||
|
return (
|
||||||
|
<MenuItemLink to={routeName}>{headerTitle}</MenuItemLink>
|
||||||
|
);
|
||||||
|
} else if(depth === 0) {
|
||||||
|
return (
|
||||||
|
<NavItemLink to={routeName}>{headerTitle}</NavItemLink>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default NavRoutesLinksLink;
|
@ -222,21 +222,7 @@ let CylandRegisterPiece = React.createClass({
|
|||||||
showStartDate={false}
|
showStartDate={false}
|
||||||
showEndDate={false}
|
showEndDate={false}
|
||||||
showPersonalMessage={false}
|
showPersonalMessage={false}
|
||||||
handleSuccess={this.handleLoanSuccess}>
|
handleSuccess={this.handleLoanSuccess} />
|
||||||
<Property
|
|
||||||
name="terms"
|
|
||||||
className="ascribe-settings-property-collapsible-toggle"
|
|
||||||
style={{paddingBottom: 0}}>
|
|
||||||
<InputCheckbox>
|
|
||||||
<span>
|
|
||||||
{' ' + getLangText('I agree to the Terms of Service of Cyland Archive') + ' '}
|
|
||||||
(<a href="https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/cyland/terms_and_contract.pdf" target="_blank" style={{fontSize: '0.9em', color: 'rgba(0,0,0,0.7)'}}>
|
|
||||||
{getLangText('read')}
|
|
||||||
</a>)
|
|
||||||
</span>
|
|
||||||
</InputCheckbox>
|
|
||||||
</Property>
|
|
||||||
</LoanForm>
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
@ -50,21 +50,7 @@ let IkonotvSubmitButton = React.createClass({
|
|||||||
enddate={enddate}
|
enddate={enddate}
|
||||||
gallery="IkonoTV archive"
|
gallery="IkonoTV archive"
|
||||||
showPersonalMessage={false}
|
showPersonalMessage={false}
|
||||||
handleSuccess={this.props.handleSuccess}>
|
handleSuccess={this.props.handleSuccess} />
|
||||||
<Property
|
|
||||||
name="terms"
|
|
||||||
className="ascribe-settings-property-collapsible-toggle"
|
|
||||||
style={{paddingBottom: 0}}>
|
|
||||||
<InputCheckbox>
|
|
||||||
<span>
|
|
||||||
{' ' + getLangText('I agree to the Terms of Service of IkonoTV Archive') + ' '}
|
|
||||||
(<a href="https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/ikonotv/ikono-tos.pdf" target="_blank" style={{fontSize: '0.9em', color: 'rgba(0,0,0,0.7)'}}>
|
|
||||||
{getLangText('read')}
|
|
||||||
</a>)
|
|
||||||
</span>
|
|
||||||
</InputCheckbox>
|
|
||||||
</Property>
|
|
||||||
</LoanForm>
|
|
||||||
</ModalWrapper>
|
</ModalWrapper>
|
||||||
|
|
||||||
);
|
);
|
||||||
|
@ -8,7 +8,6 @@ import UserStore from '../../../../../stores/user_store';
|
|||||||
|
|
||||||
import IkonotvAccordionListItem from './ascribe_accordion_list/ikonotv_accordion_list_item';
|
import IkonotvAccordionListItem from './ascribe_accordion_list/ikonotv_accordion_list_item';
|
||||||
|
|
||||||
|
|
||||||
let IkonotvPieceList = React.createClass({
|
let IkonotvPieceList = React.createClass({
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return UserStore.getState();
|
return UserStore.getState();
|
||||||
|
@ -14,7 +14,8 @@ function getWalletApiUrls(subdomain) {
|
|||||||
else if (subdomain === 'ikonotv'){
|
else if (subdomain === 'ikonotv'){
|
||||||
return {
|
return {
|
||||||
'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/',
|
'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/',
|
||||||
'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/'
|
'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/',
|
||||||
|
'user': walletConstants.walletApiEndpoint + subdomain + '/users/'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
@ -72,7 +72,7 @@ let ROUTES = {
|
|||||||
<Route name="logout" path="logout" handler={LogoutContainer} />
|
<Route name="logout" path="logout" handler={LogoutContainer} />
|
||||||
<Route name="signup" path="signup" handler={SignupContainer} />
|
<Route name="signup" path="signup" handler={SignupContainer} />
|
||||||
<Route name="password_reset" path="password_reset" handler={PasswordResetContainer} />
|
<Route name="password_reset" path="password_reset" handler={PasswordResetContainer} />
|
||||||
<Route name="request_loan" path="request_loan" handler={IkonotvRequestLoan} headerTitle="SEND NEW CONTRACT" />
|
<Route name="request_loan" path="request_loan" handler={IkonotvRequestLoan} headerTitle="SEND NEW CONTRACT" aclName="acl_send_contract" />
|
||||||
<Route name="register_piece" path="register_piece" handler={RegisterPiece} headerTitle="+ NEW WORK"/>
|
<Route name="register_piece" path="register_piece" handler={RegisterPiece} headerTitle="+ NEW WORK"/>
|
||||||
<Route name="pieces" path="collection" handler={IkonotvPieceList} headerTitle="COLLECTION"/>
|
<Route name="pieces" path="collection" handler={IkonotvPieceList} headerTitle="COLLECTION"/>
|
||||||
<Route name="piece" path="pieces/:pieceId" handler={IkonotvPieceContainer} />
|
<Route name="piece" path="pieces/:pieceId" handler={IkonotvPieceContainer} />
|
||||||
|
@ -15,8 +15,33 @@ let OwnershipFetcher = {
|
|||||||
/**
|
/**
|
||||||
* Fetch the contracts of the logged-in user from the API.
|
* Fetch the contracts of the logged-in user from the API.
|
||||||
*/
|
*/
|
||||||
fetchContractList(isActive){
|
fetchContractList(isActive, isPublic, issuer){
|
||||||
return requests.get(ApiUrls.ownership_contract_list, isActive);
|
let queryParams = {
|
||||||
|
isActive,
|
||||||
|
isPublic,
|
||||||
|
issuer
|
||||||
|
};
|
||||||
|
return requests.get(ApiUrls.ownership_contract_list, queryParams);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a contractagreement between the logged-in user and the email from the API with contract.
|
||||||
|
*/
|
||||||
|
createContractAgreement(signee, contractObj){
|
||||||
|
return requests.post(ApiUrls.ownership_contract_agreements, { body: {signee: signee, contract: contractObj.id }});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the contractagreement between the logged-in user and the email from the API.
|
||||||
|
*/
|
||||||
|
fetchContractAgreementList(issuer, accepted, pending) {
|
||||||
|
let queryParams = {
|
||||||
|
issuer,
|
||||||
|
accepted,
|
||||||
|
pending
|
||||||
|
};
|
||||||
|
return requests.get(ApiUrls.ownership_contract_agreements, queryParams);
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchLoanPieceRequestList(){
|
fetchLoanPieceRequestList(){
|
||||||
|
22
js/stores/contract_agreement_list_store.js
Normal file
22
js/stores/contract_agreement_list_store.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import alt from '../alt';
|
||||||
|
import ContractAgreementListActions from '../actions/contract_agreement_list_actions';
|
||||||
|
|
||||||
|
|
||||||
|
class ContractAgreementListStore {
|
||||||
|
constructor() {
|
||||||
|
this.contractAgreementList = null;
|
||||||
|
this.bindActions(ContractAgreementListActions);
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdateContractAgreementList(contractAgreementList) {
|
||||||
|
this.contractAgreementList = contractAgreementList;
|
||||||
|
}
|
||||||
|
|
||||||
|
onFlushContractAgreementList() {
|
||||||
|
this.contractAgreementList = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default alt.createStore(ContractAgreementListStore, 'ContractAgreementListStore');
|
@ -1,28 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import alt from '../alt';
|
|
||||||
import ContractActions from '../actions/contract_actions';
|
|
||||||
|
|
||||||
|
|
||||||
class ContractStore {
|
|
||||||
constructor() {
|
|
||||||
this.contractKey = null;
|
|
||||||
this.contractUrl = null;
|
|
||||||
this.contractEmail = null;
|
|
||||||
this.bindActions(ContractActions);
|
|
||||||
}
|
|
||||||
|
|
||||||
onUpdateContract({contractKey, contractUrl, contractEmail}) {
|
|
||||||
this.contractKey = contractKey;
|
|
||||||
this.contractUrl = contractUrl;
|
|
||||||
this.contractEmail = contractEmail;
|
|
||||||
}
|
|
||||||
|
|
||||||
onFlushContract() {
|
|
||||||
this.contractKey = null;
|
|
||||||
this.contractUrl = null;
|
|
||||||
this.contractEmail = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default alt.createStore(ContractStore, 'ContractStore');
|
|
@ -122,6 +122,34 @@ hr {
|
|||||||
height: 60px;
|
height: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//http://stackoverflow.com/questions/22228239/bootstrap-navbar-static-top-menu-breaks-on-two-lines
|
||||||
|
@media (max-width: 990px) {
|
||||||
|
.navbar-header {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
.navbar-toggle {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.navbar-collapse {
|
||||||
|
border-top: 1px solid transparent;
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255,255,255,0.1);
|
||||||
|
}
|
||||||
|
.navbar-collapse.collapse {
|
||||||
|
display: none!important;
|
||||||
|
}
|
||||||
|
.navbar-nav {
|
||||||
|
float: none!important;
|
||||||
|
margin: 7.5px -15px;
|
||||||
|
}
|
||||||
|
.navbar-nav>li {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
.navbar-nav>li>a {
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.truncate {
|
.truncate {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
Loading…
Reference in New Issue
Block a user