2019-06-26 14:56:03 +08:00
|
|
|
import React, { Component } from 'react';
|
2019-06-10 18:05:03 +08:00
|
|
|
import PropTypes from 'prop-types';
|
2019-06-26 14:56:03 +08:00
|
|
|
import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap';
|
|
|
|
import { gettext } from '../../utils/constants';
|
|
|
|
import { seafileAPI } from '../../utils/seafile-api';
|
2019-06-10 18:05:03 +08:00
|
|
|
import UserSelect from '../user-select';
|
|
|
|
import toaster from '../toast';
|
2019-07-22 16:34:25 +08:00
|
|
|
import { Utils } from '../../utils/utils';
|
2019-06-28 10:23:22 +08:00
|
|
|
import '../../css/participants-list.css';
|
2019-06-10 18:05:03 +08:00
|
|
|
|
2019-06-26 14:56:03 +08:00
|
|
|
const fileParticipantListItemPropTypes = {
|
|
|
|
participant: PropTypes.object.isRequired,
|
|
|
|
deleteFileParticipant: PropTypes.func.isRequired,
|
|
|
|
};
|
2019-06-10 18:05:03 +08:00
|
|
|
|
|
|
|
class FileParticipantListItem extends Component {
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
isOperationShow: false,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
onMouseOver = () => {
|
2019-06-26 14:56:03 +08:00
|
|
|
this.setState({ isOperationShow: true });
|
2019-06-10 18:05:03 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
onMouseLeave = () => {
|
2019-06-26 14:56:03 +08:00
|
|
|
this.setState({ isOperationShow: false });
|
2019-06-10 18:05:03 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
render() {
|
2019-06-26 14:56:03 +08:00
|
|
|
const { participant } = this.props;
|
2019-06-10 18:05:03 +08:00
|
|
|
return (
|
2019-06-28 10:23:22 +08:00
|
|
|
<div className="participant-select-info" onMouseOver={this.onMouseOver} onMouseLeave={this.onMouseLeave}>
|
2019-07-20 09:51:19 +08:00
|
|
|
<div className="d-flex" style={{maxWidth: '90%'}}>
|
2019-06-28 10:23:22 +08:00
|
|
|
<img className="avatar participant-select-avatar" src={participant.avatar_url} alt=""/>
|
|
|
|
<span className="participant-select-name ellipsis">{participant.name}</span>
|
2019-06-10 18:05:03 +08:00
|
|
|
</div>
|
2019-06-28 10:23:22 +08:00
|
|
|
<i
|
|
|
|
className={`action-icon sf2-icon-x3 ${!this.state.isOperationShow &&'o-hidden'}`}
|
|
|
|
title={gettext('Delete')}
|
|
|
|
onClick={this.props.deleteFileParticipant.bind(this, participant.email)}
|
|
|
|
></i>
|
2019-06-10 18:05:03 +08:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FileParticipantListItem.propTypes = fileParticipantListItemPropTypes;
|
|
|
|
|
|
|
|
|
2019-06-26 14:56:03 +08:00
|
|
|
const fileParticipantDialogPropTypes = {
|
|
|
|
repoID: PropTypes.string.isRequired,
|
|
|
|
filePath: PropTypes.string.isRequired,
|
|
|
|
toggleFileParticipantDialog: PropTypes.func.isRequired,
|
|
|
|
fileParticipantList: PropTypes.array.isRequired,
|
|
|
|
onParticipantsChange: PropTypes.func,
|
|
|
|
};
|
|
|
|
|
2019-06-10 18:05:03 +08:00
|
|
|
class FileParticipantDialog extends Component {
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
selectedOption: null,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
handleSelectChange = (option) => {
|
2019-06-26 14:56:03 +08:00
|
|
|
this.setState({ selectedOption: option });
|
2019-06-10 18:05:03 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
deleteFileParticipant = (email) => {
|
2019-06-28 10:23:22 +08:00
|
|
|
const { repoID, filePath } = this.props;
|
2019-06-26 14:56:03 +08:00
|
|
|
seafileAPI.deleteFileParticipant(repoID, filePath, email).then((res) => {
|
|
|
|
this.props.onParticipantsChange(repoID, filePath);
|
2019-07-22 16:34:25 +08:00
|
|
|
}).catch(error => {
|
|
|
|
let errMessage = Utils.getErrorMsg(error);
|
|
|
|
toaster.danger(errMessage);
|
2019-06-10 18:05:03 +08:00
|
|
|
});
|
|
|
|
this.refs.userSelect.clearSelect();
|
|
|
|
};
|
|
|
|
|
|
|
|
addFileParticipant = () => {
|
2019-06-26 14:56:03 +08:00
|
|
|
const { selectedOption } = this.state;
|
2019-06-28 10:23:22 +08:00
|
|
|
const { repoID, filePath } = this.props;
|
2019-06-26 14:56:03 +08:00
|
|
|
if (!selectedOption || selectedOption.length === 0) {
|
2019-06-10 18:05:03 +08:00
|
|
|
return;
|
|
|
|
}
|
2019-06-29 11:24:18 +08:00
|
|
|
for (let i = 0; i < selectedOption.length; i++) {
|
|
|
|
seafileAPI.addFileParticipant(repoID, filePath, selectedOption[i].email).then((res) => {
|
|
|
|
this.props.onParticipantsChange(repoID, filePath);
|
2019-07-22 16:34:25 +08:00
|
|
|
}).catch(error => {
|
|
|
|
let errMessage = Utils.getErrorMsg(error);
|
|
|
|
toaster.danger(errMessage);
|
2019-06-29 11:24:18 +08:00
|
|
|
});
|
|
|
|
}
|
2019-06-26 14:56:03 +08:00
|
|
|
this.setState({ selectedOption: null });
|
2019-06-10 18:05:03 +08:00
|
|
|
this.refs.userSelect.clearSelect();
|
|
|
|
};
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const renderParticipantList = this.props.fileParticipantList.map((participant, index) => {
|
|
|
|
return (
|
|
|
|
<FileParticipantListItem
|
|
|
|
key={index}
|
|
|
|
participant={participant}
|
|
|
|
deleteFileParticipant={this.deleteFileParticipant}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Modal isOpen={true} toggle={this.props.toggleFileParticipantDialog}>
|
|
|
|
<ModalHeader toggle={this.props.toggleFileParticipantDialog}>{gettext('Participants')}</ModalHeader>
|
|
|
|
<ModalBody>
|
2019-06-28 10:23:22 +08:00
|
|
|
<div className="participant-add">
|
2019-06-26 14:56:03 +08:00
|
|
|
<UserSelect
|
|
|
|
ref="userSelect"
|
2019-06-29 11:24:18 +08:00
|
|
|
isMulti={true}
|
2019-06-28 10:23:22 +08:00
|
|
|
className="participant-select"
|
2019-06-26 14:56:03 +08:00
|
|
|
placeholder={gettext('Select users...')}
|
|
|
|
onSelectChange={this.handleSelectChange}
|
|
|
|
/>
|
|
|
|
<Button className="btn btn-secondary ml-2" onClick={this.addFileParticipant}>{gettext('Add')}</Button>
|
2019-06-10 18:05:03 +08:00
|
|
|
</div>
|
2019-06-26 14:56:03 +08:00
|
|
|
{renderParticipantList}
|
2019-06-10 18:05:03 +08:00
|
|
|
</ModalBody>
|
2019-06-26 14:56:03 +08:00
|
|
|
<ModalFooter>
|
|
|
|
<Button color="secondary" onClick={this.props.toggleFileParticipantDialog}>{gettext('Close')}</Button>
|
|
|
|
</ModalFooter>
|
2019-06-10 18:05:03 +08:00
|
|
|
</Modal>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FileParticipantDialog.propTypes = fileParticipantDialogPropTypes;
|
|
|
|
|
|
|
|
export default FileParticipantDialog;
|