Improve topic popup

feat/topic-chat
Kamran Ahmed 1 week ago
parent b5caccfb51
commit 29dc2afc7f
  1. 1
      .astro/types.d.ts
  2. 6
      src/components/TopicDetail/TopicDetail.tsx
  3. 56
      src/components/TopicDetail/TopicDetailAI.tsx
  4. 6
      src/components/TopicDetail/TopicDetailsTabs.tsx

1
.astro/types.d.ts vendored

@ -1,2 +1 @@
/// <reference types="astro/client" /> /// <reference types="astro/client" />
/// <reference path="content.d.ts" />

@ -375,7 +375,7 @@ export function TopicDetail(props: TopicDetailProps) {
)} )}
{isLoading && ( {isLoading && (
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full justify-center">
<Spinner <Spinner
outerFill="#d1d5db" outerFill="#d1d5db"
className="h-6 w-6 sm:h-8 sm:w-8" className="h-6 w-6 sm:h-8 sm:w-8"
@ -392,7 +392,7 @@ export function TopicDetail(props: TopicDetailProps) {
'flex flex-col': activeTab === 'ai', 'flex flex-col': activeTab === 'ai',
})} })}
> >
<div className="flex items-center justify-between"> <div className="flex justify-between">
{shouldShowAiTab && ( {shouldShowAiTab && (
<TopicDetailsTabs <TopicDetailsTabs
activeTab={activeTab} activeTab={activeTab}
@ -570,7 +570,7 @@ export function TopicDetail(props: TopicDetailProps) {
<a <a
href={contributionUrl} href={contributionUrl}
target="_blank" target="_blank"
className="hidden rounded-md border bg-gray-200 px-2 py-2 text-sm hover:bg-gray-300 sm:flex items-center justify-center" className="hidden items-center justify-center rounded-md border bg-gray-200 px-2 py-2 text-sm hover:bg-gray-300 sm:flex"
> >
<GitHubIcon className="mr-2 inline-block h-4 w-4 text-current" /> <GitHubIcon className="mr-2 inline-block h-4 w-4 text-current" />
Help us Improve this Content Help us Improve this Content

@ -14,10 +14,11 @@ import { queryClient } from '../../stores/query-client';
import { isLoggedIn, removeAuthToken } from '../../lib/jwt'; import { isLoggedIn, removeAuthToken } from '../../lib/jwt';
import { import {
BotIcon, BotIcon,
Gift,
Loader2Icon, Loader2Icon,
LockIcon, LockIcon,
RotateCcwIcon,
SendIcon, SendIcon,
Trash2
} from 'lucide-react'; } from 'lucide-react';
import { showLoginPopup } from '../../lib/popup'; import { showLoginPopup } from '../../lib/popup';
import { cn } from '../../lib/classname'; import { cn } from '../../lib/classname';
@ -34,6 +35,7 @@ import type { ResourceType } from '../../lib/resource-progress';
import { getPercentage } from '../../lib/number'; import { getPercentage } from '../../lib/number';
import { roadmapTreeMappingOptions } from '../../queries/roadmap-tree'; import { roadmapTreeMappingOptions } from '../../queries/roadmap-tree';
import { defaultChatHistory } from './TopicDetail'; import { defaultChatHistory } from './TopicDetail';
import { AILimitsPopup } from '../GenerateCourse/AILimitsPopup';
type TopicDetailAIProps = { type TopicDetailAIProps = {
resourceId: string; resourceId: string;
@ -67,7 +69,7 @@ export function TopicDetailAI(props: TopicDetailAIProps) {
const [message, setMessage] = useState(''); const [message, setMessage] = useState('');
const [isStreamingMessage, setIsStreamingMessage] = useState(false); const [isStreamingMessage, setIsStreamingMessage] = useState(false);
const [streamedMessage, setStreamedMessage] = useState(''); const [streamedMessage, setStreamedMessage] = useState('');
const [showAILimitsPopup, setShowAILimitsPopup] = useState(false);
const { data: tokenUsage, isLoading } = useQuery( const { data: tokenUsage, isLoading } = useQuery(
getAiCourseLimitOptions(), getAiCourseLimitOptions(),
queryClient, queryClient,
@ -234,10 +236,20 @@ export function TopicDetailAI(props: TopicDetailAIProps) {
</div> </div>
)} )}
{showAILimitsPopup && (
<AILimitsPopup
onClose={() => setShowAILimitsPopup(false)}
onUpgrade={() => {
setShowAILimitsPopup(false);
onUpgrade();
}}
/>
)}
{hasSubjects && ( {hasSubjects && (
<div className="border-b border-gray-200 px-4 py-2"> <div className="border-b border-gray-200 p-3">
<h4 className="flex items-center gap-2 text-base"> <h4 className="flex items-center gap-2 text-sm">
Complete the following courses on AI Tutor Complete the following AI Tutor courses
</h4> </h4>
<div className="mt-2.5 flex flex-wrap gap-1 text-sm"> <div className="mt-2.5 flex flex-wrap gap-1 text-sm">
@ -247,7 +259,7 @@ export function TopicDetailAI(props: TopicDetailAIProps) {
key={subject} key={subject}
target="_blank" target="_blank"
href={`/ai/search?term=${subject}&difficulty=beginner&src=topic`} href={`/ai/search?term=${subject}&difficulty=beginner&src=topic`}
className="rounded-md border px-1.5" className="flex items-center bg-gray-100 gap-1 gap-2 rounded-md border border-gray-300 px-2 py-1 hover:bg-gray-200 hover:text-black"
> >
{subject} {subject}
</a> </a>
@ -259,13 +271,16 @@ export function TopicDetailAI(props: TopicDetailAIProps) {
<div <div
className={cn( className={cn(
'flex items-center justify-between gap-2 border-gray-200 px-4 py-2 text-sm', 'flex items-center justify-between gap-2 border-gray-200 px-3 py-2 text-sm',
!hasSubjects && 'border-b',
)} )}
> >
{hasSubjects && ( {hasSubjects && (
<span className="flex items-center gap-2 text-base"> <span className="flex items-center gap-2 text-sm">
or start chatting with AI <BotIcon
className="relative -top-[1px] size-4 shrink-0 text-black"
strokeWidth={2.5}
/>
Chat with AI
</span> </span>
)} )}
@ -280,29 +295,36 @@ export function TopicDetailAI(props: TopicDetailAIProps) {
)} )}
{!isDataLoading && ( {!isDataLoading && (
<div className="flex items-center gap-2.5"> <div className="flex gap-1.5">
{hasChatHistory && ( {hasChatHistory && (
<button <button
className="rounded-md bg-white p-1 text-xs font-medium text-black hover:bg-gray-200" className="rounded-md bg-white px-2 text-xs font-medium text-black hover:bg-gray-200"
onClick={() => { onClick={() => {
setAiChatHistory(defaultChatHistory); setAiChatHistory(defaultChatHistory);
}} }}
> >
<RotateCcwIcon className="size-3.5" /> <Trash2 className="size-3.5" />
</button> </button>
)} )}
{!isPaidUser && ( {!isPaidUser && (
<> <>
<button <button
className="underline underline-offset-2 hover:no-underline" className="rounded-md bg-gray-200 px-2 py-1 text-sm hover:bg-gray-300"
onClick={() => {
setShowAILimitsPopup(true);
}}
>
<span className="font-medium">{usagePercentage}%</span>{' '}
credits used
</button>
<button
className="flex items-center gap-1 rounded-md bg-yellow-400 px-2 py-1 text-sm text-black hover:bg-yellow-500"
onClick={onUpgrade} onClick={onUpgrade}
> >
<Gift className="size-4" />
Upgrade Upgrade
</button> </button>
<p className="text-sm text-gray-500">
<span className="font-medium">{usagePercentage}%</span> used
</p>
</> </>
)} )}
</div> </div>

@ -42,16 +42,16 @@ function TopicDetailsTab(props: TopicDetailsTabProps) {
return ( return (
<button <button
className="flex border data-[state=active]:border-black border-gray-300 hover:bg-gray-100 items-center gap-2 px-2 py-1 rounded-md text-sm text-gray-500 data-[state=active]:bg-black data-[state=active]:text-white" className="flex items-center gap-2 rounded-md border border-gray-300 px-2 py-1 text-sm text-gray-500 hover:border-gray-400 data-[state=active]:border-black data-[state=active]:bg-black data-[state=active]:text-white"
data-state={isActive ? 'active' : 'inactive'} data-state={isActive ? 'active' : 'inactive'}
onClick={onClick} onClick={onClick}
disabled={isActive} disabled={isActive}
type="button" type="button"
> >
<Icon className="h-4 w-4" /> <Icon className="h-4 w-4" />
{label} <span className="hidden sm:block">{label}</span>
{isNew && ( {isNew && (
<span className="text-xs bg-yellow-400 text-black rounded-sm px-1"> <span className="hidden rounded-sm bg-yellow-400 px-1 text-xs text-black sm:block">
New New
</span> </span>
)} )}

Loading…
Cancel
Save