From 8e766e2db7da410c10ce525737f93eede2bd2898 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Thu, 21 Aug 2025 01:33:20 -0700 Subject: [PATCH] Pixel/link metrics pages. --- .../admin/teams/[teamId]/AdminTeamPage.tsx | 2 +- .../websites/[websiteId]/AdminWebsitePage.tsx | 2 +- src/app/(main)/links/LinkEditForm.tsx | 5 +- src/app/(main)/links/LinkProvider.tsx | 20 ++++++ src/app/(main)/links/LinksTable.tsx | 17 +++-- .../(main)/links/[linkId]/LinkControls.tsx | 34 +++++++++ src/app/(main)/links/[linkId]/LinkHeader.tsx | 22 ++++++ .../(main)/links/[linkId]/LinkMetricsBar.tsx | 71 +++++++++++++++++++ src/app/(main)/links/[linkId]/LinkPage.tsx | 59 +++++++++++++++ src/app/(main)/links/[linkId]/page.tsx | 12 ++++ src/app/(main)/pixels/PixelEditForm.tsx | 5 +- src/app/(main)/pixels/PixelProvider.tsx | 20 ++++++ src/app/(main)/pixels/PixelsTable.tsx | 16 +++-- .../(main)/pixels/[pixelId]/PixelControls.tsx | 34 +++++++++ .../(main)/pixels/[pixelId]/PixelHeader.tsx | 22 ++++++ .../pixels/[pixelId]/PixelMetricsBar.tsx | 71 +++++++++++++++++++ src/app/(main)/pixels/[pixelId]/PixelPage.tsx | 59 +++++++++++++++ src/app/(main)/pixels/[pixelId]/page.tsx | 12 ++++ .../teams/[teamId]/TeamSettingsPage.tsx | 2 +- .../[websiteId]/WebsiteSettingsPage.tsx | 2 +- .../teams/{[teamId] => }/TeamProvider.tsx | 0 .../(main)/teams/[teamId]/TeamEditForm.tsx | 2 +- .../(main)/teams/[teamId]/TeamSettings.tsx | 2 +- .../{[websiteId] => }/WebsiteProvider.tsx | 0 ...WebsiteDetailsPage.tsx => WebsitePage.tsx} | 2 +- src/app/(main)/websites/[websiteId]/page.tsx | 6 +- .../[websiteId]/settings/WebsiteEditForm.tsx | 2 +- .../[websiteId]/settings/WebsiteSettings.tsx | 2 +- .../settings/WebsiteSettingsHeader.tsx | 2 +- .../settings/WebsiteTransferForm.tsx | 2 +- src/app/share/[...shareId]/SharePage.tsx | 6 +- src/components/common/PageHeader.tsx | 12 ++-- src/components/hooks/context/useLink.ts | 6 ++ src/components/hooks/context/usePixel.ts | 6 ++ src/components/hooks/{ => context}/useTeam.ts | 2 +- .../hooks/{ => context}/useWebsite.ts | 2 +- src/components/hooks/index.ts | 9 ++- .../hooks/queries/useUpdateQuery.ts | 7 +- src/components/hooks/useSlug.ts | 14 ++++ src/components/messages.ts | 2 +- src/components/metrics/PagesTable.tsx | 2 +- src/index.ts | 4 +- 42 files changed, 530 insertions(+), 49 deletions(-) create mode 100644 src/app/(main)/links/LinkProvider.tsx create mode 100644 src/app/(main)/links/[linkId]/LinkControls.tsx create mode 100644 src/app/(main)/links/[linkId]/LinkHeader.tsx create mode 100644 src/app/(main)/links/[linkId]/LinkMetricsBar.tsx create mode 100644 src/app/(main)/links/[linkId]/LinkPage.tsx create mode 100644 src/app/(main)/links/[linkId]/page.tsx create mode 100644 src/app/(main)/pixels/PixelProvider.tsx create mode 100644 src/app/(main)/pixels/[pixelId]/PixelControls.tsx create mode 100644 src/app/(main)/pixels/[pixelId]/PixelHeader.tsx create mode 100644 src/app/(main)/pixels/[pixelId]/PixelMetricsBar.tsx create mode 100644 src/app/(main)/pixels/[pixelId]/PixelPage.tsx create mode 100644 src/app/(main)/pixels/[pixelId]/page.tsx rename src/app/(main)/teams/{[teamId] => }/TeamProvider.tsx (100%) rename src/app/(main)/websites/{[websiteId] => }/WebsiteProvider.tsx (100%) rename src/app/(main)/websites/[websiteId]/{WebsiteDetailsPage.tsx => WebsitePage.tsx} (95%) create mode 100644 src/components/hooks/context/useLink.ts create mode 100644 src/components/hooks/context/usePixel.ts rename src/components/hooks/{ => context}/useTeam.ts (58%) rename src/components/hooks/{ => context}/useWebsite.ts (56%) create mode 100644 src/components/hooks/useSlug.ts diff --git a/src/app/(main)/admin/teams/[teamId]/AdminTeamPage.tsx b/src/app/(main)/admin/teams/[teamId]/AdminTeamPage.tsx index a7851d78..21501973 100644 --- a/src/app/(main)/admin/teams/[teamId]/AdminTeamPage.tsx +++ b/src/app/(main)/admin/teams/[teamId]/AdminTeamPage.tsx @@ -1,6 +1,6 @@ 'use client'; import { TeamSettings } from '@/app/(main)/teams/[teamId]/TeamSettings'; -import { TeamProvider } from '@/app/(main)/teams/[teamId]/TeamProvider'; +import { TeamProvider } from '@/app/(main)/teams/TeamProvider'; export function AdminTeamPage({ teamId }: { teamId: string }) { return ( diff --git a/src/app/(main)/admin/websites/[websiteId]/AdminWebsitePage.tsx b/src/app/(main)/admin/websites/[websiteId]/AdminWebsitePage.tsx index 54cb9384..5da82afd 100644 --- a/src/app/(main)/admin/websites/[websiteId]/AdminWebsitePage.tsx +++ b/src/app/(main)/admin/websites/[websiteId]/AdminWebsitePage.tsx @@ -1,6 +1,6 @@ 'use client'; import { WebsiteSettings } from '@/app/(main)/websites/[websiteId]/settings/WebsiteSettings'; -import { WebsiteProvider } from '@/app/(main)/websites/[websiteId]/WebsiteProvider'; +import { WebsiteProvider } from '@/app/(main)/websites/WebsiteProvider'; import { Panel } from '@/components/common/Panel'; export function AdminWebsitePage({ websiteId }: { websiteId: string }) { diff --git a/src/app/(main)/links/LinkEditForm.tsx b/src/app/(main)/links/LinkEditForm.tsx index a6257768..38298d9f 100644 --- a/src/app/(main)/links/LinkEditForm.tsx +++ b/src/app/(main)/links/LinkEditForm.tsx @@ -32,8 +32,8 @@ export function LinkEditForm({ onSave?: () => void; onClose?: () => void; }) { - const { formatMessage, labels } = useMessages(); - const { mutate, error, isPending, touch } = useUpdateQuery( + const { formatMessage, labels, messages } = useMessages(); + const { mutate, error, isPending, touch, toast } = useUpdateQuery( linkId ? `/links/${linkId}` : '/links', { id: linkId, @@ -48,6 +48,7 @@ export function LinkEditForm({ const handleSubmit = async (data: any) => { mutate(data, { onSuccess: async () => { + toast(formatMessage(messages.saved)); touch('links'); onSave?.(); onClose?.(); diff --git a/src/app/(main)/links/LinkProvider.tsx b/src/app/(main)/links/LinkProvider.tsx new file mode 100644 index 00000000..6593d85a --- /dev/null +++ b/src/app/(main)/links/LinkProvider.tsx @@ -0,0 +1,20 @@ +'use client'; +import { createContext, ReactNode } from 'react'; +import { useLinkQuery } from '@/components/hooks'; +import { Loading } from '@umami/react-zen'; + +export const LinkContext = createContext(null); + +export function LinkProvider({ linkId, children }: { linkId?: string; children: ReactNode }) { + const { data: link, isLoading, isFetching } = useLinkQuery(linkId); + + if (isFetching && isLoading) { + return ; + } + + if (!link) { + return null; + } + + return {children}; +} diff --git a/src/app/(main)/links/LinksTable.tsx b/src/app/(main)/links/LinksTable.tsx index 5e854a4a..b8471829 100644 --- a/src/app/(main)/links/LinksTable.tsx +++ b/src/app/(main)/links/LinksTable.tsx @@ -1,17 +1,16 @@ +import Link from 'next/link'; import { DataTable, DataColumn, Row } from '@umami/react-zen'; -import { useConfig, useMessages, useNavigation } from '@/components/hooks'; +import { useMessages, useNavigation, useSlug } from '@/components/hooks'; import { Empty } from '@/components/common/Empty'; import { DateDistance } from '@/components/common/DateDistance'; import { ExternalLink } from '@/components/common/ExternalLink'; import { LinkEditButton } from './LinkEditButton'; import { LinkDeleteButton } from './LinkDeleteButton'; -import { LINKS_URL } from '@/lib/constants'; export function LinksTable({ data = [] }) { const { formatMessage, labels } = useMessages(); - const { websiteId } = useNavigation(); - const { linksUrl } = useConfig(); - const hostUrl = linksUrl || LINKS_URL; + const { websiteId, renderUrl } = useNavigation(); + const { getSlugUrl } = useSlug('link'); if (data.length === 0) { return ; @@ -19,10 +18,14 @@ export function LinksTable({ data = [] }) { return ( - + + {({ id, name }: any) => { + return {name}; + }} + {({ slug }: any) => { - const url = `${hostUrl}/${slug}`; + const url = getSlugUrl(slug); return {url}; }} diff --git a/src/app/(main)/links/[linkId]/LinkControls.tsx b/src/app/(main)/links/[linkId]/LinkControls.tsx new file mode 100644 index 00000000..c9fd595f --- /dev/null +++ b/src/app/(main)/links/[linkId]/LinkControls.tsx @@ -0,0 +1,34 @@ +import { Column, Row } from '@umami/react-zen'; +import { WebsiteFilterButton } from '@/app/(main)/websites/[websiteId]/WebsiteFilterButton'; +import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter'; +import { FilterBar } from '@/components/input/FilterBar'; +import { WebsiteMonthSelect } from '@/components/input/WebsiteMonthSelect'; +import { ExportButton } from '@/components/input/ExportButton'; + +export function LinkControls({ + linkId: websiteId, + allowFilter = true, + allowDateFilter = true, + allowMonthFilter, + allowCompare, + allowDownload = false, +}: { + linkId: string; + allowFilter?: boolean; + allowCompare?: boolean; + allowDateFilter?: boolean; + allowMonthFilter?: boolean; + allowDownload?: boolean; +}) { + return ( + + + {allowFilter ? :
} + {allowDateFilter && } + {allowDownload && } + {allowMonthFilter && } + + {allowFilter && } + + ); +} diff --git a/src/app/(main)/links/[linkId]/LinkHeader.tsx b/src/app/(main)/links/[linkId]/LinkHeader.tsx new file mode 100644 index 00000000..6f8f7a57 --- /dev/null +++ b/src/app/(main)/links/[linkId]/LinkHeader.tsx @@ -0,0 +1,22 @@ +import { useLink, useMessages, useSlug } from '@/components/hooks'; +import { PageHeader } from '@/components/common/PageHeader'; +import { Icon, Text } from '@umami/react-zen'; +import { ExternalLink } from '@/components/icons'; +import { LinkButton } from '@/components/common/LinkButton'; + +export function LinkHeader() { + const { formatMessage, labels } = useMessages(); + const { getSlugUrl } = useSlug('link'); + const link = useLink(); + + return ( + + + + + + {formatMessage(labels.view)} + + + ); +} diff --git a/src/app/(main)/links/[linkId]/LinkMetricsBar.tsx b/src/app/(main)/links/[linkId]/LinkMetricsBar.tsx new file mode 100644 index 00000000..5e9d6cbf --- /dev/null +++ b/src/app/(main)/links/[linkId]/LinkMetricsBar.tsx @@ -0,0 +1,71 @@ +import { useDateRange, useMessages } from '@/components/hooks'; +import { MetricCard } from '@/components/metrics/MetricCard'; +import { MetricsBar } from '@/components/metrics/MetricsBar'; +import { formatLongNumber } from '@/lib/format'; +import { useWebsiteStatsQuery } from '@/components/hooks/queries/useWebsiteStatsQuery'; +import { LoadingPanel } from '@/components/common/LoadingPanel'; + +export function LinkMetricsBar({ + linkId, +}: { + linkId: string; + showChange?: boolean; + compareMode?: boolean; +}) { + const { dateRange } = useDateRange(linkId); + const { formatMessage, labels } = useMessages(); + const { data, isLoading, isFetching, error } = useWebsiteStatsQuery(linkId); + const isAllTime = dateRange.value === 'all'; + + const { pageviews, visitors, visits, comparison } = data || {}; + + const metrics = data + ? [ + { + value: visitors, + label: formatMessage(labels.visitors), + change: visitors - comparison.visitors, + formatValue: formatLongNumber, + }, + { + value: visits, + label: formatMessage(labels.visits), + change: visits - comparison.visits, + formatValue: formatLongNumber, + }, + { + value: pageviews, + label: formatMessage(labels.views), + change: pageviews - comparison.pageviews, + formatValue: formatLongNumber, + }, + ] + : null; + + return ( + + + {metrics?.map(({ label, value, prev, change, formatValue, reverseColors }: any) => { + return ( + + ); + })} + + + ); +} diff --git a/src/app/(main)/links/[linkId]/LinkPage.tsx b/src/app/(main)/links/[linkId]/LinkPage.tsx new file mode 100644 index 00000000..d57f937a --- /dev/null +++ b/src/app/(main)/links/[linkId]/LinkPage.tsx @@ -0,0 +1,59 @@ +'use client'; +import { PageBody } from '@/components/common/PageBody'; +import { LinkProvider } from '@/app/(main)/links/LinkProvider'; +import { LinkHeader } from '@/app/(main)/links/[linkId]/LinkHeader'; +import { Panel } from '@/components/common/Panel'; +import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart'; +import { LinkMetricsBar } from '@/app/(main)/links/[linkId]/LinkMetricsBar'; +import { LinkControls } from '@/app/(main)/links/[linkId]/LinkControls'; +import { Grid } from '@umami/react-zen'; +import { GridRow } from '@/components/common/GridRow'; +import { ReferrersTable } from '@/components/metrics/ReferrersTable'; +import { BrowsersTable } from '@/components/metrics/BrowsersTable'; +import { OSTable } from '@/components/metrics/OSTable'; +import { DevicesTable } from '@/components/metrics/DevicesTable'; +import { WorldMap } from '@/components/metrics/WorldMap'; +import { CountriesTable } from '@/components/metrics/CountriesTable'; + +export function LinkPage({ linkId }: { linkId: string }) { + const props = { websiteId: linkId, limit: 10, allowDownload: false }; + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/src/app/(main)/links/[linkId]/page.tsx b/src/app/(main)/links/[linkId]/page.tsx new file mode 100644 index 00000000..ae3b2c9a --- /dev/null +++ b/src/app/(main)/links/[linkId]/page.tsx @@ -0,0 +1,12 @@ +import { LinkPage } from './LinkPage'; +import { Metadata } from 'next'; + +export default async function ({ params }: { params: Promise<{ linkId: string }> }) { + const { linkId } = await params; + + return ; +} + +export const metadata: Metadata = { + title: 'Link', +}; diff --git a/src/app/(main)/pixels/PixelEditForm.tsx b/src/app/(main)/pixels/PixelEditForm.tsx index 8026c76a..6024a745 100644 --- a/src/app/(main)/pixels/PixelEditForm.tsx +++ b/src/app/(main)/pixels/PixelEditForm.tsx @@ -31,8 +31,8 @@ export function PixelEditForm({ onSave?: () => void; onClose?: () => void; }) { - const { formatMessage, labels } = useMessages(); - const { mutate, error, isPending, touch } = useUpdateQuery( + const { formatMessage, labels, messages } = useMessages(); + const { mutate, error, isPending, touch, toast } = useUpdateQuery( pixelId ? `/pixels/${pixelId}` : '/pixels', { id: pixelId, @@ -47,6 +47,7 @@ export function PixelEditForm({ const handleSubmit = async (data: any) => { mutate(data, { onSuccess: async () => { + toast(formatMessage(messages.saved)); touch('pixels'); onSave?.(); onClose?.(); diff --git a/src/app/(main)/pixels/PixelProvider.tsx b/src/app/(main)/pixels/PixelProvider.tsx new file mode 100644 index 00000000..1a5c1d5d --- /dev/null +++ b/src/app/(main)/pixels/PixelProvider.tsx @@ -0,0 +1,20 @@ +'use client'; +import { createContext, ReactNode } from 'react'; +import { usePixelQuery } from '@/components/hooks'; +import { Loading } from '@umami/react-zen'; + +export const PixelContext = createContext(null); + +export function PixelProvider({ pixelId, children }: { pixelId?: string; children: ReactNode }) { + const { data: pixel, isLoading, isFetching } = usePixelQuery(pixelId); + + if (isFetching && isLoading) { + return ; + } + + if (!pixel) { + return null; + } + + return {children}; +} diff --git a/src/app/(main)/pixels/PixelsTable.tsx b/src/app/(main)/pixels/PixelsTable.tsx index cb11554e..dcb5307c 100644 --- a/src/app/(main)/pixels/PixelsTable.tsx +++ b/src/app/(main)/pixels/PixelsTable.tsx @@ -1,16 +1,16 @@ +import Link from 'next/link'; import { DataTable, DataColumn, Row } from '@umami/react-zen'; -import { useConfig, useMessages } from '@/components/hooks'; +import { useMessages, useNavigation, useSlug } from '@/components/hooks'; import { Empty } from '@/components/common/Empty'; import { DateDistance } from '@/components/common/DateDistance'; import { PixelEditButton } from './PixelEditButton'; import { PixelDeleteButton } from './PixelDeleteButton'; -import { PIXELS_URL } from '@/lib/constants'; import { ExternalLink } from '@/components/common/ExternalLink'; export function PixelsTable({ data = [] }) { const { formatMessage, labels } = useMessages(); - const { pixelsUrl } = useConfig(); - const hostUrl = pixelsUrl || PIXELS_URL; + const { renderUrl } = useNavigation(); + const { getSlugUrl } = useSlug('pixel'); if (data.length === 0) { return ; @@ -18,10 +18,14 @@ export function PixelsTable({ data = [] }) { return ( - + + {({ id, name }: any) => { + return {name}; + }} + {({ slug }: any) => { - const url = `${hostUrl}/${slug}`; + const url = getSlugUrl(slug); return {url}; }} diff --git a/src/app/(main)/pixels/[pixelId]/PixelControls.tsx b/src/app/(main)/pixels/[pixelId]/PixelControls.tsx new file mode 100644 index 00000000..6bd829cf --- /dev/null +++ b/src/app/(main)/pixels/[pixelId]/PixelControls.tsx @@ -0,0 +1,34 @@ +import { Column, Row } from '@umami/react-zen'; +import { WebsiteFilterButton } from '@/app/(main)/websites/[websiteId]/WebsiteFilterButton'; +import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter'; +import { FilterBar } from '@/components/input/FilterBar'; +import { WebsiteMonthSelect } from '@/components/input/WebsiteMonthSelect'; +import { ExportButton } from '@/components/input/ExportButton'; + +export function PixelControls({ + pixelId: websiteId, + allowFilter = true, + allowDateFilter = true, + allowMonthFilter, + allowCompare, + allowDownload = false, +}: { + pixelId: string; + allowFilter?: boolean; + allowCompare?: boolean; + allowDateFilter?: boolean; + allowMonthFilter?: boolean; + allowDownload?: boolean; +}) { + return ( + + + {allowFilter ? :
} + {allowDateFilter && } + {allowDownload && } + {allowMonthFilter && } + + {allowFilter && } + + ); +} diff --git a/src/app/(main)/pixels/[pixelId]/PixelHeader.tsx b/src/app/(main)/pixels/[pixelId]/PixelHeader.tsx new file mode 100644 index 00000000..ad81a9bf --- /dev/null +++ b/src/app/(main)/pixels/[pixelId]/PixelHeader.tsx @@ -0,0 +1,22 @@ +import { usePixel, useMessages, useSlug } from '@/components/hooks'; +import { PageHeader } from '@/components/common/PageHeader'; +import { Icon, Text } from '@umami/react-zen'; +import { ExternalLink } from '@/components/icons'; +import { LinkButton } from '@/components/common/LinkButton'; + +export function PixelHeader() { + const { formatMessage, labels } = useMessages(); + const { getSlugUrl } = useSlug('pixel'); + const pixel = usePixel(); + + return ( + + + + + + {formatMessage(labels.view)} + + + ); +} diff --git a/src/app/(main)/pixels/[pixelId]/PixelMetricsBar.tsx b/src/app/(main)/pixels/[pixelId]/PixelMetricsBar.tsx new file mode 100644 index 00000000..5b01ef84 --- /dev/null +++ b/src/app/(main)/pixels/[pixelId]/PixelMetricsBar.tsx @@ -0,0 +1,71 @@ +import { useDateRange, useMessages } from '@/components/hooks'; +import { MetricCard } from '@/components/metrics/MetricCard'; +import { MetricsBar } from '@/components/metrics/MetricsBar'; +import { formatLongNumber } from '@/lib/format'; +import { useWebsiteStatsQuery } from '@/components/hooks/queries/useWebsiteStatsQuery'; +import { LoadingPanel } from '@/components/common/LoadingPanel'; + +export function PixelMetricsBar({ + pixelId, +}: { + pixelId: string; + showChange?: boolean; + compareMode?: boolean; +}) { + const { dateRange } = useDateRange(pixelId); + const { formatMessage, labels } = useMessages(); + const { data, isLoading, isFetching, error } = useWebsiteStatsQuery(pixelId); + const isAllTime = dateRange.value === 'all'; + + const { pageviews, visitors, visits, comparison } = data || {}; + + const metrics = data + ? [ + { + value: visitors, + label: formatMessage(labels.visitors), + change: visitors - comparison.visitors, + formatValue: formatLongNumber, + }, + { + value: visits, + label: formatMessage(labels.visits), + change: visits - comparison.visits, + formatValue: formatLongNumber, + }, + { + value: pageviews, + label: formatMessage(labels.views), + change: pageviews - comparison.pageviews, + formatValue: formatLongNumber, + }, + ] + : null; + + return ( + + + {metrics?.map(({ label, value, prev, change, formatValue, reverseColors }: any) => { + return ( + + ); + })} + + + ); +} diff --git a/src/app/(main)/pixels/[pixelId]/PixelPage.tsx b/src/app/(main)/pixels/[pixelId]/PixelPage.tsx new file mode 100644 index 00000000..eb42b125 --- /dev/null +++ b/src/app/(main)/pixels/[pixelId]/PixelPage.tsx @@ -0,0 +1,59 @@ +'use client'; +import { PageBody } from '@/components/common/PageBody'; +import { PixelProvider } from '@/app/(main)/pixels/PixelProvider'; +import { PixelHeader } from '@/app/(main)/pixels/[pixelId]/PixelHeader'; +import { Panel } from '@/components/common/Panel'; +import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart'; +import { PixelMetricsBar } from '@/app/(main)/pixels/[pixelId]/PixelMetricsBar'; +import { PixelControls } from '@/app/(main)/pixels/[pixelId]/PixelControls'; +import { Grid } from '@umami/react-zen'; +import { GridRow } from '@/components/common/GridRow'; +import { ReferrersTable } from '@/components/metrics/ReferrersTable'; +import { BrowsersTable } from '@/components/metrics/BrowsersTable'; +import { OSTable } from '@/components/metrics/OSTable'; +import { DevicesTable } from '@/components/metrics/DevicesTable'; +import { WorldMap } from '@/components/metrics/WorldMap'; +import { CountriesTable } from '@/components/metrics/CountriesTable'; + +export function PixelPage({ pixelId }: { pixelId: string }) { + const props = { websiteId: pixelId, limit: 10, allowDownload: false }; + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/src/app/(main)/pixels/[pixelId]/page.tsx b/src/app/(main)/pixels/[pixelId]/page.tsx new file mode 100644 index 00000000..1cb72c1d --- /dev/null +++ b/src/app/(main)/pixels/[pixelId]/page.tsx @@ -0,0 +1,12 @@ +import { PixelPage } from './PixelPage'; +import { Metadata } from 'next'; + +export default async function ({ params }: { params: Promise<{ pixelId: string }> }) { + const { pixelId } = await params; + + return ; +} + +export const metadata: Metadata = { + title: 'Pixel', +}; diff --git a/src/app/(main)/settings/teams/[teamId]/TeamSettingsPage.tsx b/src/app/(main)/settings/teams/[teamId]/TeamSettingsPage.tsx index 3736299d..8ad2b694 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamSettingsPage.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamSettingsPage.tsx @@ -1,5 +1,5 @@ 'use client'; -import { TeamProvider } from '@/app/(main)/teams/[teamId]/TeamProvider'; +import { TeamProvider } from '@/app/(main)/teams/TeamProvider'; import { TeamSettings } from '@/app/(main)/teams/[teamId]/TeamSettings'; export function TeamSettingsPage({ teamId }: { teamId: string }) { diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteSettingsPage.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteSettingsPage.tsx index 59df2f3c..e5140cb2 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteSettingsPage.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteSettingsPage.tsx @@ -1,6 +1,6 @@ 'use client'; import { Column } from '@umami/react-zen'; -import { WebsiteProvider } from '@/app/(main)/websites/[websiteId]/WebsiteProvider'; +import { WebsiteProvider } from '@/app/(main)/websites/WebsiteProvider'; import { WebsiteSettings } from '@/app/(main)/websites/[websiteId]/settings/WebsiteSettings'; import { WebsiteSettingsHeader } from '@/app/(main)/websites/[websiteId]/settings/WebsiteSettingsHeader'; import { Panel } from '@/components/common/Panel'; diff --git a/src/app/(main)/teams/[teamId]/TeamProvider.tsx b/src/app/(main)/teams/TeamProvider.tsx similarity index 100% rename from src/app/(main)/teams/[teamId]/TeamProvider.tsx rename to src/app/(main)/teams/TeamProvider.tsx diff --git a/src/app/(main)/teams/[teamId]/TeamEditForm.tsx b/src/app/(main)/teams/[teamId]/TeamEditForm.tsx index 9c053ac8..ec3b8fb0 100644 --- a/src/app/(main)/teams/[teamId]/TeamEditForm.tsx +++ b/src/app/(main)/teams/[teamId]/TeamEditForm.tsx @@ -10,7 +10,7 @@ import { import { getRandomChars } from '@/lib/crypto'; import { useContext } from 'react'; import { useApi, useMessages, useModified } from '@/components/hooks'; -import { TeamContext } from '@/app/(main)/teams/[teamId]/TeamProvider'; +import { TeamContext } from '@/app/(main)/teams/TeamProvider'; const generateId = () => `team_${getRandomChars(16)}`; diff --git a/src/app/(main)/teams/[teamId]/TeamSettings.tsx b/src/app/(main)/teams/[teamId]/TeamSettings.tsx index acf1a936..af2a4f32 100644 --- a/src/app/(main)/teams/[teamId]/TeamSettings.tsx +++ b/src/app/(main)/teams/[teamId]/TeamSettings.tsx @@ -1,6 +1,6 @@ import { useContext, useState } from 'react'; import { Column, Tabs, TabList, Tab, TabPanel } from '@umami/react-zen'; -import { TeamContext } from '@/app/(main)/teams/[teamId]/TeamProvider'; +import { TeamContext } from '@/app/(main)/teams/TeamProvider'; import { useLoginQuery, useMessages, useNavigation } from '@/components/hooks'; import { ROLES } from '@/lib/constants'; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteProvider.tsx b/src/app/(main)/websites/WebsiteProvider.tsx similarity index 100% rename from src/app/(main)/websites/[websiteId]/WebsiteProvider.tsx rename to src/app/(main)/websites/WebsiteProvider.tsx diff --git a/src/app/(main)/websites/[websiteId]/WebsiteDetailsPage.tsx b/src/app/(main)/websites/[websiteId]/WebsitePage.tsx similarity index 95% rename from src/app/(main)/websites/[websiteId]/WebsiteDetailsPage.tsx rename to src/app/(main)/websites/[websiteId]/WebsitePage.tsx index 33bca5ae..8a0edbfc 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteDetailsPage.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsitePage.tsx @@ -8,7 +8,7 @@ import { WebsiteMetricsBar } from './WebsiteMetricsBar'; import { WebsiteTableView } from './WebsiteTableView'; import { WebsiteControls } from './WebsiteControls'; -export function WebsiteDetailsPage({ websiteId }: { websiteId: string }) { +export function WebsitePage({ websiteId }: { websiteId: string }) { const { router, query: { view, compare }, diff --git a/src/app/(main)/websites/[websiteId]/page.tsx b/src/app/(main)/websites/[websiteId]/page.tsx index 286a4612..9755e6d0 100644 --- a/src/app/(main)/websites/[websiteId]/page.tsx +++ b/src/app/(main)/websites/[websiteId]/page.tsx @@ -1,10 +1,10 @@ -import { WebsiteDetailsPage } from './WebsiteDetailsPage'; +import { WebsitePage } from './WebsitePage'; import { Metadata } from 'next'; -export default async function WebsitePage({ params }: { params: Promise<{ websiteId: string }> }) { +export default async function ({ params }: { params: Promise<{ websiteId: string }> }) { const { websiteId } = await params; - return ; + return ; } export const metadata: Metadata = { diff --git a/src/app/(main)/websites/[websiteId]/settings/WebsiteEditForm.tsx b/src/app/(main)/websites/[websiteId]/settings/WebsiteEditForm.tsx index cb7cb0d1..dbefd669 100644 --- a/src/app/(main)/websites/[websiteId]/settings/WebsiteEditForm.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/WebsiteEditForm.tsx @@ -9,7 +9,7 @@ import { } from '@umami/react-zen'; import { useApi, useMessages, useModified } from '@/components/hooks'; import { DOMAIN_REGEX } from '@/lib/constants'; -import { WebsiteContext } from '@/app/(main)/websites/[websiteId]/WebsiteProvider'; +import { WebsiteContext } from '@/app/(main)/websites/WebsiteProvider'; export function WebsiteEditForm({ websiteId, onSave }: { websiteId: string; onSave?: () => void }) { const website = useContext(WebsiteContext); diff --git a/src/app/(main)/websites/[websiteId]/settings/WebsiteSettings.tsx b/src/app/(main)/websites/[websiteId]/settings/WebsiteSettings.tsx index baf59452..de775b22 100644 --- a/src/app/(main)/websites/[websiteId]/settings/WebsiteSettings.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/WebsiteSettings.tsx @@ -1,6 +1,6 @@ import { useContext } from 'react'; import { Tabs, TabList, Tab, TabPanel } from '@umami/react-zen'; -import { WebsiteContext } from '@/app/(main)/websites/[websiteId]/WebsiteProvider'; +import { WebsiteContext } from '@/app/(main)/websites/WebsiteProvider'; import { useMessages } from '@/components/hooks'; import { WebsiteShareForm } from './WebsiteShareForm'; import { WebsiteTrackingCode } from './WebsiteTrackingCode'; diff --git a/src/app/(main)/websites/[websiteId]/settings/WebsiteSettingsHeader.tsx b/src/app/(main)/websites/[websiteId]/settings/WebsiteSettingsHeader.tsx index ee542f2f..5f8c8536 100644 --- a/src/app/(main)/websites/[websiteId]/settings/WebsiteSettingsHeader.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/WebsiteSettingsHeader.tsx @@ -1,5 +1,5 @@ import { useContext } from 'react'; -import { WebsiteContext } from '@/app/(main)/websites/[websiteId]/WebsiteProvider'; +import { WebsiteContext } from '@/app/(main)/websites/WebsiteProvider'; import { PageHeader } from '@/components/common/PageHeader'; import { Globe } from '@/components/icons'; diff --git a/src/app/(main)/websites/[websiteId]/settings/WebsiteTransferForm.tsx b/src/app/(main)/websites/[websiteId]/settings/WebsiteTransferForm.tsx index 1545f84d..b1b3a45b 100644 --- a/src/app/(main)/websites/[websiteId]/settings/WebsiteTransferForm.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/WebsiteTransferForm.tsx @@ -11,7 +11,7 @@ import { Text, } from '@umami/react-zen'; import { useApi, useLoginQuery, useMessages, useUserTeamsQuery } from '@/components/hooks'; -import { WebsiteContext } from '@/app/(main)/websites/[websiteId]/WebsiteProvider'; +import { WebsiteContext } from '@/app/(main)/websites/WebsiteProvider'; import { ROLES } from '@/lib/constants'; export function WebsiteTransferForm({ diff --git a/src/app/share/[...shareId]/SharePage.tsx b/src/app/share/[...shareId]/SharePage.tsx index c5f734b5..ae2be609 100644 --- a/src/app/share/[...shareId]/SharePage.tsx +++ b/src/app/share/[...shareId]/SharePage.tsx @@ -1,6 +1,6 @@ 'use client'; -import { WebsiteProvider } from '@/app/(main)/websites/[websiteId]/WebsiteProvider'; -import { WebsiteDetailsPage } from '@/app/(main)/websites/[websiteId]/WebsiteDetailsPage'; +import { WebsiteProvider } from '@/app/(main)/websites/WebsiteProvider'; +import { WebsitePage } from '@/app/(main)/websites/[websiteId]/WebsitePage'; import { useShareTokenQuery } from '@/components/hooks'; import { PageBody } from '@/components/common/PageBody'; import { Header } from './Header'; @@ -17,7 +17,7 @@ export function SharePage({ shareId }) {
- +