diff --git a/packages/roomkit-react/src/Prebuilt/components/Footer/PaginatedParticipants.tsx b/packages/roomkit-react/src/Prebuilt/components/Footer/PaginatedParticipants.tsx index 288419a2b4..32d7fb1141 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Footer/PaginatedParticipants.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Footer/PaginatedParticipants.tsx @@ -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; + 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 ( + + {inProgress ? : null} + + ); +}; + +const VirtualizedParticipantItem = React.memo( + ({ + index, + data, + style, + }: { + index: number; + data: ItemData & { hasNext: boolean; loadMorePeers: () => Promise }; + style: React.CSSProperties; + }) => { + if (!data.peerList[index]) { + return ; + } + return ( + + ); + }, +); + export const PaginatedParticipants = ({ roleName, onBack }: { roleName: string; onBack: () => void }) => { const { peers, total, loadPeers, loadMorePeers } = usePaginatedParticipants({ role: roleName, limit: 20 }); const [search, setSearch] = useState(''); - const [isLoading, setIsLoading] = useState(false); const filteredPeers = peers.filter(p => p.name?.toLowerCase().includes(search)); const isConnected = useHMSStore(selectIsConnectedToRoom); const [ref, { width }] = useMeasure(); - const containerRef = useRef(null); - const height = ROW_HEIGHT * peers.length; + const height = ROW_HEIGHT * (filteredPeers.length + 1); const resetSidePane = useSidepaneReset(); const hasNext = total > peers.length; @@ -60,33 +109,16 @@ export const PaginatedParticipants = ({ roleName, onBack }: { roleName: string; - (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} - - {hasNext ? ( - - - - ) : null} + diff --git a/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.jsx b/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.jsx index fe23f71495..67bfe1d180 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/Footer/ParticipantList.jsx @@ -176,7 +176,7 @@ const VirtualizedParticipants = ({ ); }; -export const Participant = ({ peer, isConnected }) => { +export const Participant = ({ peer, isConnected, style }) => { const localPeerId = useHMSStore(selectLocalPeerID); return ( { align="center" justify="between" data-testid={'participant_' + peer.name} + style={style} > { @@ -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) {