import Workspace from "@/models/workspace"; import paths from "@/utils/paths"; import showToast from "@/utils/toast"; import { Plus, CircleNotch, Trash } from "@phosphor-icons/react"; import { useEffect, useState } from "react"; import ThreadItem from "./ThreadItem"; import { useParams } from "react-router-dom"; export const THREAD_RENAME_EVENT = "renameThread"; export default function ThreadContainer({ workspace }) { const { threadSlug = null } = useParams(); const [threads, setThreads] = useState([]); const [loading, setLoading] = useState(true); const [ctrlPressed, setCtrlPressed] = useState(false); useEffect(() => { const chatHandler = (event) => { const { threadSlug, newName } = event.detail; setThreads((prevThreads) => prevThreads.map((thread) => { if (thread.slug === threadSlug) { return { ...thread, name: newName }; } return thread; }) ); }; window.addEventListener(THREAD_RENAME_EVENT, chatHandler); return () => { window.removeEventListener(THREAD_RENAME_EVENT, chatHandler); }; }, []); useEffect(() => { async function fetchThreads() { if (!workspace.slug) return; const { threads } = await Workspace.threads.all(workspace.slug); setLoading(false); setThreads(threads); } fetchThreads(); }, [workspace.slug]); // Enable toggling of bulk-deletion by holding meta-key (ctrl on win and cmd/fn on others) useEffect(() => { const handleKeyDown = (event) => { if (["Control", "Meta"].includes(event.key)) { setCtrlPressed(true); } }; const handleKeyUp = (event) => { if (["Control", "Meta"].includes(event.key)) { setCtrlPressed(false); // when toggling, unset bulk progress so // previously marked threads that were never deleted // come back to life. setThreads((prev) => prev.map((t) => { return { ...t, deleted: false }; }) ); } }; window.addEventListener("keydown", handleKeyDown); window.addEventListener("keyup", handleKeyUp); return () => { window.removeEventListener("keydown", handleKeyDown); window.removeEventListener("keyup", handleKeyUp); }; }, []); const toggleForDeletion = (id) => { setThreads((prev) => prev.map((t) => { if (t.id !== id) return t; return { ...t, deleted: !t.deleted }; }) ); }; const handleDeleteAll = async () => { const slugs = threads.filter((t) => t.deleted === true).map((t) => t.slug); await Workspace.threads.deleteBulk(workspace.slug, slugs); setThreads((prev) => prev.filter((t) => !t.deleted)); // Only redirect if current thread is being deleted if (slugs.includes(threadSlug)) { window.location.href = paths.workspace.chat(workspace.slug); } }; function removeThread(threadId) { setThreads((prev) => prev.map((_t) => { if (_t.id !== threadId) return _t; return { ..._t, deleted: true }; }) ); // Show thread was deleted, but then remove from threads entirely so it will // not appear in bulk-selection. setTimeout(() => { setThreads((prev) => prev.filter((t) => !t.deleted)); }, 500); } if (loading) { return (
loading threads....