mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
Move share page redirect logic to ShareProvider
Centralizes the single-section redirect logic in ShareProvider instead of SharePage, reducing useEffect complexity and preventing children from rendering during redirect. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
78d467b478
commit
d028bfa1f5
3 changed files with 41 additions and 51 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
import { Loading } from '@umami/react-zen';
|
import { Loading } from '@umami/react-zen';
|
||||||
import { createContext, type ReactNode } from 'react';
|
import { usePathname, useRouter } from 'next/navigation';
|
||||||
|
import { createContext, type ReactNode, useEffect } from 'react';
|
||||||
import { useShareTokenQuery } from '@/components/hooks';
|
import { useShareTokenQuery } from '@/components/hooks';
|
||||||
import type { WhiteLabel } from '@/lib/types';
|
import type { WhiteLabel } from '@/lib/types';
|
||||||
|
|
||||||
|
|
@ -14,14 +15,48 @@ export interface ShareData {
|
||||||
|
|
||||||
export const ShareContext = createContext<ShareData>(null);
|
export const ShareContext = createContext<ShareData>(null);
|
||||||
|
|
||||||
|
const ALL_SECTION_IDS = [
|
||||||
|
'overview',
|
||||||
|
'events',
|
||||||
|
'sessions',
|
||||||
|
'realtime',
|
||||||
|
'compare',
|
||||||
|
'breakdown',
|
||||||
|
'goals',
|
||||||
|
'funnels',
|
||||||
|
'journeys',
|
||||||
|
'retention',
|
||||||
|
'utm',
|
||||||
|
'revenue',
|
||||||
|
'attribution',
|
||||||
|
];
|
||||||
|
|
||||||
export function ShareProvider({ shareId, children }: { shareId: string; children: ReactNode }) {
|
export function ShareProvider({ shareId, children }: { shareId: string; children: ReactNode }) {
|
||||||
const { share, isLoading, isFetching } = useShareTokenQuery(shareId);
|
const { share, isLoading, isFetching } = useShareTokenQuery(shareId);
|
||||||
|
const router = useRouter();
|
||||||
|
const pathname = usePathname();
|
||||||
|
const path = pathname.split('/')[3];
|
||||||
|
|
||||||
|
const allowedSections = share?.parameters
|
||||||
|
? ALL_SECTION_IDS.filter(id => share.parameters[id] !== false)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const shouldRedirect =
|
||||||
|
allowedSections.length === 1 &&
|
||||||
|
allowedSections[0] !== 'overview' &&
|
||||||
|
(path === undefined || path === '' || path === 'overview');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (shouldRedirect) {
|
||||||
|
router.replace(`/share/${shareId}/${allowedSections[0]}`);
|
||||||
|
}
|
||||||
|
}, [shouldRedirect, shareId, allowedSections, router]);
|
||||||
|
|
||||||
if (isFetching && isLoading) {
|
if (isFetching && isLoading) {
|
||||||
return <Loading placement="absolute" />;
|
return <Loading placement="absolute" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!share) {
|
if (!share || shouldRedirect) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
import { Column, Grid, Row, useTheme } from '@umami/react-zen';
|
import { Column, Grid, Row, useTheme } from '@umami/react-zen';
|
||||||
import { usePathname, useRouter } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { AttributionPage } from '@/app/(main)/websites/[websiteId]/(reports)/attribution/AttributionPage';
|
import { AttributionPage } from '@/app/(main)/websites/[websiteId]/(reports)/attribution/AttributionPage';
|
||||||
import { BreakdownPage } from '@/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage';
|
import { BreakdownPage } from '@/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage';
|
||||||
import { FunnelsPage } from '@/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage';
|
import { FunnelsPage } from '@/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage';
|
||||||
|
|
@ -39,38 +39,13 @@ const PAGE_COMPONENTS: Record<string, React.ComponentType<{ websiteId: string }>
|
||||||
attribution: AttributionPage,
|
attribution: AttributionPage,
|
||||||
};
|
};
|
||||||
|
|
||||||
// All section IDs that can be enabled/disabled via parameters
|
export function SharePage() {
|
||||||
const ALL_SECTION_IDS = [
|
|
||||||
'overview',
|
|
||||||
'events',
|
|
||||||
'sessions',
|
|
||||||
'realtime',
|
|
||||||
'compare',
|
|
||||||
'breakdown',
|
|
||||||
'goals',
|
|
||||||
'funnels',
|
|
||||||
'journeys',
|
|
||||||
'retention',
|
|
||||||
'utm',
|
|
||||||
'revenue',
|
|
||||||
'attribution',
|
|
||||||
];
|
|
||||||
|
|
||||||
export function SharePage({ shareId }: { shareId: string }) {
|
|
||||||
const share = useShare();
|
const share = useShare();
|
||||||
const { setTheme } = useTheme();
|
const { setTheme } = useTheme();
|
||||||
const router = useRouter();
|
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const path = pathname.split('/')[3];
|
const path = pathname.split('/')[3];
|
||||||
const { websiteId, parameters = {} } = share;
|
const { websiteId, parameters = {} } = share;
|
||||||
|
|
||||||
// Calculate allowed sections
|
|
||||||
const allowedSections = useMemo(() => {
|
|
||||||
if (!share?.parameters) return [];
|
|
||||||
const params = share.parameters;
|
|
||||||
return ALL_SECTION_IDS.filter(id => params[id] !== false);
|
|
||||||
}, [share?.parameters]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const url = new URL(window?.location?.href);
|
const url = new URL(window?.location?.href);
|
||||||
const theme = url.searchParams.get('theme');
|
const theme = url.searchParams.get('theme');
|
||||||
|
|
@ -80,26 +55,6 @@ export function SharePage({ shareId }: { shareId: string }) {
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 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]);
|
|
||||||
|
|
||||||
// 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
|
// Check if the requested path is allowed
|
||||||
const pageKey = path || '';
|
const pageKey = path || '';
|
||||||
const isAllowed = pageKey === '' || pageKey === 'overview' || parameters[pageKey] !== false;
|
const isAllowed = pageKey === '' || pageKey === 'overview' || parameters[pageKey] !== false;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ export default async function ({ params }: { params: Promise<{ shareId: string[]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ShareProvider shareId={slug}>
|
<ShareProvider shareId={slug}>
|
||||||
<SharePage shareId={slug} />
|
<SharePage />
|
||||||
</ShareProvider>
|
</ShareProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue