From 59a958dc6bc42ef9de1efff9efea1aaeb8fb4a97 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Tue, 9 Sep 2025 08:57:39 -0600 Subject: [PATCH] feat: remove wait page and simplify Join button with 5-minute disable logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove entire wait page directory and associated files - Update handleJoinUpcoming to create unscheduled meeting directly - Simplify Join button to single state: - Always shows "Join" text - Blue when meeting can be joined (ongoing or within 5 minutes) - Gray/disabled when more than 5 minutes away - Remove confusing "Join Now", "Join Early" text variations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- www/app/[roomName]/MeetingSelection.tsx | 15 +- .../wait/[eventId]/WaitPageClient.tsx | 190 ------------------ www/app/[roomName]/wait/[eventId]/page.tsx | 57 ------ 3 files changed, 10 insertions(+), 252 deletions(-) delete mode 100644 www/app/[roomName]/wait/[eventId]/WaitPageClient.tsx delete mode 100644 www/app/[roomName]/wait/[eventId]/page.tsx diff --git a/www/app/[roomName]/MeetingSelection.tsx b/www/app/[roomName]/MeetingSelection.tsx index 984dc36e..74976423 100644 --- a/www/app/[roomName]/MeetingSelection.tsx +++ b/www/app/[roomName]/MeetingSelection.tsx @@ -86,9 +86,9 @@ export default function MeetingSelection({ } }; - const handleJoinUpcoming = (event: CalendarEventResponse) => { - // Navigate to waiting page with event info - router.push(`/${roomName}/wait/${event.id}`); + const handleJoinUpcoming = async (event: CalendarEventResponse) => { + // Create an unscheduled meeting for this calendar event + onCreateUnscheduled(); }; const handleEndMeeting = async (meetingId: string) => { @@ -270,6 +270,10 @@ export default function MeetingSelection({ const startTime = new Date(event.start_time); const endTime = new Date(event.end_time); const isOngoing = startTime <= now && now <= endTime; + const minutesUntilStart = Math.floor( + (startTime.getTime() - now.getTime()) / (1000 * 60), + ); + const canJoinEarly = minutesUntilStart <= 5; // Allow joining 5 minutes before return ( handleJoinUpcoming(event)} + isDisabled={!isOngoing && !canJoinEarly} > - {isOngoing ? "Join Now" : "Join Early"} + Join diff --git a/www/app/[roomName]/wait/[eventId]/WaitPageClient.tsx b/www/app/[roomName]/wait/[eventId]/WaitPageClient.tsx deleted file mode 100644 index 36046c0c..00000000 --- a/www/app/[roomName]/wait/[eventId]/WaitPageClient.tsx +++ /dev/null @@ -1,190 +0,0 @@ -"use client"; - -import { useEffect, useState } from "react"; -import { - Box, - Spinner, - Text, - VStack, - Button, - HStack, - Badge, -} from "@chakra-ui/react"; -import { useRouter } from "next/navigation"; -import { useRoomGetByName } from "../../../lib/apiHooks"; -import MinimalHeader from "../../../components/MinimalHeader"; - -interface WaitPageClientProps { - params: { - roomName: string; - eventId: string; - }; -} - -const formatDateTime = (date: string | Date) => { - const d = new Date(date); - return d.toLocaleString("en-US", { - month: "short", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - }); -}; - -const formatCountdown = (startTime: string | Date) => { - const now = new Date(); - const start = new Date(startTime); - const diff = start.getTime() - now.getTime(); - - if (diff <= 0) return "Meeting should start now"; - - const minutes = Math.floor(diff / 60000); - const hours = Math.floor(minutes / 60); - const days = Math.floor(hours / 24); - - if (days > 0) return `Starts in ${days}d ${hours % 24}h ${minutes % 60}m`; - if (hours > 0) return `Starts in ${hours}h ${minutes % 60}m`; - return `Starts in ${minutes} minutes`; -}; - -export default function WaitPageClient({ params }: WaitPageClientProps) { - const { roomName, eventId } = params; - const router = useRouter(); - - const [countdown, setCountdown] = useState(""); - - // Fetch room data - const roomQuery = useRoomGetByName(roomName); - const room = roomQuery.data; - - // Mock event data - in a real implementation, you'd fetch the actual event - const mockEvent = { - id: eventId, - title: "Upcoming Meeting", - start_time: new Date(Date.now() + 15 * 60 * 1000), // 15 minutes from now - end_time: new Date(Date.now() + 75 * 60 * 1000), // 1 hour 15 minutes from now - description: "Meeting will start soon", - }; - - // Update countdown every second - useEffect(() => { - const timer = setInterval(() => { - setCountdown(formatCountdown(mockEvent.start_time)); - }, 1000); - - return () => clearInterval(timer); - }, [mockEvent.start_time]); - - // Redirect to selection if room not found - useEffect(() => { - if (roomQuery.isError) { - router.push(`/${roomName}`); - } - }, [roomQuery.isError, router, roomName]); - - const handleJoinEarly = () => { - // In a real implementation, this would create a meeting and join - alert("Join early functionality not yet implemented"); - }; - - const handleBackToSelection = () => { - router.push(`/${roomName}`); - }; - - if (roomQuery.isLoading) { - return ( - - - - - - Loading... - - - - ); - } - - return ( - - - - - - - - {mockEvent.title} - - - {countdown} - - - - - - - - Meeting Details - - - {formatDateTime(mockEvent.start_time)} -{" "} - {formatDateTime(mockEvent.end_time)} - - {mockEvent.description && ( - - {mockEvent.description} - - )} - - - - - - - The meeting hasn't started yet. You can wait here or come back - later. - - - - - - - - - - - - - ); -} diff --git a/www/app/[roomName]/wait/[eventId]/page.tsx b/www/app/[roomName]/wait/[eventId]/page.tsx deleted file mode 100644 index 1066c2de..00000000 --- a/www/app/[roomName]/wait/[eventId]/page.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { - Box, - Spinner, - Text, - VStack, - Button, - HStack, - Badge, -} from "@chakra-ui/react"; -import MinimalHeader from "../../../components/MinimalHeader"; -import { Metadata } from "next"; -import WaitPageClient from "./WaitPageClient"; - -interface WaitPageProps { - params: { - roomName: string; - eventId: string; - }; -} - -// Generate dynamic metadata for the waiting page -export async function generateMetadata({ - params, -}: WaitPageProps): Promise { - const { roomName } = params; - - try { - const response = await fetch( - `${process.env.NEXT_PUBLIC_REFLECTOR_API_URL}/v1/rooms/name/${roomName}`, - { - headers: { - "Content-Type": "application/json", - }, - }, - ); - - if (response.ok) { - const room = await response.json(); - const displayName = room.display_name || room.name; - return { - title: `Waiting for Meeting - ${displayName}'s Room`, - description: `Waiting for upcoming meeting in ${displayName}'s room on Reflector.`, - }; - } - } catch (error) { - console.error("Failed to fetch room for metadata:", error); - } - - return { - title: `Waiting for Meeting - ${roomName}'s Room`, - description: `Waiting for upcoming meeting in ${roomName}'s room on Reflector.`, - }; -} - -export default function WaitPage({ params }: WaitPageProps) { - return ; -}