-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature: Allow users to edit chat thread title #6
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,3 +30,6 @@ yarn-error.log* | |
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts | ||
|
||
# secrets | ||
start.sh | ||
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -17,30 +17,43 @@ interface Prop { | |||||
export const ChatMenu = (prop:Prop) => { | ||||||
const [items, setItems] = useState<ChatThreadModel[]>([]); | ||||||
|
||||||
// Fetch data when the component mounts | ||||||
const [refresh, setRefresh] = useState(true); | ||||||
// Fetch data when the component mounts and refreshes | ||||||
useEffect(() => { | ||||||
const fetchData = async () => { | ||||||
console.log("fetching items") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove |
||||||
const data = await FindAllChatThreadForCurrentUser(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this function handle fetching errors? |
||||||
setItems(data); | ||||||
}; | ||||||
|
||||||
fetchData(); | ||||||
}, []); | ||||||
}, [refresh]); | ||||||
|
||||||
const doRefresh = () => { | ||||||
console.log("should refresh") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove |
||||||
setRefresh(!refresh); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
|
||||||
return ( | ||||||
<div> | ||||||
<Button size={"icon"} onClick={() => prop.setIsOpen(!prop.isOpen)} > | ||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="12" height="12" stroke="currentColor"> | ||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" /> | ||||||
{prop.isOpen ? | ||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="12" height="12" stroke="currentColor"> | ||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 4v16M12 4v16M18 4v16" /> | ||||||
</svg> | ||||||
: | ||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="12" height="12" stroke="currentColor"> | ||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" /> | ||||||
</svg> | ||||||
} | ||||||
</Button> | ||||||
{prop.isOpen ? | ||||||
<Menu> | ||||||
<MenuHeader className="justify-end"> | ||||||
<NewChat /> | ||||||
</MenuHeader> | ||||||
<MenuContent> | ||||||
<MenuItems menuItems={items} /> | ||||||
<MenuItems refresh={doRefresh} menuItems={items} /> | ||||||
</MenuContent> | ||||||
<MenuFooter> | ||||||
<div className="flex flex-col gap-3"> | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,18 @@ | ||
"use client"; | ||
import { MenuItem } from "@/components/menu"; | ||
import { Button } from "@/components/ui/button"; | ||
import { SoftDeleteChatThreadByID } from "@/features/chat/chat-services/chat-thread-service"; | ||
import { FileText, MessageCircle, Trash } from "lucide-react"; | ||
import { SoftDeleteChatThreadByID, userUpdateThreadTitle } from "@/features/chat/chat-services/chat-thread-service"; | ||
import { FileText, MessageCircle, Trash, PenSquare, Navigation } from "lucide-react"; | ||
import { useParams, useRouter } from "next/navigation"; | ||
import { FC } from "react"; | ||
import { ChatThreadModel } from "../chat-services/models"; | ||
|
||
interface Prop { | ||
interface RProp { | ||
menuItems: Array<ChatThreadModel>; | ||
refresh: () => void | ||
} | ||
|
||
export const MenuItems: FC<Prop> = (props) => { | ||
export const MenuItems: FC<RProp> = (props) => { | ||
const { id } = useParams(); | ||
const router = useRouter(); | ||
|
||
|
@@ -21,6 +22,11 @@ export const MenuItems: FC<Prop> = (props) => { | |
router.replace("/chat"); | ||
}; | ||
|
||
const renameTitle = async (threadID: string, title: string) => { | ||
await userUpdateThreadTitle(threadID, title); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if this fails? |
||
props.refresh() | ||
}; | ||
|
||
return ( | ||
<> | ||
{props.menuItems.map((thread) => ( | ||
|
@@ -45,6 +51,20 @@ export const MenuItems: FC<Prop> = (props) => { | |
<span className="flex gap-2 items-center overflow-hidden flex-1"> | ||
<span className="overflow-ellipsis truncate"> {thread.name}</span> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're truncating thread names. If thread names are longer than 30 characters you will want to render ellipses here perhaps (...) |
||
</span> | ||
<Button | ||
className="invisible group-hover/item:visible" | ||
size={"sm"} | ||
variant={"ghost"} | ||
onClick={async (e) => { | ||
e.preventDefault(); | ||
const threadTitle = prompt("Enter the thread title", thread.name); | ||
if (threadTitle) { | ||
await renameTitle(thread.id, threadTitle); | ||
} | ||
}} | ||
> | ||
<PenSquare size={16} /> | ||
</Button> | ||
<Button | ||
className="invisible group-hover/item:visible hover:text-brand" | ||
size={"sm"} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -129,6 +129,23 @@ export const UpsertChatThread = async (chatThread: ChatThreadModel) => { | |
return updatedChatThread; | ||
}; | ||
|
||
export const userUpdateThreadTitle = async ( | ||
chatThreadID: string, | ||
userTitle: string | ||
) => { | ||
|
||
const threads = await FindChatThreadByID(chatThreadID); | ||
|
||
if (threads.length === 1) { | ||
const chatThread = threads[0] | ||
await UpsertChatThread({ | ||
...chatThread, | ||
name: userTitle.substring(0, 30), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of truncating here, prevent user from putting down more than 30 characters. That way we don't store truncated names in database. i.e. |
||
}); | ||
} | ||
|
||
}; | ||
|
||
export const updateChatThreadTitle = async ( | ||
chatThread: ChatThreadModel, | ||
messages: ChatMessageModel[], | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove