mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-08-22 00:43:01 +02:00
Add course upgrade button
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
|||||||
AICourseFollowUpPopover,
|
AICourseFollowUpPopover,
|
||||||
type AIChatHistoryType,
|
type AIChatHistoryType,
|
||||||
} from './AICourseFollowUpPopover';
|
} from './AICourseFollowUpPopover';
|
||||||
|
import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal';
|
||||||
|
|
||||||
type AICourseFollowUpProps = {
|
type AICourseFollowUpProps = {
|
||||||
courseSlug: string;
|
courseSlug: string;
|
||||||
@@ -15,6 +16,8 @@ export function AICourseFollowUp(props: AICourseFollowUpProps) {
|
|||||||
const { courseSlug, moduleTitle, lessonTitle } = props;
|
const { courseSlug, moduleTitle, lessonTitle } = props;
|
||||||
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
|
||||||
|
|
||||||
const [courseAIChatHistory, setCourseAIChatHistory] = useState<
|
const [courseAIChatHistory, setCourseAIChatHistory] = useState<
|
||||||
AIChatHistoryType[]
|
AIChatHistoryType[]
|
||||||
>([
|
>([
|
||||||
@@ -29,15 +32,22 @@ export function AICourseFollowUp(props: AICourseFollowUpProps) {
|
|||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<button
|
<button
|
||||||
className="mt-4 flex w-full items-center gap-2 rounded-lg border border-yellow-300 bg-yellow-100 p-4 hover:bg-yellow-200"
|
className="mt-4 flex w-full items-center gap-2 rounded-lg border border-yellow-300 bg-yellow-100 p-4 hover:bg-yellow-200 max-lg:mt-3 max-lg:text-sm"
|
||||||
onClick={() => setIsOpen(true)}
|
onClick={() => setIsOpen(true)}
|
||||||
>
|
>
|
||||||
<BotIcon className="h-4 w-4" />
|
<BotIcon className="h-4 w-4" />
|
||||||
<span>Still confused? Ask AI some follow up questions.</span>
|
<span>
|
||||||
|
<span className="max-sm:hidden">Still confused? </span>
|
||||||
|
Ask AI some follow up questions
|
||||||
|
</span>
|
||||||
|
|
||||||
<ArrowRightIcon className="ml-auto h-4 w-4" />
|
<ArrowRightIcon className="ml-auto h-4 w-4 max-sm:hidden" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{showUpgradeModal && (
|
||||||
|
<UpgradeAccountModal onClose={() => setShowUpgradeModal(false)} />
|
||||||
|
)}
|
||||||
|
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<AICourseFollowUpPopover
|
<AICourseFollowUpPopover
|
||||||
courseSlug={courseSlug}
|
courseSlug={courseSlug}
|
||||||
@@ -45,6 +55,10 @@ export function AICourseFollowUp(props: AICourseFollowUpProps) {
|
|||||||
lessonTitle={lessonTitle}
|
lessonTitle={lessonTitle}
|
||||||
courseAIChatHistory={courseAIChatHistory}
|
courseAIChatHistory={courseAIChatHistory}
|
||||||
setCourseAIChatHistory={setCourseAIChatHistory}
|
setCourseAIChatHistory={setCourseAIChatHistory}
|
||||||
|
onUpgradeClick={() => {
|
||||||
|
setIsOpen(false);
|
||||||
|
setShowUpgradeModal(true);
|
||||||
|
}}
|
||||||
onOutsideClick={() => {
|
onOutsideClick={() => {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
return;
|
return;
|
||||||
|
@@ -1,14 +1,5 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import {
|
import { BookOpen, Bot, Code, HelpCircle, LockIcon, Send } from 'lucide-react';
|
||||||
BookOpen,
|
|
||||||
Bot,
|
|
||||||
Code,
|
|
||||||
GitCompare,
|
|
||||||
HelpCircle,
|
|
||||||
LockIcon,
|
|
||||||
MessageCircle,
|
|
||||||
Send,
|
|
||||||
} from 'lucide-react';
|
|
||||||
import { useEffect, useMemo, useRef, useState, type FormEvent } from 'react';
|
import { useEffect, useMemo, useRef, useState, type FormEvent } from 'react';
|
||||||
import { flushSync } from 'react-dom';
|
import { flushSync } from 'react-dom';
|
||||||
import { useOutsideClick } from '../../hooks/use-outside-click';
|
import { useOutsideClick } from '../../hooks/use-outside-click';
|
||||||
@@ -41,6 +32,7 @@ type AICourseFollowUpPopoverProps = {
|
|||||||
setCourseAIChatHistory: (value: AIChatHistoryType[]) => void;
|
setCourseAIChatHistory: (value: AIChatHistoryType[]) => void;
|
||||||
|
|
||||||
onOutsideClick?: () => void;
|
onOutsideClick?: () => void;
|
||||||
|
onUpgradeClick: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function AICourseFollowUpPopover(props: AICourseFollowUpPopoverProps) {
|
export function AICourseFollowUpPopover(props: AICourseFollowUpPopoverProps) {
|
||||||
@@ -49,6 +41,7 @@ export function AICourseFollowUpPopover(props: AICourseFollowUpPopoverProps) {
|
|||||||
moduleTitle,
|
moduleTitle,
|
||||||
lessonTitle,
|
lessonTitle,
|
||||||
onOutsideClick,
|
onOutsideClick,
|
||||||
|
onUpgradeClick,
|
||||||
|
|
||||||
courseAIChatHistory,
|
courseAIChatHistory,
|
||||||
setCourseAIChatHistory,
|
setCourseAIChatHistory,
|
||||||
@@ -205,7 +198,7 @@ export function AICourseFollowUpPopover(props: AICourseFollowUpPopoverProps) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AIChatCard
|
<AIChatCard
|
||||||
key={index}
|
key={`chat-${index}`}
|
||||||
role={chat.role}
|
role={chat.role}
|
||||||
content={chat.content}
|
content={chat.content}
|
||||||
html={chat.html}
|
html={chat.html}
|
||||||
@@ -244,9 +237,17 @@ export function AICourseFollowUpPopover(props: AICourseFollowUpPopoverProps) {
|
|||||||
onSubmit={handleChatSubmit}
|
onSubmit={handleChatSubmit}
|
||||||
>
|
>
|
||||||
{isLimitExceeded && (
|
{isLimitExceeded && (
|
||||||
<div className="absolute inset-0 flex items-center justify-center bg-black text-white">
|
<div className="absolute inset-0 flex items-center justify-center gap-2 bg-black text-white">
|
||||||
<LockIcon className="size-4" strokeWidth={2.5} />
|
<LockIcon className="size-4 cursor-not-allowed" strokeWidth={2.5} />
|
||||||
<p>You have reached the AI usage limit for today.</p>
|
<p className="cursor-not-allowed">Limit reached for today</p>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
onUpgradeClick();
|
||||||
|
}}
|
||||||
|
className="rounded-md bg-white px-2 py-1 text-xs font-medium text-black hover:bg-gray-300"
|
||||||
|
>
|
||||||
|
Upgrade for more
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<TextareaAutosize
|
<TextareaAutosize
|
||||||
|
@@ -32,7 +32,7 @@ export function AICourseLimit() {
|
|||||||
<>
|
<>
|
||||||
<button className="mr-1 flex items-center gap-1 text-sm font-medium lg:hidden underline underline-offset-2">
|
<button className="mr-1 flex items-center gap-1 text-sm font-medium lg:hidden underline underline-offset-2">
|
||||||
<Info className="size-4" />
|
<Info className="size-4" />
|
||||||
{totalPercentage}% of limit used
|
{totalPercentage}% limit used
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button className="relative hidden h-full min-h-[38px] cursor-pointer items-center overflow-hidden rounded-lg border border-gray-300 px-3 py-1.5 text-sm hover:bg-gray-50 lg:flex">
|
<button className="relative hidden h-full min-h-[38px] cursor-pointer items-center overflow-hidden rounded-lg border border-gray-300 px-3 py-1.5 text-sm hover:bg-gray-50 lg:flex">
|
||||||
|
Reference in New Issue
Block a user