mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-13 13:50:07 +00:00
[group] 'members' dialog: scroll to the bottom and load the next batc… (#6645)
* [group] 'members' dialog: scroll to the bottom and load the next batch of members * [group] 'members' dialog: improved the member number displayed
This commit is contained in:
@@ -1,31 +1,104 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Modal, ModalHeader, ModalBody } from 'reactstrap';
|
import { Modal, ModalHeader, ModalBody } from 'reactstrap';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
import { gettext } from '../../utils/constants';
|
import { gettext } from '../../utils/constants';
|
||||||
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
|
import toaster from '../toast';
|
||||||
|
import Loading from '../loading';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
members: PropTypes.array.isRequired,
|
groupID: PropTypes.string.isRequired,
|
||||||
toggleDialog: PropTypes.func.isRequired
|
toggleDialog: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
class GroupMembers extends React.Component {
|
class GroupMembers extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isLoading: true, // first loading
|
||||||
|
isLoadingMore: false,
|
||||||
|
groupMembers: [],
|
||||||
|
page: 1,
|
||||||
|
perPage: 100,
|
||||||
|
hasNextPage: 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
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleScroll = (event) => {
|
||||||
|
// 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { members } = this.props;
|
const {
|
||||||
|
isLoading, hasNextPage, groupMembers, perPage
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
|
let memberNumber;
|
||||||
|
if (groupMembers.length < perPage) {
|
||||||
|
memberNumber = groupMembers.length;
|
||||||
|
} else {
|
||||||
|
memberNumber = `${perPage}+`;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={true} toggle={this.props.toggleDialog}>
|
<Modal isOpen={true} toggle={this.props.toggleDialog}>
|
||||||
<ModalHeader toggle={this.props.toggleDialog}>{`${gettext('Group members')} (${members.length})`}</ModalHeader>
|
<ModalHeader toggle={this.props.toggleDialog}>{`${gettext('Group members')} (${memberNumber})`}</ModalHeader>
|
||||||
<ModalBody className="px-0 group-members-container">
|
<ModalBody className="px-0 group-members-container" onScroll={this.handleScroll}>
|
||||||
<ul className="list-unstyled">
|
{isLoading ? <Loading /> : (
|
||||||
{members.map((item, index) => {
|
<>
|
||||||
return (
|
<ul className="list-unstyled">
|
||||||
<li key={index} className="group-member px-4 py-2 d-flex align-items-center">
|
{groupMembers.map((item, index) => {
|
||||||
<img src={item.avatar_url} alt={item.name} className="avatar" />
|
return (
|
||||||
<span className="ml-2 text-truncate" title={item.name}>{item.name}</span>
|
<li key={index} className="group-member px-4 py-2 d-flex align-items-center">
|
||||||
</li>
|
<img src={item.avatar_url} alt={item.name} className="avatar" />
|
||||||
);
|
<span className="ml-2 text-truncate" title={item.name}>{item.name}</span>
|
||||||
})}
|
</li>
|
||||||
</ul>
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
{hasNextPage && <Loading />}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
@@ -59,7 +59,6 @@ class GroupView extends React.Component {
|
|||||||
showTransferGroupDialog: false,
|
showTransferGroupDialog: false,
|
||||||
showImportMembersDialog: false,
|
showImportMembersDialog: false,
|
||||||
showManageMembersDialog: false,
|
showManageMembersDialog: false,
|
||||||
groupMembers: [],
|
|
||||||
isLeaveGroupDialogOpen: false,
|
isLeaveGroupDialogOpen: false,
|
||||||
isMembersDialogOpen: false
|
isMembersDialogOpen: false
|
||||||
};
|
};
|
||||||
@@ -93,7 +92,6 @@ class GroupView extends React.Component {
|
|||||||
repoList: [] // empty it for the current group
|
repoList: [] // empty it for the current group
|
||||||
}, () => {
|
}, () => {
|
||||||
this.loadRepos(this.state.currentPage);
|
this.loadRepos(this.state.currentPage);
|
||||||
this.listGroupMembers();
|
|
||||||
});
|
});
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -309,29 +307,6 @@ class GroupView 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);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleGroupMembersPopover = (state) => {
|
|
||||||
if (state === 'open') {
|
|
||||||
this.listGroupMembers();
|
|
||||||
this.setState({
|
|
||||||
showGroupMembersPopover: true
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
showGroupMembersPopover: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
sortItems = (sortBy, sortOrder) => {
|
sortItems = (sortBy, sortOrder) => {
|
||||||
cookie.save('seafile-repo-dir-sort-by', sortBy);
|
cookie.save('seafile-repo-dir-sort-by', sortBy);
|
||||||
@@ -414,7 +389,7 @@ class GroupView extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { errMessage, emptyTip, currentGroup, isDepartmentGroup,
|
const { errMessage, emptyTip, currentGroup, isDepartmentGroup,
|
||||||
groupMembers, isMembersDialogOpen
|
isMembersDialogOpen
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
let useRate = 0;
|
let useRate = 0;
|
||||||
@@ -502,7 +477,7 @@ class GroupView extends React.Component {
|
|||||||
}
|
}
|
||||||
{isMembersDialogOpen &&
|
{isMembersDialogOpen &&
|
||||||
<GroupMembersDialog
|
<GroupMembersDialog
|
||||||
members={groupMembers}
|
groupID={this.props.groupID}
|
||||||
toggleDialog={this.toggleMembersDialog}
|
toggleDialog={this.toggleMembersDialog}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user