1
0
mirror of https://github.com/ascribe/onion.git synced 2024-11-15 09:35:10 +01:00

loan request up till accept

This commit is contained in:
diminator 2015-08-26 09:50:38 +02:00
parent 5fcee39ed3
commit b2fed6426f
10 changed files with 274 additions and 16 deletions

View File

@ -0,0 +1,39 @@
'use strict';
import alt from '../alt';
import OwnershipFetcher from '../fetchers/ownership_fetcher';
class OwnershipActions {
constructor() {
this.generateActions(
'updateLoanPieceRequestList',
'updateLoanPieceRequest'
);
}
fetchLoanRequestList() {
OwnershipFetcher.fetchLoanPieceRequestList()
.then((data) => {
this.actions.updateLoanPieceRequestList(data.loan_requests);
})
.catch((err) => {
console.logGlobal(err);
this.actions.updateLoanPieceRequestList(null);
});
}
fetchLoanRequest(pieceId) {
OwnershipFetcher.fetchLoanPieceRequestList()
.then((data) => {
let loanRequests = data.loan_requests;
this.actions.updateLoanPieceRequest({loanRequests, pieceId});
})
.catch((err) => {
console.logGlobal(err);
this.actions.flushLoanPieceRequest();
});
}
}
export default alt.createActions(OwnershipActions);

View File

