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 { usePermissionStore, PERMISSION_LABELS, PERMS, type ChannelOverride, hasPermission } from '../stores/permissions.ts';
|
||||
import { useRoleStore } from '../stores/role.ts';
|
||||
import { useMemberStore } from '../stores/member.ts';
|
||||
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;
|
||||
@@ -10,7 +12,7 @@ interface ChannelSettingsModalProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
type Tab = 'permissions';
|
||||
type Tab = 'overview' | 'permissions';
|
||||
type TargetMode = 'role' | 'user';
|
||||
|
||||
interface OverrideFormData {
|
||||
@@ -76,10 +78,13 @@ function OverrideMatrix({ allow, deny, onChange }: { allow: number; deny: number
|
||||
}
|
||||
|
||||
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 [saving, setSaving] = useState(false);
|
||||
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 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'
|
||||
? roles.filter((r) => !r.is_default).map((r) => ({ id: r.id, label: r.name }))
|
||||
: 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>
|
||||
</div>
|
||||
<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 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' && (
|
||||
<div className="space-y-3">
|
||||
<div className="text-xs text-gb-fg-f">Existing overrides</div>
|
||||
|
||||
Reference in New Issue
Block a user