Files
developer-roadmap/src/components/AIRoadmap/GenerateAIRoadmap.tsx
T
Arik ChakmaandKamran Ahmed e6d10ef592 feat: ai roadmaps and chat (#8821)
* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip: ai roadmap

* wip

* wip

* Add question answers

* Update content generator

* Update question answer chat

* Refresh button not working

* UI for chat

* Update question answers functionality

* wip

* wip

* fix: ai roadmap regenerate

* Improve preferences

* feat: roadmap actions

* wip

* fix: hydration error

* Fix responsiveness issue

* fix: show preferences option only when questions exist

* fix: infinite loop issue

* feat: node click message populate

* Improve UI

* wip

* wip

* fix: roadmap regenerate

* Update UI

* Update placeholder

* Update answers

* Update navigations

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
2025-06-26 13:00:46 +01:00

116 lines
3.2 KiB
TypeScript

import { useEffect, useRef, useState } from 'react';
import { getUrlParams } from '../../lib/browser';
import { isLoggedIn } from '../../lib/jwt';
import { queryClient } from '../../stores/query-client';
import { LoadingChip } from '../LoadingChip';
import type { QuestionAnswerChatMessage } from '../ContentGenerator/QuestionAnswerChat';
import { getQuestionAnswerChatMessages } from '../../lib/ai-questions';
import { aiRoadmapOptions, generateAIRoadmap } from '../../queries/ai-roadmap';
import { AIRoadmapContent } from './AIRoadmapContent';
type GenerateAIRoadmapProps = {
onRoadmapSlugChange?: (roadmapSlug: string) => void;
};
export function GenerateAIRoadmap(props: GenerateAIRoadmapProps) {
const { onRoadmapSlugChange } = props;
const [isLoading, setIsLoading] = useState(true);
const [isStreaming, setIsStreaming] = useState(false);
const [error, setError] = useState('');
const [svgHtml, setSvgHtml] = useState('');
const [content, setContent] = useState('');
const svgRef = useRef<string | null>(null);
useEffect(() => {
const params = getUrlParams();
const paramsTerm = params?.term;
const paramsSrc = params?.src || 'search';
if (!paramsTerm) {
return;
}
let questionAndAnswers: QuestionAnswerChatMessage[] = [];
const sessionId = params?.id;
if (sessionId) {
questionAndAnswers = getQuestionAnswerChatMessages(sessionId);
}
handleGenerateDocument({
term: paramsTerm,
src: paramsSrc,
questionAndAnswers,
});
}, []);
const handleGenerateDocument = async (options: {
term: string;
isForce?: boolean;
prompt?: string;
src?: string;
questionAndAnswers?: QuestionAnswerChatMessage[];
}) => {
const { term, isForce, prompt, src, questionAndAnswers } = options;
if (!isLoggedIn()) {
window.location.href = '/ai';
return;
}
await generateAIRoadmap({
term,
isForce,
prompt,
questionAndAnswers,
onDetailsChange: (details) => {
const { roadmapId, roadmapSlug, title, userId } = details;
const aiRoadmapData = {
_id: roadmapId,
userId,
title,
term,
data: content,
questionAndAnswers,
viewCount: 0,
svgHtml: svgRef.current || '',
lastVisitedAt: new Date(),
createdAt: new Date(),
updatedAt: new Date(),
};
queryClient.setQueryData(
aiRoadmapOptions(roadmapSlug).queryKey,
aiRoadmapData,
);
onRoadmapSlugChange?.(roadmapSlug);
window.history.replaceState(null, '', `/ai-roadmaps/${roadmapSlug}`);
},
onLoadingChange: setIsLoading,
onError: setError,
onStreamingChange: setIsStreaming,
onRoadmapSvgChange: (svg) => {
const svgHtml = svg.outerHTML;
svgRef.current = svgHtml;
setSvgHtml(svgHtml);
},
});
};
if (error) {
return <div className="text-red-500">{error}</div>;
}
if (isLoading) {
return (
<div className="flex h-full w-full items-center justify-center">
<LoadingChip message="Please wait..." />
</div>
);
}
return <AIRoadmapContent isLoading={isLoading} svgHtml={svgHtml} />;
}