Skip to content

Commit

Permalink
www: refactor use-chat-state hook
Browse files Browse the repository at this point in the history
  • Loading branch information
ribeirojose committed Aug 27, 2024
1 parent a6537b4 commit 7afccf9
Show file tree
Hide file tree
Showing 12 changed files with 382 additions and 396 deletions.
1 change: 1 addition & 0 deletions www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"clsx": "^2.1.1",
"date-fns": "^3.6.0",
"geist": "^1.3.1",
"immer": "^10.1.1",
"lucide-react": "^0.427.0",
"next": "^15.0.0-rc.0",
"posthog-js": "^1.155.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function useUserAccessedTopicPosthogTracker(
topicTitle: topic.title,
topicUrl: topic.url,
});
}, [topic]);
}, [topic, posthog.capture]);

return null;
}
35 changes: 14 additions & 21 deletions www/src/components/chat/chat-bottombar.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,41 @@
import type { Message } from "@/app/data";
import { type ChatData, generateMessageParams } from "@/lib/chat-utils";
import { generateMessageParams } from "@/lib/chat-utils";
import { cn } from "@/lib/utils";
import { SendHorizontal } from "lucide-react";
import Link from "next/link";
import type React from "react";
import { useEffect, useRef } from "react";
import { buttonVariants } from "../ui/button";
import { Textarea } from "../ui/textarea";
import { useChatStore } from "./useChatState";
import { getCurrentChat, useChatStore } from "./use-chat-state";

interface ChatBottombarProps {
sendMessage: (newMessage: Message) => void;
isMobile: boolean;
isStreaming: boolean;
inputMessage: string;
setInputMessage: (message: string | ((prev: string) => string)) => void;
}

export default function ChatBottombar({
sendMessage,
isMobile,
isStreaming,
inputMessage,
setInputMessage,
}: ChatBottombarProps) {
export default function ChatBottombar({ isMobile }: ChatBottombarProps) {
const inputMessage = useChatStore.use.inputMessage();
const setInputMessage = useChatStore.use.setInputMessage();
const isStreaming = useChatStore.use.isStreaming();
const sendMessage = useChatStore.use.sendMessage();
const currentChat = getCurrentChat();
const inputRef = useRef<HTMLTextAreaElement>(null);
const { selectedChat } = useChatStore();

// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
useEffect(() => {
if (inputRef.current) {
inputRef.current.focus();
}
}, [inputMessage]);
}, []);

const handleInputChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setInputMessage(event.target.value);
};

const handleSend = () => {
if (inputMessage.trim() && !isStreaming) {
const newMessage: Message = generateMessageParams(
selectedChat?.id || "",
if (inputMessage.trim() && !isStreaming && currentChat) {
const newMessage = generateMessageParams(
currentChat.id,
inputMessage.trim(),
"anonymous",
);

sendMessage(newMessage);
Expand All @@ -68,7 +61,7 @@ export default function ChatBottombar({

return (
<div className="p-2 flex justify-between w-full items-center gap-2">
<div key="input" className="w-full relative">
<div className="w-full relative">
<Textarea
autoComplete="off"
value={inputMessage}
Expand Down
78 changes: 15 additions & 63 deletions www/src/components/chat/chat-layout.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,31 @@
"use client";

import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable";
import {
type ChatData,
addNewChat,
generateChatParams,
loadChatsFromLocalStorage,
saveChatsToLocalStorage,
} from "@/lib/chat-utils";
import { cn } from "@/lib/utils";
import React, { useEffect, useState, useCallback } from "react";
import { Sidebar } from "../sidebar";
import { Chat } from "./chat";
import { useChatStore } from "./useChatState";
import { useChatStore } from "./use-chat-state";

interface ChatLayoutProps {
defaultLayout?: number[] | undefined;
defaultCollapsed?: boolean;
navCollapsedSize?: number;
}

const defaultChatData: ChatData = {
id: "",
name: "Default Chat",
messages: [],
timestamp: Date.now(),
};

export function ChatLayout({
defaultLayout = [320, 480],
defaultCollapsed = true,
navCollapsedSize,
}: ChatLayoutProps) {
const [isCollapsed, setIsCollapsed] = useState(defaultCollapsed);
const { selectedChat, setSelectedChat } = useChatStore();
const { chats, selectedChatId, setSelectedChatId, addChat, removeChat } =
useChatStore();
const [isMobile, setIsMobile] = useState(false);
const [chats, setChats] = useState<ChatData[]>([]);
const [showSidebar, setShowSidebar] = useState(!isMobile);

useEffect(() => {
Expand All @@ -53,46 +40,17 @@ export function ChatLayout({
}, []);

useEffect(() => {
const loadedChats = loadChatsFromLocalStorage();
if (loadedChats.length > 0) {
setChats(loadedChats);
setSelectedChat(loadedChats[0]);
} else {
handleNewChat();
if (Object.keys(chats).length === 0) {
addChat();
}
}, []);
}, [addChat, chats]);

const handleNewChat = useCallback(() => {
const newChat = generateChatParams("chat");

setChats((prevChats) => {
const updatedChats = addNewChat(prevChats);
saveChatsToLocalStorage(updatedChats);
return updatedChats;
});
setSelectedChat(newChat);
addChat();
if (isMobile) {
setShowSidebar(false);
}
}, [isMobile]);

const handleRemoveChat = useCallback(
(id: string) => {
setChats((prevChats) => {
const updatedChats = prevChats.filter((chat) => chat.id !== id);
saveChatsToLocalStorage(updatedChats);

if (updatedChats.length > 0) {
setSelectedChat(updatedChats[0]);
} else {
setSelectedChat(defaultChatData);
}

return updatedChats;
});
},
[chats, selectedChat],
);
}, [isMobile, addChat]);

const toggleSidebar = useCallback(() => {
setShowSidebar((prev) => !prev);
Expand All @@ -115,14 +73,8 @@ export function ChatLayout({
collapsible={!isMobile}
minSize={isMobile ? 100 : 24}
maxSize={isMobile ? 100 : 30}
onCollapse={() => {
setIsCollapsed(true);
document.cookie = "react-resizable-panels:collapsed=true";
}}
onExpand={() => {
setIsCollapsed(false);
document.cookie = "react-resizable-panels:collapsed=false";
}}
onCollapse={() => setIsCollapsed(true)}
onExpand={() => setIsCollapsed(false)}
className={cn(
isCollapsed &&
"min-w-[50px] md:min-w-[70px] transition-all duration-300 ease-in-out",
Expand All @@ -131,22 +83,22 @@ export function ChatLayout({
>
<Sidebar
isCollapsed={isCollapsed && !isMobile}
links={chats.map((chat) => ({
links={Object.values(chats).map((chat) => ({
id: chat.id,
messages: chat.messages,
name: chat.name,
timestamp: chat.timestamp,
variant: selectedChat?.id === chat.id ? "default" : "ghost",
variant: selectedChatId === chat.id ? "default" : "ghost",
}))}
onNewChat={handleNewChat}
onRemoveChat={handleRemoveChat}
onRemoveChat={removeChat}
isMobile={isMobile}
/>
</ResizablePanel>
)}
{!isMobile && <ResizableHandle withHandle />}
<ResizablePanel defaultSize={defaultLayout[1]} minSize={30}>
{selectedChat ? (
{selectedChatId ? (
<Chat isMobile={isMobile} onToggleSidebar={toggleSidebar} />
) : (
<div className="flex items-center justify-center h-full">
Expand Down
Loading

0 comments on commit 7afccf9

Please sign in to comment.