waveform/lib/context/ServerContext.tsx
Chneemann 2321551518
All checks were successful
Deploy Waveform to VPS / deploy (push) Successful in 6m56s
feat(channels): display categories and fallback to default text channels
2026-09-13 15:56:53 +02:00

111 lines
3.2 KiB
TypeScript

/**
* @file lib/context/ServerContext.tsx
* @description Context for managing active server state and members across sidebars and mobile drawers.
*/
"use client";
import { createContext, useContext, useState } from "react";
import type { Server, Channel, Category } from "@/db/schema";
/** Type definition representing a server entity along with its associated channels array. */
export type ServerWithChannels = Server & {
channels: Channel[];
categories: Category[];
};
/** Represents a member within a server. */
export interface ServerMember {
id: string;
name: string;
isOnline?: boolean;
}
/** Interface defining the shape of the ServerContext state and update handlers. */
interface ServerContextType {
activeServer: ServerWithChannels | null;
setActiveServer: (server: ServerWithChannels | null) => void;
addChannel: (channel: Channel) => void;
removeChannel: (channelId: string) => void;
updateChannel: (channel: Channel) => void;
addCategory: (category: Category) => void;
members: ServerMember[];
setMembers: (members: ServerMember[]) => void;
}
const ServerContext = createContext<ServerContextType>({
activeServer: null,
setActiveServer: () => {},
addChannel: () => {},
removeChannel: () => {},
updateChannel: () => {},
addCategory: () => {},
members: [],
setMembers: () => {},
});
/** Provider component that wraps the application layout to provide global access to active server state and member listings. */
export function ServerProvider({ children }: { children: React.ReactNode }) {
const [activeServer, setActiveServer] = useState<ServerWithChannels | null>(
null,
);
const [members, setMembers] = useState<ServerMember[]>([]);
/** Helper function to update channels within the active server state. */
const updateChannels = (fn: (channels: Channel[]) => Channel[]) => {
setActiveServer((prev) =>
prev ? { ...prev, channels: fn(prev.channels) } : prev,
);
};
/** Adds a new channel to the active server. */
const addChannel = (channel: Channel) =>
updateChannels((prev) => [...prev, channel]);
/** Removes a channel from the active server by its identifier. */
const removeChannel = (channelId: string) =>
updateChannels((prev) => prev.filter((c) => c.id !== channelId));
/** Updates an existing channel within the active server. */
const updateChannel = (updatedChannel: Channel) =>
updateChannels((prev) =>
prev.map((c) => (c.id === updatedChannel.id ? updatedChannel : c)),
);
const addCategory = (category: Category) => {
setActiveServer((prev) =>
prev
? {
...prev,
categories: [...(prev.categories || []), category],
}
: prev,
);
};
return (
<ServerContext.Provider
value={{
activeServer,
setActiveServer,
addChannel,
removeChannel,
updateChannel,
addCategory,
members,
setMembers,
}}
>
{children}
</ServerContext.Provider>
);
}
/** Custom hook to access the active server context. */
export function useActiveServer() {
const context = useContext(ServerContext);
if (!context) {
throw new Error("useActiveServer must be used within a ServerProvider");
}
return context;
}