import { useEffect, useState } from "react"; import { usePermissionStore, PERMISSION_LABELS, PERMS, type ChannelOverride, hasPermission } from "../stores/permissions.ts"; import { useRoleStore } from "../stores/role.ts"; import { useMemberStore } from "../stores/member.ts"; import { useChannelStore } from "../stores/channel.ts"; import { api } from "../lib/api.ts"; interface ChannelSettingsModalProps { serverId: string; channelId: string; channelName: string; onClose: () => void; } type Tab = 'overview' | 'permissions'; type TargetMode = 'role' | 'user'; interface OverrideFormData { targetType: TargetMode; targetId: string; allow: number; deny: number; } function OverrideMatrix({ allow, deny, onChange }: { allow: number; deny: number; onChange: (allow: number, deny: number) => void }) { const toggle = (flag: number, state: 'allow' | 'deny' | 'inherit') => { let nextAllow = allow; let nextDeny = deny; if (state === 'allow') { nextAllow |= flag; nextDeny &= ~flag; } else if (state === 'deny') { nextAllow &= ~flag; nextDeny |= flag; } else { nextAllow &= ~flag; nextDeny &= ~flag; } onChange(nextAllow, nextDeny); }; const state = (flag: number): 'allow' | 'deny' | 'inherit' => { if (hasPermission(allow, flag)) return 'allow'; if (hasPermission(deny, flag)) return 'deny'; return 'inherit'; }; return (
{(Object.keys(PERMISSION_LABELS) as (keyof typeof PERMISSION_LABELS)[]).map((key) => { const flag = PERMS[key]; const s = state(flag); return (
{PERMISSION_LABELS[key]}
{(['inherit', 'allow', 'deny'] as const).map((opt) => ( ))}
); })}
); } export function ChannelSettingsModal({ serverId, channelId, channelName, onClose }: ChannelSettingsModalProps) { const [tab, setTab] = useState('overview'); const [form, setForm] = useState({ targetType: 'role', targetId: '', allow: 0, deny: 0 }); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const [editName, setEditName] = useState(channelName); const [savingName, setSavingName] = useState(false); const updateChannel = useChannelStore((s) => s.updateChannel); const overrides = usePermissionStore((s) => s.overridesByChannel[channelId] || []); const fetchOverrides = usePermissionStore((s) => s.fetchOverrides); const setOverride = usePermissionStore((s) => s.setOverride); const deleteOverride = usePermissionStore((s) => s.deleteOverride); const roles = useRoleStore((s) => s.roles); const fetchRoles = useRoleStore((s) => s.fetchRoles); const members = useMemberStore((s) => s.membersByServer[serverId] || []); const fetchMembers = useMemberStore((s) => s.fetchMembers); useEffect(() => { fetchOverrides(channelId).catch(() => setError('Failed to load overrides')); fetchRoles(serverId).catch(() => {}); fetchMembers(serverId).catch(() => {}); }, [channelId, serverId, fetchOverrides, fetchRoles, fetchMembers]); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [onClose]); const handleSave = async () => { if (!form.targetId) { setError('Select a target'); return; } setSaving(true); setError(null); try { await setOverride(channelId, form.targetType, form.targetId, form.allow, form.deny); setForm({ targetType: 'role', targetId: '', allow: 0, deny: 0 }); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to save override'); } finally { setSaving(false); } }; const handleSaveName = async () => { const name = editName.trim(); if (!name || name === channelName) return; setSavingName(true); setError(null); try { const updated = await api.patch<{ id: string; server_id: string; name: string; type: string; category: string | null; position: number; group_id?: string | null }>( `/servers/${serverId}/channels/${channelId}`, { name } ); updateChannel(updated as any); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to rename channel'); } finally { setSavingName(false); } }; const targets = form.targetType === 'role' ? roles.filter((r) => !r.is_default).map((r) => ({ id: r.id, label: r.name })) : members.map((m) => ({ id: m.id, label: m.username })); return (
e.stopPropagation()}>
CHANNEL SETTINGS: #{channelName}
{tab === 'overview' && (
Channel name
setEditName(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') handleSaveName(); }} className="terminal-input text-sm flex-1" />
{error &&
ERR: {error}
}
)} {tab === 'permissions' && (
Existing overrides
{overrides.length === 0 &&
[none]
} {overrides.map((o: ChannelOverride) => (
{o.target_type}:{o.target_id}
allow:{o.allow_bitflags} deny:{o.deny_bitflags}
))}
New override
setForm({ ...form, allow: a, deny: d })} /> {error &&
ERR: {error}
}
)}
); }