Add search in People drawer
authorAjay Bura <ajbura@gmail.com>
Thu, 21 Oct 2021 12:20:49 +0000 (17:50 +0530)
committerKrishan <33421343+kfiven@users.noreply.github.com>
Mon, 25 Oct 2021 12:29:57 +0000 (17:59 +0530)
Signed-off-by: Ajay Bura <ajbura@gmail.com>
src/app/organisms/room/PeopleDrawer.jsx
src/app/organisms/room/PeopleDrawer.scss

index 205047dcba1df9b833ab697ab23bfb1267315f84..dcddc76db16a59a6a0ea49ac1a89ba2851d92b01 100644 (file)
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, useCallback } from 'react';
 import PropTypes from 'prop-types';
 import './PeopleDrawer.scss';
 
@@ -6,6 +6,7 @@ import initMatrix from '../../../client/initMatrix';
 import { getPowerLabel, getUsernameOfRoomMember } from '../../../util/matrixUtil';
 import colorMXID from '../../../util/colorMXID';
 import { openInviteUser, openProfileViewer } from '../../../client/action/navigation';
+import AsyncSearch from '../../../util/AsyncSearch';
 
 import Text from '../../atoms/text/Text';
 import Header, { TitleWrapper } from '../../atoms/header/Header';
@@ -37,31 +38,88 @@ function sortByPowerLevel(m1, m2) {
   if (pl1 < pl2) return 1;
   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 }) {
   const PER_PAGE_MEMBER = 50;
-  const room = initMatrix.matrixClient.getRoom(roomId);
-  const totalMemberList = room.getJoinedMembers().sort(AtoZ).sort(sortByPowerLevel);
-  const [memberList, updateMemberList] = useState([]);
+  const mx = initMatrix.matrixClient;
+  const room = mx.getRoom(roomId);
   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() {
-    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(() => {
+    asyncSearch.setup(memberList, {
+      keys: ['name', 'username', 'userId'],
+      limit: PER_PAGE_MEMBER,
+    });
+  }, [memberList]);
+
   useEffect(() => {
-    updateMemberList(totalMemberList.slice(0, PER_PAGE_MEMBER));
+    setMemberList(
+      simplyfiMembers(
+        getMembersWithMembership(membership)
+          .sort(AtoZ).sort(sortByPowerLevel),
+      ),
+    );
     room.loadMembersIfNeeded().then(() => {
       if (isRoomChanged) return;
-      const newTotalMemberList = room.getJoinedMembers().sort(AtoZ).sort(sortByPowerLevel);
-      updateMemberList(newTotalMemberList.slice(0, PER_PAGE_MEMBER));
+      setMemberList(
+        simplyfiMembers(
+          getMembersWithMembership(membership)
+            .sort(AtoZ).sort(sortByPowerLevel),
+        ),
+      );
     });
 
+    asyncSearch.on(asyncSearch.RESULT_SENT, handleSearchData);
     return () => {
       isRoomChanged = true;
+      setMemberList([]);
+      setSearchedMembers(null);
+      setItemCount(PER_PAGE_MEMBER);
+      asyncSearch.removeListener(asyncSearch.RESULT_SENT, handleSearchData);
     };
   }, [roomId]);
 
+  const mList = searchedMembers !== null ? searchedMembers.data : memberList.slice(0, itemCount);
   return (
     <div className="people-drawer">
       <Header>
@@ -78,20 +136,20 @@ function PeopleDrawer({ roomId }) {
           <ScrollView autoHide>
             <div className="people-drawer__content">
               {
-                memberList.map((member) => (
+                mList.map((member) => (
                   <PeopleSelector
                     key={member.userId}
                     onClick={() => openProfileViewer(member.userId, roomId)}
-                    avatarSrc={member.getAvatarUrl(initMatrix.matrixClient.baseUrl, 24, 24, 'crop')}
-                    name={getUsernameOfRoomMember(member)}
+                    avatarSrc={member.avatarSrc}
+                    name={member.name}
                     color={colorMXID(member.userId)}
-                    peopleRole={getPowerLabel(member.powerLevel)}
+                    peopleRole={member.peopleRole}
                   />
                 ))
               }
               <div className="people-drawer__load-more">
                 {
-                  memberList.length !== totalMemberList.length && (
+                  mList.length !== 0 && mList.length > itemCount && (
                     <Button onClick={loadMorePeople}>View more</Button>
                   )
                 }
@@ -101,7 +159,7 @@ function PeopleDrawer({ roomId }) {
         </div>
         <div className="people-drawer__sticky">
           <form onSubmit={(e) => e.preventDefault()} className="people-search">
-            <Input type="text" placeholder="Search" required />
+            <Input type="text" onChange={handleSearch} placeholder="Search" required />
           </form>
         </div>
       </div>
index 56ac29e0739d64c7f9a29d9b551b5362f88f0657..b3a2182f96a68396c268f1b0168f3c5cdaa0b173 100644 (file)
   }
 
   &__sticky {
-    display: none;
-
     & .people-search {
-      min-height: 48px;
+      --search-input-height: 40px;
+      min-height: var(--search-input-height);
   
       margin: 0 var(--sp-normal);
 
@@ -47,7 +46,7 @@
       bottom: var(--sp-normal);
 
       & .input {
-        height: 48px;
+        height: var(--search-input-height);
       }
     }
   }
@@ -55,7 +54,7 @@
 
 .people-drawer__content {
   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 {
   padding: var(--sp-normal);