Sidebar UI, server stuff

This commit is contained in:
2025-10-18 14:10:06 +02:00
parent d878721098
commit 99af75ea25
5 changed files with 61 additions and 67 deletions
+1 -1
View File
@@ -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();
+32 -64
View File
@@ -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"
)}
>
<div className="w-16 flex flex-col items-center gap-4 py-4 bg-muted border-r">
<div className="w-16 flex flex-col items-center gap-4 py-4 border-r">
<Button
onClick={() => router.push(`/chat`)}
className="bg-transparent text-accent-foreground hover:text-accent"
@@ -151,16 +146,12 @@ export default function AppSidebar({
<MessageCircle className="h-6 w-6" />
</Button>
{servers.map(
([ip, name]) =>
ip && (
<Button
onClick={() => router.push(`/server/${ip}`)}
key={ip}
className="bg-transparent text-accent-foreground hover:text-accent"
>
<HashIcon className="h-6 w-6" />
</Button>
{Object.values(app.servers).map(
(srv) =>
srv && (
<Link href={`/server/${srv.id}`} key={srv.id} className="">
<ProfilePicture name={srv.name} url={srv.icon_url} />
</Link>
)
)}
@@ -173,41 +164,18 @@ export default function AppSidebar({
<DialogContent>
<DialogHeader>
<DialogTitle>Add server</DialogTitle>
<DialogDescription>
Add a new server to your server list.
</DialogDescription>
<DialogTitle>Join a server</DialogTitle>
</DialogHeader>
<div className="grid gap-4">
<div className="grid gap-3">
<Label htmlFor="name-1">Name</Label>
<Label htmlFor="id-1">Server ID</Label>
<Input
id="name-1"
name="name"
value={newServer.name}
onChange={(e) =>
setNewServer((prev) => ({
...prev,
name: e.target.value,
}))
}
placeholder="Voxa Server"
/>
</div>
<div className="grid gap-3">
<Label htmlFor="ip-1">Server Ip</Label>
<Input
id="ip-1"
name="ip"
value={newServer.ip}
onChange={(e) =>
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"
/>
</div>
</div>
@@ -218,7 +186,7 @@ export default function AppSidebar({
</DialogClose>
<DialogClose asChild>
<Button type="button" onClick={handleAddServer}>
Add server
Join server
</Button>
</DialogClose>
</DialogFooter>
@@ -231,7 +199,7 @@ export default function AppSidebar({
</div>
{/* Right column */}
<div className="w-full flex flex-col bg-card">
<div className="w-full flex flex-col bg-card/50">
{server ? (
<div className="p-3 border-b flex items-center gap-2">
<h2>{server.name}</h2>
+23 -1
View File
@@ -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<WebSocket | null>(null);
@@ -14,8 +17,27 @@ export default function useApp(): App {
const profile = useUser();
const [clientSettings, setClientSettings] = useClientSettings();
const [dms, setDms] = useState<UserProfile[]>([]);
const [servers, setServers] = useState<StringMap<Server>>({});
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,
+4 -1
View File
@@ -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<T> = Dispatch<SetStateAction<T>>;
@@ -13,6 +13,9 @@ export default interface App {
clientSettings: ClientSettings;
setClientSettings: SetState<ClientSettings>;
servers: StringMap<Server>;
setServers: SetState<StringMap<Server>>;
profiles: StringMap<UserProfile | null>;
setProfiles: SetState<StringMap<UserProfile | null>>;
+1
View File
@@ -15,5 +15,6 @@ export interface Message {
export interface Server {
id: string;
name: string;
icon_url: string;
channels: Channel[];
}