mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-09-03 14:22:41 +02:00
wip
This commit is contained in:
@@ -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>
|
||||
</>
|
||||
)}
|
||||
|
@@ -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={() => {
|
||||
|
@@ -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">
|
||||
|
Reference in New Issue
Block a user