|
|
@ -29,6 +29,13 @@ import { showLoginPopup } from '../../lib/popup.ts'; |
|
|
|
import { cn } from '../../lib/classname.ts'; |
|
|
|
import { cn } from '../../lib/classname.ts'; |
|
|
|
import { RoadmapTopicDetail } from './RoadmapTopicDetail.tsx'; |
|
|
|
import { RoadmapTopicDetail } from './RoadmapTopicDetail.tsx'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export type GetAIRoadmapLimitResponse = { |
|
|
|
|
|
|
|
used: number; |
|
|
|
|
|
|
|
limit: number; |
|
|
|
|
|
|
|
topicUsed: number; |
|
|
|
|
|
|
|
topicLimit: number; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const ROADMAP_ID_REGEX = new RegExp('@ROADMAPID:(\\w+)@'); |
|
|
|
const ROADMAP_ID_REGEX = new RegExp('@ROADMAPID:(\\w+)@'); |
|
|
|
|
|
|
|
|
|
|
|
export type RoadmapNodeDetails = { |
|
|
|
export type RoadmapNodeDetails = { |
|
|
@ -84,6 +91,8 @@ export function GenerateRoadmap() { |
|
|
|
|
|
|
|
|
|
|
|
const [roadmapLimit, setRoadmapLimit] = useState(0); |
|
|
|
const [roadmapLimit, setRoadmapLimit] = useState(0); |
|
|
|
const [roadmapLimitUsed, setRoadmapLimitUsed] = useState(0); |
|
|
|
const [roadmapLimitUsed, setRoadmapLimitUsed] = useState(0); |
|
|
|
|
|
|
|
const [roadmapTopicLimit, setRoadmapTopicLimit] = useState(0); |
|
|
|
|
|
|
|
const [roadmapTopicLimitUsed, setRoadmapTopicLimitUsed] = useState(0); |
|
|
|
|
|
|
|
|
|
|
|
const renderRoadmap = async (roadmap: string) => { |
|
|
|
const renderRoadmap = async (roadmap: string) => { |
|
|
|
const { nodes, edges } = generateAIRoadmapFromText(roadmap); |
|
|
|
const { nodes, edges } = generateAIRoadmapFromText(roadmap); |
|
|
@ -240,19 +249,20 @@ export function GenerateRoadmap() { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const loadAIRoadmapLimit = async () => { |
|
|
|
const loadAIRoadmapLimit = async () => { |
|
|
|
const { response, error } = await httpGet<{ |
|
|
|
const { response, error } = await httpGet<GetAIRoadmapLimitResponse>( |
|
|
|
limit: number; |
|
|
|
`${import.meta.env.PUBLIC_API_URL}/v1-get-ai-roadmap-limit`, |
|
|
|
used: number; |
|
|
|
); |
|
|
|
}>(`${import.meta.env.PUBLIC_API_URL}/v1-get-ai-roadmap-limit`); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (error || !response) { |
|
|
|
if (error || !response) { |
|
|
|
toast.error(error?.message || 'Something went wrong'); |
|
|
|
toast.error(error?.message || 'Something went wrong'); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const { limit, used } = response; |
|
|
|
const { limit, used, topicLimit, topicUsed } = response; |
|
|
|
setRoadmapLimit(limit); |
|
|
|
setRoadmapLimit(limit); |
|
|
|
setRoadmapLimitUsed(used); |
|
|
|
setRoadmapLimitUsed(used); |
|
|
|
|
|
|
|
setRoadmapTopicLimit(topicLimit); |
|
|
|
|
|
|
|
setRoadmapTopicLimitUsed(topicUsed); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const loadAIRoadmap = async (roadmapId: string) => { |
|
|
|
const loadAIRoadmap = async (roadmapId: string) => { |
|
|
@ -360,6 +370,11 @@ export function GenerateRoadmap() { |
|
|
|
parentTitle={selectedTopic.parentTitle} |
|
|
|
parentTitle={selectedTopic.parentTitle} |
|
|
|
onClose={() => setSelectedTopic(null)} |
|
|
|
onClose={() => setSelectedTopic(null)} |
|
|
|
roadmapId={currentRoadmap?.id || ''} |
|
|
|
roadmapId={currentRoadmap?.id || ''} |
|
|
|
|
|
|
|
topicLimit={roadmapTopicLimit} |
|
|
|
|
|
|
|
topicLimitUsed={roadmapTopicLimitUsed} |
|
|
|
|
|
|
|
onTopicContentGenerateComplete={async () => { |
|
|
|
|
|
|
|
await loadAIRoadmapLimit(); |
|
|
|
|
|
|
|
}} |
|
|
|
/> |
|
|
|
/> |
|
|
|
)} |
|
|
|
)} |
|
|
|
|
|
|
|
|
|
|
@ -393,10 +408,14 @@ export function GenerateRoadmap() { |
|
|
|
</span> |
|
|
|
</span> |
|
|
|
{!isLoggedIn() && ( |
|
|
|
{!isLoggedIn() && ( |
|
|
|
<button |
|
|
|
<button |
|
|
|
className="rounded-xl border border-current px-1.5 py-0.5 text-sm font-medium text-blue-500 text-left sm:text-center" |
|
|
|
className="rounded-xl border border-current px-1.5 py-0.5 text-left text-sm font-medium text-blue-500 sm:text-center" |
|
|
|
onClick={showLoginPopup} |
|
|
|
onClick={showLoginPopup} |
|
|
|
> |
|
|
|
> |
|
|
|
Generate more by <span className='font-semibold'>signing up (free, takes 2s)</span> or <span className='font-semibold'>logging in</span> |
|
|
|
Generate more by{' '} |
|
|
|
|
|
|
|
<span className="font-semibold"> |
|
|
|
|
|
|
|
signing up (free, takes 2s) |
|
|
|
|
|
|
|
</span>{' '} |
|
|
|
|
|
|
|
or <span className="font-semibold">logging in</span> |
|
|
|
</button> |
|
|
|
</button> |
|
|
|
)} |
|
|
|
)} |
|
|
|
</div> |
|
|
|
</div> |
|
|
@ -472,12 +491,14 @@ export function GenerateRoadmap() { |
|
|
|
disabled={isLoading} |
|
|
|
disabled={isLoading} |
|
|
|
> |
|
|
|
> |
|
|
|
<Save size={15} /> |
|
|
|
<Save size={15} /> |
|
|
|
<span className='hidden sm:inline'>Track your Progress on this Roadmap</span> |
|
|
|
<span className="hidden sm:inline"> |
|
|
|
<span className='inline sm:hidden'>Track Progress</span> |
|
|
|
Track your Progress on this Roadmap |
|
|
|
|
|
|
|
</span> |
|
|
|
|
|
|
|
<span className="inline sm:hidden">Track Progress</span> |
|
|
|
</button> |
|
|
|
</button> |
|
|
|
|
|
|
|
|
|
|
|
<button |
|
|
|
<button |
|
|
|
className="hidden sm:inline-flex items-center justify-center gap-2 rounded-md bg-gray-200 py-1.5 pl-2.5 pr-3 text-xs font-medium text-black transition-colors duration-300 hover:bg-gray-300 sm:text-sm" |
|
|
|
className="hidden items-center justify-center gap-2 rounded-md bg-gray-200 py-1.5 pl-2.5 pr-3 text-xs font-medium text-black transition-colors duration-300 hover:bg-gray-300 sm:inline-flex sm:text-sm" |
|
|
|
onClick={async () => { |
|
|
|
onClick={async () => { |
|
|
|
const roadmapId = await saveAIRoadmap(); |
|
|
|
const roadmapId = await saveAIRoadmap(); |
|
|
|
if (roadmapId) { |
|
|
|
if (roadmapId) { |
|
|
|