import React, { useEffect, useState, lazy, Suspense } from 'react';
import { Routes, Route, useLocation } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { getCurrentUser, checkCachedAuth, autoLogin } from './store/reducers/authSlice';
import cookieService from './services/cookieService';
import Login from './pages/Login.jsx';
import Register from './pages/Register.jsx';
import Dashboard from './pages/Dashboard.jsx';
import Sources from './pages/Sources.jsx';
import Accounts from './pages/Accounts.jsx';
import Posts from './pages/Posts.jsx';
import Schedule from './pages/Schedule.jsx';
import Home from './pages/Home.jsx';
import Header from './components/Header/Header.jsx';
import Sidebar from './components/Sidebar/Sidebar.jsx';
import LinkedInCallbackHandler from './components/LinkedInAccount/LinkedInCallbackHandler.jsx';
import './css/main.css';
// Lazy load components for better mobile performance
const LazyFeatureCard = lazy(() => import('./components/FeatureCard'));
const LazyTestimonialCard = lazy(() => import('./components/TestimonialCard'));
// Error Boundary Component
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
console.error('Error caught by boundary:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
Something went wrong.
Please refresh the page or try again later.
);
}
return this.props.children;
}
}
function App() {
const dispatch = useDispatch();
const { isAuthenticated, loading } = useSelector(state => state.auth);
const location = useLocation();
const [isCheckingAuth, setIsCheckingAuth] = useState(true);
// Auth pages should never render the Sidebar/Header
const isAuthRoute = location.pathname === '/login' || location.pathname === '/register';
const isCallbackRoute = location.pathname === '/linkedin/callback';
const showSidebar = isAuthenticated && !isAuthRoute && !isCallbackRoute && location.pathname !== '/';
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
const [isMobile, setIsMobile] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
// Detect mobile devices and set responsive behavior
useEffect(() => {
const checkMobile = () => {
const mobile = window.innerWidth < 1024; // Match sidebar breakpoint
setIsMobile(mobile);
// Auto-collapse sidebar on mobile
if (mobile && !isSidebarCollapsed) {
setIsSidebarCollapsed(true);
}
};
checkMobile();
window.addEventListener('resize', checkMobile);
return () => window.removeEventListener('resize', checkMobile);
}, [isSidebarCollapsed]);
// Optimize performance for mobile devices
useEffect(() => {
if (isMobile) {
// Reduce animation complexity on mobile
document.body.classList.add('mobile-optimized-animation');
// Enable hardware acceleration for mobile elements
const mobileElements = document.querySelectorAll('.mobile-accelerate');
mobileElements.forEach(el => {
el.classList.add('mobile-accelerated');
});
// Optimize touch interactions
const touchElements = document.querySelectorAll('.touch-optimized');
touchElements.forEach(el => {
el.classList.add('touch-optimized');
});
// Prevent double-tap zoom on mobile
const preventZoom = (e) => {
if (e.detail > 1) {
e.preventDefault();
}
};
document.addEventListener('dblclick', preventZoom, { passive: false });
return () => {
document.removeEventListener('dblclick', preventZoom);
document.body.classList.remove('mobile-optimized-animation');
};
} else {
// Clean up mobile optimizations
document.body.classList.remove('mobile-optimized-animation');
}
}, [isMobile]);
const toggleSidebar = () => {
setIsSidebarCollapsed(!isSidebarCollapsed);
};
const toggleMobileMenu = () => {
setIsMobileMenuOpen(!isMobileMenuOpen);
};
// Close mobile menu when clicking outside
useEffect(() => {
const handleClickOutside = (event) => {
// Close mobile menu when clicking outside
if (isMobileMenuOpen &&
!event.target.closest('#mobile-menu') &&
!event.target.closest('.mobile-menu-button')) {
setIsMobileMenuOpen(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [isMobileMenuOpen]);
// Handle keyboard navigation for mobile menu
useEffect(() => {
const handleGlobalKeyDown = (e) => {
// Close mobile menu with Escape
if (e.key === 'Escape' && isMobileMenuOpen) {
setIsMobileMenuOpen(false);
}
};
document.addEventListener('keydown', handleGlobalKeyDown);
return () => document.removeEventListener('keydown', handleGlobalKeyDown);
}, [isMobileMenuOpen]);
// Simplified authentication check - only run once on mount
useEffect(() => {
const initializeAuth = async () => {
try {
setIsCheckingAuth(true);
// Check for cached authentication first
const cachedResult = await dispatch(checkCachedAuth());
// If cached auth failed but we have a token, try auto login
const token = localStorage.getItem('token');
const cookieAuth = await cookieService.getAuthTokens();
if (!cachedResult.payload?.success && (token || cookieAuth?.accessToken)) {
try {
await dispatch(autoLogin());
} catch (error) {
console.log('Auto login failed, clearing tokens');
localStorage.removeItem('token');
await cookieService.clearAuthTokens();
}
}
} catch (error) {
console.error('Auth initialization failed:', error);
localStorage.removeItem('token');
await cookieService.clearAuthTokens();
} finally {
setIsCheckingAuth(false);
}
};
// Only run authentication check once on mount
if (isCheckingAuth) {
initializeAuth();
}
}, []); // Empty dependency array to run only once
// Show loading state only while checking auth on initial load
if (isCheckingAuth) {
return (
Checking authentication...
);
}
return (
) : (
<>
{/* App layout with header + sidebar for authenticated app pages */}
{/* Mobile sidebar overlay */}
{isMobile && !isSidebarCollapsed && (
setIsSidebarCollapsed(true)}
aria-label="Close sidebar"
role="button"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
setIsSidebarCollapsed(true);
}
}}
>
)}
Loading...
}>
} />
} />
} />
} />
} />
>
)}
);
}
export default App;