page transition

This commit is contained in:
alorig
2025-11-09 20:31:40 +05:00
parent 72ef276f8d
commit 6c3ca1c70d
3 changed files with 665 additions and 153 deletions

View File

@@ -1,98 +1,117 @@
import { Suspense, lazy } from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router"; import { BrowserRouter as Router, Routes, Route } from "react-router";
import SignIn from "./pages/AuthPages/SignIn";
import SignUp from "./pages/AuthPages/SignUp";
import NotFound from "./pages/OtherPage/NotFound";
import AppLayout from "./layout/AppLayout"; import AppLayout from "./layout/AppLayout";
import { ScrollToTop } from "./components/common/ScrollToTop"; import { ScrollToTop } from "./components/common/ScrollToTop";
import ProtectedRoute from "./components/auth/ProtectedRoute"; import ProtectedRoute from "./components/auth/ProtectedRoute";
import GlobalErrorDisplay from "./components/common/GlobalErrorDisplay"; import GlobalErrorDisplay from "./components/common/GlobalErrorDisplay";
import LoadingStateMonitor from "./components/common/LoadingStateMonitor"; import LoadingStateMonitor from "./components/common/LoadingStateMonitor";
import Home from "./pages/Dashboard/Home"; import PageTransition from "./components/common/PageTransition";
// Planner Module // Modern page loader component
import PlannerDashboard from "./pages/Planner/Dashboard"; const PageLoader = () => (
import Keywords from "./pages/Planner/Keywords"; <div className="flex items-center justify-center min-h-screen bg-white dark:bg-gray-900">
import Clusters from "./pages/Planner/Clusters"; <div className="flex flex-col items-center gap-3">
import Ideas from "./pages/Planner/Ideas"; <div className="relative w-12 h-12">
<div className="absolute inset-0 border-4 border-gray-200 dark:border-gray-700 rounded-full"></div>
<div className="absolute inset-0 border-4 border-transparent border-t-brand-500 rounded-full animate-spin"></div>
</div>
<div className="w-2 h-2 bg-brand-500 rounded-full animate-pulse"></div>
</div>
</div>
);
// Writer Module // Auth pages - loaded immediately (needed for login)
import WriterDashboard from "./pages/Writer/Dashboard"; import SignIn from "./pages/AuthPages/SignIn";
import Tasks from "./pages/Writer/Tasks"; import SignUp from "./pages/AuthPages/SignUp";
import Content from "./pages/Writer/Content"; import NotFound from "./pages/OtherPage/NotFound";
import Drafts from "./pages/Writer/Drafts";
import Images from "./pages/Writer/Images";
import Published from "./pages/Writer/Published";
// Thinker Module // Lazy load all other pages - only loads when navigated to
import ThinkerDashboard from "./pages/Thinker/Dashboard"; const Home = lazy(() => import("./pages/Dashboard/Home"));
import Prompts from "./pages/Thinker/Prompts";
import AuthorProfiles from "./pages/Thinker/AuthorProfiles";
import ThinkerProfile from "./pages/Thinker/Profile";
import Strategies from "./pages/Thinker/Strategies";
import ImageTesting from "./pages/Thinker/ImageTesting";
// Billing Module // Planner Module - Lazy loaded
import Credits from "./pages/Billing/Credits"; const PlannerDashboard = lazy(() => import("./pages/Planner/Dashboard"));
import Transactions from "./pages/Billing/Transactions"; const Keywords = lazy(() => import("./pages/Planner/Keywords"));
import Usage from "./pages/Billing/Usage"; const Clusters = lazy(() => import("./pages/Planner/Clusters"));
const Ideas = lazy(() => import("./pages/Planner/Ideas"));
const KeywordOpportunities = lazy(() => import("./pages/Planner/KeywordOpportunities"));
// Reference Data // Writer Module - Lazy loaded
import SeedKeywords from "./pages/Reference/SeedKeywords"; const WriterDashboard = lazy(() => import("./pages/Writer/Dashboard"));
import KeywordOpportunities from "./pages/Planner/KeywordOpportunities"; const Tasks = lazy(() => import("./pages/Writer/Tasks"));
import ReferenceIndustries from "./pages/Reference/Industries"; const Content = lazy(() => import("./pages/Writer/Content"));
const Drafts = lazy(() => import("./pages/Writer/Drafts"));
const Images = lazy(() => import("./pages/Writer/Images"));
const Published = lazy(() => import("./pages/Writer/Published"));
// Other Pages // Thinker Module - Lazy loaded
import Analytics from "./pages/Analytics"; const ThinkerDashboard = lazy(() => import("./pages/Thinker/Dashboard"));
import Schedules from "./pages/Schedules"; const Prompts = lazy(() => import("./pages/Thinker/Prompts"));
const AuthorProfiles = lazy(() => import("./pages/Thinker/AuthorProfiles"));
const ThinkerProfile = lazy(() => import("./pages/Thinker/Profile"));
const Strategies = lazy(() => import("./pages/Thinker/Strategies"));
const ImageTesting = lazy(() => import("./pages/Thinker/ImageTesting"));
// Settings // Billing Module - Lazy loaded
import GeneralSettings from "./pages/Settings/General"; const Credits = lazy(() => import("./pages/Billing/Credits"));
import Users from "./pages/Settings/Users"; const Transactions = lazy(() => import("./pages/Billing/Transactions"));
import Subscriptions from "./pages/Settings/Subscriptions"; const Usage = lazy(() => import("./pages/Billing/Usage"));
import SystemSettings from "./pages/Settings/System";
import AccountSettings from "./pages/Settings/Account";
import ModuleSettings from "./pages/Settings/Modules";
import AISettings from "./pages/Settings/AI";
import Plans from "./pages/Settings/Plans";
import Industries from "./pages/Settings/Industries";
import Status from "./pages/Settings/Status";
import Integration from "./pages/Settings/Integration";
import Sites from "./pages/Settings/Sites";
import ImportExport from "./pages/Settings/ImportExport";
// Help // Reference Data - Lazy loaded
import Help from "./pages/Help/Help"; const SeedKeywords = lazy(() => import("./pages/Reference/SeedKeywords"));
import Docs from "./pages/Help/Docs"; const ReferenceIndustries = lazy(() => import("./pages/Reference/Industries"));
import SystemTesting from "./pages/Help/SystemTesting";
import FunctionTesting from "./pages/Help/FunctionTesting";
// Components // Other Pages - Lazy loaded
import Components from "./pages/Components"; const Analytics = lazy(() => import("./pages/Analytics"));
const Schedules = lazy(() => import("./pages/Schedules"));
// UI Elements // Settings - Lazy loaded
import Alerts from "./pages/Settings/UiElements/Alerts"; const GeneralSettings = lazy(() => import("./pages/Settings/General"));
import Avatars from "./pages/Settings/UiElements/Avatars"; const Users = lazy(() => import("./pages/Settings/Users"));
import Badges from "./pages/Settings/UiElements/Badges"; const Subscriptions = lazy(() => import("./pages/Settings/Subscriptions"));
import Breadcrumb from "./pages/Settings/UiElements/Breadcrumb"; const SystemSettings = lazy(() => import("./pages/Settings/System"));
import Buttons from "./pages/Settings/UiElements/Buttons"; const AccountSettings = lazy(() => import("./pages/Settings/Account"));
import ButtonsGroup from "./pages/Settings/UiElements/ButtonsGroup"; const ModuleSettings = lazy(() => import("./pages/Settings/Modules"));
import Cards from "./pages/Settings/UiElements/Cards"; const AISettings = lazy(() => import("./pages/Settings/AI"));
import Carousel from "./pages/Settings/UiElements/Carousel"; const Plans = lazy(() => import("./pages/Settings/Plans"));
import Dropdowns from "./pages/Settings/UiElements/Dropdowns"; const Industries = lazy(() => import("./pages/Settings/Industries"));
import ImagesUI from "./pages/Settings/UiElements/Images"; const Status = lazy(() => import("./pages/Settings/Status"));
import Links from "./pages/Settings/UiElements/Links"; const Integration = lazy(() => import("./pages/Settings/Integration"));
import List from "./pages/Settings/UiElements/List"; const Sites = lazy(() => import("./pages/Settings/Sites"));
import Modals from "./pages/Settings/UiElements/Modals"; const ImportExport = lazy(() => import("./pages/Settings/ImportExport"));
import Notifications from "./pages/Settings/UiElements/Notifications";
import Pagination from "./pages/Settings/UiElements/Pagination"; // Help - Lazy loaded
import Popovers from "./pages/Settings/UiElements/Popovers"; const Help = lazy(() => import("./pages/Help/Help"));
import PricingTable from "./pages/Settings/UiElements/PricingTable"; const Docs = lazy(() => import("./pages/Help/Docs"));
import Progressbar from "./pages/Settings/UiElements/Progressbar"; const SystemTesting = lazy(() => import("./pages/Help/SystemTesting"));
import Ribbons from "./pages/Settings/UiElements/Ribbons"; const FunctionTesting = lazy(() => import("./pages/Help/FunctionTesting"));
import Spinners from "./pages/Settings/UiElements/Spinners";
import Tabs from "./pages/Settings/UiElements/Tabs"; // Components - Lazy loaded
import Tooltips from "./pages/Settings/UiElements/Tooltips"; const Components = lazy(() => import("./pages/Components"));
import Videos from "./pages/Settings/UiElements/Videos";
// UI Elements - Lazy loaded (rarely used)
const Alerts = lazy(() => import("./pages/Settings/UiElements/Alerts"));
const Avatars = lazy(() => import("./pages/Settings/UiElements/Avatars"));
const Badges = lazy(() => import("./pages/Settings/UiElements/Badges"));
const Breadcrumb = lazy(() => import("./pages/Settings/UiElements/Breadcrumb"));
const Buttons = lazy(() => import("./pages/Settings/UiElements/Buttons"));
const ButtonsGroup = lazy(() => import("./pages/Settings/UiElements/ButtonsGroup"));
const Cards = lazy(() => import("./pages/Settings/UiElements/Cards"));
const Carousel = lazy(() => import("./pages/Settings/UiElements/Carousel"));
const Dropdowns = lazy(() => import("./pages/Settings/UiElements/Dropdowns"));
const ImagesUI = lazy(() => import("./pages/Settings/UiElements/Images"));
const Links = lazy(() => import("./pages/Settings/UiElements/Links"));
const List = lazy(() => import("./pages/Settings/UiElements/List"));
const Modals = lazy(() => import("./pages/Settings/UiElements/Modals"));
const Notifications = lazy(() => import("./pages/Settings/UiElements/Notifications"));
const Pagination = lazy(() => import("./pages/Settings/UiElements/Pagination"));
const Popovers = lazy(() => import("./pages/Settings/UiElements/Popovers"));
const PricingTable = lazy(() => import("./pages/Settings/UiElements/PricingTable"));
const Progressbar = lazy(() => import("./pages/Settings/UiElements/Progressbar"));
const Ribbons = lazy(() => import("./pages/Settings/UiElements/Ribbons"));
const Spinners = lazy(() => import("./pages/Settings/UiElements/Spinners"));
const Tabs = lazy(() => import("./pages/Settings/UiElements/Tabs"));
const Tooltips = lazy(() => import("./pages/Settings/UiElements/Tooltips"));
const Videos = lazy(() => import("./pages/Settings/UiElements/Videos"));
export default function App() { export default function App() {
return ( return (
@@ -115,95 +134,497 @@ export default function App() {
} }
> >
{/* Dashboard */} {/* Dashboard */}
<Route index path="/" element={<Home />} /> <Route index path="/" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Home />
</Suspense>
</PageTransition>
} />
{/* Planner Module */} {/* Planner Module */}
<Route path="/planner" element={<PlannerDashboard />} /> <Route path="/planner" element={
<Route path="/planner/keywords" element={<Keywords />} /> <PageTransition>
<Route path="/planner/clusters" element={<Clusters />} /> <Suspense fallback={<PageLoader />}>
<Route path="/planner/ideas" element={<Ideas />} /> <PlannerDashboard />
</Suspense>
</PageTransition>
} />
<Route path="/planner/keywords" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Keywords />
</Suspense>
</PageTransition>
} />
<Route path="/planner/clusters" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Clusters />
</Suspense>
</PageTransition>
} />
<Route path="/planner/ideas" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Ideas />
</Suspense>
</PageTransition>
} />
{/* Writer Module */} {/* Writer Module */}
<Route path="/writer" element={<WriterDashboard />} /> <Route path="/writer" element={
<Route path="/writer/tasks" element={<Tasks />} /> <PageTransition>
<Route path="/writer/content" element={<Content />} /> <Suspense fallback={<PageLoader />}>
<Route path="/writer/drafts" element={<Drafts />} /> <WriterDashboard />
<Route path="/writer/images" element={<Images />} /> </Suspense>
<Route path="/writer/published" element={<Published />} /> </PageTransition>
} />
<Route path="/writer/tasks" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Tasks />
</Suspense>
</PageTransition>
} />
<Route path="/writer/content" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Content />
</Suspense>
</PageTransition>
} />
<Route path="/writer/drafts" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Drafts />
</Suspense>
</PageTransition>
} />
<Route path="/writer/images" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Images />
</Suspense>
</PageTransition>
} />
<Route path="/writer/published" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Published />
</Suspense>
</PageTransition>
} />
{/* Thinker Module */} {/* Thinker Module */}
<Route path="/thinker" element={<ThinkerDashboard />} /> <Route path="/thinker" element={
<Route path="/thinker/prompts" element={<Prompts />} /> <PageTransition>
<Route path="/thinker/author-profiles" element={<AuthorProfiles />} /> <Suspense fallback={<PageLoader />}>
<Route path="/thinker/profile" element={<ThinkerProfile />} /> <ThinkerDashboard />
<Route path="/thinker/strategies" element={<Strategies />} /> </Suspense>
<Route path="/thinker/image-testing" element={<ImageTesting />} /> </PageTransition>
} />
<Route path="/thinker/prompts" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Prompts />
</Suspense>
</PageTransition>
} />
<Route path="/thinker/author-profiles" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<AuthorProfiles />
</Suspense>
</PageTransition>
} />
<Route path="/thinker/profile" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<ThinkerProfile />
</Suspense>
</PageTransition>
} />
<Route path="/thinker/strategies" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Strategies />
</Suspense>
</PageTransition>
} />
<Route path="/thinker/image-testing" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<ImageTesting />
</Suspense>
</PageTransition>
} />
{/* Billing Module */} {/* Billing Module */}
<Route path="/billing/credits" element={<Credits />} /> <Route path="/billing/credits" element={
<Route path="/billing/transactions" element={<Transactions />} /> <PageTransition>
<Route path="/billing/usage" element={<Usage />} /> <Suspense fallback={<PageLoader />}>
<Credits />
</Suspense>
</PageTransition>
} />
<Route path="/billing/transactions" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Transactions />
</Suspense>
</PageTransition>
} />
<Route path="/billing/usage" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Usage />
</Suspense>
</PageTransition>
} />
{/* Reference Data */} {/* Reference Data */}
<Route path="/reference/seed-keywords" element={<SeedKeywords />} /> <Route path="/reference/seed-keywords" element={
<Route path="/planner/keyword-opportunities" element={<KeywordOpportunities />} /> <PageTransition>
<Route path="/reference/industries" element={<ReferenceIndustries />} /> <Suspense fallback={<PageLoader />}>
<SeedKeywords />
</Suspense>
</PageTransition>
} />
<Route path="/planner/keyword-opportunities" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<KeywordOpportunities />
</Suspense>
</PageTransition>
} />
<Route path="/reference/industries" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<ReferenceIndustries />
</Suspense>
</PageTransition>
} />
{/* Other Pages */} {/* Other Pages */}
<Route path="/analytics" element={<Analytics />} /> <Route path="/analytics" element={
<Route path="/schedules" element={<Schedules />} /> <PageTransition>
<Suspense fallback={<PageLoader />}>
<Analytics />
</Suspense>
</PageTransition>
} />
<Route path="/schedules" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Schedules />
</Suspense>
</PageTransition>
} />
{/* Settings */} {/* Settings */}
<Route path="/settings" element={<GeneralSettings />} /> <Route path="/settings" element={
<Route path="/settings/users" element={<Users />} /> <PageTransition>
<Route path="/settings/subscriptions" element={<Subscriptions />} /> <Suspense fallback={<PageLoader />}>
<Route path="/settings/system" element={<SystemSettings />} /> <GeneralSettings />
<Route path="/settings/account" element={<AccountSettings />} /> </Suspense>
<Route path="/settings/modules" element={<ModuleSettings />} /> </PageTransition>
<Route path="/settings/ai" element={<AISettings />} /> } />
<Route path="/settings/plans" element={<Plans />} /> <Route path="/settings/users" element={
<Route path="/settings/industries" element={<Industries />} /> <PageTransition>
<Route path="/settings/status" element={<Status />} /> <Suspense fallback={<PageLoader />}>
<Route path="/settings/integration" element={<Integration />} /> <Users />
<Route path="/settings/sites" element={<Sites />} /> </Suspense>
<Route path="/settings/import-export" element={<ImportExport />} /> </PageTransition>
} />
<Route path="/settings/subscriptions" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Subscriptions />
</Suspense>
</PageTransition>
} />
<Route path="/settings/system" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<SystemSettings />
</Suspense>
</PageTransition>
} />
<Route path="/settings/account" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<AccountSettings />
</Suspense>
</PageTransition>
} />
<Route path="/settings/modules" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<ModuleSettings />
</Suspense>
</PageTransition>
} />
<Route path="/settings/ai" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<AISettings />
</Suspense>
</PageTransition>
} />
<Route path="/settings/plans" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Plans />
</Suspense>
</PageTransition>
} />
<Route path="/settings/industries" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Industries />
</Suspense>
</PageTransition>
} />
<Route path="/settings/status" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Status />
</Suspense>
</PageTransition>
} />
<Route path="/settings/integration" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Integration />
</Suspense>
</PageTransition>
} />
<Route path="/settings/sites" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Sites />
</Suspense>
</PageTransition>
} />
<Route path="/settings/import-export" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<ImportExport />
</Suspense>
</PageTransition>
} />
{/* Help */} {/* Help */}
<Route path="/help" element={<Help />} /> <Route path="/help" element={
<Route path="/help/docs" element={<Docs />} /> <PageTransition>
<Route path="/help/system-testing" element={<SystemTesting />} /> <Suspense fallback={<PageLoader />}>
<Route path="/help/function-testing" element={<FunctionTesting />} /> <Help />
</Suspense>
</PageTransition>
} />
<Route path="/help/docs" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Docs />
</Suspense>
</PageTransition>
} />
<Route path="/help/system-testing" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<SystemTesting />
</Suspense>
</PageTransition>
} />
<Route path="/help/function-testing" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<FunctionTesting />
</Suspense>
</PageTransition>
} />
{/* UI Elements */} {/* UI Elements */}
<Route path="/ui-elements/alerts" element={<Alerts />} /> <Route path="/ui-elements/alerts" element={
<Route path="/ui-elements/avatars" element={<Avatars />} /> <PageTransition>
<Route path="/ui-elements/badges" element={<Badges />} /> <Suspense fallback={<PageLoader />}>
<Route path="/ui-elements/breadcrumb" element={<Breadcrumb />} /> <Alerts />
<Route path="/ui-elements/buttons" element={<Buttons />} /> </Suspense>
<Route path="/ui-elements/buttons-group" element={<ButtonsGroup />} /> </PageTransition>
<Route path="/ui-elements/cards" element={<Cards />} /> } />
<Route path="/ui-elements/carousel" element={<Carousel />} /> <Route path="/ui-elements/avatars" element={
<Route path="/ui-elements/dropdowns" element={<Dropdowns />} /> <PageTransition>
<Route path="/ui-elements/images" element={<ImagesUI />} /> <Suspense fallback={<PageLoader />}>
<Route path="/ui-elements/links" element={<Links />} /> <Avatars />
<Route path="/ui-elements/list" element={<List />} /> </Suspense>
<Route path="/ui-elements/modals" element={<Modals />} /> </PageTransition>
<Route path="/ui-elements/notifications" element={<Notifications />} /> } />
<Route path="/ui-elements/pagination" element={<Pagination />} /> <Route path="/ui-elements/badges" element={
<Route path="/ui-elements/popovers" element={<Popovers />} /> <PageTransition>
<Route path="/ui-elements/pricing-table" element={<PricingTable />} /> <Suspense fallback={<PageLoader />}>
<Route path="/ui-elements/progressbar" element={<Progressbar />} /> <Badges />
<Route path="/ui-elements/ribbons" element={<Ribbons />} /> </Suspense>
<Route path="/ui-elements/spinners" element={<Spinners />} /> </PageTransition>
<Route path="/ui-elements/tabs" element={<Tabs />} /> } />
<Route path="/ui-elements/tooltips" element={<Tooltips />} /> <Route path="/ui-elements/breadcrumb" element={
<Route path="/ui-elements/videos" element={<Videos />} /> <PageTransition>
<Suspense fallback={<PageLoader />}>
<Breadcrumb />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/buttons" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Buttons />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/buttons-group" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<ButtonsGroup />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/cards" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Cards />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/carousel" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Carousel />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/dropdowns" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Dropdowns />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/images" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<ImagesUI />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/links" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Links />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/list" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<List />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/modals" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Modals />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/notifications" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Notifications />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/pagination" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Pagination />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/popovers" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Popovers />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/pricing-table" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<PricingTable />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/progressbar" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Progressbar />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/ribbons" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Ribbons />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/spinners" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Spinners />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/tabs" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Tabs />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/tooltips" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Tooltips />
</Suspense>
</PageTransition>
} />
<Route path="/ui-elements/videos" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Videos />
</Suspense>
</PageTransition>
} />
{/* Components (Showcase Page) */} {/* Components (Showcase Page) */}
<Route path="/components" element={<Components />} /> <Route path="/components" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Components />
</Suspense>
</PageTransition>
} />
{/* Redirect old notification route */} {/* Redirect old notification route */}
<Route path="/notifications" element={<Notifications />} /> <Route path="/notifications" element={
<PageTransition>
<Suspense fallback={<PageLoader />}>
<Notifications />
</Suspense>
</PageTransition>
} />
</Route> </Route>
{/* Fallback Route */} {/* Fallback Route */}

