"use client"; import { partition } from "remeda"; import { Box, VStack, HStack, Text, Button, Spinner, Badge, Icon, Flex, } from "@chakra-ui/react"; import React from "react"; import { FaUsers, FaClock, FaCalendarAlt, FaPlus } from "react-icons/fa"; import { LuX } from "react-icons/lu"; import type { components } from "../reflector-api"; import { useRoomActiveMeetings, useRoomJoinMeeting, useMeetingDeactivate, useRoomGetByName, } from "../lib/apiHooks"; import { useRouter } from "next/navigation"; import { formatDateTime, formatStartedAgo } from "../lib/timeUtils"; import MeetingMinimalHeader from "../components/MeetingMinimalHeader"; import { NonEmptyString } from "../lib/utils"; type Meeting = components["schemas"]["Meeting"]; interface MeetingSelectionProps { roomName: NonEmptyString; isOwner: boolean; isSharedRoom: boolean; authLoading: boolean; onMeetingSelect: (meeting: Meeting) => void; onCreateUnscheduled: () => void; isCreatingMeeting?: boolean; } export default function MeetingSelection({ roomName, isOwner, isSharedRoom, onMeetingSelect, onCreateUnscheduled, isCreatingMeeting = false, }: MeetingSelectionProps) { const router = useRouter(); const roomQuery = useRoomGetByName(roomName); const activeMeetingsQuery = useRoomActiveMeetings(roomName); const joinMeetingMutation = useRoomJoinMeeting(); const deactivateMeetingMutation = useMeetingDeactivate(); const room = roomQuery.data; const allMeetings = activeMeetingsQuery.data || []; const now = new Date(); const [currentMeetings, nonCurrentMeetings] = partition( allMeetings, (meeting) => { const startTime = new Date(meeting.start_date); const endTime = new Date(meeting.end_date); // Meeting is ongoing if current time is between start and end return now >= startTime && now <= endTime; }, ); const upcomingMeetings = nonCurrentMeetings.filter((meeting) => { const startTime = new Date(meeting.start_date); // Meeting is upcoming if it hasn't started yet return now < startTime; }); const loading = roomQuery.isLoading || activeMeetingsQuery.isLoading; const error = roomQuery.error || activeMeetingsQuery.error; const handleJoinUpcoming = async (meeting: Meeting) => { // Join the upcoming meeting and navigate to local meeting page try { const joinedMeeting = await joinMeetingMutation.mutateAsync({ params: { path: { room_name: roomName, meeting_id: meeting.id, }, }, }); onMeetingSelect(joinedMeeting); } catch (err) { console.error("Failed to join upcoming meeting:", err); } }; const handleJoinDirect = (meeting: Meeting) => { // Navigate to local meeting page instead of external URL onMeetingSelect(meeting); }; const handleEndMeeting = async (meetingId: string) => { try { await deactivateMeetingMutation.mutateAsync({ params: { path: { meeting_id: meetingId, }, }, }); } catch (err) { console.error("Failed to end meeting:", err); } }; if (loading) { return ( Loading meetings... ); } if (error) { return ( Error {"Failed to load meetings"} ); } const handleLeaveMeeting = () => { router.push("/"); }; return ( {/* Loading overlay */} {isCreatingMeeting && ( Creating meeting... )} {/* Current Ongoing Meetings - BIG DISPLAY */} {currentMeetings.length > 0 ? ( {currentMeetings.map((meeting) => ( {(meeting.calendar_metadata as any)?.title || "Live Meeting"} {isOwner && (meeting.calendar_metadata as any)?.description && ( {(meeting.calendar_metadata as any).description} )} {meeting.num_clients || 0} participant {meeting.num_clients !== 1 ? "s" : ""} {formatStartedAgo(new Date(meeting.start_date))} {isOwner && (meeting.calendar_metadata as any)?.attendees && ( {(meeting.calendar_metadata as any).attendees .slice(0, 4) .map((attendee: any, idx: number) => ( {attendee.name || attendee.email} ))} {(meeting.calendar_metadata as any).attendees.length > 4 && ( + {(meeting.calendar_metadata as any).attendees .length - 4}{" "} more )} )} {isOwner && ( )} ))} ) : upcomingMeetings.length > 0 ? ( /* Upcoming Meetings - BIG DISPLAY when no ongoing meetings */ Upcoming Meeting{upcomingMeetings.length > 1 ? "s" : ""} {upcomingMeetings.map((meeting) => { const now = new Date(); const startTime = new Date(meeting.start_date); const minutesUntilStart = Math.floor( (startTime.getTime() - now.getTime()) / (1000 * 60), ); return ( {(meeting.calendar_metadata as any)?.title || "Upcoming Meeting"} {isOwner && (meeting.calendar_metadata as any)?.description && ( {(meeting.calendar_metadata as any).description} )} Starts in {minutesUntilStart} minute {minutesUntilStart !== 1 ? "s" : ""} {formatDateTime(new Date(meeting.start_date))} {isOwner && (meeting.calendar_metadata as any)?.attendees && ( {(meeting.calendar_metadata as any).attendees .slice(0, 4) .map((attendee: any, idx: number) => ( {attendee.name || attendee.email} ))} {(meeting.calendar_metadata as any).attendees .length > 4 && ( + {(meeting.calendar_metadata as any).attendees .length - 4}{" "} more )} )} {isOwner && ( )} ); })} ) : null} {/* Upcoming Meetings - SMALLER ASIDE DISPLAY when there are ongoing meetings */} {currentMeetings.length > 0 && upcomingMeetings.length > 0 && ( Starting Soon {upcomingMeetings.map((meeting) => { const now = new Date(); const startTime = new Date(meeting.start_date); const minutesUntilStart = Math.floor( (startTime.getTime() - now.getTime()) / (1000 * 60), ); return ( {(meeting.calendar_metadata as any)?.title || "Upcoming Meeting"} in {minutesUntilStart} minute {minutesUntilStart !== 1 ? "s" : ""} Starts: {formatDateTime(new Date(meeting.start_date))} ); })} )} {/* No meetings message - show when no ongoing or upcoming meetings */} {currentMeetings.length === 0 && upcomingMeetings.length === 0 && ( No meetings right now There are no ongoing or upcoming meetings in this room at the moment. )} ); }