diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 7d3b353f..e5844351 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -10,6 +10,7 @@ import ContentPlanningDashboard from './components/ContentPlanningDashboard/Cont
import FacebookWriter from './components/FacebookWriter/FacebookWriter';
import LinkedInWriter from './components/LinkedInWriter/LinkedInWriter';
import BlogWriter from './components/BlogWriter/BlogWriter';
+import ProtectedRoute from './components/shared/ProtectedRoute';
import { apiClient } from './api/client';
@@ -170,9 +171,31 @@ const App: React.FC = () => {
);
}
+ // Check if CopilotKit API key is available
+ const copilotApiKey = process.env.REACT_APP_COPILOTKIT_API_KEY;
+
+ // If no CopilotKit API key, render without CopilotKit wrapper
+ if (!copilotApiKey) {
+ return (
+
+
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
+ );
+ }
+
return (
console.error("CopilotKit Error:", e)}
@@ -182,13 +205,13 @@ const App: React.FC = () => {
} />
} />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
diff --git a/frontend/src/components/shared/ProtectedRoute.tsx b/frontend/src/components/shared/ProtectedRoute.tsx
new file mode 100644
index 00000000..befa795d
--- /dev/null
+++ b/frontend/src/components/shared/ProtectedRoute.tsx
@@ -0,0 +1,107 @@
+import React, { useState, useEffect } from 'react';
+import { Navigate } from 'react-router-dom';
+import { Box, CircularProgress, Typography } from '@mui/material';
+import { apiClient } from '../../api/client';
+
+interface ProtectedRouteProps {
+ children: React.ReactNode;
+}
+
+interface OnboardingStatus {
+ is_completed: boolean;
+ current_step: number;
+ completion_percentage: number;
+ next_step?: number;
+ started_at: string;
+ completed_at?: string;
+ can_proceed_to_final: boolean;
+}
+
+const ProtectedRoute: React.FC = ({ children }) => {
+ const [loading, setLoading] = useState(true);
+ const [onboardingComplete, setOnboardingComplete] = useState(false);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ const checkOnboardingStatus = async () => {
+ try {
+ console.log('ProtectedRoute: Checking onboarding status...');
+ const response = await apiClient.get('/api/onboarding/status');
+ const status: OnboardingStatus = response.data;
+
+ console.log('ProtectedRoute: Onboarding status:', status);
+
+ if (status.is_completed) {
+ console.log('ProtectedRoute: Onboarding is complete, allowing access');
+ setOnboardingComplete(true);
+ } else {
+ console.log('ProtectedRoute: Onboarding not complete, redirecting to onboarding');
+ setOnboardingComplete(false);
+ }
+ } catch (err) {
+ console.error('ProtectedRoute: Error checking onboarding status:', err);
+ setError('Failed to check onboarding status');
+ // On error, assume onboarding is not complete for security
+ setOnboardingComplete(false);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ checkOnboardingStatus();
+ }, []);
+
+ if (loading) {
+ return (
+
+
+
+ Verifying access...
+
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+ Access Error
+
+
+ {error}
+
+
+ Please complete the setup process first.
+
+
+ );
+ }
+
+ // If onboarding is not complete, redirect to onboarding
+ if (!onboardingComplete) {
+ console.log('ProtectedRoute: Redirecting to onboarding');
+ return ;
+ }
+
+ // If onboarding is complete, render the protected component
+ console.log('ProtectedRoute: Rendering protected component');
+ return <>{children}>;
+};
+
+export default ProtectedRoute;