View File

@@ -0,0 +1,76 @@
import { ReactNode, useEffect, useState } from 'react';
import { useLocation } from 'react-router';
interface PageTransitionProps {
children: ReactNode;
}
/**
* Smooth page transition wrapper with modern loading indicator
* Provides seamless transitions between pages without feeling like a page load
* Uses subtle fade effects and minimal loading indicator
*/
export default function PageTransition({ children }: PageTransitionProps) {
const location = useLocation();
const [isTransitioning, setIsTransitioning] = useState(false);
const [displayChildren, setDisplayChildren] = useState(children);
const [currentPath, setCurrentPath] = useState(location.pathname);
useEffect(() => {
// Only show transition if pathname actually changed
if (location.pathname === currentPath) {
setDisplayChildren(children);
return;
}
// Start transition with minimal delay
setIsTransitioning(true);
setCurrentPath(location.pathname);
// Quick fade-out, then swap content
const fadeOutTimer = setTimeout(() => {
setDisplayChildren(children);
}, 100);
// Complete transition quickly for smooth feel
const fadeInTimer = setTimeout(() => {
setIsTransitioning(false);
}, 200);
return () => {
clearTimeout(fadeOutTimer);
clearTimeout(fadeInTimer);
};
}, [location.pathname, children, currentPath]);
return (
<div className="relative min-h-screen">
{/* Subtle fade overlay - very light */}
<div
className={`absolute inset-0 bg-white/50 dark:bg-gray-900/50 backdrop-blur-sm transition-opacity duration-200 z-40 pointer-events-none ${
isTransitioning ? 'opacity-100' : 'opacity-0'
}`}
/>
{/* Minimal loading indicator - only shows briefly */}
{isTransitioning && (
<div className="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-50 pointer-events-none">
<div className="relative w-10 h-10">
<div className="absolute inset-0 border-2 border-gray-200/50 dark:border-gray-700/50 rounded-full"></div>
<div className="absolute inset-0 border-2 border-transparent border-t-brand-500 rounded-full animate-spin"></div>
</div>
</div>
)}
{/* Page content with smooth fade */}
<div
className={`transition-opacity duration-200 ease-in-out ${
isTransitioning ? 'opacity-0' : 'opacity-100'
}`}
>
{displayChildren}
</div>
</div>
);
}

