Skip to content

Commit

Permalink
feat: add infinite loader to paginated participants (#2009)
Browse files Browse the repository at this point in the history
* feat: add infinite loading to participants

* fix: limits for participant list

* refactor: reuse existing var

* refactor: simplify component
  • Loading branch information
raviteja83 authored Oct 4, 2023
1 parent 7d6bbd5 commit ac3dfc2
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,30 +1,79 @@
import React, { useEffect, useRef, useState } from 'react';
import React, { useEffect, useState } from 'react';
import { useInView } from 'react-intersection-observer';
import { useMeasure } from 'react-use';
import { FixedSizeList } from 'react-window';
import { VariableSizeList } from 'react-window';
import { selectIsConnectedToRoom, useHMSStore, usePaginatedParticipants } from '@100mslive/react-sdk';
import { ChevronLeftIcon, CrossIcon } from '@100mslive/react-icons';
import { Button } from '../../../Button';
import { IconButton } from '../../../IconButton';
import { Box, Flex } from '../../../Layout';
import { Loading } from '../../../Loading';
import { Text } from '../../../Text';
// @ts-ignore: No implicit Any
import { ParticipantSearch } from './ParticipantList';
import { itemKey, ROW_HEIGHT, VirtualizedParticipantItem } from './RoleAccordion';
import { Participant, ParticipantSearch } from './ParticipantList';
import { ItemData, itemKey, ROW_HEIGHT } from './RoleAccordion';
// @ts-ignore: No implicit Any
import { useSidepaneReset } from '../AppData/useSidepane';
// @ts-ignore: No implicit Any
import { getFormattedCount } from '../../common/utils';

const LoadMoreParticipants = ({
hasNext,
loadMore,
style,
}: {
hasNext: boolean;
loadMore: () => Promise<void>;
style: React.CSSProperties;
}) => {
const { ref, inView } = useInView();
const [inProgress, setInProgress] = useState(false);

useEffect(() => {
if (hasNext && inView && !inProgress) {
setInProgress(true);
loadMore()
.catch(console.error)
.finally(() => setInProgress(false));
}
}, [hasNext, loadMore, inView, inProgress]);
return (
<Flex ref={ref} style={style} align="center" justify="center">
{inProgress ? <Loading size={16} /> : null}
</Flex>
);
};

const VirtualizedParticipantItem = React.memo(
({
index,
data,
style,
}: {
index: number;
data: ItemData & { hasNext: boolean; loadMorePeers: () => Promise<void> };
style: React.CSSProperties;
}) => {
if (!data.peerList[index]) {
return <LoadMoreParticipants hasNext={data.hasNext} loadMore={data.loadMorePeers} style={style} />;
}
return (
<Participant
key={data.peerList[index].id}
peer={data.peerList[index]}
isConnected={data.isConnected}
style={style}
/>
);
},
);

export const PaginatedParticipants = ({ roleName, onBack }: { roleName: string; onBack: () => void }) => {
const { peers, total, loadPeers, loadMorePeers } = usePaginatedParticipants({ role: roleName, limit: 20 });
const [search, setSearch] = useState<string>('');
const [isLoading, setIsLoading] = useState(false);
const filteredPeers = peers.filter(p => p.name?.toLowerCase().includes(search));
const isConnected = useHMSStore(selectIsConnectedToRoom);
const [ref, { width }] = useMeasure<HTMLDivElement>();
const containerRef = useRef<HTMLDivElement | null>(null);
const height = ROW_HEIGHT * peers.length;
const height = ROW_HEIGHT * (filteredPeers.length + 1);
const resetSidePane = useSidepaneReset();
const hasNext = total > peers.length;

Expand Down Expand Up @@ -60,33 +109,16 @@ export const PaginatedParticipants = ({ roleName, onBack }: { roleName: string;
</Text>
</Flex>
<Box css={{ flex: '1 1 0', overflowY: 'auto', overflowX: 'hidden', mr: '-$10' }}>
<FixedSizeList
itemSize={ROW_HEIGHT}
itemData={{ peerList: filteredPeers, isConnected: isConnected === true }}
<VariableSizeList
itemSize={index => (index === filteredPeers.length + 1 ? 16 : ROW_HEIGHT)}
itemData={{ peerList: filteredPeers, hasNext, loadMorePeers, isConnected: isConnected === true }}
itemKey={itemKey}
itemCount={filteredPeers.length}
itemCount={filteredPeers.length + 1}
width={width}
height={height}
outerRef={containerRef}
>
{VirtualizedParticipantItem}
</FixedSizeList>
{hasNext ? (
<Flex justify="center" css={{ w: '100%' }}>
<Button
css={{ w: 'max-content', p: '$4' }}
onClick={() => {
setIsLoading(true);
loadMorePeers()
.catch(console.error)
.finally(() => setIsLoading(false));
}}
disabled={isLoading}
>
{isLoading ? <Loading size={16} /> : 'Load More'}
</Button>
</Flex>
) : null}
</VariableSizeList>
</Box>
</Flex>
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ const VirtualizedParticipants = ({
);
};

export const Participant = ({ peer, isConnected }) => {
export const Participant = ({ peer, isConnected, style }) => {
const localPeerId = useHMSStore(selectLocalPeerID);
return (
<Flex
Expand All @@ -191,6 +191,7 @@ export const Participant = ({ peer, isConnected }) => {
align="center"
justify="between"
data-testid={'participant_' + peer.name}
style={style}
>
<Text
variant="sm"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface ItemData {
}

export function itemKey(index: number, data: ItemData) {
return data.peerList[index].id;
return data.peerList[index]?.id;
}

export const VirtualizedParticipantItem = React.memo(({ index, data }: { index: number; data: ItemData }) => {
Expand Down Expand Up @@ -64,8 +64,8 @@ export const RoleAccordion = ({
return null;
}

const height = ROW_HEIGHT * (peers.length || peerList.length);
const peersInAccordion = isOffStageRole && isLargeRoom ? peers : peerList;
const height = ROW_HEIGHT * peersInAccordion.length;
const hasNext = total > peersInAccordion.length;

if (peersInAccordion.length === 0) {
Expand Down

0 comments on commit ac3dfc2

Please sign in to comment.