From bb9dcfb678e1f64f942d5bc45b73b28e1ba8d037 Mon Sep 17 00:00:00 2001 From: Arik Chakma Date: Fri, 1 Mar 2024 03:20:49 +0600 Subject: [PATCH] feat: add limit count --- .../GenerateRoadmap/GenerateRoadmap.tsx | 101 ++++++++++++++++-- .../GenerateRoadmap/RoadmapSearch.tsx | 15 ++- 2 files changed, 107 insertions(+), 9 deletions(-) diff --git a/src/components/GenerateRoadmap/GenerateRoadmap.tsx b/src/components/GenerateRoadmap/GenerateRoadmap.tsx index 72a80f082..cced06f3b 100644 --- a/src/components/GenerateRoadmap/GenerateRoadmap.tsx +++ b/src/components/GenerateRoadmap/GenerateRoadmap.tsx @@ -1,4 +1,4 @@ -import { useRef, useState, type FormEvent } from 'react'; +import { useEffect, useRef, useState, type FormEvent } from 'react'; import fp from '@fingerprintjs/fingerprintjs'; import './GenerateRoadmap.css'; import { useToast } from '../../hooks/use-toast'; @@ -11,12 +11,16 @@ import { RoadmapSearch } from './RoadmapSearch.tsx'; import { Spinner } from '../ReactIcons/Spinner.tsx'; import { Download, PenSquare, Wand } from 'lucide-react'; import { ShareRoadmapButton } from '../ShareRoadmapButton.tsx'; -import { httpPost } from '../../lib/http.ts'; +import { httpGet, httpPost } from '../../lib/http.ts'; import { pageProgressMessage } from '../../stores/page.ts'; +import { getUrlParams, setUrlParams } from '../../lib/browser.ts'; + +const ROADMAP_ID_REGEX = new RegExp('@ROADMAPID:(\\w+)@'); export function GenerateRoadmap() { const roadmapContainerRef = useRef(null); + const { id: roadmapId } = getUrlParams() as { id: string }; const toast = useToast(); const [hasSubmitted, setHasSubmitted] = useState(false); @@ -24,6 +28,9 @@ export function GenerateRoadmap() { const [roadmapTopic, setRoadmapTopic] = useState(''); const [generatedRoadmap, setGeneratedRoadmap] = useState(''); + const [roadmapLimit, setRoadmapLimit] = useState(0); + const [roadmapLimitUsed, setRoadmapLimitUsed] = useState(0); + const handleSubmit = async (e: FormEvent) => { e.preventDefault(); setIsLoading(true); @@ -71,6 +78,15 @@ export function GenerateRoadmap() { await readAIRoadmapStream(reader, { onStream: async (result) => { + if (result.includes('@ROADMAPID')) { + // @ROADMAPID: is a special token that we use to identify the roadmap + // @ROADMAPID:1234@ is the format, we will remove the token and the id + // and replace it with a empty string + const roadmapId = result.match(ROADMAP_ID_REGEX)?.[1] || ''; + setUrlParams({ id: roadmapId }); + result = result.replace(ROADMAP_ID_REGEX, ''); + } + const { nodes, edges } = generateAIRoadmapFromText(result); const svg = await renderFlowJSON({ nodes, edges }); if (roadmapContainerRef?.current) { @@ -78,7 +94,9 @@ export function GenerateRoadmap() { } }, onStreamEnd: async (result) => { + result = result.replace(ROADMAP_ID_REGEX, ''); setGeneratedRoadmap(result); + loadAIRoadmapLimit().finally(() => {}); }, }); @@ -159,16 +177,83 @@ export function GenerateRoadmap() { } }; + const loadAIRoadmapLimit = async () => { + pageProgressMessage.set('Loading Roadmap Limit'); + + const { response, error } = await httpGet<{ + limit: number; + used: number; + }>(`${import.meta.env.PUBLIC_API_URL}/v1-get-ai-roadmap-limit`); + + if (error || !response) { + toast.error(error?.message || 'Something went wrong'); + return; + } + + const { limit, used } = response; + setRoadmapLimit(limit); + setRoadmapLimitUsed(used); + + pageProgressMessage.set(''); + }; + + const loadAIRoadmap = async (roadmapId: string) => { + setIsLoading(true); + pageProgressMessage.set('Loading Roadmap'); + + const { response, error } = await httpGet<{ + topic: string; + data: string; + }>(`${import.meta.env.PUBLIC_API_URL}/v1-get-ai-roadmap/${roadmapId}`); + + if (error || !response) { + toast.error(error?.message || 'Something went wrong'); + setIsLoading(false); + return; + } + + const { topic, data } = response; + + const { nodes, edges } = generateAIRoadmapFromText(data); + const svg = await renderFlowJSON({ nodes, edges }); + if (roadmapContainerRef?.current) { + replaceChildren(roadmapContainerRef?.current, svg); + } + + setRoadmapTopic(topic); + setGeneratedRoadmap(data); + }; + + useEffect(() => { + loadAIRoadmapLimit().finally(() => {}); + }, []); + + useEffect(() => { + if (!roadmapId) { + return; + } + + setHasSubmitted(true); + loadAIRoadmap(roadmapId).then(() => { + setIsLoading(false); + pageProgressMessage.set(''); + }); + }, [roadmapId]); + if (!hasSubmitted) { return ( ); } + const pageUrl = `https://roadmap.sh/ai?id=${roadmapId}`; + return (
@@ -182,7 +267,7 @@ export function GenerateRoadmap() {
- 0 of 5 roadmaps generated{' '} + {roadmapLimitUsed} of {roadmapLimit} roadmaps generated{' '} @@ -219,10 +304,12 @@ export function GenerateRoadmap() { Download - + {roadmapId && ( + + )}