diff --git a/src/app/(main)/SideNav.tsx b/src/app/(main)/SideNav.tsx
index 53932bec..2ca497d5 100644
--- a/src/app/(main)/SideNav.tsx
+++ b/src/app/(main)/SideNav.tsx
@@ -1,5 +1,14 @@
+import { ReactNode } from 'react';
import Link from 'next/link';
-import { Sidebar, SidebarHeader, SidebarSection, SidebarItem } from '@umami/react-zen';
+import {
+ Sidebar,
+ SidebarHeader,
+ SidebarSection,
+ SidebarItem,
+ Button,
+ Icon,
+ Row,
+} from '@umami/react-zen';
import {
Globe,
LayoutDashboard,
@@ -8,62 +17,209 @@ import {
Grid2X2,
Settings,
LockKeyhole,
+ PanelLeft,
+ Eye,
+ Lightning,
+ User,
+ Clock,
+ Target,
+ Funnel,
+ Path,
+ Magnet,
+ Tag,
+ Money,
+ Network,
+ Arrow,
+ Sheet,
} from '@/components/icons';
import { useMessages, useNavigation, useGlobalState } from '@/components/hooks';
+import { LinkButton } from '@/components/common/LinkButton';
+
+type NavLink = {
+ id: string;
+ label: string;
+ path: string;
+ icon: ReactNode;
+};
export function SideNav(props: any) {
const { formatMessage, labels } = useMessages();
- const { renderUrl, pathname } = useNavigation();
- const [isCollapsed] = useGlobalState('sidenav-collapsed');
+ const { websiteId, pathname, renderUrl } = useNavigation();
+ const [isCollapsed, setCollapsed] = useGlobalState('sidenav-collapsed');
+ const isWebsite = websiteId && !pathname.includes('/settings');
const links = [
{
+ id: 'websites',
label: formatMessage(labels.websites),
- href: renderUrl('/websites', false),
+ path: '/websites',
icon: ,
},
{
+ id: 'boards',
label: formatMessage(labels.boards),
- href: renderUrl('/boards', false),
+ path: '/boards',
icon: ,
},
{
+ id: 'links',
label: formatMessage(labels.links),
- href: renderUrl('/links', false),
+ path: '/links',
icon: ,
},
{
+ id: 'pixels',
label: formatMessage(labels.pixels),
- href: renderUrl('/pixels', false),
+ path: '/pixels',
icon: ,
},
+ ];
+
+ const websiteLinks = [
{
+ id: 'overview',
+ label: formatMessage(labels.overview),
+ icon: ,
+ path: '/',
+ },
+ {
+ id: 'events',
+ label: formatMessage(labels.events),
+ icon: ,
+ path: '/events',
+ },
+ {
+ id: 'sessions',
+ label: formatMessage(labels.sessions),
+ icon: ,
+ path: '/sessions',
+ },
+ {
+ id: 'realtime',
+ label: formatMessage(labels.realtime),
+ icon: ,
+ path: '/realtime',
+ },
+ {
+ id: 'breakdown',
+ label: formatMessage(labels.breakdown),
+ icon: ,
+ path: '/breakdown',
+ },
+ {
+ id: 'goals',
+ label: formatMessage(labels.goals),
+ icon: ,
+ path: '/goals',
+ },
+ {
+ id: 'funnel',
+ label: formatMessage(labels.funnels),
+ icon: ,
+ path: '/funnels',
+ },
+ {
+ id: 'journeys',
+ label: formatMessage(labels.journeys),
+ icon: ,
+ path: '/journeys',
+ },
+ {
+ id: 'retention',
+ label: formatMessage(labels.retention),
+ icon: ,
+ path: '/retention',
+ },
+ {
+ id: 'utm',
+ label: formatMessage(labels.utm),
+ icon: ,
+ path: '/utm',
+ },
+ {
+ id: 'revenue',
+ label: formatMessage(labels.revenue),
+ icon: ,
+ path: '/revenue',
+ },
+ {
+ id: 'attribution',
+ label: formatMessage(labels.attribution),
+ icon: ,
+ path: '/attribution',
+ },
+ ];
+
+ const bottomLinks = [
+ {
+ id: 'settings',
label: formatMessage(labels.settings),
- href: '/settings',
+ path: '/settings',
icon: ,
},
{
+ id: 'admin',
label: formatMessage(labels.admin),
- href: '/admin',
+ path: '/admin',
icon: ,
},
- ].filter(n => n);
+ ];
return (
-
+
} />
-
- {links.map(({ href, label, icon }) => {
- return (
-
-
-
- );
- })}
+
+ {!isWebsite && }
+ {isWebsite && (
+ <>
+
+
+
+
+
+
+
+
+ >
+ )}
+
+
+ {!isWebsite && }
+
+
+
+
+
- {``}
);
}
+
+const NavItems = ({
+ items,
+ prefix = '',
+ params,
+}: {
+ items: NavLink[];
+ prefix?: string;
+ params?: Record | false;
+}) => {
+ const { renderUrl, pathname, websiteId } = useNavigation();
+
+ return items.map(({ id, path, label, icon }) => {
+ const isSelected = websiteId
+ ? (path === '/' && pathname.endsWith(websiteId)) || pathname.endsWith(path)
+ : pathname.startsWith(path);
+ return (
+
+
+
+ );
+ });
+};
diff --git a/src/app/(main)/TopNav.tsx b/src/app/(main)/TopNav.tsx
index 550e3e5e..db1eefdb 100644
--- a/src/app/(main)/TopNav.tsx
+++ b/src/app/(main)/TopNav.tsx
@@ -1,13 +1,12 @@
-import { ThemeButton, Row, Button, Icon } from '@umami/react-zen';
+import { ThemeButton, Row, Icon } from '@umami/react-zen';
import { LanguageButton } from '@/components/input/LanguageButton';
import { ProfileButton } from '@/components/input/ProfileButton';
import { TeamsButton } from '@/components/input/TeamsButton';
import { WebsiteSelect } from '@/components/input/WebsiteSelect';
-import { PanelLeft, Slash } from '@/components/icons';
-import { useNavigation, useGlobalState } from '@/components/hooks';
+import { Slash } from '@/components/icons';
+import { useNavigation } from '@/components/hooks';
export function TopNav() {
- const [isCollapsed, setCollapsed] = useGlobalState('sidenav-collapsed');
const { teamId, websiteId, pathname } = useNavigation();
const isSettings = pathname.includes('/settings');
@@ -22,11 +21,6 @@ export function TopNav() {
width="100%"
>
-
{websiteId && !isSettings && (
diff --git a/src/app/(main)/websites/[websiteId]/reports/attribution/Attribution.tsx b/src/app/(main)/websites/[websiteId]/(reports)/attribution/Attribution.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/attribution/Attribution.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/attribution/Attribution.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/attribution/AttributionPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/attribution/AttributionPage.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/attribution/AttributionPage.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/attribution/AttributionPage.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/attribution/page.tsx b/src/app/(main)/websites/[websiteId]/(reports)/attribution/page.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/attribution/page.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/attribution/page.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/breakdown/Breakdown.tsx b/src/app/(main)/websites/[websiteId]/(reports)/breakdown/Breakdown.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/breakdown/Breakdown.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/breakdown/Breakdown.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/breakdown/BreakdownPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx
similarity index 97%
rename from src/app/(main)/websites/[websiteId]/reports/breakdown/BreakdownPage.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx
index 993b6aab..58aa55a6 100644
--- a/src/app/(main)/websites/[websiteId]/reports/breakdown/BreakdownPage.tsx
+++ b/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx
@@ -6,7 +6,7 @@ import { ListCheck } from '@/components/icons';
import { Panel } from '@/components/common/Panel';
import { Breakdown } from './Breakdown';
import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls';
-import { FieldSelectForm } from '@/app/(main)/websites/[websiteId]/reports/breakdown/FieldSelectForm';
+import { FieldSelectForm } from '@/app/(main)/websites/[websiteId]/(reports)/breakdown/FieldSelectForm';
export function BreakdownPage({ websiteId }: { websiteId: string }) {
const {
diff --git a/src/app/(main)/websites/[websiteId]/reports/breakdown/FieldSelectForm.tsx b/src/app/(main)/websites/[websiteId]/(reports)/breakdown/FieldSelectForm.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/breakdown/FieldSelectForm.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/breakdown/FieldSelectForm.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/breakdown/page.tsx b/src/app/(main)/websites/[websiteId]/(reports)/breakdown/page.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/breakdown/page.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/breakdown/page.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/funnels/Funnel.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/funnels/Funnel.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/funnels/FunnelAddButton.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelAddButton.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/funnels/FunnelAddButton.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelAddButton.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/funnels/FunnelEditForm.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelEditForm.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/funnels/FunnelEditForm.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelEditForm.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/funnels/FunnelsPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/funnels/FunnelsPage.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/funnels/page.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/page.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/funnels/page.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/funnels/page.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/goals/Goal.tsx b/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/goals/Goal.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/goals/GoalAddButton.tsx b/src/app/(main)/websites/[websiteId]/(reports)/goals/GoalAddButton.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/goals/GoalAddButton.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/goals/GoalAddButton.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/goals/GoalEditForm.tsx b/src/app/(main)/websites/[websiteId]/(reports)/goals/GoalEditForm.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/goals/GoalEditForm.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/goals/GoalEditForm.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/goals/GoalsPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/goals/GoalsPage.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/goals/GoalsPage.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/goals/GoalsPage.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/goals/page.tsx b/src/app/(main)/websites/[websiteId]/(reports)/goals/page.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/goals/page.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/goals/page.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/journeys/Journey.module.css b/src/app/(main)/websites/[websiteId]/(reports)/journeys/Journey.module.css
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/journeys/Journey.module.css
rename to src/app/(main)/websites/[websiteId]/(reports)/journeys/Journey.module.css
diff --git a/src/app/(main)/websites/[websiteId]/reports/journeys/Journey.tsx b/src/app/(main)/websites/[websiteId]/(reports)/journeys/Journey.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/journeys/Journey.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/journeys/Journey.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/journeys/JourneysPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/journeys/JourneysPage.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/journeys/JourneysPage.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/journeys/JourneysPage.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/journeys/page.tsx b/src/app/(main)/websites/[websiteId]/(reports)/journeys/page.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/journeys/page.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/journeys/page.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/page.tsx b/src/app/(main)/websites/[websiteId]/(reports)/page.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/page.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/page.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/retention/Retention.tsx b/src/app/(main)/websites/[websiteId]/(reports)/retention/Retention.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/retention/Retention.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/retention/Retention.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/retention/RetentionPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/retention/RetentionPage.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/retention/RetentionPage.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/retention/RetentionPage.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/retention/page.tsx b/src/app/(main)/websites/[websiteId]/(reports)/retention/page.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/retention/page.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/retention/page.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/revenue/Revenue.tsx b/src/app/(main)/websites/[websiteId]/(reports)/revenue/Revenue.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/revenue/Revenue.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/revenue/Revenue.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/revenue/RevenuePage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/revenue/RevenuePage.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/revenue/RevenuePage.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/revenue/RevenuePage.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/revenue/RevenueTable.tsx b/src/app/(main)/websites/[websiteId]/(reports)/revenue/RevenueTable.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/revenue/RevenueTable.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/revenue/RevenueTable.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/revenue/page.tsx b/src/app/(main)/websites/[websiteId]/(reports)/revenue/page.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/revenue/page.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/revenue/page.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/utm/UTM.tsx b/src/app/(main)/websites/[websiteId]/(reports)/utm/UTM.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/utm/UTM.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/utm/UTM.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/utm/UTMPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/utm/UTMPage.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/utm/UTMPage.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/utm/UTMPage.tsx
diff --git a/src/app/(main)/websites/[websiteId]/reports/utm/page.tsx b/src/app/(main)/websites/[websiteId]/(reports)/utm/page.tsx
similarity index 100%
rename from src/app/(main)/websites/[websiteId]/reports/utm/page.tsx
rename to src/app/(main)/websites/[websiteId]/(reports)/utm/page.tsx
diff --git a/src/app/(main)/websites/[websiteId]/events/EventsTable.tsx b/src/app/(main)/websites/[websiteId]/events/EventsTable.tsx
index c034c9ea..d0ea43e3 100644
--- a/src/app/(main)/websites/[websiteId]/events/EventsTable.tsx
+++ b/src/app/(main)/websites/[websiteId]/events/EventsTable.tsx
@@ -1,4 +1,4 @@
-import { DataTable, DataColumn, Icon, Row } from '@umami/react-zen';
+import { DataTable, DataColumn, Icon, Row, Text } from '@umami/react-zen';
import { useFormat, useMessages, useNavigation } from '@/components/hooks';
import { Empty } from '@/components/common/Empty';
import { Avatar } from '@/components/common/Avatar';
@@ -21,13 +21,17 @@ export function EventsTable({ data = [] }) {
{(row: any) => {
return (
-
+
{row.eventName ? : }
- {formatMessage(row.eventName ? labels.triggeredEvent : labels.viewedPage)}
- {row.eventName || row.urlPath}
+
+ {formatMessage(row.eventName ? labels.triggeredEvent : labels.viewedPage)}
+
+
+ {row.eventName || row.urlPath}
+
);
}}
@@ -39,14 +43,14 @@ export function EventsTable({ data = [] }) {
)}
-
+
{(row: any) => (
{formatValue(row.browser, 'browser')}
)}
-
+
{(row: any) => (
{formatValue(row.device, 'device')}
diff --git a/src/app/(main)/websites/[websiteId]/reports/ReportsLayout.tsx b/src/app/(main)/websites/[websiteId]/reports/ReportsLayout.tsx
deleted file mode 100644
index 70e33146..00000000
--- a/src/app/(main)/websites/[websiteId]/reports/ReportsLayout.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-'use client';
-import { ReactNode } from 'react';
-import { Grid, Column } from '@umami/react-zen';
-import { ReportsNav } from './ReportsNav';
-
-export function ReportsLayout({ websiteId, children }: { websiteId: string; children: ReactNode }) {
- return (
-
-
-
-
- {children}
-
- );
-}
diff --git a/src/app/(main)/websites/[websiteId]/reports/ReportsNav.tsx b/src/app/(main)/websites/[websiteId]/reports/ReportsNav.tsx
deleted file mode 100644
index 3741bc53..00000000
--- a/src/app/(main)/websites/[websiteId]/reports/ReportsNav.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import { Row, NavMenu, NavMenuItem, Icon, Text } from '@umami/react-zen';
-import { useMessages, useNavigation } from '@/components/hooks';
-import { Funnel, Sheet, Magnet, Money, Network, Path, Tag, Target } from '@/components/icons';
-import Link from 'next/link';
-
-export function ReportsNav({ websiteId }: { websiteId: string }) {
- const { formatMessage, labels } = useMessages();
- const { pathname, renderUrl } = useNavigation();
-
- const links = [
- {
- id: 'goals',
- label: formatMessage(labels.goals),
- icon: ,
- path: '/goals',
- },
- {
- id: 'funnel',
- label: formatMessage(labels.funnels),
- icon: ,
- path: '/funnels',
- },
- {
- id: 'journeys',
- label: formatMessage(labels.journeys),
- icon: ,
- path: '/journeys',
- },
- {
- id: 'retention',
- label: formatMessage(labels.retention),
- icon: ,
- path: '/retention',
- },
- {
- id: 'breakdown',
- label: formatMessage(labels.breakdown),
- icon: ,
- path: '/breakdown',
- },
- {
- id: 'utm',
- label: formatMessage(labels.utm),
- icon: ,
- path: '/utm',
- },
- {
- id: 'revenue',
- label: formatMessage(labels.revenue),
- icon: ,
- path: '/revenue',
- },
- {
- id: 'attribution',
- label: formatMessage(labels.attribution),
- icon: ,
- path: '/attribution',
- },
- ];
-
- const selected = links.find(({ path }) => path && pathname.endsWith(path))?.id || 'goals';
-
- return (
-
- {links.map(({ id, label, icon, path }) => {
- const isSelected = selected === id;
-
- return (
-
-
-
- {icon}
- {label}
-
-
-
- );
- })}
-
- );
-}
diff --git a/src/app/(main)/websites/[websiteId]/reports/layout.tsx b/src/app/(main)/websites/[websiteId]/reports/layout.tsx
deleted file mode 100644
index ced1c684..00000000
--- a/src/app/(main)/websites/[websiteId]/reports/layout.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import { Metadata } from 'next';
-import { ReportsLayout } from './ReportsLayout';
-
-export default async function ({
- children,
- params,
-}: {
- children: any;
- params: Promise<{ websiteId: string }>;
-}) {
- const { websiteId } = await params;
-
- return {children};
-}
-
-export const metadata: Metadata = {
- title: {
- template: '%s | Umami',
- default: 'Websites | Umami',
- },
-};