diff --git a/src/components/GenerateRoadmap/GenerateRoadmap.tsx b/src/components/GenerateRoadmap/GenerateRoadmap.tsx index d22c8e2d2..3b68e9467 100644 --- a/src/components/GenerateRoadmap/GenerateRoadmap.tsx +++ b/src/components/GenerateRoadmap/GenerateRoadmap.tsx @@ -13,7 +13,7 @@ import { renderFlowJSON } from '../../../editor/renderer/renderer'; import { replaceChildren } from '../../lib/dom'; import { readAIRoadmapStream } from '../../helper/read-stream'; import { - getOpenAPIKey, + getOpenAIKey, isLoggedIn, removeAuthToken, visitAIRoadmap, @@ -103,7 +103,7 @@ export function GenerateRoadmap() { const [roadmapTopicLimitUsed, setRoadmapTopicLimitUsed] = useState(0); const [isConfiguring, setIsConfiguring] = useState(false); - const openAPIKey = getOpenAPIKey(); + const openAPIKey = getOpenAIKey(); const renderRoadmap = async (roadmap: string) => { const { nodes, edges } = generateAIRoadmapFromText(roadmap); @@ -401,6 +401,10 @@ export function GenerateRoadmap() { nodeType={selectedNode.nodeType} nodeTitle={selectedNode.nodeTitle} parentTitle={selectedNode.parentTitle} + onConfigureOpenAI={() => { + setSelectedNode(null); + setIsConfiguring(true); + }} onClose={() => { setSelectedNode(null); loadAIRoadmapLimit().finally(() => {}); @@ -470,7 +474,7 @@ export function GenerateRoadmap() { className="flex flex-row items-center gap-1 rounded-xl border border-current px-2 py-0.5 text-sm text-blue-500 transition-colors hover:bg-blue-400 hover:text-white" > - Configure OpenAI API key + Configure OpenAI key )} diff --git a/src/components/GenerateRoadmap/OpenAISettings.tsx b/src/components/GenerateRoadmap/OpenAISettings.tsx index ced58b7cb..2e361111b 100644 --- a/src/components/GenerateRoadmap/OpenAISettings.tsx +++ b/src/components/GenerateRoadmap/OpenAISettings.tsx @@ -1,9 +1,9 @@ import { Modal } from '../Modal.tsx'; import { useEffect, useState } from 'react'; import { - deleteOpenAPIKey, - getOpenAPIKey, - saveOpenAPIKey, + deleteOpenAIKey, + getOpenAIKey, + saveOpenAIKey, } from '../../lib/jwt.ts'; import { cn } from '../../lib/classname.ts'; import { CloseIcon } from '../ReactIcons/CloseIcon.tsx'; @@ -26,7 +26,7 @@ export function OpenAISettings(props: OpenAISettingsProps) { const toast = useToast(); useEffect(() => { - const apiKey = getOpenAPIKey(); + const apiKey = getOpenAIKey(); setOpenaiApiKey(apiKey || ''); setDefaultOpenAIKey(apiKey || ''); }, []); @@ -59,7 +59,7 @@ export function OpenAISettings(props: OpenAISettingsProps) { const normalizedKey = openaiApiKey.trim(); if (!normalizedKey) { - deleteOpenAPIKey(); + deleteOpenAIKey(); toast.success('OpenAI API key removed'); onClose(); return; @@ -85,7 +85,7 @@ export function OpenAISettings(props: OpenAISettingsProps) { } // Save the API key to cookies - saveOpenAPIKey(normalizedKey); + saveOpenAIKey(normalizedKey); toast.success('OpenAI API key saved'); onClose(); }} @@ -151,7 +151,7 @@ export function OpenAISettings(props: OpenAISettingsProps) { )}

diff --git a/src/components/GenerateRoadmap/RoadmapTopicDetail.tsx b/src/components/GenerateRoadmap/RoadmapTopicDetail.tsx index 184203e82..f3db8525c 100644 --- a/src/components/GenerateRoadmap/RoadmapTopicDetail.tsx +++ b/src/components/GenerateRoadmap/RoadmapTopicDetail.tsx @@ -3,13 +3,14 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import { useKeydown } from '../../hooks/use-keydown'; import { useOutsideClick } from '../../hooks/use-outside-click'; import { markdownToHtml } from '../../lib/markdown'; -import { Ban, FileText, X } from 'lucide-react'; +import { Ban, Cog, FileText, X } from 'lucide-react'; import { Spinner } from '../ReactIcons/Spinner'; import type { RoadmapNodeDetails } from './GenerateRoadmap'; -import { isLoggedIn, removeAuthToken } from '../../lib/jwt'; +import { getOpenAIKey, isLoggedIn, removeAuthToken } from '../../lib/jwt'; import { readAIRoadmapContentStream } from '../../helper/read-stream'; import { cn } from '../../lib/classname'; import { showLoginPopup } from '../../lib/popup'; +import { OpenAISettings } from './OpenAISettings.tsx'; type RoadmapTopicDetailProps = RoadmapNodeDetails & { onClose?: () => void; @@ -17,6 +18,7 @@ type RoadmapTopicDetailProps = RoadmapNodeDetails & { topicLimitUsed: number; topicLimit: number; onTopicContentGenerateComplete?: () => void; + onConfigureOpenAI?: () => void; }; export function RoadmapTopicDetail(props: RoadmapTopicDetailProps) { @@ -28,6 +30,7 @@ export function RoadmapTopicDetail(props: RoadmapTopicDetailProps) { topicLimit, topicLimitUsed, onTopicContentGenerateComplete, + onConfigureOpenAI, } = props; const [isLoading, setIsLoading] = useState(false); @@ -121,6 +124,7 @@ export function RoadmapTopicDetail(props: RoadmapTopicDetailProps) { }, []); const hasContent = topicHtml?.length > 0; + const openAIKey = getOpenAIKey(); return (
@@ -129,7 +133,7 @@ export function RoadmapTopicDetail(props: RoadmapTopicDetailProps) { tabIndex={0} className="fixed right-0 top-0 z-40 h-screen w-full overflow-y-auto bg-white p-4 focus:outline-0 sm:max-w-[600px] sm:p-6" > -
+
- Generate more by{' '} - logging in + Generate more by logging in + + )} + {isLoggedIn() && !openAIKey && ( + + )} + {isLoggedIn() && openAIKey && ( + )}
diff --git a/src/lib/jwt.ts b/src/lib/jwt.ts index 22643b589..d3206b083 100644 --- a/src/lib/jwt.ts +++ b/src/lib/jwt.ts @@ -64,14 +64,14 @@ export function visitAIRoadmap(roadmapId: string) { }); } -export function deleteOpenAPIKey() { +export function deleteOpenAIKey() { Cookies.remove('oak', { path: '/', domain: import.meta.env.DEV ? 'localhost' : '.roadmap.sh', }); } -export function saveOpenAPIKey(apiKey: string) { +export function saveOpenAIKey(apiKey: string) { Cookies.set('oak', apiKey, { path: '/', expires: 365, @@ -81,6 +81,6 @@ export function saveOpenAPIKey(apiKey: string) { }); } -export function getOpenAPIKey() { +export function getOpenAIKey() { return Cookies.get('oak'); }