import '../styles/globals.css'; import type {AppProps} from 'next/app'; import {useRouter} from 'next/router'; import React, {useEffect} from 'react'; import {Toaster} from 'sonner'; import {SWRConfig} from 'swr'; import {DefaultSeo} from 'next-seo'; import {Loader} from '@plunk/ui'; import {ActiveProjectProvider} from '../lib/contexts/ActiveProjectProvider'; import {useProjects} from '../lib/hooks/useProject'; import {useUser} from '../lib/hooks/useUser'; import {network} from '../lib/network'; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; import advancedFormat from 'dayjs/plugin/advancedFormat'; // Configure dayjs plugins globally dayjs.extend(relativeTime); dayjs.extend(advancedFormat); // Routes that don't require authentication const PUBLIC_ROUTES = [ '/auth/login', '/auth/signup', '/auth/reset-password', '/auth/verify-email', '/unsubscribe', '/subscribe', '/manage', ]; // Routes that don't require a project const NO_PROJECT_ROUTES = ['/projects/create']; function App({Component, pageProps}: AppProps) { return ( <> ); } function AuthGuard({children}: {children: React.ReactNode}) { const {data: user, isLoading} = useUser(); const router = useRouter(); const isPublicRoute = PUBLIC_ROUTES.some( route => router.pathname === route || router.pathname.startsWith(`${route}/`), ); useEffect(() => { // If not loading, no user, and trying to access a protected route, redirect to login if (!isLoading && !user && !isPublicRoute) { void router.push('/auth/login'); } // If user is logged in and trying to access login/signup, redirect to home if (!isLoading && user && (router.pathname === '/auth/login' || router.pathname === '/auth/signup')) { void router.push('/'); } }, [user, isLoading, router, isPublicRoute]); // Show loading state while checking authentication (only for protected routes) if (isLoading && !isPublicRoute) { return ; } // Don't render protected content if redirecting if (!user && !isPublicRoute) { return null; } return <>{children}; } function ProjectGuard({children}: {children: React.ReactNode}) { const {data: projects, isLoading} = useProjects(); const router = useRouter(); const isNoProjectRoute = NO_PROJECT_ROUTES.includes(router.pathname); useEffect(() => { // If not loading, user has no projects, and not already on project creation page if (!isLoading && projects && projects.length === 0 && !isNoProjectRoute) { void router.push('/projects/create'); } }, [projects, isLoading, router, isNoProjectRoute]); // Show loading state while checking projects (only for routes that need a project) if (isLoading && !isNoProjectRoute) { return ; } // Don't render protected content if redirecting if (!isLoading && projects && projects.length === 0 && !isNoProjectRoute) { return null; } return <>{children}; } /** * Main app root component that houses all components * @param props Default nextjs props */ export default function WithProviders(props: AppProps) { return ( network.fetch('GET', url), shouldRetryOnError: false, }} > ); } function Root(props: AppProps) { const router = useRouter(); const isPublicRoute = PUBLIC_ROUTES.some( route => router.pathname === route || router.pathname.startsWith(`${route}/`), ); return ( <>
{isPublicRoute ? ( ) : ( )}
); }