Skip to content

Commit

Permalink
fix: webinar presentation layout update (#131)
Browse files Browse the repository at this point in the history
* refactor: update variable name

* refactor: webinar presentation layout
  • Loading branch information
faiq-naufal authored Jan 29, 2024
1 parent 8a447ae commit 1ede017
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 175 deletions.
14 changes: 7 additions & 7 deletions app/(pages)/room/[roomID]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,25 +52,25 @@ export default async function Page({ searchParams }: PageProps) {
if (isModerator) {
const moderatorMeta = await serverSDK.getMetadata(
roomData.id,
'moderatorIDs'
'moderatorClientIDs'
);
const moderatorIDs = moderatorMeta?.data?.moderatorIDs;
const moderatorClientIDs = moderatorMeta?.data?.moderatorClientIDs;

try {
if (Array.isArray(moderatorIDs)) {
if (Array.isArray(moderatorClientIDs)) {
await serverSDK.setMetadata(roomData.id, {
moderatorIDs: [...moderatorIDs, userClient.clientID],
moderatorClientIDs: [...moderatorClientIDs, userClient.clientID],
});
} else {
await serverSDK.setMetadata(roomData.id, {
moderatorIDs: [userClient.clientID],
moderatorClientIDs: [userClient.clientID],
});
}
} catch (error) {
Sentry.captureException(error, {
extra: {
message: `API call error when trying to add client ID to metadata moderatorIDs`,
moderatorIDs: moderatorIDs,
message: `API call error when trying to add client ID to metadata moderatorClientIDs`,
moderatorClientIDs: moderatorClientIDs,
clientID: userClient.clientID,
},
});
Expand Down
72 changes: 0 additions & 72 deletions app/_features/room/components/conference-presentation-layout.tsx

This file was deleted.

18 changes: 9 additions & 9 deletions app/_features/room/components/conference-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ export default function ConferenceScreen({
const { peer } = usePeerContext();
const { datachannels } = useDataChannelContext();
const { roomID } = useClientContext();
const { speakers, moderatorIDs, isModerator, roomType } =
const { speakerClientIDs, moderatorClientIDs, isModerator, roomType } =
useMetadataContext();

const isHost = moderatorIDs.includes(stream.clientId);
const isHost = moderatorClientIDs.includes(stream.clientId);
const [rtcLocalStats, setRtcLocalStats] = useState({
videoRtcOutbound: undefined as RTCOutboundRtpStreamStats | undefined,
audioRtcOutbound: undefined as RTCOutboundRtpStreamStats | undefined,
Expand Down Expand Up @@ -185,12 +185,12 @@ export default function ConferenceScreen({
if (confirmed) {
try {
await clientSDK.setMetadata(roomID, {
speakers: [...speakers, stream.clientId],
speakerClientIDs: [...speakerClientIDs, stream.clientId],
});
} catch (error) {
Sentry.captureException(error, {
extra: {
message: `API call error when trying to set metadata speakers`,
message: `API call error when trying to set metadata speakerClientIDs`,
},
});
console.error(error);
Expand All @@ -205,25 +205,25 @@ export default function ConferenceScreen({

if (confirmed) {
try {
const newSpeakers = speakers.filter((speaker) => {
const newSpeakerClientIDs = speakerClientIDs.filter((speaker) => {
return speaker !== stream.clientId;
});

await clientSDK.setMetadata(roomID, {
speakers: newSpeakers,
speakerClientIDs: newSpeakerClientIDs,
});
} catch (error) {
Sentry.captureException(error, {
extra: {
message: `API call error when trying to set metadata speakers`,
message: `API call error when trying to set metadata speakerClientIDs`,
},
});
console.error(error);
}
}
}
},
[roomID, speakers, stream, isModerator]
[roomID, speakerClientIDs, stream, isModerator]
);

const localVideoScreen =
Expand Down Expand Up @@ -444,7 +444,7 @@ export default function ConferenceScreen({
</Button>
</DropdownTrigger>
<DropdownMenu aria-label="More options" onAction={onMoreSelection}>
{speakers.includes(stream.clientId) ? (
{speakerClientIDs.includes(stream.clientId) ? (
<DropdownItem key="set-regular-participant">
Set as a regular participant
</DropdownItem>
Expand Down
11 changes: 6 additions & 5 deletions app/_features/room/components/conference-speaker-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,28 @@ export default function ConferenceSpeakerLayout({
}: {
streams: ParticipantStream[];
}) {
const { moderatorIDs, speakers: speakerClientIDs } = useMetadataContext();
const { moderatorClientIDs, speakerClientIDs } = useMetadataContext();

const speakers = useMemo(() => {
return streams.filter((stream) => {
return (
(moderatorIDs.includes(stream.clientId) && stream.source === 'media') ||
(moderatorClientIDs.includes(stream.clientId) &&
stream.source === 'media') ||
(speakerClientIDs.includes(stream.clientId) &&
stream.source === 'media')
);
});
}, [streams, moderatorIDs, speakerClientIDs]);
}, [streams, moderatorClientIDs, speakerClientIDs]);

const participants = useMemo(() => {
return streams.filter((stream) => {
return (
!moderatorIDs.includes(stream.clientId) &&
!moderatorClientIDs.includes(stream.clientId) &&
!speakerClientIDs.includes(stream.clientId) &&
stream.source === 'media'
);
});
}, [streams, moderatorIDs, speakerClientIDs]);
}, [streams, moderatorClientIDs, speakerClientIDs]);

const MAX_VISIBLE_PARTICIPANTS = 20;
const slicedParticipants = participants.slice(0, MAX_VISIBLE_PARTICIPANTS);
Expand Down
2 changes: 1 addition & 1 deletion app/_features/room/components/conference.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import MeetingOneOnOneLayout from './meeting-one-on-one-layout';
import MeetingGalleryLayout from './meeting-gallery-layout';
import MeetingPresentationLayout from './meeting-presentation-layout';
import WebinarSpeakerLayout from './conference-speaker-layout';
import WebinarPresentationLayout from './conference-presentation-layout';
import WebinarPresentationLayout from './webinar-presentation-layout';
import PlugConnectedFillIcon from '@/_shared/components/icons/plug-connected-fill-icon';
import PlugDisconnectedFillIcon from '@/_shared/components/icons/plug-disconnected-fill-icon';

Expand Down
127 changes: 127 additions & 0 deletions app/_features/room/components/webinar-presentation-layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
'use client';

import { useMemo } from 'react';
import ConferenceScreen from '@/_features/room/components/conference-screen';
import ConferenceScreenHidden from './conference-screen-hidden';
import { useMetadataContext } from '@/_features/room/contexts/metadata-context';
import { type ParticipantStream } from '@/_features/room/contexts/participant-context';
import '../styles/webinar-presentation-layout.css';

export default function WebinarPresentationLayout({
streams,
}: {
streams: ParticipantStream[];
}) {
const { moderatorClientIDs, speakerClientIDs } = useMetadataContext();
const MAX_VISIBLE_PARTICIPANTS = 6;

const { speakers, participants } = useMemo(() => {
return streams.reduce(
(accumulator, currentStream) => {
if (
moderatorClientIDs.includes(currentStream.clientId) ||
speakerClientIDs.includes(currentStream.clientId)
) {
return {
...accumulator,
speakers: [...accumulator.speakers, currentStream],
};
} else {
return {
...accumulator,
participants: [...accumulator.participants, currentStream],
};
}
},
{
speakers: [] as ParticipantStream[],
participants: [] as ParticipantStream[],
}
);
}, [streams, moderatorClientIDs, speakerClientIDs]);

const { speakerMedias, speakerScreens } = useMemo(() => {
return speakers.reduce(
(accumulator, currentValue) => {
if (currentValue.source === 'screen') {
return {
...accumulator,
speakerScreens: [...accumulator.speakerScreens, currentValue],
};
} else {
return {
...accumulator,
speakerMedias: [...accumulator.speakerMedias, currentValue],
};
}
},
{
speakerScreens: [] as ParticipantStream[],
speakerMedias: [] as ParticipantStream[],
}
);
}, [speakers]);

const spotlightScreen = speakerScreens.pop();
const visibleSpeakerScreens = speakerScreens.slice(
0,
MAX_VISIBLE_PARTICIPANTS
);
const hiddenSpeakerScreens = speakerScreens.slice(MAX_VISIBLE_PARTICIPANTS);

const visibleSpeakers =
visibleSpeakerScreens.length < MAX_VISIBLE_PARTICIPANTS
? speakerMedias.slice(
0,
MAX_VISIBLE_PARTICIPANTS - visibleSpeakerScreens.length
)
: [];

const hiddenSpeakers = speakerMedias.slice(visibleSpeakers.length);

const visibleStreams = [...visibleSpeakerScreens, ...visibleSpeakers];
const hiddenStreams = [
...hiddenSpeakerScreens,
...hiddenSpeakers,
...participants,
];

const maxColumns = Math.ceil(Math.sqrt(visibleStreams.length));

return (
<div className="webinar-presentation-layout">
<div className="presentation-container">
<div className="relative h-full w-full">
{spotlightScreen && <ConferenceScreen stream={spotlightScreen} />}
</div>
</div>
<div className="participant-container">
<div
className={`participant-grid grid gap-3`}
style={{
gridTemplateColumns: `repeat(${maxColumns}, minmax(auto, 180px))`,
}}
>
{visibleStreams.map((stream) => {
return (
<div
className="participant-item"
key={`visible-stream-${stream.id}`}
>
<ConferenceScreen stream={stream} />
</div>
);
})}
{hiddenStreams.map((stream) => {
return (
<ConferenceScreenHidden
key={`hidden-screen-${stream.id}`}
stream={stream}
/>
);
})}
</div>
</div>
</div>
);
}
4 changes: 2 additions & 2 deletions app/_features/room/contexts/metadata-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import { usePeerContext } from '@/_features/room/contexts/peer-context';

const defaultData = {
isModerator: false as boolean,
moderatorIDs: [] as string[],
moderatorClientIDs: [] as string[],
roomType: 'meeting' as string,
previousLayout: 'gallery' as 'gallery' | 'speaker' | 'presentation',
currentLayout: 'gallery' as 'gallery' | 'speaker' | 'presentation',
speakers: [] as string[],
speakerClientIDs: [] as string[],
};

const MetadataContext = createContext(defaultData);
Expand Down
Loading

0 comments on commit 1ede017

Please sign in to comment.