1
0
mirror of https://github.com/ascribe/onion.git synced 2024-12-23 01:39:36 +01:00

Merge branch 'AD-1255-refactor-aclbuttons-form-creatio' into AD-1309-change-share-to-email

This commit is contained in:
Brett Sun 2015-11-09 20:08:11 +01:00
commit 61cd316a86
22 changed files with 456 additions and 283 deletions

View File

@ -1,187 +0,0 @@
'use strict';
import React from 'react';
import ConsignForm from '../ascribe_forms/form_consign';
import UnConsignForm from '../ascribe_forms/form_unconsign';
import TransferForm from '../ascribe_forms/form_transfer';
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 ModalWrapper from '../ascribe_modal/modal_wrapper';
import AppConstants from '../../constants/application_constants';
import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions';
import ApiUrls from '../../constants/api_urls';
import { getAclFormMessage } from '../../utils/form_utils';
import { getLangText } from '../../utils/lang_utils';
let AclButton = React.createClass({
propTypes: {
action: React.PropTypes.oneOf(AppConstants.aclList).isRequired,
availableAcls: React.PropTypes.object.isRequired,
pieceOrEditions: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
]).isRequired,
currentUser: React.PropTypes.object,
buttonAcceptName: React.PropTypes.string,
buttonAcceptClassName: React.PropTypes.string,
handleSuccess: React.PropTypes.func.isRequired,
className: React.PropTypes.string
},
isPiece(){
return this.props.pieceOrEditions.constructor !== Array;
},
actionProperties(){
let message = getAclFormMessage(this.props.action, this.getTitlesString(), this.props.currentUser.username);
if (this.props.action === 'acl_consign'){
return {
title: getLangText('Consign artwork'),
tooltip: getLangText('Have someone else sell the artwork'),
form: (
<ConsignForm
message={message}
id={this.getFormDataId()}
url={ApiUrls.ownership_consigns}/>
),
handleSuccess: this.showNotification
};
}
if (this.props.action === 'acl_unconsign'){
return {
title: getLangText('Unconsign artwork'),
tooltip: getLangText('Have the owner manage his sales again'),
form: (
<UnConsignForm
message={message}
id={this.getFormDataId()}
url={ApiUrls.ownership_unconsigns}/>
),
handleSuccess: this.showNotification
};
}else if (this.props.action === 'acl_transfer') {
return {
title: getLangText('Transfer artwork'),
tooltip: getLangText('Transfer the ownership of the artwork'),
form: (
<TransferForm
message={message}
id={this.getFormDataId()}
url={ApiUrls.ownership_transfers}/>
),
handleSuccess: this.showNotification
};
}
else if (this.props.action === 'acl_loan'){
return {
title: getLangText('Loan artwork'),
tooltip: getLangText('Loan your artwork for a limited period of time'),
form: (<LoanForm
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_loan_request'){
return {
title: getLangText('Loan artwork'),
tooltip: getLangText('Someone requested you to loan your artwork for a limited period of time'),
form: (<LoanRequestAnswerForm
message={message}
id={this.getFormDataId()}
url={ApiUrls.ownership_loans_pieces_request_confirm}/>
),
handleSuccess: this.showNotification
};
}
else if (this.props.action === 'acl_share'){
return {
title: getLangText('Share artwork'),
tooltip: getLangText('Share the artwork'),
form: (
<ShareForm
message={message}
id={this.getFormDataId()}
url={this.isPiece() ? ApiUrls.ownership_shares_pieces : ApiUrls.ownership_shares_editions }/>
),
handleSuccess: this.showNotification
};
} else {
throw new Error('Your specified action did not match a form.');
}
},
showNotification(response){
this.props.handleSuccess();
if(response.notification) {
let notification = new GlobalNotificationModel(response.notification, 'success');
GlobalNotificationActions.appendGlobalNotification(notification);
}
},
// plz move to share form
getTitlesString(){
if (this.isPiece()){
return '\"' + this.props.pieceOrEditions.title + '\"';
}
else {
return this.props.pieceOrEditions.map(function(edition) {
return '- \"' + edition.title + ', ' + getLangText('edition') + ' ' + edition.edition_number + '\"\n';
}).join('');
}
},
getFormDataId(){
if (this.isPiece()) {
return {piece_id: this.props.pieceOrEditions.id};
}
else {
return {bitcoin_id: this.props.pieceOrEditions.map(function(edition){
return edition.bitcoin_id;
}).join()};
}
},
// Removes the acl_ prefix and converts to upper case
sanitizeAction() {
if (this.props.buttonAcceptName) {
return this.props.buttonAcceptName;
}
return this.props.action.split('acl_')[1].toUpperCase();
},
render() {
if (this.props.availableAcls){
let shouldDisplay = this.props.availableAcls[this.props.action];
let aclProps = this.actionProperties();
let buttonClassName = this.props.buttonAcceptClassName ? this.props.buttonAcceptClassName : '';
return (
<ModalWrapper
trigger={
<button
className={shouldDisplay ? 'btn btn-default btn-sm ' + buttonClassName : 'hidden'}>
{this.sanitizeAction()}
</button>
}
handleSuccess={aclProps.handleSuccess}
title={aclProps.title}>
{aclProps.form}
</ModalWrapper>
);
}
return null;
}
});
export default AclButton;

