Add search in People drawer
Signed-off-by: Ajay Bura <ajbura@gmail.com>
This commit is contained in:
parent
dc7fca4f4c
commit
36380fe5fd
2 changed files with 76 additions and 19 deletions
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useCallback } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import './PeopleDrawer.scss';
|
import './PeopleDrawer.scss';
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import initMatrix from '../../../client/initMatrix';
|
||||||
import { getPowerLabel, getUsernameOfRoomMember } from '../../../util/matrixUtil';
|
import { getPowerLabel, getUsernameOfRoomMember } from '../../../util/matrixUtil';
|
||||||
import colorMXID from '../../../util/colorMXID';
|
import colorMXID from '../../../util/colorMXID';
|
||||||
import { openInviteUser, openProfileViewer } from '../../../client/action/navigation';
|
import { openInviteUser, openProfileViewer } from '../../../client/action/navigation';
|
||||||
|
import AsyncSearch from '../../../util/AsyncSearch';
|
||||||
|
|
||||||
import Text from '../../atoms/text/Text';
|
import Text from '../../atoms/text/Text';
|
||||||
import Header, { TitleWrapper } from '../../atoms/header/Header';
|
import Header, { TitleWrapper } from '../../atoms/header/Header';
|
||||||
|
@ -37,31 +38,88 @@ function sortByPowerLevel(m1, m2) {
|
||||||
if (pl1 < pl2) return 1;
|
if (pl1 < pl2) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
function simplyfiMembers(members) {
|
||||||
|
const mx = initMatrix.matrixClient;
|
||||||
|
return members.map((member) => ({
|
||||||
|
userId: member.userId,
|
||||||
|
name: getUsernameOfRoomMember(member),
|
||||||
|
username: member.userId.slice(1, member.userId.indexOf(':')),
|
||||||
|
avatarSrc: member.getAvatarUrl(mx.baseUrl, 24, 24, 'crop'),
|
||||||
|
peopleRole: getPowerLabel(member.powerLevel),
|
||||||
|
powerLevel: members.powerLevel,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const asyncSearch = new AsyncSearch();
|
||||||
function PeopleDrawer({ roomId }) {
|
function PeopleDrawer({ roomId }) {
|
||||||
const PER_PAGE_MEMBER = 50;
|
const PER_PAGE_MEMBER = 50;
|
||||||
const room = initMatrix.matrixClient.getRoom(roomId);
|
const mx = initMatrix.matrixClient;
|
||||||
const totalMemberList = room.getJoinedMembers().sort(AtoZ).sort(sortByPowerLevel);
|
const room = mx.getRoom(roomId);
|
||||||
const [memberList, updateMemberList] = useState([]);
|
|
||||||
let isRoomChanged = false;
|
let isRoomChanged = false;
|
||||||
|
|
||||||
|
const [itemCount, setItemCount] = useState(PER_PAGE_MEMBER);
|
||||||
|
const [membership, setMembership] = useState('join');
|
||||||
|
const [memberList, setMemberList] = useState([]);
|
||||||
|
const [searchedMembers, setSearchedMembers] = useState(null);
|
||||||
|
|
||||||
|
const getMembersWithMembership = useCallback(
|
||||||
|
(mship) => room.getMembersWithMembership(mship),
|
||||||
|
[roomId, membership],
|
||||||
|
);
|
||||||
|
|
||||||
function loadMorePeople() {
|
function loadMorePeople() {
|
||||||
updateMemberList(totalMemberList.slice(0, memberList.length + PER_PAGE_MEMBER));
|
setItemCount(itemCount + PER_PAGE_MEMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSearchData(data) {
|
||||||
|
// NOTICE: data is passed as object property
|
||||||
|
// because react sucks at handling state update with array.
|
||||||
|
setSearchedMembers({ data });
|
||||||
|
setItemCount(PER_PAGE_MEMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSearch(e) {
|
||||||
|
if (e.target.value === '') {
|
||||||
|
setSearchedMembers(null);
|
||||||
|
setItemCount(PER_PAGE_MEMBER);
|
||||||
|
} else asyncSearch.search(e.target.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateMemberList(totalMemberList.slice(0, PER_PAGE_MEMBER));
|
asyncSearch.setup(memberList, {
|
||||||
|
keys: ['name', 'username', 'userId'],
|
||||||
|
limit: PER_PAGE_MEMBER,
|
||||||
|
});
|
||||||
|
}, [memberList]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMemberList(
|
||||||
|
simplyfiMembers(
|
||||||
|
getMembersWithMembership(membership)
|
||||||
|
.sort(AtoZ).sort(sortByPowerLevel),
|
||||||
|
),
|
||||||
|
);
|
||||||
room.loadMembersIfNeeded().then(() => {
|
room.loadMembersIfNeeded().then(() => {
|
||||||
if (isRoomChanged) return;
|
if (isRoomChanged) return;
|
||||||
const newTotalMemberList = room.getJoinedMembers().sort(AtoZ).sort(sortByPowerLevel);
|
setMemberList(
|
||||||
updateMemberList(newTotalMemberList.slice(0, PER_PAGE_MEMBER));
|
simplyfiMembers(
|
||||||
|
getMembersWithMembership(membership)
|
||||||
|
.sort(AtoZ).sort(sortByPowerLevel),
|
||||||
|
),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
asyncSearch.on(asyncSearch.RESULT_SENT, handleSearchData);
|
||||||
return () => {
|
return () => {
|
||||||
isRoomChanged = true;
|
isRoomChanged = true;
|
||||||
|
setMemberList([]);
|
||||||
|
setSearchedMembers(null);
|
||||||
|
setItemCount(PER_PAGE_MEMBER);
|
||||||
|
asyncSearch.removeListener(asyncSearch.RESULT_SENT, handleSearchData);
|
||||||
};
|
};
|
||||||
}, [roomId]);
|
}, [roomId]);
|
||||||
|
|
||||||
|
const mList = searchedMembers !== null ? searchedMembers.data : memberList.slice(0, itemCount);
|
||||||
return (
|
return (
|
||||||
<div className="people-drawer">
|
<div className="people-drawer">
|
||||||
<Header>
|
<Header>
|
||||||
|
@ -78,20 +136,20 @@ function PeopleDrawer({ roomId }) {
|
||||||
<ScrollView autoHide>
|
<ScrollView autoHide>
|
||||||
<div className="people-drawer__content">
|
<div className="people-drawer__content">
|
||||||
{
|
{
|
||||||
memberList.map((member) => (
|
mList.map((member) => (
|
||||||
<PeopleSelector
|
<PeopleSelector
|
||||||
key={member.userId}
|
key={member.userId}
|
||||||
onClick={() => openProfileViewer(member.userId, roomId)}
|
onClick={() => openProfileViewer(member.userId, roomId)}
|
||||||
avatarSrc={member.getAvatarUrl(initMatrix.matrixClient.baseUrl, 24, 24, 'crop')}
|
avatarSrc={member.avatarSrc}
|
||||||
name={getUsernameOfRoomMember(member)}
|
name={member.name}
|
||||||
color={colorMXID(member.userId)}
|
color={colorMXID(member.userId)}
|
||||||
peopleRole={getPowerLabel(member.powerLevel)}
|
peopleRole={member.peopleRole}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
<div className="people-drawer__load-more">
|
<div className="people-drawer__load-more">
|
||||||
{
|
{
|
||||||
memberList.length !== totalMemberList.length && (
|
mList.length !== 0 && mList.length > itemCount && (
|
||||||
<Button onClick={loadMorePeople}>View more</Button>
|
<Button onClick={loadMorePeople}>View more</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -101,7 +159,7 @@ function PeopleDrawer({ roomId }) {
|
||||||
</div>
|
</div>
|
||||||
<div className="people-drawer__sticky">
|
<div className="people-drawer__sticky">
|
||||||
<form onSubmit={(e) => e.preventDefault()} className="people-search">
|
<form onSubmit={(e) => e.preventDefault()} className="people-search">
|
||||||
<Input type="text" placeholder="Search" required />
|
<Input type="text" onChange={handleSearch} placeholder="Search" required />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -36,10 +36,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&__sticky {
|
&__sticky {
|
||||||
display: none;
|
|
||||||
|
|
||||||
& .people-search {
|
& .people-search {
|
||||||
min-height: 48px;
|
--search-input-height: 40px;
|
||||||
|
min-height: var(--search-input-height);
|
||||||
|
|
||||||
margin: 0 var(--sp-normal);
|
margin: 0 var(--sp-normal);
|
||||||
|
|
||||||
|
@ -47,7 +46,7 @@
|
||||||
bottom: var(--sp-normal);
|
bottom: var(--sp-normal);
|
||||||
|
|
||||||
& .input {
|
& .input {
|
||||||
height: 48px;
|
height: var(--search-input-height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +54,7 @@
|
||||||
|
|
||||||
.people-drawer__content {
|
.people-drawer__content {
|
||||||
padding-top: var(--sp-extra-tight);
|
padding-top: var(--sp-extra-tight);
|
||||||
padding-bottom: calc( var(--sp-extra-tight) + var(--sp-normal));
|
padding-bottom: calc(2 * var(--sp-normal));
|
||||||
}
|
}
|
||||||
.people-drawer__load-more {
|
.people-drawer__load-more {
|
||||||
padding: var(--sp-normal);
|
padding: var(--sp-normal);
|
||||||
|
|
Loading…
Reference in a new issue