feat: UI for server/channel creation, settings link, role management backend
Frontend: - Settings link in header next to logout - [+] button to create server (name + optional icon) - [#] button to join server via invite code - [+] button to create channel (name, type, category) - Server name shown instead of UUID in channel list header - /invites/:code route wired for JoinServer component Backend: - Wire role CRUD + member-role assignment routes (MANAGE_SERVER gated) - Seed @everyone default role on server creation
This commit is contained in:
@@ -1,14 +1,17 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useServerStore } from '../stores/server.ts';
|
||||
import { useChannelStore } from '../stores/channel.ts';
|
||||
import { VoiceChannel } from './VoiceChannel.tsx';
|
||||
import { CreateChannelModal } from './CreateChannelModal.tsx';
|
||||
|
||||
export function ChannelList() {
|
||||
const activeServerId = useServerStore((state) => state.activeServerId);
|
||||
const servers = useServerStore((state) => state.servers);
|
||||
const channelsByServer = useChannelStore((state) => state.channelsByServer);
|
||||
const fetchChannels = useChannelStore((state) => state.fetchChannels);
|
||||
const activeChannelId = useChannelStore((state) => state.activeChannelId);
|
||||
const setActiveChannel = useChannelStore((state) => state.setActiveChannel);
|
||||
const [showCreate, setShowCreate] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeServerId) {
|
||||
@@ -16,7 +19,14 @@ export function ChannelList() {
|
||||
}
|
||||
}, [activeServerId, fetchChannels]);
|
||||
|
||||
const channels = activeServerId ? channelsByServer[activeServerId] || [] : [];
|
||||
const channels = useMemo(() => {
|
||||
return activeServerId ? channelsByServer[activeServerId] || [] : [];
|
||||
}, [activeServerId, channelsByServer]);
|
||||
|
||||
const activeServer = useMemo(() => {
|
||||
if (!activeServerId) return null;
|
||||
return servers.find((s) => s.id === activeServerId) || null;
|
||||
}, [servers, activeServerId]);
|
||||
|
||||
const categories = useMemo(() => {
|
||||
const map = new Map<string, typeof channels>();
|
||||
@@ -34,8 +44,17 @@ export function ChannelList() {
|
||||
|
||||
return (
|
||||
<div className="h-full w-56 bg-gb-bg-s border-r border-gb-bg-t flex flex-col">
|
||||
<div className="terminal-border border-t-0 border-x-0 px-3 py-2 text-gb-fg truncate">
|
||||
{activeServerId ? `[SERVER ${activeServerId}]` : '[NO SERVER]'}
|
||||
<div className="terminal-border border-t-0 border-x-0 px-3 py-2 text-gb-fg truncate flex items-center justify-between">
|
||||
<span>{activeServerId ? `[SERVER ${activeServer?.name ?? activeServerId}]` : '[NO SERVER]'}</span>
|
||||
{activeServerId && (
|
||||
<button
|
||||
onClick={() => setShowCreate(true)}
|
||||
className="terminal-button text-xs"
|
||||
title="Create channel"
|
||||
>
|
||||
[+]
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto p-2 font-mono text-sm">
|
||||
{categories.length === 0 && (
|
||||
@@ -68,6 +87,9 @@ export function ChannelList() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{showCreate && activeServerId && (
|
||||
<CreateChannelModal serverId={activeServerId} onClose={() => setShowCreate(false)} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user