diff --git a/.gitignore b/.gitignore index 8b543f6b9..de893d0f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,48 +1,46 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -node_modules -.pnp -.pnp.js -.pnpm-store -package-lock.json - -# testing -/coverage - -# next.js -/.next -/out - -# production -/build -/public/script.js -/geo -/dist -/generated -/src/generated -pm2.yml - -# misc -.DS_Store -.idea -.yarn -*.iml -*.log -.vscode -.tool-versions -.claude -nul - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env -.env.* -*.env.* - -*.dev.yml - +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +node_modules +.pnp +.pnp.js +.pnpm-store +package-lock.json + +# testing +/coverage + +# next.js +/.next +/out + +# production +/build +/public/script.js +/geo +/dist +/generated +/src/generated +pm2.yml + +# misc +.DS_Store +.idea +.yarn +*.iml +*.log +.vscode +.tool-versions + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env +.env.* +*.env.* + +*.dev.yml + diff --git a/package.json b/package.json index ee22a9eed..ac2ea36c2 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ }, "type": "module", "scripts": { - "dev": "next dev -p 3002 --turbo", + "dev": "next dev -p 3001 --turbo", "build": "npm-run-all check-env build-db check-db build-tracker build-geo build-app", "start": "next start", "build-docker": "npm-run-all build-db build-tracker build-geo build-app", diff --git a/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx index d81519d76..e336a3db6 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx @@ -1,6 +1,6 @@ import { Box, Column, Dialog, Grid, Icon, ProgressBar, Row, Text } from '@umami/react-zen'; import { LoadingPanel } from '@/components/common/LoadingPanel'; -import { useMessages, useNavigation, useResultQuery } from '@/components/hooks'; +import { useMessages, useResultQuery } from '@/components/hooks'; import { File, User } from '@/components/icons'; import { ReportEditButton } from '@/components/input/ReportEditButton'; import { ChangeLabel } from '@/components/metrics/ChangeLabel'; @@ -20,8 +20,6 @@ type FunnelResult = { export function Funnel({ id, name, type, parameters, websiteId }) { const { formatMessage, labels } = useMessages(); - const { pathname } = useNavigation(); - const isSharePage = pathname.includes('/share/'); const { data, error, isLoading } = useResultQuery(type, { websiteId, ...parameters, @@ -38,22 +36,21 @@ export function Funnel({ id, name, type, parameters, websiteId }) { - {!isSharePage && ( - - - {({ close }) => { - return ( - - - - ); - }} - - - )} + + + {({ close }) => { + return ( + + + + ); + }} + + {data?.map( ( diff --git a/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage.tsx index a56917b76..57bce52f8 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage.tsx @@ -4,7 +4,7 @@ import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteContro import { LoadingPanel } from '@/components/common/LoadingPanel'; import { Panel } from '@/components/common/Panel'; import { SectionHeader } from '@/components/common/SectionHeader'; -import { useDateRange, useNavigation, useReportsQuery } from '@/components/hooks'; +import { useDateRange, useReportsQuery } from '@/components/hooks'; import { Funnel } from './Funnel'; import { FunnelAddButton } from './FunnelAddButton'; @@ -13,17 +13,13 @@ export function FunnelsPage({ websiteId }: { websiteId: string }) { const { dateRange: { startDate, endDate }, } = useDateRange(); - const { pathname } = useNavigation(); - const isSharePage = pathname.includes('/share/'); return ( - {!isSharePage && ( - - - - )} + + + {data && ( diff --git a/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx b/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx index 1d0b96e50..b6c4a11d6 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx @@ -1,6 +1,6 @@ import { Column, Dialog, Grid, Icon, ProgressBar, Row, Text } from '@umami/react-zen'; import { LoadingPanel } from '@/components/common/LoadingPanel'; -import { useMessages, useNavigation, useResultQuery } from '@/components/hooks'; +import { useMessages, useResultQuery } from '@/components/hooks'; import { File, User } from '@/components/icons'; import { ReportEditButton } from '@/components/input/ReportEditButton'; import { Lightning } from '@/components/svg'; @@ -25,8 +25,6 @@ export type GoalData = { num: number; total: number }; export function Goal({ id, name, type, parameters, websiteId, startDate, endDate }: GoalProps) { const { formatMessage, labels } = useMessages(); - const { pathname } = useNavigation(); - const isSharePage = pathname.includes('/share/'); const { data, error, isLoading, isFetching } = useResultQuery(type, { websiteId, startDate, @@ -47,23 +45,21 @@ export function Goal({ id, name, type, parameters, websiteId, startDate, endDate - {!isSharePage && ( - - - {({ close }) => { - return ( - - - - ); - }} - - - )} + + + {({ close }) => { + return ( + + + + ); + }} + + diff --git a/src/app/(main)/websites/[websiteId]/(reports)/goals/GoalsPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/goals/GoalsPage.tsx index fe4550d6e..ff7b49fbd 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/goals/GoalsPage.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/goals/GoalsPage.tsx @@ -4,7 +4,7 @@ import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteContro import { LoadingPanel } from '@/components/common/LoadingPanel'; import { Panel } from '@/components/common/Panel'; import { SectionHeader } from '@/components/common/SectionHeader'; -import { useDateRange, useNavigation, useReportsQuery } from '@/components/hooks'; +import { useDateRange, useReportsQuery } from '@/components/hooks'; import { Goal } from './Goal'; import { GoalAddButton } from './GoalAddButton'; @@ -13,17 +13,13 @@ export function GoalsPage({ websiteId }: { websiteId: string }) { const { dateRange: { startDate, endDate }, } = useDateRange(); - const { pathname } = useNavigation(); - const isSharePage = pathname.includes('/share/'); return ( - {!isSharePage && ( - - - - )} + + + {data && ( diff --git a/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx b/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx index 1dee80220..e79576dd3 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx @@ -6,13 +6,7 @@ import { useMessages, useNavigation, useWebsite } from '@/components/hooks'; import { Edit } from '@/components/icons'; import { ActiveUsers } from '@/components/metrics/ActiveUsers'; -export function WebsiteHeader({ - showActions, - allowLink = true, -}: { - showActions?: boolean; - allowLink?: boolean; -}) { +export function WebsiteHeader({ showActions }: { showActions?: boolean }) { const website = useWebsite(); const { renderUrl, pathname } = useNavigation(); const isSettings = pathname.endsWith('/settings'); @@ -27,7 +21,7 @@ export function WebsiteHeader({ } - titleHref={allowLink ? renderUrl(`/websites/${website.id}`, false) : undefined} + titleHref={renderUrl(`/websites/${website.id}`, false)} > diff --git a/src/app/(main)/websites/[websiteId]/settings/ShareCreateForm.tsx b/src/app/(main)/websites/[websiteId]/settings/ShareCreateForm.tsx new file mode 100644 index 000000000..a16f2dc54 --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/settings/ShareCreateForm.tsx @@ -0,0 +1,81 @@ +import { + Button, + Checkbox, + Column, + Form, + FormField, + FormSubmitButton, + Row, + Text, +} from '@umami/react-zen'; +import { useState } from 'react'; +import { useApi, useMessages, useModified } from '@/components/hooks'; +import { SHARE_NAV_ITEMS } from './constants'; + +export interface ShareCreateFormProps { + websiteId: string; + onSave?: () => void; + onClose?: () => void; +} + +export function ShareCreateForm({ websiteId, onSave, onClose }: ShareCreateFormProps) { + const { formatMessage, labels } = useMessages(); + const { post } = useApi(); + const { touch } = useModified(); + const [isPending, setIsPending] = useState(false); + + // Build default values - only overview and events enabled by default + const defaultValues: Record = {}; + SHARE_NAV_ITEMS.forEach(section => { + section.items.forEach(item => { + defaultValues[item.id] = item.id === 'overview' || item.id === 'events'; + }); + }); + + const handleSubmit = async (data: any) => { + setIsPending(true); + try { + const parameters: Record = {}; + SHARE_NAV_ITEMS.forEach(section => { + section.items.forEach(item => { + parameters[item.id] = data[item.id] ?? false; + }); + }); + await post(`/websites/${websiteId}/shares`, { parameters }); + touch('shares'); + onSave?.(); + onClose?.(); + } finally { + setIsPending(false); + } + }; + + return ( +
+ + {SHARE_NAV_ITEMS.map(section => ( + + + {formatMessage((labels as any)[section.section])} + + + {section.items.map(item => ( + + {formatMessage((labels as any)[item.label])} + + ))} + + + ))} + + {onClose && ( + + )} + {formatMessage(labels.save)} + + +
+ ); +} diff --git a/src/app/(main)/websites/[websiteId]/settings/ShareEditForm.tsx b/src/app/(main)/websites/[websiteId]/settings/ShareEditForm.tsx index 4b86247ac..c5bd85a60 100644 --- a/src/app/(main)/websites/[websiteId]/settings/ShareEditForm.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/ShareEditForm.tsx @@ -5,7 +5,6 @@ import { Form, FormField, FormSubmitButton, - Grid, Label, Loading, Row, @@ -14,30 +13,25 @@ import { } from '@umami/react-zen'; import { useEffect, useState } from 'react'; import { useApi, useConfig, useMessages, useModified } from '@/components/hooks'; +import { useUpdateQuery } from '@/components/hooks/queries/useUpdateQuery'; import { SHARE_NAV_ITEMS } from './constants'; export function ShareEditForm({ shareId, - websiteId, onSave, onClose, }: { - shareId?: string; - websiteId?: string; + shareId: string; onSave?: () => void; onClose?: () => void; }) { - const { formatMessage, labels, getErrorMessage } = useMessages(); + const { formatMessage, labels, messages, getErrorMessage } = useMessages(); + const { mutateAsync, error, isPending, touch, toast } = useUpdateQuery(`/share/id/${shareId}`); const { cloudMode } = useConfig(); - const { get, post } = useApi(); - const { touch } = useModified(); + const { get } = useApi(); const { modified } = useModified('shares'); const [share, setShare] = useState(null); - const [isLoading, setIsLoading] = useState(!!shareId); - const [isPending, setIsPending] = useState(false); - const [error, setError] = useState(null); - - const isEditing = !!shareId; + const [isLoading, setIsLoading] = useState(true); const getUrl = (slug: string) => { if (cloudMode) { @@ -47,8 +41,6 @@ export function ShareEditForm({ }; useEffect(() => { - if (!shareId) return; - const loadShare = async () => { setIsLoading(true); try { @@ -69,35 +61,27 @@ export function ShareEditForm({ }); }); - setIsPending(true); - setError(null); - - try { - if (isEditing) { - await post(`/share/id/${shareId}`, { name: data.name, slug: share.slug, parameters }); - } else { - await post(`/websites/${websiteId}/shares`, { name: data.name, parameters }); - } - touch('shares'); - onSave?.(); - onClose?.(); - } catch (e) { - setError(e); - } finally { - setIsPending(false); - } + await mutateAsync( + { slug: share.slug, parameters }, + { + onSuccess: async () => { + toast(formatMessage(messages.saved)); + touch('shares'); + onSave?.(); + onClose?.(); + }, + }, + ); }; if (isLoading) { return ; } - const url = isEditing ? getUrl(share?.slug || '') : null; + const url = getUrl(share?.slug || ''); // Build default values from share parameters - const defaultValues: Record = { - name: share?.name || '', - }; + const defaultValues: Record = {}; SHARE_NAV_ITEMS.forEach(section => { section.items.forEach(item => { const defaultSelected = item.id === 'overview' || item.id === 'events'; @@ -105,60 +89,34 @@ export function ShareEditForm({ }); }); - // Get all item ids for validation - const allItemIds = SHARE_NAV_ITEMS.flatMap(section => section.items.map(item => item.id)); - return (
- {({ watch }) => { - const values = watch(); - const hasSelection = allItemIds.some(id => values[id]); - - return ( - - {url && ( - - - - - )} - - - - - {SHARE_NAV_ITEMS.map(section => ( - - {formatMessage((labels as any)[section.section])} - - {section.items.map(item => ( - - {formatMessage((labels as any)[item.label])} - - ))} - - + + + + + + {SHARE_NAV_ITEMS.map(section => ( + + {formatMessage((labels as any)[section.section])} + + {section.items.map(item => ( + + {formatMessage((labels as any)[item.label])} + ))} - - - {onClose && ( - - )} - - {formatMessage(labels.save)} - - + - ); - }} + ))} + + {onClose && ( + + )} + {formatMessage(labels.save)} + +
); } diff --git a/src/app/(main)/websites/[websiteId]/settings/SharesTable.tsx b/src/app/(main)/websites/[websiteId]/settings/SharesTable.tsx index 57701ac67..05e8b357b 100644 --- a/src/app/(main)/websites/[websiteId]/settings/SharesTable.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/SharesTable.tsx @@ -10,14 +10,14 @@ export function SharesTable(props: DataTableProps) { const { cloudMode } = useConfig(); const getUrl = (slug: string) => { - return `${cloudMode ? process.env.cloudUrl : window?.location.origin}${process.env.basePath || ''}/share/${slug}`; + if (cloudMode) { + return `${process.env.cloudUrl}/share/${slug}`; + } + return `${window?.location.origin}${process.env.basePath || ''}/share/${slug}`; }; return ( - - {({ name }: any) => name} - {({ slug }: any) => { const url = getUrl(slug); diff --git a/src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx b/src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx index 8472ca977..7453b4028 100644 --- a/src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx @@ -2,7 +2,7 @@ import { Column, Heading, Row, Text } from '@umami/react-zen'; import { Plus } from 'lucide-react'; import { useMessages, useWebsiteSharesQuery } from '@/components/hooks'; import { DialogButton } from '@/components/input/DialogButton'; -import { ShareEditForm } from './ShareEditForm'; +import { ShareCreateForm } from './ShareCreateForm'; import { SharesTable } from './SharesTable'; export interface WebsiteShareFormProps { @@ -25,9 +25,9 @@ export function WebsiteShareForm({ websiteId }: WebsiteShareFormProps) { label={formatMessage(labels.add)} title={formatMessage(labels.share)} variant="primary" - width="600px" + width="400px" > - {({ close }) => } + {({ close }) => }
{hasShares ? ( diff --git a/src/app/api/share/[slug]/route.ts b/src/app/api/share/[slug]/route.ts index e7d5372fe..ed3271eab 100644 --- a/src/app/api/share/[slug]/route.ts +++ b/src/app/api/share/[slug]/route.ts @@ -1,47 +1,7 @@ -import { ROLES } from '@/lib/constants'; import { secret } from '@/lib/crypto'; import { createToken } from '@/lib/jwt'; -import prisma from '@/lib/prisma'; -import redis from '@/lib/redis'; import { json, notFound } from '@/lib/response'; -import type { WhiteLabel } from '@/lib/types'; -import { getShareByCode, getWebsite } from '@/queries/prisma'; - -async function getAccountId(website: { userId?: string; teamId?: string }): Promise { - if (website.userId) { - return website.userId; - } - - if (website.teamId) { - const teamOwner = await prisma.client.teamUser.findFirst({ - where: { - teamId: website.teamId, - role: ROLES.teamOwner, - }, - select: { - userId: true, - }, - }); - - return teamOwner?.userId || null; - } - - return null; -} - -async function getWhiteLabel(accountId: string): Promise { - if (!redis.enabled) { - return null; - } - - const data = await redis.client.get(`white-label:${accountId}`); - - if (data) { - return data as WhiteLabel; - } - - return null; -} +import { getShareByCode } from '@/queries/prisma'; export async function GET(_request: Request, { params }: { params: Promise<{ slug: string }> }) { const { slug } = await params; @@ -52,25 +12,12 @@ export async function GET(_request: Request, { params }: { params: Promise<{ slu return notFound(); } - const website = await getWebsite(share.entityId); - - const data: Record = { + const data = { shareId: share.id, websiteId: share.entityId, parameters: share.parameters, }; + const token = createToken(data, secret()); - data.token = createToken(data, secret()); - - const accountId = await getAccountId(website); - - if (accountId) { - const whiteLabel = await getWhiteLabel(accountId); - - if (whiteLabel) { - data.whiteLabel = whiteLabel; - } - } - - return json(data); + return json({ ...data, token }); } diff --git a/src/app/api/share/id/[shareId]/route.ts b/src/app/api/share/id/[shareId]/route.ts index 80da17b80..da7dcf562 100644 --- a/src/app/api/share/id/[shareId]/route.ts +++ b/src/app/api/share/id/[shareId]/route.ts @@ -25,7 +25,6 @@ export async function GET(request: Request, { params }: { params: Promise<{ shar export async function POST(request: Request, { params }: { params: Promise<{ shareId: string }> }) { const schema = z.object({ - name: z.string().max(200), slug: z.string().max(100), parameters: anyObjectParam, }); @@ -37,7 +36,7 @@ export async function POST(request: Request, { params }: { params: Promise<{ sha } const { shareId } = await params; - const { name, slug, parameters } = body; + const { slug, parameters } = body; const share = await getShare(shareId); @@ -50,7 +49,6 @@ export async function POST(request: Request, { params }: { params: Promise<{ sha } const result = await updateShare(shareId, { - name, slug, parameters, } as any); diff --git a/src/app/api/websites/[websiteId]/shares/route.ts b/src/app/api/websites/[websiteId]/shares/route.ts index 65d53771d..db079d497 100644 --- a/src/app/api/websites/[websiteId]/shares/route.ts +++ b/src/app/api/websites/[websiteId]/shares/route.ts @@ -44,7 +44,6 @@ export async function POST( { params }: { params: Promise<{ websiteId: string }> }, ) { const schema = z.object({ - name: z.string().max(200), parameters: anyObjectParam.optional(), }); @@ -55,8 +54,7 @@ export async function POST( } const { websiteId } = await params; - const { name, parameters } = body; - const shareParameters = parameters ?? {}; + const { parameters = {} } = body; if (!(await canUpdateWebsite(auth, websiteId))) { return unauthorized(); @@ -68,9 +66,8 @@ export async function POST( id: uuid(), entityId: websiteId, shareType: ENTITY_TYPE.website, - name, slug, - parameters: shareParameters, + parameters, }); return json(share); diff --git a/src/app/share/[...shareId]/Footer.tsx b/src/app/share/[...shareId]/Footer.tsx new file mode 100644 index 000000000..f29486286 --- /dev/null +++ b/src/app/share/[...shareId]/Footer.tsx @@ -0,0 +1,12 @@ +import { Row, Text } from '@umami/react-zen'; +import { CURRENT_VERSION, HOMEPAGE_URL } from '@/lib/constants'; + +export function Footer() { + return ( + + + umami {`v${CURRENT_VERSION}`} + + + ); +} diff --git a/src/app/share/[...shareId]/Header.tsx b/src/app/share/[...shareId]/Header.tsx new file mode 100644 index 000000000..d7b7dcb42 --- /dev/null +++ b/src/app/share/[...shareId]/Header.tsx @@ -0,0 +1,24 @@ +import { Icon, Row, Text, ThemeButton } from '@umami/react-zen'; +import { LanguageButton } from '@/components/input/LanguageButton'; +import { PreferencesButton } from '@/components/input/PreferencesButton'; +import { Logo } from '@/components/svg'; + +export function Header() { + return ( + + + + + + + umami + + + + + + + + + ); +} diff --git a/src/app/share/[...shareId]/ShareFooter.tsx b/src/app/share/[...shareId]/ShareFooter.tsx deleted file mode 100644 index 5348ac63c..000000000 --- a/src/app/share/[...shareId]/ShareFooter.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Row, Text } from '@umami/react-zen'; -import { CURRENT_VERSION, HOMEPAGE_URL } from '@/lib/constants'; -import type { WhiteLabel } from '@/lib/types'; - -export function ShareFooter({ whiteLabel }: { whiteLabel?: WhiteLabel }) { - if (whiteLabel) { - return ( - - - {whiteLabel.name} - - - ); - } - - return ( - - - umami {`v${CURRENT_VERSION}`} - - - ); -} diff --git a/src/app/share/[...shareId]/ShareHeader.tsx b/src/app/share/[...shareId]/ShareHeader.tsx deleted file mode 100644 index abd8511df..000000000 --- a/src/app/share/[...shareId]/ShareHeader.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { Icon, Row, Text, ThemeButton } from '@umami/react-zen'; -import { LanguageButton } from '@/components/input/LanguageButton'; -import { PreferencesButton } from '@/components/input/PreferencesButton'; -import { Logo } from '@/components/svg'; -import type { WhiteLabel } from '@/lib/types'; - -export function ShareHeader({ whiteLabel }: { whiteLabel?: WhiteLabel }) { - const logoUrl = whiteLabel?.url || 'https://umami.is'; - const logoName = whiteLabel?.name || 'umami'; - const logoImage = whiteLabel?.image; - - return ( - - - - {logoImage ? ( - {logoName} - ) : ( - - - - )} - {logoName} - - - - - - - - - ); -} diff --git a/src/app/share/[...shareId]/SharePage.tsx b/src/app/share/[...shareId]/SharePage.tsx index 91a8b298c..3e1cedc06 100644 --- a/src/app/share/[...shareId]/SharePage.tsx +++ b/src/app/share/[...shareId]/SharePage.tsx @@ -1,7 +1,6 @@ 'use client'; -import { Column, Grid, Row, useTheme } from '@umami/react-zen'; -import { useRouter } from 'next/navigation'; -import { useEffect, useMemo } from 'react'; +import { Column, Grid, useTheme } from '@umami/react-zen'; +import { useEffect } 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'; @@ -19,9 +18,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 { MobileMenuButton } from '@/components/input/MobileMenuButton'; -import { ShareFooter } from './ShareFooter'; -import { ShareHeader } from './ShareHeader'; +import { Footer } from './Footer'; +import { Header } from './Header'; import { ShareNav } from './ShareNav'; const PAGE_COMPONENTS: Record> = { @@ -41,34 +39,9 @@ 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); @@ -79,31 +52,11 @@ 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; - } + const { websiteId, parameters = {} } = shareToken; // Check if the requested path is allowed const pageKey = path || ''; @@ -117,16 +70,8 @@ export function SharePage({ shareId, path = '' }: { shareId: string; path?: stri return ( +
- - - - {({ close }) => { - return ; - }} - - - - - - + - + - - +