1
0
mirror of https://github.com/kamranahmedse/developer-roadmap.git synced 2025-09-03 14:22:41 +02:00
This commit is contained in:
Arik Chakma
2025-06-10 12:19:47 +06:00
parent 9ed6f00aba
commit f93f8cb6ba
3 changed files with 80 additions and 18 deletions

View File

@@ -18,6 +18,7 @@ export function AIChatHistory(props: AIChatHistoryProps) {
const [keyTrigger, setKeyTrigger] = useState(0);
const [isLoading, setIsLoading] = useState(true);
const [isChatHistoryLoading, setIsChatHistoryLoading] = useState(true);
const [chatHistoryId, setChatHistoryId] = useState<string | undefined>(
defaultChatHistoryId || undefined,
);
@@ -35,7 +36,8 @@ export function AIChatHistory(props: AIChatHistoryProps) {
useEffect(() => {
if (!defaultChatHistoryId) {
return setIsLoading(false);
setIsLoading(false);
return;
}
if (!data) {
@@ -43,6 +45,7 @@ export function AIChatHistory(props: AIChatHistoryProps) {
}
setIsLoading(false);
setIsChatHistoryLoading(false);
}, [data, defaultChatHistoryId]);
const isDataLoading = isLoading || isBillingDetailsLoading;
@@ -85,7 +88,16 @@ export function AIChatHistory(props: AIChatHistoryProps) {
return;
}
setIsLoading(true);
// so that we can show the loading state when the chat history is not fetched yet
// it will help us to avoid the flash of content
const hasAlreadyFetched = queryClient.getQueryData(
chatHistoryOptions(chatHistoryId).queryKey,
);
if (!hasAlreadyFetched) {
setIsChatHistoryLoading(true);
}
setChatHistoryId(chatHistoryId);
window.history.replaceState(
null,
@@ -106,21 +118,29 @@ export function AIChatHistory(props: AIChatHistoryProps) {
/>
)}
<div className="flex grow">
<AIChat
key={keyTrigger}
messages={data?.messages}
chatHistoryId={chatHistoryId}
setChatHistoryId={(id) => {
setChatHistoryId(id);
window.history.replaceState(null, '', `/ai/chat/${id}`);
queryClient.invalidateQueries({
predicate: (query) => {
return query.queryKey[0] === 'list-chat-history';
},
});
}}
/>
<div className="relative flex grow">
{isChatHistoryLoading && (
<div className="absolute inset-0 z-20 flex items-center justify-center">
<Loader2Icon className="h-8 w-8 animate-spin stroke-[2.5]" />
</div>
)}
{!isChatHistoryLoading && (
<AIChat
key={keyTrigger}
messages={data?.messages}
chatHistoryId={chatHistoryId}
setChatHistoryId={(id) => {
setChatHistoryId(id);
window.history.replaceState(null, '', `/ai/chat/${id}`);
queryClient.invalidateQueries({
predicate: (query) => {
return query.queryKey[0] === 'list-chat-history';
},
});
}}
/>
)}
</div>
</>
)}

View File

@@ -8,6 +8,8 @@ import { ChatHistoryItem } from './ChatHistoryItem';
import {
AlertCircleIcon,
Loader2Icon,
PanelLeftCloseIcon,
PanelLeftIcon,
PlusIcon,
SearchIcon,
} from 'lucide-react';
@@ -16,6 +18,7 @@ import { useEffect, useMemo, useState } from 'react';
import { useDebounceValue } from '../../hooks/use-debounce';
import { ListChatHistorySkeleton } from './ListChatHistorySkeleton';
import { ChatHistoryError } from './ChatHistoryError';
import { cn } from '../../lib/classname';
type ListChatHistoryProps = {
activeChatHistoryId?: string;
@@ -26,6 +29,7 @@ type ListChatHistoryProps = {
export function ListChatHistory(props: ListChatHistoryProps) {
const { activeChatHistoryId, onChatHistoryClick, onDelete } = props;
const [isOpen, setIsOpen] = useState(true);
const [query, setQuery] = useState('');
const {
data,
@@ -79,13 +83,45 @@ export function ListChatHistory(props: ListChatHistoryProps) {
);
}, [data?.pages]);
if (!isOpen) {
return (
<div className="absolute top-1 left-1 z-20">
<button
className="flex size-8 items-center justify-center rounded-lg p-1 hover:bg-gray-200"
onClick={() => {
setIsOpen(true);
}}
>
<PanelLeftIcon className="h-4.5 w-4.5" />
</button>
</div>
);
}
return (
<div className="w-[255px] shrink-0 border-r border-gray-200 bg-white p-2">
<div
className={cn(
'w-[255px] shrink-0 border-r border-gray-200 bg-white p-2',
!isOpen && 'hidden',
)}
>
{isLoading && <ListChatHistorySkeleton />}
{!isLoading && isError && <ChatHistoryError error={error} />}
{!isLoading && !isError && (
<>
<div className="mb-4 flex items-center justify-between">
<h1 className="font-medium text-gray-900">Chat History</h1>
<button
className="flex size-8 items-center justify-center rounded-lg p-1 hover:bg-gray-100"
onClick={() => {
setIsOpen(false);
}}
>
<PanelLeftCloseIcon className="h-4.5 w-4.5" />
</button>
</div>
<button
className="flex w-full items-center justify-center gap-2 rounded-lg bg-black p-2 text-sm text-white"
onClick={() => {

View File

@@ -1,6 +1,12 @@
export function ListChatHistorySkeleton() {
return (
<>
<div className="mb-4 flex items-center justify-between gap-2">
<div className="h-6 w-1/2 animate-pulse rounded bg-gray-200" />
<div className="size-8 animate-pulse rounded-md bg-gray-200" />
</div>
<div className="h-9 w-full animate-pulse rounded-lg bg-gray-200" />
<div className="relative mt-2">