@ -6,6 +6,7 @@ import ConsignForm from '../ascribe_forms/form_consign';
import UnConsignForm from '../ascribe_forms/form_unconsign'; import UnConsignForm from '../ascribe_forms/form_unconsign';
import TransferForm from '../ascribe_forms/form_transfer'; import TransferForm from '../ascribe_forms/form_transfer';
import LoanForm from '../ascribe_forms/form_loan'; import LoanForm from '../ascribe_forms/form_loan';
import LoanRequestAnswerForm from '../ascribe_forms/form_loan_request_answer';
import ShareForm from '../ascribe_forms/form_share_email'; import ShareForm from '../ascribe_forms/form_share_email';
import ModalWrapper from '../ascribe_modal/modal_wrapper'; import ModalWrapper from '../ascribe_modal/modal_wrapper';
import AppConstants from '../../constants/application_constants'; import AppConstants from '../../constants/application_constants';
@ -27,6 +28,8 @@ let AclButton = React.createClass({
React.PropTypes.array React.PropTypes.array
]).isRequired, ]).isRequired,
currentUser: React.PropTypes.object, currentUser: React.PropTypes.object,
buttonAcceptName: React.PropTypes.string,
buttonAcceptClassName: React.PropTypes.string,
handleSuccess: React.PropTypes.func.isRequired, handleSuccess: React.PropTypes.func.isRequired,
className: React.PropTypes.string className: React.PropTypes.string
}, },
@ -89,6 +92,18 @@ let AclButton = React.createClass({
handleSuccess: this.showNotification handleSuccess: this.showNotification
}; };
} }
else if (this.props.action === 'acl_loan_request'){
return {
title: getLangText('Loan artwork'),
tooltip: getLangText('Loan your artwork for a limited period of time'),
form: (<LoanRequestAnswerForm
message={message}
id={this.getFormDataId()}
url={this.isPiece() ? ApiUrls.ownership_loans_pieces : ApiUrls.ownership_loans_editions}/>
),
handleSuccess: this.showNotification
};
}
else if (this.props.action === 'acl_share'){ else if (this.props.action === 'acl_share'){
return { return {
title: getLangText('Share artwork'), title: getLangText('Share artwork'),
@ -140,17 +155,20 @@ let AclButton = React.createClass({
// Removes the acl_ prefix and converts to upper case // Removes the acl_ prefix and converts to upper case
sanitizeAction() { sanitizeAction() {
if (this.props.buttonAcceptName) {
return this.props.buttonAcceptName;
}
return this.props.action.split('acl_')[1].toUpperCase(); return this.props.action.split('acl_')[1].toUpperCase();
}, },
render() { render() {
let shouldDisplay = this.props.availableAcls[this.props.action]; let shouldDisplay = this.props.availableAcls[this.props.action];
let aclProps = this.actionProperties(); let aclProps = this.actionProperties();
let buttonClassName = this.props.buttonAcceptClassName ? this.props.buttonAcceptClassName : '';
return ( return (
<ModalWrapper <ModalWrapper
trigger={ trigger={
<button className={shouldDisplay ? 'btn btn-default btn-sm ' : 'hidden'}> <button className={shouldDisplay ? 'btn btn-default btn-sm ' + buttonClassName : 'hidden'}>
{this.sanitizeAction()} {this.sanitizeAction()}
</button> </button>
} }

View File

@ -28,6 +28,9 @@ let LoanForm = React.createClass({
startdate: React.PropTypes.object, startdate: React.PropTypes.object,
enddate: React.PropTypes.object, enddate: React.PropTypes.object,
showPersonalMessage: React.PropTypes.bool, showPersonalMessage: React.PropTypes.bool,
showEndDate: React.PropTypes.bool,
showStartDate: React.PropTypes.bool,
showPassword: React.PropTypes.bool,
url: React.PropTypes.string, url: React.PropTypes.string,
id: React.PropTypes.object, id: React.PropTypes.object,
message: React.PropTypes.string, message: React.PropTypes.string,
@ -37,7 +40,10 @@ let LoanForm = React.createClass({
getDefaultProps() { getDefaultProps() {
return { return {
loanHeading: '', loanHeading: '',
showPersonalMessage: true showPersonalMessage: true,
showEndDate: false,
showStartDate: false,
showPassword: true
}; };
}, },
@ -155,7 +161,7 @@ let LoanForm = React.createClass({
required/> required/>
</Property> </Property>
<Property <Property
name='gallery_name' name='gallery'
label={getLangText('Gallery/exhibition (optional)')} label={getLangText('Gallery/exhibition (optional)')}
editable={!this.props.gallery} editable={!this.props.gallery}
overrideForm={!!this.props.gallery}> overrideForm={!!this.props.gallery}>
@ -167,7 +173,7 @@ let LoanForm = React.createClass({
<Property <Property
name='startdate' name='startdate'
label={getLangText('Start date')} label={getLangText('Start date')}
hidden={this.props.startdate}> hidden={!this.props.showStartDate}>
<InputDate <InputDate
defaultValue={this.props.startdate} defaultValue={this.props.startdate}
placeholderText={getLangText('Loan start date')} /> placeholderText={getLangText('Loan start date')} />
@ -175,7 +181,7 @@ let LoanForm = React.createClass({
<Property <Property
name='enddate' name='enddate'
label={getLangText('End date')} label={getLangText('End date')}
hidden={this.props.enddate}> hidden={!this.props.showEndDate}>
<InputDate <InputDate
defaultValue={this.props.enddate} defaultValue={this.props.enddate}
placeholderText={getLangText('Loan end date')} /> placeholderText={getLangText('Loan end date')} />
@ -194,11 +200,12 @@ let LoanForm = React.createClass({
</Property> </Property>
<Property <Property
name='password' name='password'
label={getLangText('Password')}> label={getLangText('Password')}
hidden={!this.props.showPassword}>
<input <input
type="password" type="password"
placeholder={getLangText('Enter your password')} placeholder={getLangText('Enter your password')}
required/> required={this.props.showPassword ? 'required' : ''}/>
</Property> </Property>
{this.getContractCheckbox()} {this.getContractCheckbox()}
{this.props.children} {this.props.children}

View File

@ -0,0 +1,88 @@
'use strict';
import React from 'react';
import classnames from 'classnames';
import Button from 'react-bootstrap/lib/Button';
import LoanForm from './form_loan';
import Property from './property';
import InputTextAreaToggable from './input_textarea_toggable';
import InputDate from './input_date';
import InputCheckbox from './input_checkbox';
import OwnershipActions from '../../actions/ownership_actions';
import OwnershipStore from '../../stores/ownership_store';
import AppConstants from '../../constants/application_constants';
import { getLangText } from '../../utils/lang_utils';
let LoanRequestAnswerForm = React.createClass({
propTypes: {
loanHeading: React.PropTypes.string,
email: React.PropTypes.string,
gallery: React.PropTypes.string,
startdate: React.PropTypes.object,
enddate: React.PropTypes.object,
showPersonalMessage: React.PropTypes.bool,
showEndDate: React.PropTypes.bool,
showStartDate: React.PropTypes.bool,
showPassword: React.PropTypes.bool,
url: React.PropTypes.string,
id: React.PropTypes.object,
message: React.PropTypes.string,
handleSuccess: React.PropTypes.func
},
getDefaultProps() {
return {
loanHeading: '',
showPersonalMessage: true,
showEndDate: false,
showStartDate: false,
showPassword: true
};
},
getInitialState() {
return OwnershipStore.getState();
},
componentDidMount() {
OwnershipStore.listen(this.onChange);
OwnershipActions.fetchLoanRequest(this.props.id.piece_id);
},
componentWillUnmount() {
OwnershipStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
render() {
console.log(this.state.loanRequest)
if (this.state.loanRequest) {
return (
<LoanForm
loanHeading={null}
message={''}
id={this.props.id}
url={this.props.url}
email={""}
gallery={this.state.loanRequest.gallery}
showPassword={true}
showPersonalMessage={false}
handleSuccess={this.handleLoanSuccess}/>
);
}
return null;
}
});
export default LoanRequestAnswerForm;

View File

@ -90,6 +90,18 @@ let RequestActionForm = React.createClass({
<AclButton <AclButton
availableAcls={{'acl_unconsign': true}} availableAcls={{'acl_unconsign': true}}
action="acl_unconsign" action="acl_unconsign"
buttonAcceptClassName='inline pull-right'
pieceOrEditions={this.props.pieceOrEditions}
currentUser={this.props.currentUser}
handleSuccess={this.props.handleSuccess} />
);
} else if(this.props.requestAction === 'loan_request') {
return (
<AclButton
availableAcls={{'acl_loan_request': true}}
action="acl_loan_request"
buttonAcceptName="LOAN"
buttonAcceptClassName='inline pull-right'
pieceOrEditions={this.props.pieceOrEditions} pieceOrEditions={this.props.pieceOrEditions}
currentUser={this.props.currentUser} currentUser={this.props.currentUser}
handleSuccess={this.props.handleSuccess} /> handleSuccess={this.props.handleSuccess} />

View File

@ -2,6 +2,7 @@
import React from 'react'; import React from 'react';
import Router from 'react-router'; import Router from 'react-router';
import Moment from 'moment';
import StarRating from 'react-star-rating'; import StarRating from 'react-star-rating';
@ -15,6 +16,7 @@ import PrizeRatingActions from '../../actions/prize_rating_actions';
import PrizeRatingStore from '../../stores/prize_rating_store'; import PrizeRatingStore from '../../stores/prize_rating_store';
import UserStore from '../../../../../stores/user_store'; import UserStore from '../../../../../stores/user_store';
import WhitelabelStore from '../../../../../stores/whitelabel_store';
import Piece from '../../../../../components/ascribe_detail/piece'; import Piece from '../../../../../components/ascribe_detail/piece';
import Note from '../../../../../components/ascribe_detail/note'; import Note from '../../../../../components/ascribe_detail/note';
@ -27,6 +29,9 @@ import InputTextAreaToggable from '../../../../../components/ascribe_forms/input
import CollapsibleParagraph from '../../../../../components/ascribe_collapsible/collapsible_paragraph'; import CollapsibleParagraph from '../../../../../components/ascribe_collapsible/collapsible_paragraph';
import InputCheckbox from '../../../../ascribe_forms/input_checkbox'; import InputCheckbox from '../../../../ascribe_forms/input_checkbox';
import LoanForm from '../../../../ascribe_forms/form_loan';
import RequestActionForm from '../../../../ascribe_forms/form_request_action';
import ModalWrapper from '../../../../ascribe_modal/modal_wrapper';
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';
@ -61,7 +66,6 @@ let PieceContainer = React.createClass({
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if(this.props.params.pieceId !== nextProps.params.pieceId) { if(this.props.params.pieceId !== nextProps.params.pieceId) {
PieceActions.updatePiece({}); PieceActions.updatePiece({});
console.log('update')
PieceActions.fetchOne(nextProps.params.pieceId); PieceActions.fetchOne(nextProps.params.pieceId);
} }
}, },
@ -86,6 +90,21 @@ let PieceContainer = React.createClass({
this.setState(this.state); this.setState(this.state);
}, },
getActions(){
if (this.state.piece &&
this.state.piece.request_action &&
this.state.piece.request_action.length > 0) {
return (
<RequestActionForm
currentUser={this.state.currentUser}
pieceOrEditions={ this.state.piece }
requestAction={this.state.piece.request_action}
requestUser={this.state.piece.user_registered}
handleSuccess={this.loadPiece}/>);
}
return null;
},
render() { render() {
if('title' in this.state.piece) { if('title' in this.state.piece) {
let artistName = ((this.state.currentUser.is_jury && !this.state.currentUser.is_judge) || let artistName = ((this.state.currentUser.is_jury && !this.state.currentUser.is_judge) ||
@ -104,6 +123,7 @@ let PieceContainer = React.createClass({
<h1 className="ascribe-detail-title">{this.state.piece.title}</h1> <h1 className="ascribe-detail-title">{this.state.piece.title}</h1>
<DetailProperty label="BY" value={artistName} /> <DetailProperty label="BY" value={artistName} />
<DetailProperty label="DATE" value={ this.state.piece.date_created.slice(0, 4) } /> <DetailProperty label="DATE" value={ this.state.piece.date_created.slice(0, 4) } />
{this.getActions()}
<hr/> <hr/>
</div> </div>
} }
@ -169,7 +189,8 @@ let PrizePieceRatings = React.createClass({
getInitialState() { getInitialState() {
return mergeOptions( return mergeOptions(
PieceListStore.getState(), PieceListStore.getState(),
PrizeRatingStore.getState() PrizeRatingStore.getState(),
WhitelabelStore.getState()
); );
}, },
@ -178,6 +199,7 @@ let PrizePieceRatings = React.createClass({
PrizeRatingActions.fetchOne(this.props.piece.id); PrizeRatingActions.fetchOne(this.props.piece.id);
PrizeRatingActions.fetchAverage(this.props.piece.id); PrizeRatingActions.fetchAverage(this.props.piece.id);
PieceListStore.listen(this.onChange); PieceListStore.listen(this.onChange);
WhitelabelStore.listen(this.onChange);
}, },
componentWillUnmount() { componentWillUnmount() {
@ -188,6 +210,7 @@ let PrizePieceRatings = React.createClass({
PrizeRatingActions.updateRating({}); PrizeRatingActions.updateRating({});
PrizeRatingStore.unlisten(this.onChange); PrizeRatingStore.unlisten(this.onChange);
PieceListStore.unlisten(this.onChange); PieceListStore.unlisten(this.onChange);
WhitelabelStore.unlisten(this.onChange);
}, },
// The StarRating component does not have a property that lets us set // The StarRating component does not have a property that lets us set
@ -213,6 +236,39 @@ let PrizePieceRatings = React.createClass({
); );
}, },
getLoanButton(){
let today = new Moment();
let endDate = new Moment();
endDate.add(6, 'months');
return (
<ModalWrapper
trigger={
<button className='btn btn-default btn-sm'>
SEND LOAN REQUEST
</button>
}
handleSuccess={this.handleLoanRequestSuccess}
title='REQUEST LOAN'>
<LoanForm
loanHeading={null}
message={'Congratulations,\nYou have been selected for the sluice screens.\n' +
'Please accept the loan request to proceed\n\nBest regards,\n\nSluice.'}
id={{piece_id: this.props.piece.id}}
url={ApiUrls.ownership_loans_pieces_request}
email={this.state.whitelabel.user}
gallery={this.props.piece.prize.name}
startdate={today}
enddate={endDate}
showPersonalMessage={true}
showStartDate={true}
showEndDate={true}
showPassword={false}
handleSuccess={this.handleLoanSuccess} />
</ModalWrapper>);
},
handleLoanRequestSuccess(){},
refreshPieceData() { refreshPieceData() {
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
this.state.orderBy, this.state.orderAsc, this.state.filterBy); this.state.orderBy, this.state.orderAsc, this.state.filterBy);
@ -241,10 +297,7 @@ let PrizePieceRatings = React.createClass({
</InputCheckbox> </InputCheckbox>
</span> </span>
<span className="pull-right"> <span className="pull-right">
{this.props.piece.selected ? {this.props.piece.selected ? this.getLoanButton() : null}
<button className={'btn btn-default btn-sm '}>
SEND LOAN REQUEST
</button> : null}
</span> </span>
</div> </div>
<hr /> <hr />

View File

@ -32,6 +32,7 @@ let ApiUrls = {
'ownership_loans_pieces': AppConstants.apiEndpoint + 'ownership/loans/pieces/', 'ownership_loans_pieces': AppConstants.apiEndpoint + 'ownership/loans/pieces/',
'ownership_loans_pieces_confirm': AppConstants.apiEndpoint + 'ownership/loans/pieces/confirm/', 'ownership_loans_pieces_confirm': AppConstants.apiEndpoint + 'ownership/loans/pieces/confirm/',
'ownership_loans_pieces_deny': AppConstants.apiEndpoint + 'ownership/loans/pieces/deny/', 'ownership_loans_pieces_deny': AppConstants.apiEndpoint + 'ownership/loans/pieces/deny/',
'ownership_loans_pieces_request': AppConstants.apiEndpoint + 'ownership/loans/pieces/request/',
'ownership_loans_editions': AppConstants.apiEndpoint + 'ownership/loans/editions/', 'ownership_loans_editions': AppConstants.apiEndpoint + 'ownership/loans/editions/',
'ownership_loans_confirm': AppConstants.apiEndpoint + 'ownership/loans/editions/confirm/', 'ownership_loans_confirm': AppConstants.apiEndpoint + 'ownership/loans/editions/confirm/',
'ownership_loans_deny': AppConstants.apiEndpoint + 'ownership/loans/editions/deny/', 'ownership_loans_deny': AppConstants.apiEndpoint + 'ownership/loans/editions/deny/',

View File

@ -17,8 +17,11 @@ let OwnershipFetcher = {
*/ */
fetchLoanContractList(){ fetchLoanContractList(){
return requests.get(ApiUrls.ownership_loans_contract); return requests.get(ApiUrls.ownership_loans_contract);
} },
fetchLoanPieceRequestList(){
return requests.get(ApiUrls.ownership_loans_pieces_request);
}
}; };
export default OwnershipFetcher; export default OwnershipFetcher;

View File

@ -0,0 +1,35 @@
'use strict';
import alt from '../alt';
import OwnershipActions from '../actions/ownership_actions';
class OwnershipStore {
constructor() {
this.loanRequestList = [];
this.loanRequest = null;
this.bindActions(OwnershipActions);
}
onUpdateLoanPieceRequestList(loanRequests) {
this.loanRequestList = loanRequests;
}
onUpdateLoanPieceRequest({loanRequests, pieceId}) {
this.loanRequestList = loanRequests;
this.loanRequest = loanRequests.filter((item) => item.piece_id === pieceId.toString());
if (this.loanRequest.length > 0){
this.loanRequest = this.loanRequest[0];
}
else {
this.loanRequest = null;
}
}
flushLoanPieceRequest(){
this.loanRequestList = [];
this.loanRequest = null;
}
}
export default alt.createStore(OwnershipStore, 'OwnershipStore');

View File

@ -23,6 +23,8 @@ export function getAclFormMessage(aclName, entities, senderName) {
message += getLangText('I un-consign'); message += getLangText('I un-consign');
} else if(aclName === 'acl_loan') { } else if(aclName === 'acl_loan') {
message += getLangText('I loan'); message += getLangText('I loan');
} else if(aclName === 'acl_loan_request') {
message += getLangText('I request to loan');
} else if(aclName === 'acl_share') { } else if(aclName === 'acl_share') {
message += getLangText('I share'); message += getLangText('I share');
} else { } else {
@ -34,7 +36,7 @@ export function getAclFormMessage(aclName, entities, senderName) {
if(aclName === 'acl_transfer' || aclName === 'acl_loan' || aclName === 'acl_consign') { if(aclName === 'acl_transfer' || aclName === 'acl_loan' || aclName === 'acl_consign') {
message += getLangText('to you'); message += getLangText('to you');
} else if(aclName === 'acl_unconsign') { } else if(aclName === 'acl_unconsign' || aclName === 'acl_loan_request') {
message += getLangText('from you'); message += getLangText('from you');
} else if(aclName === 'acl_share') { } else if(aclName === 'acl_share') {
message += getLangText('with you'); message += getLangText('with you');