diff --git a/src/app/share/[...shareId]/Footer.tsx b/src/app/share/[...shareId]/ShareFooter.tsx similarity index 100% rename from src/app/share/[...shareId]/Footer.tsx rename to src/app/share/[...shareId]/ShareFooter.tsx diff --git a/src/app/share/[...shareId]/Header.tsx b/src/app/share/[...shareId]/ShareHeader.tsx similarity index 100% rename from src/app/share/[...shareId]/Header.tsx rename to src/app/share/[...shareId]/ShareHeader.tsx diff --git a/src/app/share/[...shareId]/SharePage.tsx b/src/app/share/[...shareId]/SharePage.tsx index 9e8bd8bf..86a0dbda 100644 --- a/src/app/share/[...shareId]/SharePage.tsx +++ b/src/app/share/[...shareId]/SharePage.tsx @@ -1,6 +1,7 @@ 'use client'; import { Column, Grid, useTheme } from '@umami/react-zen'; -import { useEffect } from 'react'; +import { useRouter } from 'next/navigation'; +import { useEffect, useMemo } from 'react'; import { AttributionPage } from '@/app/(main)/websites/[websiteId]/(reports)/attribution/AttributionPage'; import { BreakdownPage } from '@/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage'; import { FunnelsPage } from '@/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage'; @@ -18,8 +19,8 @@ import { WebsitePage } from '@/app/(main)/websites/[websiteId]/WebsitePage'; import { WebsiteProvider } from '@/app/(main)/websites/WebsiteProvider'; import { PageBody } from '@/components/common/PageBody'; import { useShareTokenQuery } from '@/components/hooks'; -import { Footer } from './Footer'; -import { Header } from './Header'; +import { ShareFooter } from './ShareFooter'; +import { ShareHeader } from './ShareHeader'; import { ShareNav } from './ShareNav'; const PAGE_COMPONENTS: Record> = { @@ -39,9 +40,34 @@ const PAGE_COMPONENTS: Record attribution: AttributionPage, }; +// All section IDs that can be enabled/disabled via parameters +const ALL_SECTION_IDS = [ + 'overview', + 'events', + 'sessions', + 'realtime', + 'compare', + 'breakdown', + 'goals', + 'funnels', + 'journeys', + 'retention', + 'utm', + 'revenue', + 'attribution', +]; + export function SharePage({ shareId, path = '' }: { shareId: string; path?: string }) { const { shareToken, isLoading } = useShareTokenQuery(shareId); const { setTheme } = useTheme(); + const router = useRouter(); + + // Calculate allowed sections + const allowedSections = useMemo(() => { + if (!shareToken?.parameters) return []; + const params = shareToken.parameters; + return ALL_SECTION_IDS.filter(id => params[id] !== false); + }, [shareToken?.parameters]); useEffect(() => { const url = new URL(window?.location?.href); @@ -52,12 +78,32 @@ export function SharePage({ shareId, path = '' }: { shareId: string; path?: stri } }, []); + // Redirect to the only allowed section if there's just one and we're on the base path + useEffect(() => { + if ( + allowedSections.length === 1 && + allowedSections[0] !== 'overview' && + (path === '' || path === 'overview') + ) { + router.replace(`/share/${shareId}/${allowedSections[0]}`); + } + }, [allowedSections, shareId, path, router]); + if (isLoading || !shareToken) { return null; } const { websiteId, parameters = {}, whiteLabel } = shareToken; + // Redirect to only allowed section - return null while redirecting + if ( + allowedSections.length === 1 && + allowedSections[0] !== 'overview' && + (path === '' || path === 'overview') + ) { + return null; + } + // Check if the requested path is allowed const pageKey = path || ''; const isAllowed = pageKey === '' || pageKey === 'overview' || parameters[pageKey] !== false; @@ -69,8 +115,7 @@ export function SharePage({ shareId, path = '' }: { shareId: string; path?: stri const PageComponent = PAGE_COMPONENTS[pageKey] || WebsitePage; return ( - -
+ -
+ -