View File

@@ -99,27 +99,42 @@ const LayoutContent: React.FC = () => {
} }
}, [activeSite?.id, activeSite?.is_active]); // Depend on both ID and is_active }, [activeSite?.id, activeSite?.is_active]); // Depend on both ID and is_active
// Refresh user data on mount and periodically to get latest account/plan changes // Refresh user data on mount and when app version changes (after code updates)
// This ensures changes are reflected immediately without requiring re-login // This ensures changes are reflected immediately without requiring re-login
useEffect(() => { useEffect(() => {
if (!isAuthenticated) return; if (!isAuthenticated) return;
const refreshUserData = async () => { const APP_VERSION = import.meta.env.VITE_APP_VERSION || '2.0.2';
const VERSION_STORAGE_KEY = 'igny8-app-version';
const refreshUserData = async (force = false) => {
const now = Date.now(); const now = Date.now();
// Throttle: only refresh if last refresh was more than 30 seconds ago // Throttle: only refresh if last refresh was more than 30 seconds ago (unless forced)
if (now - lastUserRefresh.current < 30000) return; if (!force && now - lastUserRefresh.current < 30000) return;
try { try {
lastUserRefresh.current = now; lastUserRefresh.current = now;
await refreshUser(); await refreshUser();
// Store current version after successful refresh
if (force) {
localStorage.setItem(VERSION_STORAGE_KEY, APP_VERSION);
}
} catch (error) { } catch (error) {
// Silently fail - user might still be authenticated // Silently fail - user might still be authenticated
console.debug('User data refresh failed (non-critical):', error); console.debug('User data refresh failed (non-critical):', error);
} }
}; };
// Refresh on mount // Check if app version changed (indicates code update)
refreshUserData(); const storedVersion = localStorage.getItem(VERSION_STORAGE_KEY);
if (storedVersion !== APP_VERSION) {
// Force refresh on version change
refreshUserData(true);
} else {
// Normal refresh on mount
refreshUserData();
}
// Refresh when window becomes visible (user switches back to tab) // Refresh when window becomes visible (user switches back to tab)
const handleVisibilityChange = () => { const handleVisibilityChange = () => {
@@ -134,7 +149,7 @@ const LayoutContent: React.FC = () => {
}; };
// Periodic refresh every 2 minutes // Periodic refresh every 2 minutes
const intervalId = setInterval(refreshUserData, 120000); const intervalId = setInterval(() => refreshUserData(), 120000);
document.addEventListener('visibilitychange', handleVisibilityChange); document.addEventListener('visibilitychange', handleVisibilityChange);
window.addEventListener('focus', handleFocus); window.addEventListener('focus', handleFocus);