diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..bdc732e --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2024-05-23 - [Lazy Loading Routes] +**Learning:** Wrapped `AnimatedRoutes` in `Suspense` to enable `React.lazy` for route-based code splitting. This significantly reduces initial bundle size but requires a loading fallback. +**Action:** Always check if code splitting is actually implemented vs just documented. diff --git a/src/App.jsx b/src/App.jsx index 4822715..c278c15 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,33 +1,42 @@ -import React from 'react'; +import React, { Suspense, lazy } from 'react'; import { BrowserRouter as Router, Routes, Route, useLocation } from 'react-router-dom'; import { AnimatePresence } from 'framer-motion'; -import PublicLayout from './layouts/PublicLayout'; -import LandingPage from './pages/LandingPage'; -import AboutPage from './pages/AboutPage'; -import FeaturesPage from './pages/FeaturesPage'; -import FaqPage from './pages/FaqPage'; -import AuthPage from './pages/AuthPage'; -import PricingPage from './pages/PricingPage'; -import TermsPage from './pages/TermsPage'; -import PrivacyPage from './pages/PrivacyPage'; -import CookiesPage from './pages/CookiesPage'; +import LoadingSpinner from './components/LoadingSpinner'; import CookieConsent from './components/CookieConsent'; -import DashboardLayout from './layouts/DashboardLayout'; -import DashboardHome from './pages/dashboard/DashboardHome'; -import DocumentProcessing from './pages/dashboard/DocumentProcessing'; -import DocumentResult from './pages/dashboard/DocumentResult'; -import History from './pages/dashboard/History'; -import MyDocuments from './pages/dashboard/MyDocuments'; -import Analytics from './pages/dashboard/Analytics'; -import Settings from './pages/dashboard/Settings'; -import Billing from './pages/dashboard/Billing'; -import Support from './pages/dashboard/Support'; -import Notifications from './pages/dashboard/Notifications'; -import AdminLayout from './layouts/AdminLayout'; -import AdminHome from './pages/admin/AdminHome'; import AuthProvider from './context/AuthProvider'; import ProtectedRoute from './components/auth/ProtectedRoute'; +// Lazy load layouts +const PublicLayout = lazy(() => import('./layouts/PublicLayout')); +const DashboardLayout = lazy(() => import('./layouts/DashboardLayout')); +const AdminLayout = lazy(() => import('./layouts/AdminLayout')); + +// Lazy load pages +const LandingPage = lazy(() => import('./pages/LandingPage')); +const AboutPage = lazy(() => import('./pages/AboutPage')); +const FeaturesPage = lazy(() => import('./pages/FeaturesPage')); +const FaqPage = lazy(() => import('./pages/FaqPage')); +const AuthPage = lazy(() => import('./pages/AuthPage')); +const PricingPage = lazy(() => import('./pages/PricingPage')); +const TermsPage = lazy(() => import('./pages/TermsPage')); +const PrivacyPage = lazy(() => import('./pages/PrivacyPage')); +const CookiesPage = lazy(() => import('./pages/CookiesPage')); + +// Lazy load dashboard pages +const DashboardHome = lazy(() => import('./pages/dashboard/DashboardHome')); +const DocumentProcessing = lazy(() => import('./pages/dashboard/DocumentProcessing')); +const DocumentResult = lazy(() => import('./pages/dashboard/DocumentResult')); +const History = lazy(() => import('./pages/dashboard/History')); +const MyDocuments = lazy(() => import('./pages/dashboard/MyDocuments')); +const Analytics = lazy(() => import('./pages/dashboard/Analytics')); +const Settings = lazy(() => import('./pages/dashboard/Settings')); +const Billing = lazy(() => import('./pages/dashboard/Billing')); +const Support = lazy(() => import('./pages/dashboard/Support')); +const Notifications = lazy(() => import('./pages/dashboard/Notifications')); + +// Lazy load admin pages +const AdminHome = lazy(() => import('./pages/admin/AdminHome')); + function AnimatedRoutes() { const location = useLocation(); @@ -76,8 +85,10 @@ function App() { return ( - - + }> + + + ); diff --git a/src/components/LoadingSpinner.jsx b/src/components/LoadingSpinner.jsx new file mode 100644 index 0000000..a63e0a6 --- /dev/null +++ b/src/components/LoadingSpinner.jsx @@ -0,0 +1,14 @@ +import React from 'react'; +import styles from './LoadingSpinner.module.css'; + +const LoadingSpinner = () => { + return ( +
+
+ Loading... +
+
+ ); +}; + +export default LoadingSpinner; diff --git a/src/components/LoadingSpinner.module.css b/src/components/LoadingSpinner.module.css new file mode 100644 index 0000000..4b20f57 --- /dev/null +++ b/src/components/LoadingSpinner.module.css @@ -0,0 +1,34 @@ +.container { + display: flex; + justify-content: center; + align-items: center; + min-height: 200px; + width: 100%; +} + +.spinner { + width: 40px; + height: 40px; + border: 3px solid rgba(100, 108, 255, 0.1); + border-radius: 50%; + border-top-color: #646cff; + animation: cz-spin 0.8s ease-in-out infinite; +} + +.srOnly { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +@keyframes cz-spin { + to { + transform: rotate(360deg); + } +} diff --git a/verification/1_redirect_check.png b/verification/1_redirect_check.png deleted file mode 100644 index 502ff77..0000000 Binary files a/verification/1_redirect_check.png and /dev/null differ diff --git a/verification/2_dashboard_access.png b/verification/2_dashboard_access.png deleted file mode 100644 index b87d86b..0000000 Binary files a/verification/2_dashboard_access.png and /dev/null differ diff --git a/verification/verify_auth.py b/verification/verify_auth.py deleted file mode 100644 index 45477b7..0000000 --- a/verification/verify_auth.py +++ /dev/null @@ -1,37 +0,0 @@ -from playwright.sync_api import sync_playwright - -def verify_dashboard_protection(): - with sync_playwright() as p: - browser = p.chromium.launch(headless=True) - page = browser.new_page() - - # 1. Try to access dashboard directly (should redirect to login) - print("Navigating to dashboard...") - page.goto("http://localhost:5173/dashboard") - page.wait_for_load_state("networkidle") - - # Check if redirected to login - if "/login" in page.url: - print("Successfully redirected to login page") - else: - print(f"Failed to redirect. Current URL: {page.url}") - - page.screenshot(path="verification/1_redirect_check.png") - - # 2. Login - print("Attempting login...") - page.fill("input[type='email']", "john.smith@email.com") - page.fill("input[type='password']", "password123") - page.click("button:has-text('Log In')") - - # Wait for redirection to dashboard - page.wait_for_url("**/dashboard") - page.wait_for_load_state("networkidle") - - print(f"Logged in. Current URL: {page.url}") - page.screenshot(path="verification/2_dashboard_access.png") - - browser.close() - -if __name__ == "__main__": - verify_dashboard_protection()