import { Avatar, AvatarFallback, AvatarImage, Button, ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger, } from "@tensamin/ui"; import { focusParticipant, getRoomMetadata, setCallView, startWatchingStream, useCall, } from "../../store"; import { Track, type Participant } from "livekit-client"; import { useEffect, useRef, useState } from "react"; import { useUser, type User } from "@tensamin/user/context"; import { useIsSpeaking } from "../../speakingState"; import VideoViewer from "../videoViewer"; import { HeadphoneOff, MicOff, Monitor, Plus, Shield } from "lucide-react"; function getTrackPublicationBySource( participant: Participant | undefined, source: Track.Source, ) { if (!participant) { return undefined; } return [...participant.trackPublications.values()].find( (publication) => publication.source === source, ); } function TransparentButton({ children }: { children: React.ReactNode }) { return (
{children}
); } function Overlay({ type, user, participant, }: { type: "user" | "stream"; user: User; participant: Participant; }) { const isAdmin = getRoomMetadata()?.admins.includes(user.user_id) === true; const isDeafened = participant.attributes["deafened"] === "true"; return (
{type === "user" && ( <> {!participant.isMicrophoneEnabled && ( )} {isDeafened && ( )} {isAdmin && ( )} )} {type === "stream" && ( )}

{user.display}

); } export default function Base({ participant, type, fill = false, flush = false, }: { participant: Participant | undefined; type: "user" | "stream"; fill?: boolean; flush?: boolean; }) { const { get } = useUser(); const focusedParticipantId = useCall((state) => state.focusedParticipantId); const view = useCall((state) => state.view); const [user, setUser] = useState(null); const isSpeaking = useIsSpeaking(user?.user_id ?? -1); const screenSharePublication = getTrackPublicationBySource( participant, Track.Source.ScreenShare, ); const screenSharePreview = participant?.attributes["screenSharePreview"]; useEffect(() => { const participantId = Number(participant?.identity); if ( !participant || !Number.isInteger(participantId) || participantId <= 0 ) { // eslint-disable-next-line setUser(null); return; } let active = true; void get(participantId).then((nextUser) => { if (active) { setUser(nextUser); } }); return () => { active = false; }; }, [participant, get]); // Avatar calc const currentCard = useRef(null); if (!participant || !user) { return (
); } const onClick = () => { if (view === "grid") { focusParticipant(user.user_id, type); } else { if (user.user_id === focusedParticipantId) { setCallView("grid"); } else { focusParticipant(user.user_id, type); } } }; const showStream = screenSharePublication?.isSubscribed && screenSharePublication.track; const isFocusedInFocusedView = view === "focused" && user.user_id === focusedParticipantId; return (
<> {type === "stream" && !showStream && (
{!isFocusedInFocusedView && ( )}
)} {view === "grid" || (view === "focused" && user.user_id !== focusedParticipantId) ? ( ) : null}
{/* Detect video / user and place here */} {type === "stream" && (showStream ? ( ) : screenSharePreview ? (
) : null)} {type === "user" && ( {user.display.slice(0, 2).toUpperCase()} )}
} /> Stop Watching ); }