Files
dumpsterChat/web/src/components/ThreadListPanel.tsx
T

70 lines
2.3 KiB
TypeScript

import { useEffect, useState } from 'react';
import { useThreadStore, type Thread } from '../stores/thread.ts';
interface ThreadListPanelProps {
channelId: string;
onSelect: (thread: { id: string; name: string }) => void;
onClose: () => void;
}
export function ThreadListPanel({ channelId, onSelect, onClose }: ThreadListPanelProps) {
const threads = useThreadStore((s) => s.threadsByParent[channelId] || []);
const fetchThreads = useThreadStore((s) => s.fetchThreads);
const createThread = useThreadStore((s) => s.createThread);
const [name, setName] = useState('');
const [loading, setLoading] = useState(false);
useEffect(() => {
fetchThreads(channelId);
}, [channelId, fetchThreads]);
const handleCreate = async () => {
if (!name.trim()) return;
setLoading(true);
try {
const t = await createThread(channelId, { name: name.trim() });
onSelect({ id: t.id, name: t.name });
setName('');
} finally {
setLoading(false);
}
};
return (
<div className="bg-gb-bg-s border-b border-gb-bg-t p-3 font-mono text-sm">
<div className="flex items-center justify-between mb-2">
<span className="text-gb-orange text-xs">THREADS</span>
<button onClick={onClose} className="text-xs text-gb-fg-f hover:text-gb-orange">[x]</button>
</div>
<div className="flex gap-2 mb-2">
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="new thread name"
className="terminal-input flex-1 text-xs"
/>
<button
onClick={handleCreate}
disabled={loading || !name.trim()}
className="text-xs bg-gb-orange text-gb-bg px-2 disabled:opacity-50"
>
[+]
</button>
</div>
{threads.length === 0 && <div className="text-gb-fg-f text-xs">[no threads]</div>}
<div className="space-y-1">
{threads.map((t: Thread) => (
<button
key={t.id}
onClick={() => onSelect({ id: t.id, name: t.name })}
className="w-full text-left text-xs text-gb-fg hover:text-gb-orange truncate"
>
{t.name} <span className="text-gb-fg-f">({t.message_count})</span>
</button>
))}
</div>
</div>
);
}