1
0
mirror of https://github.com/kamranahmedse/developer-roadmap.git synced 2025-09-03 14:22:41 +02:00

Handle error screen

This commit is contained in:
Kamran Ahmed
2025-05-22 13:48:36 +01:00
parent 041f090a47
commit 85fec7a6af
5 changed files with 47 additions and 28 deletions

View File

@@ -2,8 +2,7 @@ import './RoadmapAIChat.css';
import { useQuery } from '@tanstack/react-query';
import {
roadmapDetailsOptions,
roadmapJSONOptions,
roadmapJSONOptions
} from '../../queries/roadmap';
import { queryClient } from '../../stores/query-client';
import {
@@ -14,7 +13,7 @@ import {
useRef,
useState,
} from 'react';
import { BotIcon, Loader2Icon, PauseCircleIcon, SendIcon } from 'lucide-react';
import { BotIcon, Frown, Loader2Icon, PauseCircleIcon, SendIcon } from 'lucide-react';
import { ChatEditor } from '../ChatEditor/ChatEditor';
import { roadmapTreeMappingOptions } from '../../queries/roadmap-tree';
import { type AllowedAIChatRole } from '../GenerateCourse/AICourseLessonChat';
@@ -72,12 +71,7 @@ export function RoadmapAIChat(props: RoadmapAIChatProps) {
const [streamedMessage, setStreamedMessage] =
useState<React.ReactNode | null>(null);
const { data: roadmapDetailsData } = useQuery(
roadmapDetailsOptions(roadmapId),
queryClient,
);
const { data: roadmapJSONData } = useQuery(
const { data: roadmapDetail, error: roadmapDetailError } = useQuery(
roadmapJSONOptions(roadmapId),
queryClient,
);
@@ -94,20 +88,20 @@ export function RoadmapAIChat(props: RoadmapAIChatProps) {
const roadmapContainerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!roadmapJSONData || !roadmapContainerRef.current) {
if (!roadmapDetail || !roadmapContainerRef.current) {
return;
}
roadmapContainerRef.current.replaceChildren(roadmapJSONData.svg);
}, [roadmapJSONData]);
roadmapContainerRef.current.replaceChildren(roadmapDetail.svg);
}, [roadmapDetail]);
useEffect(() => {
if (!roadmapTreeData || !roadmapJSONData || !roadmapDetailsData) {
if (!roadmapTreeData || !roadmapDetail) {
return;
}
setIsLoading(false);
}, [roadmapTreeData, roadmapJSONData, roadmapDetailsData]);
}, [roadmapTreeData, roadmapDetail]);
const abortControllerRef = useRef<AbortController | null>(null);
const handleChatSubmit = (json: JSONContent) => {
@@ -282,6 +276,18 @@ export function RoadmapAIChat(props: RoadmapAIChatProps) {
scrollToBottom();
}, []);
if (roadmapDetailError) {
return (
<div className="flex flex-grow flex-col items-center justify-center">
<Frown className="mb-4 size-16" />
<h1 className="mb-2 text-2xl font-bold">There was an error</h1>
<p className="max-w-sm text-balance text-gray-500">
{roadmapDetailError.message}
</p>
</div>
);
}
return (
<div className="flex flex-grow flex-row">
<div className="relative h-full flex-grow overflow-y-scroll">
@@ -290,13 +296,15 @@ export function RoadmapAIChat(props: RoadmapAIChatProps) {
<Loader2Icon className="size-6 animate-spin stroke-[2.5]" />
</div>
)}
{roadmapJSONData?.json && !isLoading && (
<div className="mx-auto max-w-[968px] px-4">
<ChatRoadmapRenderer
roadmapId={roadmapId}
nodes={roadmapJSONData?.json.nodes}
edges={roadmapJSONData?.json.edges}
/>
{roadmapDetail?.json && !isLoading && (
<div>
<div className="mx-auto max-w-[968px] px-4">
<ChatRoadmapRenderer
roadmapId={roadmapId}
nodes={roadmapDetail?.json.nodes}
edges={roadmapDetail?.json.edges}
/>
</div>
</div>
)}
</div>

View File

@@ -80,6 +80,8 @@ export async function httpCall<ResponseType = AppResponse>(
if (!response.ok) {
if (data.errors) {
throw new FetchError(response?.status, data.message);
} else if (data.message) {
throw new FetchError(response?.status, data.message);
} else {
throw new Error('An unexpected error occurred');
}

View File

@@ -59,7 +59,7 @@ export const GET: APIRoute = async function ({ params, request, props }) {
);
if (!fs.existsSync(roadmapFilePath)) {
return new Response(JSON.stringify({ error: 'Roadmap file not found' }), {
return new Response(JSON.stringify({ message: 'Roadmap not found' }), {
status: 404,
});
}

View File

@@ -21,8 +21,7 @@ const { roadmapId } = Astro.params as Props;
wrapperClassName='flex-row p-0 lg:p-0 overflow-hidden'
client:load
>
<!-- Make it client:load please -->
<RoadmapAIChat roadmapId={roadmapId} client:only='react' />
<RoadmapAIChat roadmapId={roadmapId} client:load />
<CheckSubscriptionVerification client:load />
</AITutorLayout>
</SkeletonLayout>

View File

@@ -2,15 +2,25 @@ import { queryOptions } from '@tanstack/react-query';
import { httpGet } from '../lib/query-http';
import { type Node, type Edge, renderFlowJSON } from '@roadmapsh/editor';
type RoadmapJSON = {
_id: string;
title: string;
description: string;
slug: string;
nodes: Node[];
edges: Edge[];
createdAt: string;
updatedAt: string;
};
export function roadmapJSONOptions(roadmapId: string) {
return queryOptions({
queryKey: ['roadmap-json', roadmapId],
queryFn: async () => {
const baseUrl = import.meta.env.PUBLIC_APP_URL;
const roadmapJSON = await httpGet<{
nodes: Node[];
edges: Edge[];
}>(`${baseUrl}/${roadmapId}.json`);
const roadmapJSON = await httpGet<RoadmapJSON>(
`${baseUrl}/${roadmapId}.json`,
);
const svg = await renderFlowJSON(roadmapJSON);