1
0
mirror of https://github.com/kamranahmedse/developer-roadmap.git synced 2025-09-03 06:12:53 +02:00

feat: show chat history always

This commit is contained in:
Arik Chakma
2025-06-12 00:34:11 +06:00
parent c1415e55b7
commit 9414b23b68
3 changed files with 79 additions and 35 deletions

View File

@@ -30,10 +30,9 @@ import {
type MessagePartRenderer,
} from '../../lib/render-chat-message';
import { RoadmapRecommendations } from '../RoadmapAIChat/RoadmapRecommendations';
import type { RoadmapAIChatHistoryType } from '../RoadmapAIChat/RoadmapAIChat';
import type { RoadmapAIChatHistoryType } from '../../hooks/use-roadmap-ai-chat';
import { AIChatCourse } from './AIChatCouse';
import { showLoginPopup } from '../../lib/popup';
import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal';
import { readChatStream } from '../../lib/chat';
import { chatHistoryOptions } from '../../queries/chat-history';
import { cn } from '../../lib/classname';
@@ -51,6 +50,7 @@ type AIChatProps = {
messages?: RoadmapAIChatHistoryType[];
chatHistoryId?: string;
setChatHistoryId?: (chatHistoryId: string) => void;
onUpgrade?: () => void;
};
export function AIChat(props: AIChatProps) {
@@ -58,6 +58,7 @@ export function AIChat(props: AIChatProps) {
messages: defaultMessages,
chatHistoryId: defaultChatHistoryId,
setChatHistoryId: setDefaultChatHistoryId,
onUpgrade,
} = props;
const toast = useToast();
@@ -70,7 +71,6 @@ export function AIChat(props: AIChatProps) {
RoadmapAIChatHistoryType[]
>(defaultMessages ?? []);
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
const [isPersonalizedResponseFormOpen, setIsPersonalizedResponseFormOpen] =
useState(false);
const [isUploadResumeModalOpen, setIsUploadResumeModalOpen] = useState(false);
@@ -128,7 +128,7 @@ export function AIChat(props: AIChatProps) {
if (isLimitExceeded) {
if (!isPaidUser) {
setShowUpgradeModal(true);
onUpgrade?.();
}
toast.error('Limit reached for today. Please wait until tomorrow.');
@@ -343,7 +343,7 @@ export function AIChat(props: AIChatProps) {
(index: number) => {
if (isLimitExceeded) {
if (!isPaidUser) {
setShowUpgradeModal(true);
onUpgrade?.();
}
toast.error('Limit reached for today. Please wait until tomorrow.');
@@ -430,10 +430,6 @@ export function AIChat(props: AIChatProps) {
/>
)}
{showUpgradeModal && (
<UpgradeAccountModal onClose={() => setShowUpgradeModal(false)} />
)}
<div
className="pointer-events-none absolute right-0 bottom-0 left-0 mx-auto w-full max-w-3xl px-4"
ref={chatContainerRef}
@@ -447,7 +443,7 @@ export function AIChat(props: AIChatProps) {
</div>
<button
type="button"
onClick={() => setShowUpgradeModal(true)}
onClick={() => onUpgrade?.()}
className="shrink-0 cursor-pointer rounded-md bg-yellow-200 px-2 py-1 text-xs font-medium text-yellow-800 hover:bg-yellow-200"
>
Upgrade to Pro
@@ -541,7 +537,7 @@ export function AIChat(props: AIChatProps) {
<button
type="button"
onClick={() => {
setShowUpgradeModal(true);
onUpgrade?.();
}}
className="rounded-md bg-white px-2 py-1 text-xs font-medium text-black hover:bg-gray-300"
>

View File

@@ -9,6 +9,7 @@ import { ListChatHistory } from './ListChatHistory';
import { billingDetailsOptions } from '../../queries/billing';
import { ChatHistoryError } from './ChatHistoryError';
import { useClientMount } from '../../hooks/use-client-mount';
import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal';
type AIChatHistoryProps = {
chatHistoryId?: string;
@@ -19,6 +20,7 @@ export function AIChatHistory(props: AIChatHistoryProps) {
const isClientMounted = useClientMount();
const [keyTrigger, setKeyTrigger] = useState(0);
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
const [isChatHistoryLoading, setIsChatHistoryLoading] = useState(true);
const [chatHistoryId, setChatHistoryId] = useState<string | undefined>(
defaultChatHistoryId || undefined,
@@ -116,13 +118,15 @@ export function AIChatHistory(props: AIChatHistoryProps) {
return (
<AIChatLayout>
<div className="relative flex grow">
{isPaidUser && (
<ListChatHistory
activeChatHistoryId={chatHistoryId}
onChatHistoryClick={handleChatHistoryClick}
onDelete={handleDelete}
/>
)}
<ListChatHistory
activeChatHistoryId={chatHistoryId}
onChatHistoryClick={handleChatHistoryClick}
onDelete={handleDelete}
isPaidUser={isPaidUser}
onUpgrade={() => {
setShowUpgradeModal(true);
}}
/>
<div className="relative flex grow">
{showLoader && (
@@ -151,10 +155,17 @@ export function AIChatHistory(props: AIChatHistoryProps) {
},
});
}}
onUpgrade={() => {
setShowUpgradeModal(true);
}}
/>
)}
</div>
</div>
{showUpgradeModal && (
<UpgradeAccountModal onClose={() => setShowUpgradeModal(false)} />
)}
</AIChatLayout>
);
}

View File

@@ -7,6 +7,7 @@ import { queryClient } from '../../stores/query-client';
import { ChatHistoryItem } from './ChatHistoryItem';
import {
Loader2Icon,
LockIcon,
PanelLeftCloseIcon,
PanelLeftIcon,
PlusIcon,
@@ -25,10 +26,18 @@ type ListChatHistoryProps = {
activeChatHistoryId?: string;
onChatHistoryClick: (chatHistoryId: string | null) => void;
onDelete?: (chatHistoryId: string) => void;
isPaidUser?: boolean;
onUpgrade?: () => void;
};
export function ListChatHistory(props: ListChatHistoryProps) {
const { activeChatHistoryId, onChatHistoryClick, onDelete } = props;
const {
activeChatHistoryId,
onChatHistoryClick,
onDelete,
isPaidUser,
onUpgrade,
} = props;
const [isOpen, setIsOpen] = useState(true);
const [isLoading, setIsLoading] = useState(true);
@@ -122,14 +131,49 @@ export function ListChatHistory(props: ListChatHistoryProps) {
(group) => group.histories.length === 0,
);
return (
<div
className={cn(
'flex w-[255px] shrink-0 flex-col justify-start border-r border-gray-200 bg-white p-2',
'max-md:absolute max-md:inset-0 max-md:z-20 max-md:w-full',
!isOpen && 'hidden',
)}
const classNames = cn(
'flex w-[255px] shrink-0 flex-col justify-start border-r border-gray-200 bg-white p-2',
'max-md:absolute max-md:inset-0 max-md:z-20 max-md:w-full',
!isOpen && 'hidden',
);
const closeButton = (
<button
className="flex size-8 items-center justify-center rounded-lg p-1 text-gray-500 hover:bg-gray-100 hover:text-black"
onClick={() => {
setIsOpen(false);
}}
>
<PanelLeftCloseIcon className="h-4.5 w-4.5" />
</button>
);
if (!isPaidUser) {
return (
<div className={cn(classNames, 'relative')}>
<div className="absolute top-2 right-2">{closeButton}</div>
<div className="flex grow flex-col items-center justify-center">
<LockIcon className="size-8 text-gray-500" />
<p className="mt-4 text-center text-sm text-balance text-gray-500">
Upgrade to Pro to keep your chat history.
</p>
<button
type="button"
className="mt-2 shrink-0 cursor-pointer rounded-md bg-yellow-200 px-2.5 py-1.5 text-sm font-medium text-yellow-800 hover:bg-yellow-200"
onClick={() => {
onUpgrade?.();
}}
>
Upgrade to Pro
</button>
</div>
</div>
);
}
return (
<div className={classNames}>
{isLoading && <ListChatHistorySkeleton />}
{!isLoading && isError && <ChatHistoryError error={error} />}
@@ -138,18 +182,11 @@ export function ListChatHistory(props: ListChatHistoryProps) {
<div>
<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>
{closeButton}
</div>
<button
className="flex w-full items-center hover:opacity-80 justify-center gap-2 rounded-lg bg-black p-2 text-sm text-white"
className="flex w-full items-center justify-center gap-2 rounded-lg bg-black p-2 text-sm text-white hover:opacity-80"
onClick={() => {
if (isMobile) {
setIsOpen(false);