feat: channel settings modal now has name editing
Added [OVERVIEW] tab to ChannelSettingsModal with an editable channel name field. The ⚙ button on each channel opens the modal. Users can rename channels without needing to know about the right-click context menu.
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from "react";
|
||||||
import { usePermissionStore, PERMISSION_LABELS, PERMS, type ChannelOverride, hasPermission } from '../stores/permissions.ts';
|
import { usePermissionStore, PERMISSION_LABELS, PERMS, type ChannelOverride, hasPermission } from "../stores/permissions.ts";
|
||||||
import { useRoleStore } from '../stores/role.ts';
|
import { useRoleStore } from "../stores/role.ts";
|
||||||
import { useMemberStore } from '../stores/member.ts';
|
import { useMemberStore } from "../stores/member.ts";
|
||||||
|
import { useChannelStore } from "../stores/channel.ts";
|
||||||
|
import { api } from "../lib/api.ts";
|
||||||
|
|
||||||
interface ChannelSettingsModalProps {
|
interface ChannelSettingsModalProps {
|
||||||
serverId: string;
|
serverId: string;
|
||||||
@@ -10,7 +12,7 @@ interface ChannelSettingsModalProps {
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tab = 'permissions';
|
type Tab = 'overview' | 'permissions';
|
||||||
type TargetMode = 'role' | 'user';
|
type TargetMode = 'role' | 'user';
|
||||||
|
|
||||||
interface OverrideFormData {
|
interface OverrideFormData {
|
||||||
@@ -76,10 +78,13 @@ function OverrideMatrix({ allow, deny, onChange }: { allow: number; deny: number
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ChannelSettingsModal({ serverId, channelId, channelName, onClose }: ChannelSettingsModalProps) {
|
export function ChannelSettingsModal({ serverId, channelId, channelName, onClose }: ChannelSettingsModalProps) {
|
||||||
const [tab] = useState<Tab>('permissions');
|
const [tab, setTab] = useState<Tab>('overview');
|
||||||
const [form, setForm] = useState<OverrideFormData>({ targetType: 'role', targetId: '', allow: 0, deny: 0 });
|
const [form, setForm] = useState<OverrideFormData>({ targetType: 'role', targetId: '', allow: 0, deny: 0 });
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(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 overrides = usePermissionStore((s) => s.overridesByChannel[channelId] || []);
|
||||||
const fetchOverrides = usePermissionStore((s) => s.fetchOverrides);
|
const fetchOverrides = usePermissionStore((s) => s.fetchOverrides);
|
||||||
@@ -122,6 +127,24 @@ export function ChannelSettingsModal({ serverId, channelId, channelName, onClose
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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'
|
const targets = form.targetType === 'role'
|
||||||
? roles.filter((r) => !r.is_default).map((r) => ({ id: r.id, label: r.name }))
|
? roles.filter((r) => !r.is_default).map((r) => ({ id: r.id, label: r.name }))
|
||||||
: members.map((m) => ({ id: m.id, label: m.username }));
|
: members.map((m) => ({ id: m.id, label: m.username }));
|
||||||
@@ -134,9 +157,31 @@ export function ChannelSettingsModal({ serverId, channelId, channelName, onClose
|
|||||||
<button onClick={onClose} className="text-xs text-gb-red">[x]</button>
|
<button onClick={onClose} className="text-xs text-gb-red">[x]</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex border-b border-gb-bg-t">
|
<div className="flex border-b border-gb-bg-t">
|
||||||
<button className="px-4 py-2 text-xs text-gb-orange bg-gb-bg-s">[PERMISSIONS]</button>
|
<button onClick={() => setTab('overview')} className={`px-4 py-2 text-xs ${tab === 'overview' ? 'text-gb-orange bg-gb-bg-s' : 'text-gb-fg-s hover:text-gb-fg'}`}>[OVERVIEW]</button>
|
||||||
|
<button onClick={() => setTab('permissions')} className={`px-4 py-2 text-xs ${tab === 'permissions' ? 'text-gb-orange bg-gb-bg-s' : 'text-gb-fg-s hover:text-gb-fg'}`}>[PERMISSIONS]</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 overflow-y-auto p-4">
|
<div className="flex-1 overflow-y-auto p-4">
|
||||||
|
{tab === 'overview' && (
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="text-xs text-gb-fg-f">Channel name</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<input
|
||||||
|
value={editName}
|
||||||
|
onChange={(e) => setEditName(e.target.value)}
|
||||||
|
onKeyDown={(e) => { if (e.key === 'Enter') handleSaveName(); }}
|
||||||
|
className="terminal-input text-sm flex-1"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={handleSaveName}
|
||||||
|
disabled={savingName || !editName.trim() || editName.trim() === channelName}
|
||||||
|
className="px-3 py-1 bg-gb-orange text-gb-bg text-xs disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{savingName ? 'SAVING...' : '[SAVE]'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{error && <div className="text-xs text-gb-red">ERR: {error}</div>}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{tab === 'permissions' && (
|
{tab === 'permissions' && (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="text-xs text-gb-fg-f">Existing overrides</div>
|
<div className="text-xs text-gb-fg-f">Existing overrides</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user