parent
61f5a81d20
commit
4fbea4680c
5 changed files with 160 additions and 99 deletions
@ -0,0 +1,46 @@ |
||||
import { useQuery } from '@tanstack/react-query'; |
||||
import { AITutorLimits } from './AITutorLimits'; |
||||
import { getAiCourseLimitOptions } from '../../queries/ai-course'; |
||||
import { queryClient } from '../../stores/query-client'; |
||||
|
||||
type AITutorHeaderProps = { |
||||
title: string; |
||||
isPaidUser: boolean; |
||||
isPaidUserLoading: boolean; |
||||
setShowUpgradePopup: (show: boolean) => void; |
||||
children?: React.ReactNode; |
||||
}; |
||||
|
||||
export function AITutorHeader(props: AITutorHeaderProps) { |
||||
const { |
||||
title, |
||||
isPaidUser, |
||||
isPaidUserLoading, |
||||
setShowUpgradePopup, |
||||
children, |
||||
} = props; |
||||
|
||||
const { data: limits } = useQuery(getAiCourseLimitOptions(), queryClient); |
||||
|
||||
const { used, limit } = limits ?? { used: 0, limit: 0 }; |
||||
|
||||
return ( |
||||
<div className="mb-3 flex min-h-[35px] items-center justify-between max-sm:mb-1"> |
||||
<div className="flex items-center gap-2"> |
||||
<h2 className="text-lg font-semibold">{title}</h2> |
||||
</div> |
||||
|
||||
<div className="flex items-center gap-2"> |
||||
<AITutorLimits |
||||
used={used} |
||||
limit={limit} |
||||
isPaidUser={isPaidUser} |
||||
isPaidUserLoading={isPaidUserLoading} |
||||
onUpgradeClick={() => setShowUpgradePopup(true)} |
||||
/> |
||||
|
||||
{children} |
||||
</div> |
||||
</div> |
||||
); |
||||
} |
@ -0,0 +1,45 @@ |
||||
import { Gift } from 'lucide-react'; |
||||
import { cn } from '../../lib/classname'; |
||||
|
||||
type AITutorLimitsProps = { |
||||
used: number; |
||||
limit: number; |
||||
isPaidUser: boolean; |
||||
isPaidUserLoading: boolean; |
||||
onUpgradeClick: () => void; |
||||
}; |
||||
|
||||
export function AITutorLimits(props: AITutorLimitsProps) { |
||||
const limitUsedPercentage = Math.round((props.used / props.limit) * 100); |
||||
|
||||
if (props.used <= 0 || props.limit <= 0 || props.isPaidUserLoading) { |
||||
return null; |
||||
} |
||||
|
||||
return ( |
||||
<div |
||||
className={cn( |
||||
'pointer-events-none flex items-center gap-2 opacity-0 transition-opacity', |
||||
{ |
||||
'pointer-events-auto opacity-100': !props.isPaidUser, |
||||
}, |
||||
)} |
||||
> |
||||
<p className="flex items-center text-sm text-yellow-600"> |
||||
<span className="max-md:hidden"> |
||||
{limitUsedPercentage}% of daily limit used{' '} |
||||
</span> |
||||
<span className="inline md:hidden"> |
||||
{limitUsedPercentage}% used |
||||
</span> |
||||
<button |
||||
onClick={props.onUpgradeClick} |
||||
className="ml-1.5 flex items-center gap-1 rounded-full bg-yellow-600 py-0.5 pr-2 pl-1.5 text-xs text-white" |
||||
> |
||||
<Gift className="size-4" /> |
||||
Upgrade |
||||
</button> |
||||
</p> |
||||
</div> |
||||
); |
||||
}
|
Loading…
Reference in new issue