From 99af75ea25310d0c3c5e58add2b4a1251915271d Mon Sep 17 00:00:00 2001 From: Leo dev Date: Sat, 18 Oct 2025 14:10:06 +0200 Subject: [PATCH] Sidebar UI, server stuff --- src/app/api/server/[id]/route.ts | 2 +- src/components/Sidebar.tsx | 96 +++++++++++--------------------- src/hooks/use-app.ts | 24 +++++++- src/types/app.ts | 5 +- src/types/types.ts | 1 + 5 files changed, 61 insertions(+), 67 deletions(-) diff --git a/src/app/api/server/[id]/route.ts b/src/app/api/server/[id]/route.ts index f695cac..edbe085 100644 --- a/src/app/api/server/[id]/route.ts +++ b/src/app/api/server/[id]/route.ts @@ -13,7 +13,7 @@ export async function GET( const { data: profile } = await supabase .from("servers") - .select("id, created_at, owner, address") + .select("id, name, created_at, owner, address, icon_url") .eq("id", id) .maybeSingle(); diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 1b887b7..50f66ae 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -14,7 +14,6 @@ import { Dialog, DialogClose, DialogContent, - DialogDescription, DialogFooter, DialogHeader, DialogTitle, @@ -37,6 +36,7 @@ import App from "@/types/app"; import { ProfileSettings } from "@/types/settings"; import axios from "axios"; import { useIsMobile } from "@/hooks/is-mobile"; +import { get } from "@/lib/request"; export default function AppSidebar({ children, @@ -51,8 +51,7 @@ export default function AppSidebar({ server?: Server | undefined; app: App; }>) { - const [servers, setServers] = useState<[string, string][]>([]); - const [newServer, setNewServer] = useState({ name: "", ip: "" }); + const [newServer, setNewServer] = useState(""); const [query, setQuery] = useState(""); const router = useRouter(); const isMobile = useIsMobile(); @@ -82,15 +81,7 @@ export default function AppSidebar({ load(); }, [dms, query]); - useEffect(() => { - const stored = Cookies.get("servers"); - if (!stored) return; - const parsed = stored - .split(",") - .map((x) => x.trim().split("@")) - .filter(([ip, name]) => ip && name) as [string, string][]; - setServers(parsed); - }, []); + useEffect(() => {}, []); useEffect(() => { if (!app.profile?.node_address) return; @@ -123,16 +114,20 @@ export default function AppSidebar({ }); }, [chatWith, app.profile]); - const handleAddServer = () => { - if (!newServer.ip) return; - const updatedServers = [ - ...servers, - [newServer.ip, newServer.name] as [string, string], - ]; + const handleAddServer = async () => { + if (!newServer || Object.hasOwn(app.servers, newServer)) return; - setServers(updatedServers); - Cookies.set("servers", updatedServers.map((x) => x.join("@")).join(",")); - setNewServer({ name: "", ip: "" }); + try { + const server = (await get(`/api/server/${newServer}`)).data as Server; + app.setServers((prev) => ({ + ...prev, + [server.id]: server, + })); + Cookies.set("servers", Object.keys(app.servers).join(",")); + setNewServer(""); + } catch (e: any) { + toast.error(e); + } }; return ( @@ -143,7 +138,7 @@ export default function AppSidebar({ app.sidebarOpen && isMobile ? "w-5xl md:w-md" : "w-0 md:w-md" )} > -
+
- {servers.map( - ([ip, name]) => - ip && ( - + {Object.values(app.servers).map( + (srv) => + srv && ( + + + ) )} @@ -173,41 +164,18 @@ export default function AppSidebar({ - Add server - - Add a new server to your server list. - + Join a server
- + - setNewServer((prev) => ({ - ...prev, - name: e.target.value, - })) - } - placeholder="Voxa Server" - /> -
-
- - - setNewServer((prev) => ({ - ...prev, - ip: e.target.value, - })) - } - placeholder="192.168.1.5" + id="id-1" + name="id" + value={newServer} + onChange={(e) => setNewServer(e.target.value)} + placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" />
@@ -218,7 +186,7 @@ export default function AppSidebar({ @@ -231,7 +199,7 @@ export default function AppSidebar({
{/* Right column */} -
+
{server ? (

{server.name}

diff --git a/src/hooks/use-app.ts b/src/hooks/use-app.ts index ec226ec..b90180d 100644 --- a/src/hooks/use-app.ts +++ b/src/hooks/use-app.ts @@ -1,10 +1,13 @@ import App from "@/types/app"; -import { useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useMessages } from "./use-messages"; import { StringMap } from "@/types/typeUtils"; import useUser, { UserProfile } from "./get-user"; import { useClientSettings } from "./use-settings"; import { get, Response } from "@/lib/request"; +import { Server } from "@/types/types"; +import Cookies from "js-cookie"; +import { toast } from "sonner"; export default function useApp(): App { const node = useRef(null); @@ -14,8 +17,27 @@ export default function useApp(): App { const profile = useUser(); const [clientSettings, setClientSettings] = useClientSettings(); const [dms, setDms] = useState([]); + const [servers, setServers] = useState>({}); + + useEffect(() => { + const stored = Cookies.get("servers"); + if (!stored) return; + Promise.all( + stored + .split(",") + .map((x) => x.trim()) + .filter((id) => id) + .map((id) => get(`/api/server/${id}`)) + ) + .then((o) => + setServers(Object.fromEntries(o.map((i) => [i.data.id, i.data]))) + ) + .catch(toast.error); + }, []); return { + servers, + setServers, dms, setDms, node, diff --git a/src/types/app.ts b/src/types/app.ts index 2624abb..45f7ceb 100644 --- a/src/types/app.ts +++ b/src/types/app.ts @@ -1,7 +1,7 @@ import { Dispatch, RefObject, SetStateAction } from "react"; import { StringMap } from "./typeUtils"; import { UserProfile } from "@/hooks/get-user"; -import { Message } from "./types"; +import { Message, Server } from "./types"; import { ClientSettings } from "./settings"; export type SetState = Dispatch>; @@ -13,6 +13,9 @@ export default interface App { clientSettings: ClientSettings; setClientSettings: SetState; + servers: StringMap; + setServers: SetState>; + profiles: StringMap; setProfiles: SetState>; diff --git a/src/types/types.ts b/src/types/types.ts index 9bb3c32..6301fa3 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -15,5 +15,6 @@ export interface Message { export interface Server { id: string; name: string; + icon_url: string; channels: Channel[]; }