/// import { Cell, computed, Default, handler, ifElse, NAME, navigateTo, pattern, UI, } from "commontools"; import GroupChatRoom, { Message, User } from "./group-chat-room.tsx"; /** * Group Chat Lobby Pattern * * Apple iOS-style lobby where unlimited users can join. * Shows all joined users and a form for new users. */ interface LobbyInput { chatName: Default; messages: Cell>; users: Cell>; sessionId: Cell>; } interface LobbyOutput { chatName: Default; messages: Cell>; users: Cell>; sessionId: Cell>; } // Random color selection from a pool of distinct colors function getRandomColor(): string { const colors = [ "#007AFF", // Apple blue "#34C759", // Apple green "#FF9500", // Apple orange "#AF52DE", // Apple purple "#FF3B30", // Apple red "#5856D6", // Apple indigo "#FF2D55", // Apple pink "#00C7BE", // Apple teal ]; return colors[Math.floor(Math.random() * colors.length)]; } // Get initials from name function getInitials(name: string): string { if (!name || typeof name !== "string") return "?"; return name .trim() .split(/\s+/) .map((word) => word[0]) .join("") .toUpperCase() .slice(0, 2); } // Handler to reset the lobby (clear all state and generate new session) const resetLobby = handler< unknown, { messages: Cell; users: Cell; sessionId: Cell } >((_event, { messages, users, sessionId }) => { console.log("[resetLobby] Resetting all chat state..."); // Generate new session ID to invalidate all existing chat room connections const newSessionId = `session-${Date.now()}-${ Math.random().toString(36).slice(2) }`; sessionId.set(newSessionId); messages.set([]); users.set([]); console.log( "[resetLobby] Chat state reset complete, new session:", newSessionId, ); }); // Handler for joining the chat const joinChat = handler< unknown, { chatName: string; messages: Cell; users: Cell; sessionId: Cell; nameInput: Cell; } >((_event, { messages, users, sessionId, nameInput }) => { const name = nameInput.get().trim(); if (!name) { console.log("[joinChat] No name entered, returning"); return; } console.log("[joinChat] Name:", name); // Initialize session ID if not set (first user joining) let currentSessionId = sessionId.get(); if (!currentSessionId) { currentSessionId = `session-${Date.now()}-${ Math.random().toString(36).slice(2) }`; sessionId.set(currentSessionId); console.log("[joinChat] Initialized new session:", currentSessionId); } // Get existing users const existingUsers = users.get() || []; // Check if user already exists const existingUser = existingUsers.find((u) => u.name === name); if (!existingUser) { // Create new user and add to list const newUser: User = { name, joinedAt: Date.now(), color: getRandomColor(), }; users.set([...existingUsers, newUser]); console.log("[joinChat] User added:", name); // Add system message for join const existingMessages = messages.get() || []; messages.set([ ...existingMessages, { id: `msg-${Date.now()}-${Math.random().toString(36).slice(2)}`, author: "System", content: `${name} joined the chat`, timestamp: Date.now(), type: "system", reactions: [], }, ]); } // Clear the name input nameInput.set(""); // Create chat room instance and navigate // Pass both the session ID at join time (mySessionId) and the Cell reference to check against (currentSessionId) console.log( "[joinChat] Navigating to chat room with session:", currentSessionId, ); const roomInstance = GroupChatRoom({ messages, users, myName: name, mySessionId: currentSessionId, currentSessionId: sessionId, }); return navigateTo(roomInstance); }); export default pattern( ({ chatName, messages, users, sessionId }) => { // Name input for new users const nameInput = Cell.of(""); // Note: Use direct property access to avoid transformer bug // with || [] fallback (see computed-var-then-map.issue.md) const userCount = computed(() => users.get().length); return { [NAME]: computed(() => `${chatName} - Lobby`), [UI]: (

{chatName}

Enter your name to join the conversation

{/* Join Form Card */}
Join as
{/* Active Users Section */} {ifElse( userCount,
Now chatting
{users.map((user) => (
{computed(() => user ? getInitials(user.name) : "?")}
{user.name}
))}
, <>, )} {/* Reset Button */}
), chatName, messages, users, sessionId, }; }, );