mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-09 10:50:24 +00:00
Group manage member (#4805)
* [group manage members] added 'scroll to load more members' * [group manage members] fixup for 'add/delete/modify member'
This commit is contained in:
@@ -1,12 +1,14 @@
|
|||||||
import React from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { gettext } from '../../utils/constants';
|
|
||||||
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Table } from 'reactstrap';
|
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Table } from 'reactstrap';
|
||||||
import { seafileAPI } from '../../utils/seafile-api.js';
|
|
||||||
import RoleEditor from '../select-editor/role-editor';
|
|
||||||
import UserSelect from '../user-select.js';
|
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
|
import { gettext } from '../../utils/constants';
|
||||||
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
|
import RoleEditor from '../select-editor/role-editor';
|
||||||
|
import UserSelect from '../user-select';
|
||||||
import toaster from '../toast';
|
import toaster from '../toast';
|
||||||
|
import Loading from '../loading';
|
||||||
|
|
||||||
import '../../css/manage-members-dialog.css';
|
import '../../css/manage-members-dialog.css';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
@@ -21,13 +23,45 @@ class ManageMembersDialog extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
isLoading: true, // first loading
|
||||||
|
isLoadingMore: false,
|
||||||
groupMembers: [],
|
groupMembers: [],
|
||||||
|
page: 1,
|
||||||
|
perPage: 100,
|
||||||
|
hasNextPage: false,
|
||||||
selectedOption: null,
|
selectedOption: null,
|
||||||
errMessage: [],
|
errMessage: [],
|
||||||
isItemFreezed: false,
|
isItemFreezed: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.listGroupMembers(this.state.page);
|
||||||
|
}
|
||||||
|
|
||||||
|
listGroupMembers = (page) => {
|
||||||
|
const { groupID } = this.props;
|
||||||
|
const { perPage, groupMembers } = this.state;
|
||||||
|
seafileAPI.listGroupMembers(groupID, page, perPage).then((res) => {
|
||||||
|
const members = res.data;
|
||||||
|
this.setState({
|
||||||
|
isLoading: false,
|
||||||
|
isLoadingMore: false,
|
||||||
|
page: page,
|
||||||
|
hasNextPage: members.length < perPage ? false : true,
|
||||||
|
groupMembers: groupMembers.concat(members)
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
this.setState({
|
||||||
|
isLoading: false,
|
||||||
|
isLoadingMore: false,
|
||||||
|
hasNextPage: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onSelectChange = (option) => {
|
onSelectChange = (option) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedOption: option,
|
selectedOption: option,
|
||||||
@@ -41,8 +75,9 @@ class ManageMembersDialog extends React.Component {
|
|||||||
emails.push(this.state.selectedOption[i].email);
|
emails.push(this.state.selectedOption[i].email);
|
||||||
}
|
}
|
||||||
seafileAPI.addGroupMembers(this.props.groupID, emails).then((res) => {
|
seafileAPI.addGroupMembers(this.props.groupID, emails).then((res) => {
|
||||||
this.onGroupMembersChange();
|
const newMembers = res.data.success;
|
||||||
this.setState({
|
this.setState({
|
||||||
|
groupMembers: [].concat(newMembers, this.state.groupMembers),
|
||||||
selectedOption: null,
|
selectedOption: null,
|
||||||
});
|
});
|
||||||
this.refs.userSelect.clearSelect();
|
this.refs.userSelect.clearSelect();
|
||||||
@@ -57,21 +92,6 @@ class ManageMembersDialog extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
listGroupMembers = () => {
|
|
||||||
seafileAPI.listGroupMembers(this.props.groupID).then((res) => {
|
|
||||||
this.setState({
|
|
||||||
groupMembers: res.data
|
|
||||||
});
|
|
||||||
}).catch(error => {
|
|
||||||
let errMessage = Utils.getErrorMsg(error);
|
|
||||||
toaster.danger(errMessage);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onGroupMembersChange = () => {
|
|
||||||
this.listGroupMembers();
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleItemFreezed = (isFreezed) => {
|
toggleItemFreezed = (isFreezed) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
isItemFreezed: isFreezed
|
isItemFreezed: isFreezed
|
||||||
@@ -82,11 +102,43 @@ class ManageMembersDialog extends React.Component {
|
|||||||
this.props.toggleManageMembersDialog();
|
this.props.toggleManageMembersDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
handleScroll = (event) => {
|
||||||
this.listGroupMembers();
|
// isLoadingMore: to avoid repeated request
|
||||||
|
const { page, hasNextPage, isLoadingMore } = this.state;
|
||||||
|
if (hasNextPage && !isLoadingMore) {
|
||||||
|
const clientHeight = event.target.clientHeight;
|
||||||
|
const scrollHeight = event.target.scrollHeight;
|
||||||
|
const scrollTop = event.target.scrollTop;
|
||||||
|
const isBottom = (clientHeight + scrollTop + 1 >= scrollHeight);
|
||||||
|
if (isBottom) { // scroll to the bottom
|
||||||
|
this.setState({isLoadingMore: true}, () => {
|
||||||
|
this.listGroupMembers(page + 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changeMember = (targetMember) => {
|
||||||
|
this.setState({
|
||||||
|
groupMembers: this.state.groupMembers.map((item) => {
|
||||||
|
if (item.email == targetMember.email) {
|
||||||
|
item = targetMember;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteMember = (targetMember) => {
|
||||||
|
const groupMembers = this.state.groupMembers;
|
||||||
|
groupMembers.splice(groupMembers.indexOf(targetMember), 1);
|
||||||
|
this.setState({
|
||||||
|
groupMembers: groupMembers
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { isLoading, hasNextPage } = this.state;
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={true} toggle={this.toggle}>
|
<Modal isOpen={true} toggle={this.toggle}>
|
||||||
<ModalHeader toggle={this.toggle}>{gettext('Manage group members')}</ModalHeader>
|
<ModalHeader toggle={this.toggle}>{gettext('Manage group members')}</ModalHeader>
|
||||||
@@ -113,7 +165,9 @@ class ManageMembersDialog extends React.Component {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
<div className="manage-members">
|
<div className="manage-members" onScroll={this.handleScroll}>
|
||||||
|
{isLoading ? <Loading /> : (
|
||||||
|
<Fragment>
|
||||||
<Table size="sm" className="manage-members-table">
|
<Table size="sm" className="manage-members-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -126,23 +180,26 @@ class ManageMembersDialog extends React.Component {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{
|
{
|
||||||
this.state.groupMembers.length > 0 &&
|
this.state.groupMembers.length > 0 &&
|
||||||
this.state.groupMembers.map((item, index = 0) => {
|
this.state.groupMembers.map((item, index) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={index}>
|
|
||||||
<Member
|
<Member
|
||||||
|
key={index}
|
||||||
item={item}
|
item={item}
|
||||||
onGroupMembersChange={this.onGroupMembersChange}
|
changeMember={this.changeMember}
|
||||||
|
deleteMember={this.deleteMember}
|
||||||
groupID={this.props.groupID}
|
groupID={this.props.groupID}
|
||||||
isOwner={this.props.isOwner}
|
isOwner={this.props.isOwner}
|
||||||
isItemFreezed={this.state.isItemFreezed}
|
isItemFreezed={this.state.isItemFreezed}
|
||||||
toggleItemFreezed={this.toggleItemFreezed}
|
toggleItemFreezed={this.toggleItemFreezed}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
</Table>
|
</Table>
|
||||||
|
{hasNextPage && <Loading />}
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
@@ -157,7 +214,8 @@ ManageMembersDialog.propTypes = propTypes;
|
|||||||
|
|
||||||
const MemberPropTypes = {
|
const MemberPropTypes = {
|
||||||
item: PropTypes.object.isRequired,
|
item: PropTypes.object.isRequired,
|
||||||
onGroupMembersChange: PropTypes.func.isRequired,
|
changeMember: PropTypes.func.isRequired,
|
||||||
|
deleteMember: PropTypes.func.isRequired,
|
||||||
groupID: PropTypes.string.isRequired,
|
groupID: PropTypes.string.isRequired,
|
||||||
isOwner: PropTypes.bool.isRequired,
|
isOwner: PropTypes.bool.isRequired,
|
||||||
};
|
};
|
||||||
@@ -175,16 +233,18 @@ class Member extends React.PureComponent {
|
|||||||
onChangeUserRole = (role) => {
|
onChangeUserRole = (role) => {
|
||||||
let isAdmin = role === 'Admin' ? 'True' : 'False';
|
let isAdmin = role === 'Admin' ? 'True' : 'False';
|
||||||
seafileAPI.setGroupAdmin(this.props.groupID, this.props.item.email, isAdmin).then((res) => {
|
seafileAPI.setGroupAdmin(this.props.groupID, this.props.item.email, isAdmin).then((res) => {
|
||||||
this.props.onGroupMembersChange();
|
this.props.changeMember(res.data);
|
||||||
});
|
}).catch(error => {
|
||||||
this.setState({
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
highlight: false,
|
toaster.danger(errMessage);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteMember = (name) => {
|
deleteMember = () => {
|
||||||
seafileAPI.deleteGroupMember(this.props.groupID, name).then((res) => {
|
const { item } = this.props;
|
||||||
this.props.onGroupMembersChange();
|
seafileAPI.deleteGroupMember(this.props.groupID, item.email).then((res) => {
|
||||||
|
this.props.deleteMember(item);
|
||||||
|
toaster.success(gettext('Successfully deleted {name}.').replace('{name}', item.name));
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
let errMessage = Utils.getErrorMsg(error);
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
toaster.danger(errMessage);
|
toaster.danger(errMessage);
|
||||||
@@ -243,8 +303,7 @@ class Member extends React.PureComponent {
|
|||||||
{(deleteAuthority && !this.props.isItemFreezed) &&
|
{(deleteAuthority && !this.props.isItemFreezed) &&
|
||||||
<i
|
<i
|
||||||
className="fa fa-times delete-group-member-icon"
|
className="fa fa-times delete-group-member-icon"
|
||||||
name={item.email}
|
onClick={this.deleteMember}>
|
||||||
onClick={this.deleteMember.bind(this, item.email)}>
|
|
||||||
</i>
|
</i>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
|
Reference in New Issue
Block a user