Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@ export function App({ socket }: AppProps) {
const [roomID, setRoomID] = useState<string>("");
const [rooms, setRooms] = useState<RoomSummary[]>([]);
const [joinedRooms, setJoinedRooms] = useState<Set<string>>(new Set());
// <<<<<< codex/update-chat-bubble-alignment
const [messagesByRoom, setMessagesByRoom] = useState<Record<string, Chat[]>>({});
const [userName] = useState(() => createGuestName());
const [userToken] = useState(() => crypto.randomUUID());
// =======
const [messagesByRoom, setMessagesByRoom] = useState<Record<string, ChatMessage[]>>({});
const [isConnected, setIsConnected] = useState(false);
const hasSentConnect = useRef(false);
const pendingTimers = useRef<Map<string, number>>(new Map());
const identity = useMemo(() => createIdentity(), []);
// >>>>>>> main

const handleListRooms = useCallback((response: Response) => {
if (response.type === "list_rooms") {
Expand Down Expand Up @@ -146,8 +152,22 @@ export function App({ socket }: AppProps) {
}, []);

const sendMessageRequest = useWsRequest(socket, undefined);
const connectRequest = useWsRequest(socket, undefined);

useEffect(() => {
if (!socket) {
return;
}

connectRequest({ type: "connect", token: userToken, name: userName });
}, [connectRequest, socket, userName, userToken]);

const onMessageSent = (content: string) => {
// <<<<<< codex/update-chat-bubble-alignment
const chat: Chat = { content, user: { name: userName } };

// =======
// >>>>>>> main
if (!roomID) {
return;
}
Expand Down Expand Up @@ -215,12 +235,29 @@ export function App({ socket }: AppProps) {

return (
<>
{roomID ? <ChatPanel messages={messagesByRoom[roomID] ?? []} onMessageSent={onMessageSent} /> : <EmptyChat />}
{roomID ? (
<ChatPanel
currentUserName={userName}
messages={messagesByRoom[roomID] ?? []}
onMessageSent={onMessageSent}
/>
) : (
<EmptyChat />
)}
<Rooms roomID={roomID} rooms={rooms} joinedRooms={joinedRooms} setRoomID={setRoomID} joinRoom={joinRoom} />
</>
);
}

// <<<<<< codex/update-chat-bubble-alignment
function createGuestName(): string {
const adjectives = ["Amber", "Brisk", "Golden", "Quiet", "Sandy", "Silver", "Sunny", "Velvet"];
const nouns = ["Comet", "Dawn", "Drift", "Ember", "Harbor", "Horizon", "Lumen", "Spark"];
const adjective = adjectives[Math.floor(Math.random() * adjectives.length)];
const noun = nouns[Math.floor(Math.random() * nouns.length)];
const suffix = Math.floor(100 + Math.random() * 900);
return `${adjective}${noun}${suffix}`;
// ======
function createIdentity(): Identity {
const token = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : fallbackId();
return {
Expand All @@ -238,4 +275,5 @@ function createMessageId(): string {

function fallbackId(): string {
return Math.random().toString(36).slice(2, 10);
// >>>>>> main
}
24 changes: 23 additions & 1 deletion frontend/src/ChatPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,39 @@ export type ChatMessage = {
};

type ChatPanelProps = {
// <<<<< codex/update-chat-bubble-alignment
currentUserName: string;
messages: Chat[];
//=======
messages: ChatMessage[];
// >>>>>>> main
onMessageSent: (message: string) => void;
};

export function ChatPanel({ messages, onMessageSent }: ChatPanelProps) {
export function ChatPanel({ currentUserName, messages, onMessageSent }: ChatPanelProps) {
const [draft, setDraft] = useState("");

return (
<div className="flex-1 min-w-0 p-4">
<div className="h-full w-full p-4 flex flex-col">
<h2 className="text-lg font-semibold">Chat</h2>
<div className="space-y-3 overflow-y-auto flex-1">
// <<<<< codex/update-chat-bubble-alignment
{messages.map((message, index) => {
const isOwnMessage = message.user.name === currentUserName;
const chatAlignment = isOwnMessage ? "chat-end" : "chat-start";
const bubbleTone = isOwnMessage ? "chat-bubble-primary" : "chat-bubble-secondary";
const footerText = isOwnMessage ? "Sent" : "Delivered";

return (
<div className={`chat ${chatAlignment}`} key={`${message.user.name ?? "unknown"}-${index}`}>
<div className="chat-header">
{isOwnMessage ? "You" : (message.user.name ?? "Anonymous")}
<time className="text-xs opacity-50">{isOwnMessage ? "Just now" : "Moments ago"}</time>
</div>
<div className={`chat-bubble ${bubbleTone}`}>{message.content}</div>
<div className="chat-footer opacity-50">{footerText}</div>
// =======
{messages.map((message) => {
const bubbleClass =
message.status === "pending"
Expand All @@ -39,6 +60,7 @@ export function ChatPanel({ messages, onMessageSent }: ChatPanelProps) {
{message.status === "error" ? (
<div className="text-xs text-error mt-1">Delivery failed</div>
) : null}
// >>>>>> main
</div>
);
})}
Expand Down