From d689e017f2ab06f7ba4a19c5b3fb50abb9c43caf Mon Sep 17 00:00:00 2001 From: Ramon Candel Segura Date: Tue, 27 Jan 2026 18:17:27 +0100 Subject: [PATCH 1/2] add loading spinner and error handling for participants list --- lang/main-es.json | 1 + lang/main.json | 1 + .../views/PreMeeting/PreMeetingScreen.tsx | 17 ++- .../components/ParticipantsList.tsx | 35 +++--- .../PreMeeting/components/PreMeetingModal.tsx | 103 +++++++++++++++--- 5 files changed, 124 insertions(+), 33 deletions(-) diff --git a/lang/main-es.json b/lang/main-es.json index deaf52d65984..315e85345870 100644 --- a/lang/main-es.json +++ b/lang/main-es.json @@ -818,6 +818,7 @@ "participants": "Participantes", "participant": "Participante", "upToParticipants": "Hasta {{num}} participantes", + "participantsNotAvailable": "Participantes no disponibles", "upgrade": "Actualizar", "upgradeMessage": "Meet no está disponible con tu plan. \nActualiza ahora para empezar a realizar reuniones privadas." }, diff --git a/lang/main.json b/lang/main.json index 683af4d8bdce..36de15ac3b82 100644 --- a/lang/main.json +++ b/lang/main.json @@ -937,6 +937,7 @@ "participants": "Participants", "participant": "Participant", "upToParticipants": "Up to {{num}} participants", + "participantsNotAvailable": "Participants not available", "upgrade": "Upgrade", "upgradeMessage": "Meet is not available with your plan. \nUpgrade now to start private meetings." }, diff --git a/react/features/base/meet/views/PreMeeting/PreMeetingScreen.tsx b/react/features/base/meet/views/PreMeeting/PreMeetingScreen.tsx index becb78f0e18c..198490babfab 100644 --- a/react/features/base/meet/views/PreMeeting/PreMeetingScreen.tsx +++ b/react/features/base/meet/views/PreMeeting/PreMeetingScreen.tsx @@ -209,6 +209,9 @@ const PreMeetingScreen = ({ const [isNameInputFocused, setIsNameInputFocused] = useState(false); const [isCreatingMeeting, setIsCreatingMeeting] = useState(false); const [meetingUsersData, setMeetingUsersData] = useState([]); + const [isLoadingParticipants, setIsLoadingParticipants] = useState(false); + const [participantsLoadError, setParticipantsLoadError] = useState(false); + const userData = useUserData(); const [openLogin, setOpenLogin] = useState(true); @@ -246,8 +249,16 @@ const PreMeetingScreen = ({ const getUsersInMeeting = async () => { if (!isInNewMeeting) { - const meetingUsers = await MeetingService.instance.getCurrentUsersInCall(room); - setMeetingUsersData(meetingUsers); + setIsLoadingParticipants(true); + setParticipantsLoadError(false); + try { + const meetingUsers = await MeetingService.instance.getCurrentUsersInCall(room); + setMeetingUsersData(meetingUsers); + } catch { + setParticipantsLoadError(true); + } finally { + setIsLoadingParticipants(false); + } } }; @@ -355,6 +366,8 @@ const PreMeetingScreen = ({ setUserName={setName} setIsNameInputFocused={setIsNameInputFocused} participants={meetingUsersData} + isLoadingParticipants={isLoadingParticipants} + participantsLoadError={participantsLoadError} joinConference={async () => { if (createConference) { setIsCreatingMeeting(true); diff --git a/react/features/base/meet/views/PreMeeting/components/ParticipantsList.tsx b/react/features/base/meet/views/PreMeeting/components/ParticipantsList.tsx index 6b6cdf672ed8..9541a2914851 100644 --- a/react/features/base/meet/views/PreMeeting/components/ParticipantsList.tsx +++ b/react/features/base/meet/views/PreMeeting/components/ParticipantsList.tsx @@ -1,31 +1,30 @@ -import { Avatar } from "@internxt/ui"; import React from "react"; +import { Avatar } from "@internxt/ui"; import { MeetingUser } from "../../../services/types/meeting.types"; -const ParticipantsList = ({ - participants, - translate, -}: { +interface ParticipantsListProps { participants: MeetingUser[]; translate: (key: string) => string; -}) => { +} + +const ParticipantsList = ({ participants, translate }: ParticipantsListProps) => { const participantsNumber = participants.length; - return ( -
-
- {translate("meet.internxtMeet")} - - {participantsNumber}{" "} - {participantsNumber === 1 - ? translate("meet.preMeeting.participant") - : translate("meet.preMeeting.participants")} - -
+ return ( +
+ + {participantsNumber}{" "} + {participantsNumber === 1 + ? translate("meet.preMeeting.participant") + : translate("meet.preMeeting.participants")} +
{participants.map((participant, index) => ( -
+
( + + + + +); + +interface ParticipantsStatusProps { + isCreatingConference?: boolean; + isLoadingParticipants?: boolean; + participantsLoadError?: boolean; + participants: MeetingUser[]; + maxParticipants: number; + translate: (key: string, options?: Record) => string; +} + +const ParticipantsStatus = ({ + isCreatingConference, + isLoadingParticipants, + participantsLoadError, + participants, + maxParticipants, + translate: t, +}: ParticipantsStatusProps) => { + if (isCreatingConference) { + return ( + + {t("meet.preMeeting.upToParticipants", { num: maxParticipants })} + + ); + } + + if (isLoadingParticipants) { + return ( +
+ +
+ ); + } + + if (participantsLoadError) { + return ( + + {t("meet.preMeeting.participantsNotAvailable")} + + ); + } + + return ; +}; + interface PreMeetingModalProps { /** * The video track to render as preview @@ -50,6 +117,16 @@ interface PreMeetingModalProps { */ participants: MeetingUser[]; + /** + * Flag to indicate if participants are loading + */ + isLoadingParticipants?: boolean; + + /** + * Flag to indicate if there was an error loading participants + */ + participantsLoadError?: boolean; + /** * Join conference handler */ @@ -88,6 +165,8 @@ const PreMeetingModal = ({ setUserName, setIsNameInputFocused, participants, + isLoadingParticipants, + participantsLoadError, joinConference, disableJoinButton, flipX, @@ -119,19 +198,17 @@ const PreMeetingModal = ({ />
- {isCreatingConference ? ( -
-
- {t("meet.internxtMeet")} - - - {t("meet.preMeeting.upToParticipants", { num })} - -
-
- ) : ( - - )} +
+ {t("meet.internxtMeet")} + +
{!!errorMessage && (
From df7bdbafcc924ed7602b1985642dba4774eaf807 Mon Sep 17 00:00:00 2001 From: Ramon Candel Segura Date: Wed, 28 Jan 2026 11:53:16 +0100 Subject: [PATCH 2/2] Modified key from list to use unique ids --- .../meet/views/PreMeeting/components/ParticipantsList.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/react/features/base/meet/views/PreMeeting/components/ParticipantsList.tsx b/react/features/base/meet/views/PreMeeting/components/ParticipantsList.tsx index 9541a2914851..a298ed261f84 100644 --- a/react/features/base/meet/views/PreMeeting/components/ParticipantsList.tsx +++ b/react/features/base/meet/views/PreMeeting/components/ParticipantsList.tsx @@ -20,9 +20,9 @@ const ParticipantsList = ({ participants, translate }: ParticipantsListProps) =>
- {participants.map((participant, index) => ( + {participants.map((participant) => (