Enhance user experience with protected routes and AI chat improvements
Adds protected routes with loading skeletons, fixes AI chat data handling, and handles task array checks. 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/b010d0e6-5a54-4e9e-b559-909112e9dc8a.jpg
This commit is contained in:
+74
-18
@@ -1,10 +1,10 @@
|
||||
import { Switch, Route } from "wouter";
|
||||
import { Switch, Route, Redirect } from "wouter";
|
||||
import { queryClient } from "./lib/queryClient";
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { Toaster } from "@/components/ui/toaster";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { FloatingVoiceControl } from "@/components/voice/FloatingVoiceControl";
|
||||
import { AuthProvider } from "@/context/AuthContext";
|
||||
import { AuthProvider, useAuth } from "@/context/AuthContext";
|
||||
import { ThemeProvider } from "@/context/ThemeContext";
|
||||
import { AdaptiveThemeProvider } from "@/context/AdaptiveThemeContext";
|
||||
import { VoiceProvider } from "@/context/VoiceProvider";
|
||||
@@ -12,6 +12,7 @@ import { NotificationProvider } from "@/context/NotificationProvider";
|
||||
import { TourManagerProvider } from "@/components/onboarding/TourManager";
|
||||
import { MoodDetector } from "@/components/MoodDetector";
|
||||
import { RTLProvider } from "@/components/RTLProvider";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import LandingPage from "@/pages/LandingPage";
|
||||
import DashboardPage from "@/pages/DashboardPage";
|
||||
import LoginPage from "@/pages/LoginPage";
|
||||
@@ -31,26 +32,81 @@ import ChatPage from "@/pages/ChatPage";
|
||||
import ComfortHubPage from "@/pages/ComfortHubPage";
|
||||
import NotFound from "@/pages/not-found";
|
||||
|
||||
// Protected Route wrapper
|
||||
function ProtectedRoute({ component: Component }: { component: React.ComponentType }) {
|
||||
const { user, isLoading } = useAuth();
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center">
|
||||
<div className="space-y-4 w-full max-w-md p-6">
|
||||
<Skeleton className="h-8 w-3/4" />
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-2/3" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return <Redirect to="/login" />;
|
||||
}
|
||||
|
||||
// Check if user needs onboarding
|
||||
if (!user.onboardingComplete) {
|
||||
return <Redirect to="/onboarding" />;
|
||||
}
|
||||
|
||||
return <Component />;
|
||||
}
|
||||
|
||||
// Public route that redirects authenticated users
|
||||
function PublicRoute({ component: Component }: { component: React.ComponentType }) {
|
||||
const { user, isLoading } = useAuth();
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center">
|
||||
<div className="space-y-4 w-full max-w-md p-6">
|
||||
<Skeleton className="h-8 w-3/4" />
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-2/3" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (user) {
|
||||
if (!user.onboardingComplete) {
|
||||
return <Redirect to="/onboarding" />;
|
||||
}
|
||||
return <Redirect to="/dashboard" />;
|
||||
}
|
||||
|
||||
return <Component />;
|
||||
}
|
||||
|
||||
function Router() {
|
||||
return (
|
||||
<Switch>
|
||||
<Route path="/" component={LandingPage} />
|
||||
<Route path="/login" component={LoginPage} />
|
||||
<Route path="/register" component={LoginPage} />
|
||||
<Route path="/" component={() => <PublicRoute component={LandingPage} />} />
|
||||
<Route path="/login" component={() => <PublicRoute component={LoginPage} />} />
|
||||
<Route path="/register" component={() => <PublicRoute component={LoginPage} />} />
|
||||
<Route path="/onboarding" component={OnboardingPage} />
|
||||
<Route path="/dashboard" component={DashboardPage} />
|
||||
<Route path="/tasks" component={TasksPage} />
|
||||
<Route path="/finances" component={FinancesPage} />
|
||||
<Route path="/voice" component={VoicePage} />
|
||||
<Route path="/ai" component={AIPage} />
|
||||
<Route path="/analytics" component={AnalyticsPage} />
|
||||
<Route path="/monitoring" component={SystemMonitoringPage} />
|
||||
<Route path="/focus" component={FocusPage} />
|
||||
<Route path="/themes" component={ThemePage} />
|
||||
<Route path="/chat" component={ChatPage} />
|
||||
<Route path="/comfort" component={ComfortHubPage} />
|
||||
<Route path="/settings" component={SettingsPage} />
|
||||
<Route path="/professionals" component={ProfessionalDirectory} />
|
||||
<Route path="/dashboard" component={() => <ProtectedRoute component={DashboardPage} />} />
|
||||
<Route path="/tasks" component={() => <ProtectedRoute component={TasksPage} />} />
|
||||
<Route path="/finances" component={() => <ProtectedRoute component={FinancesPage} />} />
|
||||
<Route path="/voice" component={() => <ProtectedRoute component={VoicePage} />} />
|
||||
<Route path="/ai" component={() => <ProtectedRoute component={AIPage} />} />
|
||||
<Route path="/analytics" component={() => <ProtectedRoute component={AnalyticsPage} />} />
|
||||
<Route path="/monitoring" component={() => <ProtectedRoute component={SystemMonitoringPage} />} />
|
||||
<Route path="/focus" component={() => <ProtectedRoute component={FocusPage} />} />
|
||||
<Route path="/themes" component={() => <ProtectedRoute component={ThemePage} />} />
|
||||
<Route path="/chat" component={() => <ProtectedRoute component={ChatPage} />} />
|
||||
<Route path="/comfort" component={() => <ProtectedRoute component={ComfortHubPage} />} />
|
||||
<Route path="/settings" component={() => <ProtectedRoute component={SettingsPage} />} />
|
||||
<Route path="/professionals" component={() => <ProtectedRoute component={ProfessionalDirectory} />} />
|
||||
<Route path="/benchmark" component={() => <ProtectedRoute component={BenchmarkPage} />} />
|
||||
<Route component={NotFound} />
|
||||
</Switch>
|
||||
);
|
||||
|
||||
@@ -38,14 +38,12 @@ export default function AIPage() {
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
const response = await apiRequest("/api/ai/chat", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ message }),
|
||||
});
|
||||
const response = await apiRequest("POST", "/api/ai/chat", { message });
|
||||
const data = await response.json();
|
||||
|
||||
const aiMessage = {
|
||||
role: "assistant",
|
||||
content: response.content || "I'm here to help! How can I assist you today?",
|
||||
content: data.content || "I'm here to help! How can I assist you today?",
|
||||
timestamp: new Date()
|
||||
};
|
||||
setChatHistory(prev => [...prev, aiMessage]);
|
||||
|
||||
@@ -48,7 +48,7 @@ export default function TasksPage() {
|
||||
|
||||
// Filter and sort tasks
|
||||
const filteredAndSortedTasks = useMemo(() => {
|
||||
if (!tasks) return [];
|
||||
if (!Array.isArray(tasks)) return [];
|
||||
|
||||
const filtered = tasks.filter((task: any) => {
|
||||
const matchesSearch = task.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
@@ -68,9 +68,9 @@ export default function TasksPage() {
|
||||
bValue = b.title.toLowerCase();
|
||||
break;
|
||||
case "priority":
|
||||
const priorityOrder = { high: 3, medium: 2, low: 1 };
|
||||
aValue = priorityOrder[a.priority] || 0;
|
||||
bValue = priorityOrder[b.priority] || 0;
|
||||
const priorityOrder: Record<string, number> = { high: 3, medium: 2, low: 1 };
|
||||
aValue = priorityOrder[a.priority as string] || 0;
|
||||
bValue = priorityOrder[b.priority as string] || 0;
|
||||
break;
|
||||
case "dueDate":
|
||||
aValue = a.dueDate ? new Date(a.dueDate) : new Date('9999-12-31');
|
||||
|
||||
Reference in New Issue
Block a user