View File

@ -5,21 +5,25 @@ import React from 'react/addons';
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 AclButton from '../ascribe_buttons/acl_button'; import ConsignButton from './acls/consign_button';
import LoanButton from './acls/loan_button';
import LoanRequestButton from './acls/loan_request_button';
import ShareButton from './acls/share_button';
import TransferButton from './acls/transfer_button';
import UnconsignButton from './acls/unconsign_button';
import { mergeOptions } from '../../utils/general_utils'; import { mergeOptions } from '../../utils/general_utils';
let AclButtonList = React.createClass({ let AclButtonList = React.createClass({
propTypes: { propTypes: {
className: React.PropTypes.string, className: React.PropTypes.string,
editions: React.PropTypes.oneOfType([ pieceOrEditions: React.PropTypes.oneOfType([
React.PropTypes.object, React.PropTypes.object,
React.PropTypes.array React.PropTypes.array
]), ]).isRequired,
availableAcls: React.PropTypes.object, availableAcls: React.PropTypes.object.isRequired,
buttonsStyle: React.PropTypes.object, buttonsStyle: React.PropTypes.object,
handleSuccess: React.PropTypes.func, handleSuccess: React.PropTypes.func.isRequired,
children: React.PropTypes.oneOfType([ children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element), React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element React.PropTypes.element
@ -78,7 +82,7 @@ let AclButtonList = React.createClass({
const { className, const { className,
buttonsStyle, buttonsStyle,
availableAcls, availableAcls,
editions, pieceOrEditions,
handleSuccess } = this.props; handleSuccess } = this.props;
const { currentUser } = this.state; const { currentUser } = this.state;
@ -86,34 +90,29 @@ let AclButtonList = React.createClass({
return ( return (
<div className={className}> <div className={className}>
<span ref="buttonList" style={buttonsStyle}> <span ref="buttonList" style={buttonsStyle}>
<AclButton <ShareButton
availableAcls={availableAcls} availableAcls={availableAcls}
action="acl_share" pieceOrEditions={pieceOrEditions}
pieceOrEditions={editions}
currentUser={currentUser} currentUser={currentUser}
handleSuccess={handleSuccess} /> handleSuccess={handleSuccess} />
<AclButton <TransferButton
availableAcls={availableAcls} availableAcls={availableAcls}
action="acl_transfer" pieceOrEditions={pieceOrEditions}
pieceOrEditions={editions}
currentUser={currentUser} currentUser={currentUser}
handleSuccess={handleSuccess}/> handleSuccess={handleSuccess}/>
<AclButton <ConsignButton
availableAcls={availableAcls} availableAcls={availableAcls}
action="acl_consign" pieceOrEditions={pieceOrEditions}
pieceOrEditions={editions}
currentUser={currentUser} currentUser={currentUser}
handleSuccess={handleSuccess} /> handleSuccess={handleSuccess} />
<AclButton <UnconsignButton
availableAcls={availableAcls} availableAcls={availableAcls}
action="acl_unconsign" pieceOrEditions={pieceOrEditions}
pieceOrEditions={editions}
currentUser={currentUser} currentUser={currentUser}
handleSuccess={handleSuccess} /> handleSuccess={handleSuccess} />
<AclButton <LoanButton
availableAcls={availableAcls} availableAcls={availableAcls}
action="acl_loan" pieceOrEditions={pieceOrEditions}
pieceOrEditions={editions}
currentUser={currentUser} currentUser={currentUser}
handleSuccess={handleSuccess} /> handleSuccess={handleSuccess} />
{this.renderChildren()} {this.renderChildren()}

View File

@ -0,0 +1,85 @@
'use strict';
import React from 'react';
import classNames from 'classnames';
import AclProxy from '../../acl_proxy';
import AclFormFactory from '../../ascribe_forms/acl_form_factory';
import ModalWrapper from '../../ascribe_modal/modal_wrapper';
import AppConstants from '../../../constants/application_constants';
import GlobalNotificationModel from '../../../models/global_notification_model';
import GlobalNotificationActions from '../../../actions/global_notification_actions';
import ApiUrls from '../../../constants/api_urls';
import { getAclFormMessage, getAclFormDataId } from '../../../utils/form_utils';
import { getLangText } from '../../../utils/lang_utils';
export default function ({ action, displayName, title, tooltip }) {
if (AppConstants.aclList.indexOf(action) < 0) {
console.warn('Your specified aclName did not match a an acl class.');
}
return React.createClass({
displayName: displayName,
propTypes: {
availableAcls: React.PropTypes.object.isRequired,
buttonAcceptName: React.PropTypes.string,
buttonAcceptClassName: React.PropTypes.string,
currentUser: React.PropTypes.object.isRequired,
email: React.PropTypes.string,
pieceOrEditions: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
]).isRequired,
handleSuccess: React.PropTypes.func.isRequired,
className: React.PropTypes.string
},
// Removes the acl_ prefix and converts to upper case
sanitizeAction() {
if (this.props.buttonAcceptName) {
return this.props.buttonAcceptName;
}
return action.split('acl_')[1].toUpperCase();
},
render() {
const {
availableAcls,
buttonAcceptClassName,
currentUser,
email,
pieceOrEditions,
handleSuccess } = this.props;
return (
<AclProxy
aclName={action}
aclObject={availableAcls}>
<ModalWrapper
trigger={
<button
className={classNames('btn', 'btn-default', 'btn-sm', buttonAcceptClassName)}>
{this.sanitizeAction()}
</button>
}
handleSuccess={handleSuccess}
title={title}>
<AclFormFactory
action={action}
currentUser={currentUser}
email={email}
pieceOrEditions={pieceOrEditions}
showNotification />
</ModalWrapper>
</AclProxy>
);
}
});
}

View File

@ -0,0 +1,14 @@
'use strict';
import React from 'react';
import AclButton from './acl_button';
import { getLangText } from '../../../utils/lang_utils';
export default AclButton({
action: 'acl_consign',
displayName: 'ConsignButton',
title: getLangText('Consign artwork'),
tooltip: getLangText('Have someone else sell the artwork')
});

View File

@ -0,0 +1,14 @@
'use strict';
import React from 'react';
import AclButton from './acl_button';
import { getLangText } from '../../../utils/lang_utils';
export default AclButton({
action: 'acl_loan',
displayName: 'LoanButton',
title: getLangText('Loan artwork'),
tooltip: getLangText('Loan your artwork for a limited period of time')
});

View File

@ -0,0 +1,14 @@
'use strict';
import React from 'react';
import AclButton from './acl_button';
import { getLangText } from '../../../utils/lang_utils';
export default AclButton({
action: 'acl_loan_request',
displayName: 'LoanRequestButton',
title: getLangText('Loan artwork'),
tooltip: getLangText('Someone requested you to loan your artwork for a limited period of time')
});

View File

@ -0,0 +1,14 @@
'use strict';
import React from 'react';
import AclButton from './acl_button';
import { getLangText } from '../../../utils/lang_utils';
export default AclButton({
action: 'acl_share',
displayName: 'ShareButton',
title: getLangText('Share artwork'),
tooltip: getLangText('Share the artwork')
});

View File

@ -0,0 +1,14 @@
'use strict';
import React from 'react';
import AclButton from './acl_button';
import { getLangText } from '../../../utils/lang_utils';
export default AclButton({
action: 'acl_transfer',
displayName: 'TransferButton',
title: getLangText('Transfer artwork'),
tooltip: getLangText('Transfer the ownership of the artwork')
});

View File

@ -0,0 +1,14 @@
'use strict';
import React from 'react';
import AclButton from './acl_button';
import { getLangText } from '../../../utils/lang_utils';
export default AclButton({
action: 'acl_unconsign',
displayName: 'UnconsignButton',
title: getLangText('Unconsign artwork'),
tooltip: getLangText('Have the owner manage his sales again')
});

View File

@ -107,7 +107,7 @@ let EditionActionPanel = React.createClass({
<AclButtonList <AclButtonList
className="ascribe-button-list" className="ascribe-button-list"
availableAcls={edition.acl} availableAcls={edition.acl}
editions={[edition]} pieceOrEditions={[edition]}
handleSuccess={this.handleSuccess}> handleSuccess={this.handleSuccess}>
<AclProxy <AclProxy
aclObject={edition.acl} aclObject={edition.acl}

View File

@ -201,7 +201,7 @@ let PieceContainer = React.createClass({
<AclButtonList <AclButtonList
className="ascribe-button-list" className="ascribe-button-list"
availableAcls={piece.acl} availableAcls={piece.acl}
editions={piece} pieceOrEditions={piece}
handleSuccess={this.loadPiece}> handleSuccess={this.loadPiece}>
<CreateEditionsButton <CreateEditionsButton
label={getLangText('CREATE EDITIONS')} label={getLangText('CREATE EDITIONS')}

View File

@ -0,0 +1,128 @@
'use strict';
import React from 'react';
import ConsignForm from '../ascribe_forms/form_consign';
import UnConsignForm from '../ascribe_forms/form_unconsign';
import TransferForm from '../ascribe_forms/form_transfer';
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 AppConstants from '../../constants/application_constants';
import ApiUrls from '../../constants/api_urls';
import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions';
import { getAclFormMessage, getAclFormDataId } from '../../utils/form_utils';
let AclFormFactory = React.createClass({
propTypes: {
action: React.PropTypes.oneOf(AppConstants.aclList).isRequired,
currentUser: React.PropTypes.object.isRequired,
email: React.PropTypes.string,
message: React.PropTypes.string,
pieceOrEditions: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
]).isRequired,
handleSuccess: React.PropTypes.func,
showNotification: React.PropTypes.bool
},
isPiece() {
return this.props.pieceOrEditions.constructor !== Array;
},
getFormDataId() {
return getAclFormDataId(this.isPiece(), this.props.pieceOrEditions);
},
showSuccessNotification(response) {
if (typeof this.props.handleSuccess === 'function') {
this.props.handleSuccess();
}
if (response.notification) {
const notification = new GlobalNotificationModel(response.notification, 'success');
GlobalNotificationActions.appendGlobalNotification(notification);
}
},
render() {
const {
action,
pieceOrEditions,
currentUser,
email,
message,
handleSuccess,
showNotification } = this.props;
const formMessage = message || getAclFormMessage({
aclName: action,
entities: pieceOrEditions,
isPiece: this.isPiece(),
senderName: currentUser.username
});
if (action === 'acl_consign') {
return (
<ConsignForm
email={email}
message={formMessage}
id={this.getFormDataId()}
url={ApiUrls.ownership_consigns}
handleSuccess={showNotification ? this.showSuccessNotification : handleSuccess} />
);
} else if (action === 'acl_unconsign') {
return (
<UnConsignForm
message={formMessage}
id={this.getFormDataId()}
url={ApiUrls.ownership_unconsigns}
handleSuccess={showNotification ? this.showSuccessNotification : handleSuccess} />
);
} else if (action === 'acl_transfer') {
return (
<TransferForm
message={formMessage}
id={this.getFormDataId()}
url={ApiUrls.ownership_transfers}
handleSuccess={showNotification ? this.showSuccessNotification : handleSuccess} />
);
} else if (action === 'acl_loan') {
return (
<LoanForm
email={email}
message={formMessage}
id={this.getFormDataId()}
url={this.isPiece() ? ApiUrls.ownership_loans_pieces
: ApiUrls.ownership_loans_editions}
handleSuccess={showNotification ? this.showSuccessNotification : handleSuccess} />
);
} else if (action === 'acl_loan_request') {
return (
<LoanRequestAnswerForm
message={formMessage}
id={this.getFormDataId()}
url={ApiUrls.ownership_loans_pieces_request_confirm}
handleSuccess={showNotification ? this.showSuccessNotification : handleSuccess} />
);
} else if (action === 'acl_share') {
return (
<ShareForm
message={formMessage}
id={this.getFormDataId()}
url={this.isPiece() ? ApiUrls.ownership_shares_pieces
: ApiUrls.ownership_shares_editions}
handleSuccess={showNotification ? this.showSuccessNotification : handleSuccess} />
);
} else {
throw new Error('Your specified action did not match a form.');
}
}
});
export default AclFormFactory;

View File

@ -2,10 +2,13 @@
import React from 'react'; import React from 'react';
import AclButton from './../ascribe_buttons/acl_button';
import ActionPanel from '../ascribe_panel/action_panel';
import Form from './form'; import Form from './form';
import LoanRequestButton from '../ascribe_buttons/acls/loan_request_button';
import UnconsignButton from '../ascribe_buttons/acls/unconsign_button';
import ActionPanel from '../ascribe_panel/action_panel';
import NotificationActions from '../../actions/notification_actions'; import NotificationActions from '../../actions/notification_actions';
import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationModel from '../../models/global_notification_model';
@ -13,9 +16,9 @@ import GlobalNotificationActions from '../../actions/global_notification_actions
import ApiUrls from '../../constants/api_urls'; import ApiUrls from '../../constants/api_urls';
import { getAclFormDataId } from '../../utils/form_utils';
import { getLangText } from '../../utils/lang_utils.js'; import { getLangText } from '../../utils/lang_utils.js';
let RequestActionForm = React.createClass({ let RequestActionForm = React.createClass({
propTypes: { propTypes: {
pieceOrEditions: React.PropTypes.oneOfType([ pieceOrEditions: React.PropTypes.oneOfType([
@ -55,36 +58,27 @@ let RequestActionForm = React.createClass({
}, },
getFormData() { getFormData() {
if (this.isPiece()) { return getAclFormDataId(this.isPiece(), this.props.pieceOrEditions);
return {piece_id: this.props.pieceOrEditions.id};
}
else {
return {bitcoin_id: this.props.pieceOrEditions.map(function(edition){
return edition.bitcoin_id;
}).join()};
}
}, },
showNotification(option, action, owner) { showNotification(option, action, owner) {
return () => { return () => {
let message = getLangText('You have successfully') + ' ' + option + ' the ' + action + ' request ' + getLangText('from') + ' ' + owner; const message = getLangText('You have successfully %s the %s request from %s', getLangText(option), getLangText(action), owner);
const notifications = new GlobalNotificationModel(message, 'success');
let notifications = new GlobalNotificationModel(message, 'success');
GlobalNotificationActions.appendGlobalNotification(notifications); GlobalNotificationActions.appendGlobalNotification(notifications);
this.handleSuccess(); this.handleSuccess();
}; };
}, },
handleSuccess() { handleSuccess() {
if (this.isPiece()) { if (this.isPiece()) {
NotificationActions.fetchPieceListNotifications(); NotificationActions.fetchPieceListNotifications();
} } else {
else {
NotificationActions.fetchEditionListNotifications(); NotificationActions.fetchEditionListNotifications();
} }
if(this.props.handleSuccess) {
if (typeof this.props.handleSuccess === 'function') {
this.props.handleSuccess(); this.props.handleSuccess();
} }
}, },
@ -100,9 +94,8 @@ let RequestActionForm = React.createClass({
getAcceptButtonForm(urls) { getAcceptButtonForm(urls) {
if (this.props.notifications.action === 'unconsign') { if (this.props.notifications.action === 'unconsign') {
return ( return (
<AclButton <UnconsignButton
availableAcls={{'acl_unconsign': true}} availableAcls={{'acl_unconsign': true}}
action="acl_unconsign"
buttonAcceptClassName='inline pull-right btn-sm ascribe-margin-1px' buttonAcceptClassName='inline pull-right btn-sm ascribe-margin-1px'
pieceOrEditions={this.props.pieceOrEditions} pieceOrEditions={this.props.pieceOrEditions}
currentUser={this.props.currentUser} currentUser={this.props.currentUser}
@ -110,9 +103,8 @@ let RequestActionForm = React.createClass({
); );
} else if (this.props.notifications.action === 'loan_request') { } else if (this.props.notifications.action === 'loan_request') {
return ( return (
<AclButton <LoanRequestButton
availableAcls={{'acl_loan_request': true}} availableAcls={{'acl_loan_request': true}}
action="acl_loan_request"
buttonAcceptName="LOAN" buttonAcceptName="LOAN"
buttonAcceptClassName='inline pull-right btn-sm ascribe-margin-1px' buttonAcceptClassName='inline pull-right btn-sm ascribe-margin-1px'
pieceOrEditions={this.props.pieceOrEditions} pieceOrEditions={this.props.pieceOrEditions}
@ -125,7 +117,7 @@ let RequestActionForm = React.createClass({
url={urls.accept} url={urls.accept}
getFormData={this.getFormData} getFormData={this.getFormData}
handleSuccess={ handleSuccess={
this.showNotification(getLangText('accepted'), this.props.notifications.action, this.props.notifications.by) this.showNotification('accepted', this.props.notifications.action, this.props.notifications.by)
} }
isInline={true} isInline={true}
className='inline pull-right'> className='inline pull-right'>
@ -140,8 +132,8 @@ let RequestActionForm = React.createClass({
}, },
getButtonForm() { getButtonForm() {
let urls = this.getUrls(); const urls = this.getUrls();
let acceptButtonForm = this.getAcceptButtonForm(urls); const acceptButtonForm = this.getAcceptButtonForm(urls);
return ( return (
<div> <div>
@ -150,7 +142,7 @@ let RequestActionForm = React.createClass({
isInline={true} isInline={true}
getFormData={this.getFormData} getFormData={this.getFormData}
handleSuccess={ handleSuccess={
this.showNotification(getLangText('denied'), this.props.notifications.action, this.props.notifications.by) this.showNotification('denied', this.props.notifications.action, this.props.notifications.by)
} }
className='inline pull-right'> className='inline pull-right'>
<button <button

View File

@ -117,7 +117,7 @@ let PieceListBulkModal = React.createClass({
<div className="row-fluid"> <div className="row-fluid">
<AclButtonList <AclButtonList
availableAcls={availableAcls} availableAcls={availableAcls}
editions={selectedEditions} pieceOrEditions={selectedEditions}
handleSuccess={this.handleSuccess} handleSuccess={this.handleSuccess}
className="text-center ascribe-button-list collapse-group"> className="text-center ascribe-button-list collapse-group">
<DeleteButton <DeleteButton

View File

@ -31,6 +31,8 @@ export default function AuthProxyHandler({to, when}) {
return (Component) => { return (Component) => {
return React.createClass({ return React.createClass({
displayName: 'AuthProxyHandler',
propTypes: { propTypes: {
location: object location: object
}, },

View File

@ -47,7 +47,7 @@ let WalletActionPanel = React.createClass({
<AclButtonList <AclButtonList
className="text-center ascribe-button-list" className="text-center ascribe-button-list"
availableAcls={availableAcls} availableAcls={availableAcls}
editions={this.props.piece} pieceOrEditions={this.props.piece}
handleSuccess={this.props.loadPiece}> handleSuccess={this.props.loadPiece}>
<AclProxy <AclProxy
aclObject={this.props.currentUser.acl} aclObject={this.props.currentUser.acl}

View File

@ -220,7 +220,12 @@ let CylandRegisterPiece = React.createClass({
<Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}> <Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}>
<LoanForm <LoanForm
loanHeading={getLangText('Loan to Cyland archive')} loanHeading={getLangText('Loan to Cyland archive')}
message={getAclFormMessage('acl_loan', '\"' + this.state.piece.title + '\"', this.state.currentUser.username)} message={getAclFormMessage({
aclName: 'acl_loan',
entities: this.state.piece,
isPiece: true,
senderName: this.state.currentUser.username
})}
id={{piece_id: this.state.piece.id}} id={{piece_id: this.state.piece.id}}
url={ApiUrls.ownership_loans_pieces} url={ApiUrls.ownership_loans_pieces}
email={this.state.whitelabel.user} email={this.state.whitelabel.user}

View File

@ -11,7 +11,7 @@ let constants = {
'serverUrl': window.SERVER_URL, 'serverUrl': window.SERVER_URL,
'baseUrl': window.BASE_URL, 'baseUrl': window.BASE_URL,
'aclList': ['acl_coa', 'acl_consign', 'acl_delete', 'acl_download', 'acl_edit', 'acl_create_editions', 'acl_view_editions', 'aclList': ['acl_coa', 'acl_consign', 'acl_delete', 'acl_download', 'acl_edit', 'acl_create_editions', 'acl_view_editions',
'acl_loan', 'acl_share', 'acl_transfer', 'acl_unconsign', 'acl_unshare', 'acl_view', 'acl_loan', 'acl_loan_request', 'acl_share', 'acl_transfer', 'acl_unconsign', 'acl_unshare', 'acl_view',
'acl_withdraw_transfer', 'acl_wallet_submit'], 'acl_withdraw_transfer', 'acl_wallet_submit'],
'version': 0.1, 'version': 0.1,

View File

@ -2,14 +2,40 @@
import { getLangText } from './lang_utils'; import { getLangText } from './lang_utils';
/**
* Get the data ids of the given piece or editions.
* @param {boolean} isPiece Is the given entities parameter a piece? (False: array of editions)
* @param {(object|object[])} pieceOrEditions Piece or array of editions
* @return {(object|object[])} Data IDs of the pieceOrEditions for the form
*/
export function getAclFormDataId(isPiece, pieceOrEditions) {
if (isPiece) {
return {piece_id: pieceOrEditions.id};
} else {
return {bitcoin_id: pieceOrEditions.map(function(edition){
return edition.bitcoin_id;
}).join()};
}
}
/** /**
* Generates a message for submitting a form * Generates a message for submitting a form
* @param {string} aclName Enum name of a acl * @param {object} options Options object for creating the message:
* @param {string} entities Already computed name of entities * @param {string} options.aclName Enum name of an acl
* @param {string} senderName Name of the sender * @param {(object|object[])} options.entities Piece or array of Editions
* @param {boolean} options.isPiece Is the given entities parameter a piece? (False: array of editions)
* @param {string} [options.senderName] Name of the sender
* @return {string} Completed message * @return {string} Completed message
*/ */
export function getAclFormMessage(aclName, entities, senderName) { export function getAclFormMessage(options) {
if (!options || options.aclName === undefined || options.isPiece === undefined ||
!(typeof options.entities === 'object' || options.entities.constructor === Array)) {
throw new Error('You must specify an acl class, entities in the correct format, and entity type');
}
let aclName = options.aclName;
let entityTitles = options.isPiece ? getTitlesStringOfPiece(options.entities)
: getTitlesStringOfEditions(options.entities);
let message = ''; let message = '';
message += getLangText('Hi'); message += getLangText('Hi');
@ -32,7 +58,7 @@ export function getAclFormMessage(aclName, entities, senderName) {
} }
message += ':\n'; message += ':\n';
message += entities; message += entityTitles;
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');
@ -44,10 +70,22 @@ export function getAclFormMessage(aclName, entities, senderName) {
throw new Error('Your specified aclName did not match a an acl class.'); throw new Error('Your specified aclName did not match a an acl class.');
} }
if (options.senderName) {
message += '\n\n'; message += '\n\n';
message += getLangText('Truly yours,'); message += getLangText('Truly yours,');
message += '\n'; message += '\n';
message += senderName; message += options.senderName;
}
return message; return message;
} }
function getTitlesStringOfPiece(piece){
return '\"' + piece.title + '\"';
}
function getTitlesStringOfEditions(editions) {
return editions.map(function(edition) {
return '- \"' + edition.title + ', ' + getLangText('edition') + ' ' + edition.edition_number + '\"\n';
}).join('');
}

View File

@ -196,14 +196,41 @@ export function escapeHTML(s) {
return document.createElement('div').appendChild(document.createTextNode(s)).parentNode.innerHTML; return document.createElement('div').appendChild(document.createTextNode(s)).parentNode.innerHTML;
} }
export function excludePropFromObject(obj, propList){ /**
let clonedObj = mergeOptions({}, obj); * Returns a copy of the given object's own and inherited enumerable
for (let item in propList){ * properties, omitting any keys that pass the given filter function.
if (clonedObj[propList[item]]){ */
delete clonedObj[propList[item]]; function filterObjOnFn(obj, filterFn) {
const filteredObj = {};
for (let key in obj) {
const val = obj[key];
if (filterFn == null || !filterFn(val, key)) {
filteredObj[key] = val;
} }
} }
return clonedObj;
return filteredObj;
}
/**
* Similar to lodash's _.omit(), this returns a copy of the given object's
* own and inherited enumerable properties, omitting any keys that are
* in the given array or whose value pass the given filter function.
* @param {object} obj Source object
* @param {array|function} filter Array of key names to omit or function to invoke per iteration
* @return {object} The new object
*/
export function omitFromObject(obj, filter) {
if (filter && filter.constructor === Array) {
return filterObjOnFn(obj, (_, key) => {
return filter.indexOf(key) >= 0;
});
} else if (filter && typeof filter === 'function') {
return filterObjOnFn(obj, filter);
} else {
throw new Error('The given filter is not an array or function. Exclude aborted');
}
} }
/** /**

View File

@ -22,15 +22,15 @@ export function getLangText(s, ...args) {
let lang = getLang(); let lang = getLang();
try { try {
if(lang in languages) { if(lang in languages) {
return formatText(languages[lang][s], args); return formatText(languages[lang][s], ...args);
} else { } else {
// just use the english language // just use the english language
return formatText(languages['en-US'][s], args); return formatText(languages['en-US'][s], ...args);
} }
} catch(err) { } catch(err) {
//if(!(s in languages[lang])) { //if(!(s in languages[lang])) {
//console.warn('Language-string is not in constants file. Add: "' + s + '" to the "' + lang + '" language file. Defaulting to keyname'); //console.warn('Language-string is not in constants file. Add: "' + s + '" to the "' + lang + '" language file. Defaulting to keyname');
return formatText(s, args); return formatText(s, ...args);
//} else { //} else {
// console.error(err); // console.error(err);
//} //}

View File

@ -6,7 +6,7 @@ import { argsToQueryParams, getCookie } from '../utils/fetch_api_utils';
import AppConstants from '../constants/application_constants'; import AppConstants from '../constants/application_constants';
import {excludePropFromObject} from '../utils/general_utils'; import { omitFromObject } from '../utils/general_utils';
class Requests { class Requests {
_merge(defaults, options) { _merge(defaults, options) {
@ -139,8 +139,8 @@ class Requests {
} }
_putOrPost(url, paramsAndBody, method) { _putOrPost(url, paramsAndBody, method) {
let paramsCopy = this._merge(paramsAndBody); let paramsCopy = Object.assign({}, paramsAndBody);
let params = excludePropFromObject(paramsAndBody, ['body']); let params = omitFromObject(paramsAndBody, ['body']);
let newUrl = this.prepareUrl(url, params); let newUrl = this.prepareUrl(url, params);
let body = null; let body = null;
if (paramsCopy && paramsCopy.body) { if (paramsCopy && paramsCopy.body) {