import { lazy, Suspense } from 'react' import { FaMicrophoneSlash, FaUserTimes } from 'react-icons/fa' import { VideoroomParticipantDto, VideoroomLayoutDto } from '@/proxy/videoroom/models' import { Button } from '@/components/ui' const VideoPlayer = lazy(() => import('./VideoPlayer').then((module) => ({ default: module.VideoPlayer })), ) interface RoomParticipantProps { participants: VideoroomParticipantDto[] localStream?: MediaStream | null currentUserId: string currentUserName: string isTeacher: boolean isAudioEnabled: boolean isVideoEnabled: boolean onMuteParticipant?: (participantId: string, isMuted: boolean, isTeacher: boolean) => void layout: VideoroomLayoutDto focusedParticipant?: string onParticipantFocus?: (participantId: string | undefined) => void onKickParticipant?: (participantId: string) => void hasSidePanel?: boolean } export const RoomParticipant = ({ participants, localStream, currentUserId, currentUserName, isTeacher, isAudioEnabled, isVideoEnabled, onMuteParticipant, layout, focusedParticipant, onParticipantFocus, onKickParticipant, hasSidePanel = false, }: RoomParticipantProps) => { // Only show current user's video once const currentUserParticipant = { id: currentUserId, name: currentUserName, isTeacher, stream: localStream ?? undefined, } as unknown as VideoroomParticipantDto // Eğer hiç katılımcı yoksa ve localStream de yoksa hiçbir şey render etme if (!localStream && (!participants || participants.length === 0)) { return null } const allParticipants = [currentUserParticipant, ...participants] // Ortak ana video kutusu container class'ı const mainVideoContainerClass = 'w-full h-full flex flex-col justify-center' const renderGridLayout = () => { const getGridClass = (participantCount: number) => { if (participantCount === 1) return 'grid-cols-1' if (participantCount <= 2) return 'grid-cols-1 sm:grid-cols-2' if (participantCount <= 4) return 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-2' if (participantCount <= 6) return 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3' if (participantCount <= 9) return 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3' return 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-4' } const getGridRows = (participantCount: number) => { if (participantCount === 1) return 'grid-rows-1' if (participantCount <= 2) return 'grid-rows-1 sm:grid-rows-1' if (participantCount <= 4) return 'grid-rows-2 lg:grid-rows-2' if (participantCount <= 6) return 'grid-rows-3 sm:grid-rows-2' if (participantCount <= 9) return 'grid-rows-3' return 'grid-rows-4 sm:grid-rows-3' } const getPadding = (participantCount: number) => { if (participantCount === 1) return '' if (participantCount <= 4) return 'p-2 sm:p-4' return 'p-1 sm:p-2' } const getGap = (participantCount: number) => { if (participantCount === 1) return 'gap-0' if (participantCount <= 4) return 'gap-2 sm:gap-3' return 'gap-1 sm:gap-2' } // Mobilde: En üstte öğretmen, altında katılımcılar 2'li grid ve dikey scroll const mainParticipant = allParticipants[0] const otherParticipants = allParticipants.slice(1) return ( <> {/* Mobil özel layout */}
{/* Ana katılımcı */}
{renderParticipant(mainParticipant, true)}
{/* Diğer katılımcılar 2'li grid ve dikey scroll */} {otherParticipants.length > 0 && (
{Array.from({ length: Math.ceil(otherParticipants.length / 2) }).map((_, rowIdx) => (
{otherParticipants.slice(rowIdx * 2, rowIdx * 2 + 2).map((participant) => (
{renderParticipant(participant, false, true)}
))} {otherParticipants.length % 2 === 1 && rowIdx === Math.floor(otherParticipants.length / 2) ? (
) : null}
))}
)}
{/* Masaüstü ve tablet için eski grid layout */}
{allParticipants.map((participant) => (
{renderParticipant(participant, false)}
))}
) } const renderSidebarLayout = () => { const mainParticipant = focusedParticipant ? allParticipants.find((p) => p.id === focusedParticipant) || allParticipants[0] : allParticipants[0] const otherParticipants = allParticipants.filter((p) => p.id !== mainParticipant.id) const sidebarWidth = hasSidePanel ? 'w-20 sm:w-24 md:w-32 lg:w-40' : 'w-24 sm:w-32 md:w-40 lg:w-48' // Eğer hiç katılımcı yoksa, video player öğretmen odaklı gibi ortalanır ve geniş olur return (
{renderParticipant(mainParticipant, true)}
{otherParticipants.length > 0 && (
{otherParticipants.map((participant) => (
{renderParticipant(participant, false, true)}
))}
)}
) } const renderTeacherFocusLayout = () => { // Sadece öğretmen gösterilecek, katılımcılar asla gösterilmeyecek const teacher = allParticipants.find((p) => p.isTeacher) || allParticipants[0] return (
{renderParticipant(teacher, true)}
) } const renderParticipant = ( participant: VideoroomParticipantDto, isMain: boolean = false, isSmall: boolean = false, ) => (
!isMain && onParticipantFocus?.(participant.id)} style={{ minHeight: 0, minWidth: 0 }} >
}>
{/* Teacher controls for students */} {isTeacher && participant.id !== currentUserId && (
)}
) const renderLayout = () => { switch (layout.type) { case 'sidebar': return renderSidebarLayout() case 'teacher-focus': return renderTeacherFocusLayout() default: return renderGridLayout() } } return
{renderLayout()}
}