diff --git a/package.json b/package.json index 28fe37a..f57cf9e 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "scripts": { "playground:dev": "pnpm run --filter=playground dev", "lint": "eslint --cache --cache-location ./node_modules/.cache/eslint .", + "lint:fix": "npm run lint -- --fix", "build": "pnpm run -r build", "test": "pnpm run -r test", "typecheck": "pnpm run -r typecheck" diff --git a/packages/bolt/app/components/header/Header.tsx b/packages/bolt/app/components/header/Header.tsx index 2aa4d48..15cf4bf 100644 --- a/packages/bolt/app/components/header/Header.tsx +++ b/packages/bolt/app/components/header/Header.tsx @@ -3,6 +3,7 @@ import { ClientOnly } from 'remix-utils/client-only'; import { chatStore } from '~/lib/stores/chat'; import { classNames } from '~/utils/classNames'; import { HeaderActionButtons } from './HeaderActionButtons.client'; +import { ChatDescription } from '~/lib/persistence/ChatDescription.client'; export function Header() { const chat = useStore(chatStore); @@ -23,7 +24,9 @@ export function Header() { -
+ + {() => } + {chat.started && ( {() => ( diff --git a/packages/bolt/app/components/sidebar/Menu.client.tsx b/packages/bolt/app/components/sidebar/Menu.client.tsx index 3438214..cfeeb3c 100644 --- a/packages/bolt/app/components/sidebar/Menu.client.tsx +++ b/packages/bolt/app/components/sidebar/Menu.client.tsx @@ -4,7 +4,7 @@ import { toast } from 'react-toastify'; import { Dialog, DialogButton, DialogDescription, DialogRoot, DialogTitle } from '~/components/ui/Dialog'; import { IconButton } from '~/components/ui/IconButton'; import { ThemeSwitch } from '~/components/ui/ThemeSwitch'; -import { db, deleteId, getAll, type ChatHistoryItem } from '~/lib/persistence'; +import { db, deleteById, getAll, chatId, type ChatHistoryItem } from '~/lib/persistence'; import { cubicEasingFn } from '~/utils/easings'; import { logger } from '~/utils/logger'; import { HistoryItem } from './HistoryItem'; @@ -52,8 +52,15 @@ export function Menu() { event.preventDefault(); if (db) { - deleteId(db, item.id) - .then(() => loadEntries()) + deleteById(db, item.id) + .then(() => { + loadEntries(); + + if (chatId.get() === item.id) { + // hard page navigation to clear the stores + window.location.pathname = '/'; + } + }) .catch((error) => { toast.error('Failed to delete conversation'); logger.error(error); diff --git a/packages/bolt/app/lib/persistence/ChatDescription.client.tsx b/packages/bolt/app/lib/persistence/ChatDescription.client.tsx new file mode 100644 index 0000000..9c7cbf2 --- /dev/null +++ b/packages/bolt/app/lib/persistence/ChatDescription.client.tsx @@ -0,0 +1,6 @@ +import { useStore } from '@nanostores/react'; +import { description } from './useChatHistory'; + +export function ChatDescription() { + return useStore(description); +} diff --git a/packages/bolt/app/lib/persistence/db.ts b/packages/bolt/app/lib/persistence/db.ts index 786ad91..7a952e3 100644 --- a/packages/bolt/app/lib/persistence/db.ts +++ b/packages/bolt/app/lib/persistence/db.ts @@ -92,7 +92,7 @@ export async function getMessagesById(db: IDBDatabase, id: string): Promise { +export async function deleteById(db: IDBDatabase, id: string): Promise { return new Promise((resolve, reject) => { const transaction = db.transaction('chats', 'readwrite'); const store = transaction.objectStore('chats'); diff --git a/packages/bolt/app/lib/persistence/useChatHistory.ts b/packages/bolt/app/lib/persistence/useChatHistory.ts index 3b5e181..9d6d324 100644 --- a/packages/bolt/app/lib/persistence/useChatHistory.ts +++ b/packages/bolt/app/lib/persistence/useChatHistory.ts @@ -1,6 +1,7 @@ import { useLoaderData, useNavigate } from '@remix-run/react'; +import { useState, useEffect } from 'react'; +import { atom } from 'nanostores'; import type { Message } from 'ai'; -import { useEffect, useState } from 'react'; import { toast } from 'react-toastify'; import { AnalyticsAction, sendAnalyticsEvent } from '~/lib/analytics'; import { workbenchStore } from '~/lib/stores/workbench'; @@ -18,16 +19,16 @@ const persistenceEnabled = !import.meta.env.VITE_DISABLE_PERSISTENCE; export const db = persistenceEnabled ? await openDatabase() : undefined; +export const chatId = atom(undefined); +export const description = atom(undefined); + export function useChatHistory() { const navigate = useNavigate(); const { id: mixedId } = useLoaderData<{ id?: string }>(); - const [chatId, setChatId] = useState(mixedId); const [initialMessages, setInitialMessages] = useState([]); const [ready, setReady] = useState(false); - const [entryId, setEntryId] = useState(); const [urlId, setUrlId] = useState(); - const [description, setDescription] = useState(); useEffect(() => { if (!db) { @@ -40,14 +41,14 @@ export function useChatHistory() { return; } - if (chatId) { - getMessages(db, chatId) + if (mixedId) { + getMessages(db, mixedId) .then((storedMessages) => { if (storedMessages && storedMessages.messages.length > 0) { setInitialMessages(storedMessages.messages); setUrlId(storedMessages.urlId); - setDescription(storedMessages.description); - setChatId(storedMessages.id); + description.set(storedMessages.description); + chatId.set(storedMessages.id); } else { navigate(`/`, { replace: true }); } @@ -61,7 +62,7 @@ export function useChatHistory() { }, []); return { - ready: !chatId || ready, + ready: !mixedId || ready, initialMessages, storeMessageHistory: async (messages: Message[]) => { if (!db || messages.length === 0) { @@ -77,27 +78,21 @@ export function useChatHistory() { setUrlId(urlId); } - if (!description && firstArtifact?.title) { - setDescription(firstArtifact?.title); + if (!description.get() && firstArtifact?.title) { + description.set(firstArtifact?.title); } - if (initialMessages.length === 0) { - if (!entryId) { - const nextId = await getNextId(db); + if (initialMessages.length === 0 && !chatId.get()) { + const nextId = await getNextId(db); - await setMessages(db, nextId, messages, urlId, description); + chatId.set(nextId); - setEntryId(nextId); - - if (!urlId) { - navigateChat(nextId); - } - } else { - await setMessages(db, entryId, messages, urlId, description); + if (!urlId) { + navigateChat(nextId); } - } else { - await setMessages(db, chatId as string, messages, urlId, description); } + + await setMessages(db, chatId.get() as string, messages, urlId, description.get()); }, }; }