mirror of
https://github.com/ascribe/onion.git
synced 2024-12-22 17:33:14 +01:00
unshare and delete functionality + store updates for all views
This commit is contained in:
parent
adf4630efd
commit
5a0663ea14
@ -6,7 +6,11 @@ import Router from 'react-router';
|
||||
import Button from 'react-bootstrap/lib/Button';
|
||||
|
||||
import EditionDeleteForm from '../ascribe_forms/form_delete_edition';
|
||||
import PieceDeleteForm from '../ascribe_forms/form_delete_piece';
|
||||
|
||||
import EditionRemoveFromCollectionForm from '../ascribe_forms/form_remove_editions_from_collection';
|
||||
import PieceRemoveFromCollectionForm from '../ascribe_forms/form_remove_piece_from_collection';
|
||||
|
||||
import ModalWrapper from '../ascribe_modal/modal_wrapper';
|
||||
|
||||
import { getAvailableAcls } from '../../utils/acl_utils';
|
||||
@ -15,23 +19,47 @@ import { getLangText } from '../../utils/lang_utils.js';
|
||||
|
||||
let DeleteButton = React.createClass({
|
||||
propTypes: {
|
||||
editions: React.PropTypes.array.isRequired,
|
||||
editions: React.PropTypes.array,
|
||||
piece: React.PropTypes.object,
|
||||
handleSuccess: React.PropTypes.func
|
||||
},
|
||||
|
||||
mixins: [Router.Navigation],
|
||||
|
||||
render: function () {
|
||||
let availableAcls = getAvailableAcls(this.props.editions);
|
||||
let btnDelete = null;
|
||||
let content = null;
|
||||
let availableAcls;
|
||||
let btnDelete;
|
||||
let content;
|
||||
let title;
|
||||
|
||||
if (availableAcls.acl_delete) {
|
||||
content = <EditionDeleteForm editions={ this.props.editions }/>;
|
||||
btnDelete = <Button bsStyle="danger" className="btn-delete" bsSize="small">{getLangText('DELETE')}</Button>;
|
||||
if(this.props.piece && !this.props.editions) {
|
||||
availableAcls = getAvailableAcls([this.props.piece]);
|
||||
} else {
|
||||
availableAcls = getAvailableAcls(this.props.editions);
|
||||
}
|
||||
else if (availableAcls.acl_unshare || (this.props.editions.constructor !== Array && this.props.editions.acl.acl_unshare)){
|
||||
content = <EditionRemoveFromCollectionForm editions={ this.props.editions }/>;
|
||||
|
||||
if(availableAcls.acl_delete) {
|
||||
|
||||
if(this.props.piece && !this.props.editions) {
|
||||
content = <PieceDeleteForm pieceId={this.props.piece.id}/>;
|
||||
title = getLangText('Remove Piece');
|
||||
} else {
|
||||
content = <EditionDeleteForm editions={this.props.editions}/>;
|
||||
title = getLangText('Remove Edition');
|
||||
}
|
||||
|
||||
btnDelete = <Button bsStyle="danger" className="btn-delete" bsSize="small">{getLangText('DELETE')}</Button>;
|
||||
|
||||
} else if(availableAcls.acl_unshare){
|
||||
|
||||
if(this.props.editions && this.props.editions.constructor !== Array && this.props.editions.acl.acl_unshare) {
|
||||
content = <EditionRemoveFromCollectionForm editions={this.props.editions}/>;
|
||||
title = getLangText('Remove Edition from Collection');
|
||||
} else {
|
||||
content = <PieceRemoveFromCollectionForm pieceId={this.props.piece.id}/>;
|
||||
title = getLangText('Remove Piece from Collection');
|
||||
}
|
||||
|
||||
btnDelete = <Button bsStyle="danger" className="btn-delete" bsSize="small">{getLangText('REMOVE FROM COLLECTION')}</Button>;
|
||||
}
|
||||
else {
|
||||
@ -41,9 +69,8 @@ let DeleteButton = React.createClass({
|
||||
<ModalWrapper
|
||||
button={btnDelete}
|
||||
handleSuccess={this.props.handleSuccess}
|
||||
title={getLangText('Remove Edition')}
|
||||
tooltip={getLangText('Click to remove edition')}>
|
||||
{ content }
|
||||
title={title}>
|
||||
{content}
|
||||
</ModalWrapper>
|
||||
);
|
||||
}
|
||||
|
@ -63,11 +63,13 @@ let Edition = React.createClass({
|
||||
|
||||
componentDidMount() {
|
||||
UserStore.listen(this.onChange);
|
||||
PieceListStore.listen(this.onChange);
|
||||
UserActions.fetchCurrentUser();
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
UserStore.unlisten(this.onChange);
|
||||
PieceListStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
|
||||
import Row from 'react-bootstrap/lib/Row';
|
||||
import Col from 'react-bootstrap/lib/Col';
|
||||
@ -14,6 +15,11 @@ import FurtherDetails from './further_details';
|
||||
import UserActions from '../../actions/user_actions';
|
||||
import UserStore from '../../stores/user_store';
|
||||
|
||||
import PieceListActions from '../../actions/piece_list_actions';
|
||||
import PieceListStore from '../../stores/piece_list_store';
|
||||
|
||||
import EditionListActions from '../../actions/edition_list_actions';
|
||||
|
||||
import PieceActions from '../../actions/piece_actions';
|
||||
|
||||
import MediaContainer from './media_container';
|
||||
@ -23,6 +29,7 @@ import EditionDetailProperty from './detail_property';
|
||||
import AclButtonList from './../ascribe_buttons/acl_button_list';
|
||||
import CreateEditionsForm from '../ascribe_forms/create_editions_form';
|
||||
import CreateEditionsButton from '../ascribe_buttons/create_editions_button';
|
||||
import DeleteButton from '../ascribe_buttons/delete_button';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
@ -39,9 +46,12 @@ let Piece = React.createClass({
|
||||
loadPiece: React.PropTypes.func
|
||||
},
|
||||
|
||||
mixins: [Router.Navigation],
|
||||
|
||||
getInitialState() {
|
||||
return mergeOptions(
|
||||
UserStore.getState(),
|
||||
PieceListStore.getState(),
|
||||
{
|
||||
showCreateEditionsDialog: false
|
||||
}
|
||||
@ -50,11 +60,13 @@ let Piece = React.createClass({
|
||||
|
||||
componentDidMount() {
|
||||
UserStore.listen(this.onChange);
|
||||
PieceListStore.listen(this.onChange);
|
||||
UserActions.fetchCurrentUser();
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
UserStore.unlisten(this.onChange);
|
||||
PieceListStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
@ -72,6 +84,20 @@ let Piece = React.createClass({
|
||||
this.toggleCreateEditionsDialog();
|
||||
},
|
||||
|
||||
handleDeleteSuccess(response) {
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc);
|
||||
|
||||
// since we're deleting a piece, we just need to close
|
||||
// all editions dialogs and not reload them
|
||||
EditionListActions.closeAllEditionLists();
|
||||
EditionListActions.clearAllEditionSelections();
|
||||
|
||||
let notification = new GlobalNotificationModel(response.notification, 'success');
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
|
||||
this.transitionTo('pieces');
|
||||
},
|
||||
|
||||
getCreateEditionsDialog() {
|
||||
if(this.props.piece.num_editions < 1 && this.state.showCreateEditionsDialog) {
|
||||
return (
|
||||
@ -127,6 +153,9 @@ let Piece = React.createClass({
|
||||
piece={this.props.piece}
|
||||
toggleCreateEditionsDialog={this.toggleCreateEditionsDialog}
|
||||
onPollingSuccess={this.handlePollingSuccess}/>
|
||||
<DeleteButton
|
||||
handleSuccess={this.handleDeleteSuccess}
|
||||
piece={this.props.piece}/>
|
||||
</AclButtonList>
|
||||
|
||||
{this.getCreateEditionsDialog()}
|
||||
|
41
js/components/ascribe_forms/form_delete_piece.js
Normal file
41
js/components/ascribe_forms/form_delete_piece.js
Normal file
@ -0,0 +1,41 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import requests from '../../utils/requests';
|
||||
import ApiUrls from '../../constants/api_urls';
|
||||
import FormMixin from '../../mixins/form_mixin';
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
let PieceDeleteForm = React.createClass({
|
||||
propTypes: {
|
||||
pieceId: React.PropTypes.number
|
||||
},
|
||||
|
||||
mixins: [FormMixin],
|
||||
|
||||
url() {
|
||||
return requests.prepareUrl(ApiUrls.piece, {piece_id: this.props.pieceId});
|
||||
},
|
||||
|
||||
httpVerb() {
|
||||
return 'delete';
|
||||
},
|
||||
|
||||
renderForm () {
|
||||
return (
|
||||
<div className="modal-body">
|
||||
<p>{getLangText('Are you sure you would like to permanently delete this piece')}?</p>
|
||||
<p>{getLangText('This is an irrevocable action%s', '.')}</p>
|
||||
<div className="modal-footer">
|
||||
<button type="submit" className="btn btn-danger btn-delete btn-sm ascribe-margin-1px" onClick={this.submit}>{getLangText('YES, DELETE')}</button>
|
||||
<button className="btn btn-default btn-sm ascribe-margin-1px" style={{marginLeft: '0'}}
|
||||
onClick={this.props.onRequestHide}>{getLangText('CLOSE')}</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export default PieceDeleteForm;
|
@ -12,13 +12,9 @@ let EditionRemoveFromCollectionForm = React.createClass({
|
||||
mixins: [FormMixin],
|
||||
|
||||
url() {
|
||||
if (this.props.editions.constructor === Array) {
|
||||
return requests.prepareUrl(apiUrls.edition_remove_from_collection, {edition_id: this.getBitcoinIds().join()});
|
||||
}
|
||||
else {
|
||||
return requests.prepareUrl(apiUrls.piece_remove_from_collection, {piece_id: this.props.editions.id});
|
||||
}
|
||||
return requests.prepareUrl(apiUrls.edition_remove_from_collection, {edition_id: this.getBitcoinIds().join()});
|
||||
},
|
||||
|
||||
httpVerb(){
|
||||
return 'delete';
|
||||
},
|
||||
|
@ -0,0 +1,42 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils.js';
|
||||
import requests from '../../utils/requests';
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
import FormMixin from '../../mixins/form_mixin';
|
||||
|
||||
let PieceRemoveFromCollectionForm = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
pieceId: React.PropTypes.number
|
||||
},
|
||||
|
||||
mixins: [FormMixin],
|
||||
|
||||
url() {
|
||||
return requests.prepareUrl(apiUrls.piece_remove_from_collection, {piece_id: this.props.pieceId});
|
||||
},
|
||||
|
||||
httpVerb(){
|
||||
return 'delete';
|
||||
},
|
||||
|
||||
renderForm () {
|
||||
return (
|
||||
<div className="modal-body">
|
||||
<p>{getLangText('Are you sure you would like to remove this piece from your collection')}?</p>
|
||||
<p>{getLangText('This is an irrevocable action%s', '.')}</p>
|
||||
<div className="modal-footer">
|
||||
<button type="submit" className="btn btn-danger btn-delete btn-sm ascribe-margin-1px" onClick={this.submit}>{getLangText('YES, REMOVE')}</button>
|
||||
<button className="btn btn-default btn-sm ascribe-margin-1px" style={{marginLeft: '0'}}
|
||||
onClick={this.props.onRequestHide}>{getLangText('CLOSE')}</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export default PieceRemoveFromCollectionForm;
|
@ -17,24 +17,41 @@ let ModalWrapper = React.createClass({
|
||||
handleSuccess: React.PropTypes.func.isRequired,
|
||||
button: React.PropTypes.object.isRequired,
|
||||
children: React.PropTypes.object,
|
||||
tooltip: React.PropTypes.string.isRequired
|
||||
tooltip: React.PropTypes.string
|
||||
},
|
||||
|
||||
getModalTrigger() {
|
||||
return (
|
||||
<ModalTrigger modal={
|
||||
<ModalBody
|
||||
title={this.props.title}
|
||||
handleSuccess={this.props.handleSuccess}>
|
||||
{this.props.children}
|
||||
</ModalBody>
|
||||
}>
|
||||
{this.props.button}
|
||||
</ModalTrigger>
|
||||
);
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<OverlayTrigger delay={500} placement="left"
|
||||
overlay={<Tooltip>{this.props.tooltip}</Tooltip>}>
|
||||
<ModalTrigger modal={
|
||||
<ModalBody
|
||||
title={this.props.title}
|
||||
handleSuccess={this.props.handleSuccess}>
|
||||
{this.props.children}
|
||||
</ModalBody>
|
||||
}>
|
||||
{this.props.button}
|
||||
</ModalTrigger>
|
||||
</OverlayTrigger>
|
||||
);
|
||||
if(this.props.tooltip) {
|
||||
return (
|
||||
<OverlayTrigger
|
||||
delay={500}
|
||||
placement="left"
|
||||
overlay={<Tooltip>{this.props.tooltip}</Tooltip>}>
|
||||
{this.getModalTrigger()}
|
||||
</OverlayTrigger>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<span>
|
||||
{/* This needs to be some kind of inline-block */}
|
||||
{this.getModalTrigger()}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -8,7 +8,7 @@ function intersectAcls(a, b) {
|
||||
|
||||
export function getAvailableAcls(editions, filterFn) {
|
||||
let availableAcls = [];
|
||||
if (editions.constructor !== Array){
|
||||
if (!editions || editions.constructor !== Array){
|
||||
return [];
|
||||
}
|
||||
// if you copy a javascript array of objects using slice, then
|
||||
|
@ -54,6 +54,11 @@ class Requests {
|
||||
}
|
||||
|
||||
getUrl(url) {
|
||||
// Handle case, that the url string is not defined at all
|
||||
if (!url) {
|
||||
throw new Error('Url was not defined and could therefore not be mapped.');
|
||||
}
|
||||
|
||||
let name = url;
|
||||
if (!url.match(/^http/)) {
|
||||
url = this.urlMap[url];
|
||||
@ -66,9 +71,16 @@ class Requests {
|
||||
}
|
||||
|
||||
prepareUrl(url, params, attachParamsToQuery) {
|
||||
let newUrl = this.getUrl(url);
|
||||
let newUrl;
|
||||
let re = /\${(\w+)}/g;
|
||||
|
||||
// catch errors and throw them to react
|
||||
try {
|
||||
newUrl = this.getUrl(url);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
newUrl = newUrl.replace(re, (match, key) => {
|
||||
let val = params[key];
|
||||
if (!val) {
|
||||
|
Loading…
Reference in New Issue
Block a user