Improve AI page with enhanced error handling and data display

Refactors AIPage.tsx to improve data handling, error resilience, and API request structure using try-catch blocks.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 6bac2659-689a-442d-ae16-f45f8d1450c7
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/9777c70b-fc38-4831-8d6b-78dfffe041b0/7ef4e00c-25b0-4098-932c-00d235018b09.jpg
This commit is contained in:
ghaddaditw
2025-06-08 16:18:50 +00:00
parent 3eaff970ce
commit 5a8e72c176
3 changed files with 24 additions and 18 deletions
+3 -1
View File
@@ -25,7 +25,7 @@ import {
} from "lucide-react"; } from "lucide-react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
export default function Header() { export function Header() {
const { user, logout } = useAuth(); const { user, logout } = useAuth();
const { theme, toggleTheme } = useTheme(); const { theme, toggleTheme } = useTheme();
const { t } = useTranslation(); const { t } = useTranslation();
@@ -160,3 +160,5 @@ export default function Header() {
</header> </header>
); );
} }
export default Header;
+2
View File
@@ -233,3 +233,5 @@ export default function Sidebar({ className }: SidebarProps) {
</div> </div>
); );
} }
export default Sidebar;
+19 -17
View File
@@ -18,14 +18,17 @@ export default function AIPage() {
const { data: dailyJoke } = useQuery({ const { data: dailyJoke } = useQuery({
queryKey: ["/api/ai/daily-joke"], queryKey: ["/api/ai/daily-joke"],
select: (data: any) => data || { joke: "Why don't AI assistants ever get tired? Because they run on endless loops!" }
}); });
const { data: status } = useQuery({ const { data: status } = useQuery({
queryKey: ["/api/ai/status"], queryKey: ["/api/ai/status"],
select: (data: any) => data || { loaded: true }
}); });
const { data: interactions = [] } = useQuery({ const { data: interactions = [] } = useQuery({
queryKey: ["/api/ai/interactions"], queryKey: ["/api/ai/interactions"],
select: (data: any) => Array.isArray(data) ? data : []
}); });
const handleSendMessage = async (e: React.FormEvent) => { const handleSendMessage = async (e: React.FormEvent) => {
@@ -60,12 +63,11 @@ export default function AIPage() {
const generatePersonalizedJoke = async () => { const generatePersonalizedJoke = async () => {
try { try {
const response = await apiRequest("/api/ai/joke", { const response = await apiRequest("POST", "/api/ai/generate-joke", {});
method: "POST", const data = await response.json();
});
toast({ toast({
title: "Here's a joke for you!", title: "Here's a joke for you!",
description: response.content || "Why don't tasks ever get lonely? Because they always have deadlines to meet!", description: data.content || "Why don't tasks ever get lonely? Because they always have deadlines to meet!",
}); });
} catch (error) { } catch (error) {
toast({ toast({
@@ -78,13 +80,13 @@ export default function AIPage() {
const generateInsight = async (type: string) => { const generateInsight = async (type: string) => {
try { try {
const response = await apiRequest("/api/ai/insight", { const response = await apiRequest("POST", "/api/ai/chat", {
method: "POST", message: `Generate an insight about my ${type} data`
body: JSON.stringify({ type }),
}); });
const data = await response.json();
toast({ toast({
title: `${type.charAt(0).toUpperCase() + type.slice(1)} Insight`, title: `${type.charAt(0).toUpperCase() + type.slice(1)} Insight`,
description: response.content || "Here's an insight based on your data!", description: data.content || "Here's an insight based on your data!",
}); });
} catch (error) { } catch (error) {
toast({ toast({
@@ -183,14 +185,14 @@ export default function AIPage() {
<div className="space-y-3"> <div className="space-y-3">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<span className="text-sm">Model Status</span> <span className="text-sm">Model Status</span>
<Badge variant={status?.loaded ? "default" : "secondary"}> <Badge variant={(status as any)?.loaded ? "default" : "secondary"}>
{status?.loaded ? "Ready" : "Loading"} {(status as any)?.loaded ? "Ready" : "Loading"}
</Badge> </Badge>
</div> </div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<span className="text-sm">Interactions Today</span> <span className="text-sm">Interactions Today</span>
<Badge variant="outline"> <Badge variant="outline">
{interactions.length} {Array.isArray(interactions) ? interactions.length : 0}
</Badge> </Badge>
</div> </div>
</div> </div>
@@ -235,24 +237,24 @@ export default function AIPage() {
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<p className="text-sm italic">"{dailyJoke.joke}"</p> <p className="text-sm italic">"{(dailyJoke as any)?.joke || 'Why don\'t AI assistants ever get tired? Because they run on endless loops!'}"</p>
</CardContent> </CardContent>
</Card> </Card>
)} )}
{/* Recent Interactions */} {/* Recent Interactions */}
{interactions.length > 0 && ( {Array.isArray(interactions) && interactions.length > 0 && (
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>Recent Interactions</CardTitle> <CardTitle>Recent Interactions</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="space-y-2"> <div className="space-y-2">
{interactions.slice(0, 5).map((interaction: any) => ( {(interactions as any[]).slice(0, 5).map((interaction: any, index: number) => (
<div key={interaction.id} className="text-xs p-2 bg-gray-50 dark:bg-gray-800 rounded"> <div key={interaction.id || index} className="text-xs p-2 bg-gray-50 dark:bg-gray-800 rounded">
<div className="font-medium">{interaction.type}</div> <div className="font-medium">{interaction.type || 'AI Interaction'}</div>
<div className="text-gray-600 dark:text-gray-300"> <div className="text-gray-600 dark:text-gray-300">
{new Date(interaction.createdAt).toLocaleDateString()} {interaction.createdAt ? new Date(interaction.createdAt).toLocaleDateString() : 'Today'}
</div> </div>
</div> </div>
))} ))}