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

Separate form building concerns from AclButton

AclButton’s form building is now delegated to AclFormFactory so other
components can use the same forms with ease. Its show/hide behaviour is
also now controlled with AclProxy.
This commit is contained in:
Brett Sun 2015-10-30 11:10:31 +01:00
parent c242cffdbd
commit 03e0bbd024
11 changed files with 372 additions and 197 deletions

View File

@ -1,174 +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, getAclFormDataId } 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,
email: React.PropTypes.string,
handleSuccess: React.PropTypes.func.isRequired,
className: React.PropTypes.string
},
isPiece() {
return this.props.pieceOrEditions.constructor !== Array;
},
actionProperties() {
let message = getAclFormMessage({
aclName: this.props.action,
entities: this.props.pieceOrEditions,
isPiece: this.isPiece(),
senderName: 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
email={this.props.email}
message={message}
id={this.getFormDataId()}
url={ApiUrls.ownership_consigns}/>
),
handleSuccess: this.showNotification
};
} else 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
email={this.props.email}
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);
}
},
getFormDataId(){
return getAclFormDataId(this.isPiece(), this.props.pieceOrEditions);
},
// 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 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';
let AclButtonList = React.createClass({
propTypes: {
className: React.PropTypes.string,
editions: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
]),
availableAcls: React.PropTypes.object,
]).isRequired,
availableAcls: React.PropTypes.object.isRequired,
buttonsStyle: React.PropTypes.object,
handleSuccess: React.PropTypes.func,
handleSuccess: React.PropTypes.func.isRequired,
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
@ -86,33 +90,28 @@ let AclButtonList = React.createClass({
return (
<div className={className}>
<span ref="buttonList" style={buttonsStyle}>
<AclButton
<ShareButton
availableAcls={availableAcls}
action="acl_share"
pieceOrEditions={editions}
currentUser={currentUser}
handleSuccess={handleSuccess} />
<AclButton
<TransferButton
availableAcls={availableAcls}
action="acl_transfer"
pieceOrEditions={editions}
currentUser={currentUser}
handleSuccess={handleSuccess}/>
<AclButton
<ConsignButton
availableAcls={availableAcls}
action="acl_consign"
pieceOrEditions={editions}
currentUser={currentUser}
handleSuccess={handleSuccess} />
<AclButton
<UnconsignButton
availableAcls={availableAcls}
action="acl_unconsign"
pieceOrEditions={editions}
currentUser={currentUser}
handleSuccess={handleSuccess} />
<AclButton
<LoanButton
availableAcls={availableAcls}
action="acl_loan"
pieceOrEditions={editions}
currentUser={currentUser}
handleSuccess={handleSuccess} />
@ -123,4 +122,4 @@ let AclButtonList = React.createClass({
}
});
export default AclButtonList;
export default AclButtonList;

View File

@ -0,0 +1,89 @@
'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';
let AclButton = React.createClass({
propTypes: {
action: React.PropTypes.oneOf(AppConstants.aclList).isRequired,
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,
title: React.PropTypes.string,
handleSuccess: React.PropTypes.func.isRequired,
className: React.PropTypes.string
},
getDefaultProps() {
return {
buttonAcceptClassName: ''
};
},
// 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() {
const {
action,
availableAcls,
buttonAcceptClassName,
currentUser,
email,
pieceOrEditions,
handleSuccess,
title } = 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>
);
}
});
export default AclButton;

View File

@ -0,0 +1,21 @@
'use strict';
import React from 'react';
import AclButton from './acl_button';
import { getLangText } from '../../../utils/lang_utils';
let ConsignButton = React.createClass({
render() {
return (
<AclButton
{...this.props}
action='acl_consign'
title={getLangText('Consign artwork')}
tooltip={getLangText('Have someone else sell the artwork')} />
);
}
});
export default ConsignButton;

View File

@ -0,0 +1,21 @@
'use strict';
import React from 'react';
import AclButton from './acl_button';
import { getLangText } from '../../../utils/lang_utils';
let LoanButton = React.createClass({
render() {
return (
<AclButton
{...this.props}
action='acl_loan'
title={getLangText('Loan artwork')}
tooltip={getLangText('Loan your artwork for a limited period of time')} />
);
}
});
export default LoanButton;

View File

@ -0,0 +1,21 @@
'use strict';
import React from 'react';
import AclButton from './acl_button';
import { getLangText } from '../../../utils/lang_utils';
let LoanButton = React.createClass({
render() {
return (
<AclButton
{...this.props}
action='acl_loan_request'
title={getLangText('Loan artwork')}
tooltip={getLangText('Someone requested you to loan your artwork for a limited period of time')} />
);
}
});
export default LoanButton;

View File

@ -0,0 +1,21 @@
'use strict';
import React from 'react';
import AclButton from './acl_button';
import { getLangText } from '../../../utils/lang_utils';
let ShareButton = React.createClass({
render() {
return (
<AclButton
{...this.props}
action='acl_share'
title={getLangText('Share artwork')}
tooltip={getLangText('Share the artwork')} />
);
}
});
export default ShareButton;

View File

@ -0,0 +1,21 @@
'use strict';
import React from 'react';
import AclButton from './acl_button';
import { getLangText } from '../../../utils/lang_utils';
let TransferButton = React.createClass({
render() {
return (
<AclButton
{...this.props}
action='acl_transfer'
title={getLangText('Transfer artwork')}
tooltip={getLangText('Transfer the ownership of the artwork')} />
);
}
});
export default TransferButton;

View File

@ -0,0 +1,21 @@
'use strict';
import React from 'react';
import AclButton from './acl_button';
import { getLangText } from '../../../utils/lang_utils';
let UnconsignButton = React.createClass({
render() {
return (
<AclButton
{...this.props}
action='acl_unconsign'
title={getLangText('Unconsign artwork')}
tooltip={getLangText('Have the owner manage his sales again')} />
);
}
});
export default UnconsignButton;

View File

@ -0,0 +1,134 @@
'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
},
getDefaultProps() {
return {
showNotification: false
};
},
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 AclButton from './../ascribe_buttons/acl_button';
import ActionPanel from '../ascribe_panel/action_panel';
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 GlobalNotificationModel from '../../models/global_notification_model';
@ -100,9 +103,8 @@ let RequestActionForm = React.createClass({
getAcceptButtonForm(urls) {
if(this.props.notifications.action === 'unconsign') {
return (
<AclButton
<UnconsignButton
availableAcls={{'acl_unconsign': true}}
action="acl_unconsign"
buttonAcceptClassName='inline pull-right btn-sm ascribe-margin-1px'
pieceOrEditions={this.props.pieceOrEditions}
currentUser={this.props.currentUser}
@ -110,9 +112,8 @@ let RequestActionForm = React.createClass({
);
} else if(this.props.notifications.action === 'loan_request') {
return (
<AclButton
<LoanRequestButton
availableAcls={{'acl_loan_request': true}}
action="acl_loan_request"
buttonAcceptName="LOAN"
buttonAcceptClassName='inline pull-right btn-sm ascribe-margin-1px'
pieceOrEditions={this.props.pieceOrEditions}
@ -174,4 +175,4 @@ let RequestActionForm = React.createClass({
});
export default RequestActionForm;
export default RequestActionForm;