237 lines
7.1 KiB
TypeScript
237 lines
7.1 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
|
import { Box, CircularProgress, Typography } from '@mui/material';
|
|
import Wizard from './components/OnboardingWizard/Wizard';
|
|
import MainDashboard from './components/MainDashboard/MainDashboard';
|
|
import SEODashboard from './components/SEODashboard/SEODashboard';
|
|
import ContentPlanningDashboard from './components/ContentPlanningDashboard/ContentPlanningDashboard';
|
|
import { apiClient } from './api/client';
|
|
|
|
interface OnboardingStatus {
|
|
onboarding_required: boolean;
|
|
onboarding_complete: boolean;
|
|
current_step?: number;
|
|
total_steps?: number;
|
|
completion_percentage?: number;
|
|
}
|
|
|
|
const App: React.FC = () => {
|
|
const [loading, setLoading] = useState(true);
|
|
const [onboardingStatus, setOnboardingStatus] = useState<OnboardingStatus | null>(null);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
checkOnboardingStatus();
|
|
}, []);
|
|
|
|
const checkOnboardingStatus = async () => {
|
|
try {
|
|
setLoading(true);
|
|
// Use the correct endpoint that exists in our backend
|
|
const response = await apiClient.get('/api/onboarding/status');
|
|
const status: any = response.data;
|
|
|
|
// Transform the backend response to match frontend expectations
|
|
const transformedStatus: OnboardingStatus = {
|
|
onboarding_required: !status.is_completed,
|
|
onboarding_complete: status.is_completed || false,
|
|
current_step: status.current_step,
|
|
total_steps: 6, // We know there are 6 steps
|
|
completion_percentage: status.completion_percentage
|
|
};
|
|
|
|
setOnboardingStatus(transformedStatus);
|
|
} catch (err) {
|
|
console.error('Error checking onboarding status:', err);
|
|
// If the endpoint doesn't exist, assume onboarding is required
|
|
setOnboardingStatus({
|
|
onboarding_required: true,
|
|
onboarding_complete: false,
|
|
current_step: 1,
|
|
total_steps: 6,
|
|
completion_percentage: 0
|
|
});
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleOnboardingComplete = async () => {
|
|
// Refresh onboarding status after completion
|
|
await checkOnboardingStatus();
|
|
};
|
|
|
|
if (loading) {
|
|
return (
|
|
<Box
|
|
display="flex"
|
|
justifyContent="center"
|
|
alignItems="center"
|
|
minHeight="100vh"
|
|
flexDirection="column"
|
|
>
|
|
<CircularProgress size={60} />
|
|
<Typography variant="h6" sx={{ mt: 2 }}>
|
|
Loading Alwrity...
|
|
</Typography>
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<Box
|
|
display="flex"
|
|
justifyContent="center"
|
|
alignItems="center"
|
|
minHeight="100vh"
|
|
flexDirection="column"
|
|
>
|
|
<Typography variant="h6" color="error">
|
|
{error}
|
|
</Typography>
|
|
<Typography variant="body2" sx={{ mt: 1 }}>
|
|
Please refresh the page to try again.
|
|
</Typography>
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Router>
|
|
<Routes>
|
|
{/* Dashboard Route */}
|
|
<Route
|
|
path="/dashboard"
|
|
element={
|
|
<DashboardWrapper />
|
|
}
|
|
/>
|
|
|
|
{/* SEO Dashboard Route */}
|
|
<Route
|
|
path="/seo-dashboard"
|
|
element={
|
|
<SEODashboard />
|
|
}
|
|
/>
|
|
|
|
{/* Content Planning Dashboard Route */}
|
|
<Route
|
|
path="/content-planning"
|
|
element={
|
|
<ContentPlanningDashboard />
|
|
}
|
|
/>
|
|
|
|
{/* Root Route - Show onboarding or redirect to dashboard */}
|
|
<Route
|
|
path="/"
|
|
element={
|
|
onboardingStatus?.onboarding_required ? (
|
|
<Wizard onComplete={handleOnboardingComplete} />
|
|
) : (
|
|
<Navigate to="/dashboard" replace />
|
|
)
|
|
}
|
|
/>
|
|
|
|
{/* Catch all other routes */}
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Routes>
|
|
</Router>
|
|
);
|
|
};
|
|
|
|
// Separate component to handle dashboard logic
|
|
const DashboardWrapper: React.FC = () => {
|
|
const [dashboardLoading, setDashboardLoading] = useState(true);
|
|
const [onboardingComplete, setOnboardingComplete] = useState(false);
|
|
const [retryCount, setRetryCount] = useState(0);
|
|
|
|
useEffect(() => {
|
|
const checkDashboardAccess = async () => {
|
|
try {
|
|
console.log('DashboardWrapper: Checking dashboard access...');
|
|
// Check if onboarding is complete
|
|
const response = await apiClient.get('/api/onboarding/status');
|
|
const status = response.data;
|
|
|
|
console.log('DashboardWrapper: Backend status:', status);
|
|
console.log('DashboardWrapper: is_completed:', status.is_completed);
|
|
console.log('DashboardWrapper: current_step:', status.current_step);
|
|
|
|
if (status.is_completed) {
|
|
console.log('DashboardWrapper: Onboarding is complete, showing dashboard');
|
|
setOnboardingComplete(true);
|
|
} else {
|
|
console.log('DashboardWrapper: Onboarding not complete, retry count:', retryCount);
|
|
|
|
// If onboarding is not complete, try a few times with delay
|
|
if (retryCount < 3) {
|
|
console.log('DashboardWrapper: Retrying in 1 second...');
|
|
setTimeout(() => {
|
|
setRetryCount(prev => prev + 1);
|
|
}, 1000);
|
|
return;
|
|
} else {
|
|
console.log('DashboardWrapper: Max retries reached, redirecting to root');
|
|
// If onboarding is not complete after retries, redirect to root
|
|
window.location.href = '/';
|
|
return;
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('DashboardWrapper: Error checking dashboard access:', error);
|
|
|
|
// If there's an error, try a few times before redirecting
|
|
if (retryCount < 3) {
|
|
console.log('DashboardWrapper: Error occurred, retrying in 1 second...');
|
|
setTimeout(() => {
|
|
setRetryCount(prev => prev + 1);
|
|
}, 1000);
|
|
return;
|
|
} else {
|
|
console.log('DashboardWrapper: Max retries reached after error, redirecting to root');
|
|
// If there's an error after retries, redirect to root
|
|
window.location.href = '/';
|
|
return;
|
|
}
|
|
} finally {
|
|
setDashboardLoading(false);
|
|
}
|
|
};
|
|
|
|
checkDashboardAccess();
|
|
}, [retryCount]);
|
|
|
|
if (dashboardLoading) {
|
|
return (
|
|
<Box
|
|
display="flex"
|
|
justifyContent="center"
|
|
alignItems="center"
|
|
minHeight="100vh"
|
|
flexDirection="column"
|
|
>
|
|
<CircularProgress size={60} />
|
|
<Typography variant="h6" sx={{ mt: 2 }}>
|
|
Loading Dashboard...
|
|
</Typography>
|
|
{retryCount > 0 && (
|
|
<Typography variant="body2" color="text.secondary" sx={{ mt: 1 }}>
|
|
Checking onboarding status... (Attempt {retryCount + 1}/3)
|
|
</Typography>
|
|
)}
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
if (!onboardingComplete) {
|
|
return <Navigate to="/" replace />;
|
|
}
|
|
|
|
return <MainDashboard />;
|
|
};
|
|
|
|
export default App;
|