diff --git a/frontend/src/HomeScreen.tsx b/frontend/src/HomeScreen.tsx index e147ba5..e5d60ae 100644 --- a/frontend/src/HomeScreen.tsx +++ b/frontend/src/HomeScreen.tsx @@ -1,27 +1,39 @@ -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { AppShell, - Avatar, Badge, Box, + Burger, Button, - Code, + Center, Group, - Paper, + Loader, Stack, Text, Title, } from "@mantine/core"; -import { IconLogout, IconUserCircle } from "@tabler/icons-react"; -import { GetSession, Logout } from "../wailsjs/go/main/MatrixService"; +import { useDisclosure } from "@mantine/hooks"; +import { notifications } from "@mantine/notifications"; +import { + IconLock, + IconLogout, + IconUserCircle, +} from "@tabler/icons-react"; +import { + Logout, + SendMarkdown, + SendText, + Start, + Stop, +} from "../wailsjs/go/main/MatrixService"; +import { EventsOn } from "../wailsjs/runtime/runtime"; +import RoomList from "./components/RoomList"; +import Timeline from "./components/Timeline"; +import Composer from "./components/Composer"; +import { useMatrixRooms } from "./hooks/useMatrixRooms"; +import { useMatrixTimeline } from "./hooks/useMatrixTimeline"; -interface Session { - user_id: string; - device_id: string; - homeserver_url: string; - has_token: boolean; - expires_at?: string; -} +const NAVBAR_WIDTH = 300; export default function HomeScreen({ userID, @@ -30,12 +42,63 @@ export default function HomeScreen({ userID: string; onLogout: () => void; }) { - const [session, setSession] = useState(null); + const [navOpen, navHandlers] = useDisclosure(true); + const [activeRoomID, setActiveRoomID] = useState(null); + const [started, setStarted] = useState(false); + const [startError, setStartError] = useState(null); + const { rooms } = useMatrixRooms(started); + const { events, loading: timelineLoading, error: timelineError } = useMatrixTimeline( + activeRoomID, + 50, + ); + + // Boot sync on mount; tear down on unmount. useEffect(() => { - GetSession(userID).then((s) => setSession(s as Session | null)); + let cancelled = false; + (async () => { + try { + await Start(userID); + if (!cancelled) setStarted(true); + } catch (e: any) { + if (!cancelled) { + const msg = String(e?.message ?? e); + setStartError(msg); + notifications.show({ + title: "Sync error", + message: msg, + color: "red", + autoClose: false, + }); + } + } + })(); + return () => { + cancelled = true; + Stop().catch(() => {}); + }; }, [userID]); + // Show transient Matrix errors as toast notifications. + useEffect(() => { + const off = EventsOn("matrix:error", (msg: string) => { + notifications.show({ + title: "Matrix", + message: String(msg), + color: "orange", + autoClose: 6000, + }); + }); + return () => { + if (typeof off === "function") off(); + }; + }, []); + + const activeRoom = useMemo( + () => rooms.find((r) => r.room_id === activeRoomID) || null, + [rooms, activeRoomID], + ); + async function handleLogout() { try { await Logout(userID); @@ -44,22 +107,43 @@ export default function HomeScreen({ } } - const initials = userID - .replace("@", "") - .split(":")[0] - .slice(0, 2) - .toUpperCase(); + async function handleSendText(body: string) { + if (!activeRoomID) return; + await SendText(activeRoomID, body); + } + + async function handleSendMarkdown(md: string) { + if (!activeRoomID) return; + await SendMarkdown(activeRoomID, md); + } return ( - + - - + + + matrix_client_pc - v0.1.0 + v0.2.0 + + {userID} +