diff --git a/src/app/(main)/MobileNav.tsx b/src/app/(main)/MobileNav.tsx index a19449606..d3ff51ddc 100644 --- a/src/app/(main)/MobileNav.tsx +++ b/src/app/(main)/MobileNav.tsx @@ -1,19 +1,15 @@ -import { WebsiteNav } from '@/app/(main)/websites/[websiteId]/WebsiteNav'; -import { useMessages, useNavigation } from '@/components/hooks'; +import { Row, NavMenu, NavMenuItem, IconLabel, Text, Grid } from '@umami/react-zen'; import { Globe, Grid2x2, LinkIcon } from '@/components/icons'; -import { MobileMenuButton } from '@/components/input/MobileMenuButton'; -import { NavButton } from '@/components/input/NavButton'; -import { Logo } from '@/components/svg'; -import { Grid, IconLabel, NavMenu, NavMenuItem, Row, Text } from '@umami/react-zen'; +import { useMessages, useNavigation } from '@/components/hooks'; import Link from 'next/link'; -import { AdminNav } from './admin/AdminNav'; -import { SettingsNav } from './settings/SettingsNav'; +import { WebsiteNav } from '@/app/(main)/websites/[websiteId]/WebsiteNav'; +import { Logo } from '@/components/svg'; +import { NavButton } from '@/components/input/NavButton'; +import { MobileMenuButton } from '@/components/input/MobileMenuButton'; export function MobileNav() { const { formatMessage, labels } = useMessages(); - const { pathname, websiteId, renderUrl } = useNavigation(); - const isAdmin = pathname.includes('/admin'); - const isSettings = pathname.includes('/settings'); + const { websiteId, renderUrl } = useNavigation(); const links = [ { @@ -55,8 +51,6 @@ export function MobileNav() { })} {websiteId && } - {isAdmin && } - {isSettings && } ); }} diff --git a/src/app/(main)/admin/AdminLayout.tsx b/src/app/(main)/admin/AdminLayout.tsx index 3cc5aed39..8b1387854 100644 --- a/src/app/(main)/admin/AdminLayout.tsx +++ b/src/app/(main)/admin/AdminLayout.tsx @@ -1,32 +1,61 @@ 'use client'; -import { PageBody } from '@/components/common/PageBody'; -import { useLoginQuery } from '@/components/hooks'; -import { Column, Grid } from '@umami/react-zen'; import { ReactNode } from 'react'; -import { AdminNav } from './AdminNav'; +import { Grid, Column } from '@umami/react-zen'; +import { useLoginQuery, useMessages, useNavigation } from '@/components/hooks'; +import { User, Users, Globe } from '@/components/icons'; +import { SideMenu } from '@/components/common/SideMenu'; +import { PageBody } from '@/components/common/PageBody'; export function AdminLayout({ children }: { children: ReactNode }) { const { user } = useLoginQuery(); + const { formatMessage, labels } = useMessages(); + const { pathname } = useNavigation(); if (!user.isAdmin || process.env.cloudMode) { return null; } + const items = [ + { + label: formatMessage(labels.manage), + items: [ + { + id: 'users', + label: formatMessage(labels.users), + path: '/admin/users', + icon: , + }, + { + id: 'websites', + label: formatMessage(labels.websites), + path: '/admin/websites', + icon: , + }, + { + id: 'teams', + label: formatMessage(labels.teams), + path: '/admin/teams', + icon: , + }, + ], + }, + ]; + + const selectedKey = items + .flatMap(e => e.items) + ?.find(({ path }) => path && pathname.startsWith(path))?.id; + return ( - - - - - - {children} + + + + {children} ); } diff --git a/src/app/(main)/admin/AdminNav.tsx b/src/app/(main)/admin/AdminNav.tsx deleted file mode 100644 index 20c011554..000000000 --- a/src/app/(main)/admin/AdminNav.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { SideMenu } from '@/components/common/SideMenu'; -import { useMessages, useNavigation } from '@/components/hooks'; -import { Globe, User, Users } from '@/components/icons'; - -export function AdminNav({ onItemClick }: { onItemClick?: () => void }) { - const { formatMessage, labels } = useMessages(); - const { pathname } = useNavigation(); - - const items = [ - { - label: formatMessage(labels.manage), - items: [ - { - id: 'users', - label: formatMessage(labels.users), - path: '/admin/users', - icon: , - }, - { - id: 'websites', - label: formatMessage(labels.websites), - path: '/admin/websites', - icon: , - }, - { - id: 'teams', - label: formatMessage(labels.teams), - path: '/admin/teams', - icon: , - }, - ], - }, - ]; - - const selectedKey = items - .flatMap(e => e.items) - ?.find(({ path }) => path && pathname.startsWith(path))?.id; - - return ( - - ); -} diff --git a/src/app/(main)/admin/teams/AdminTeamsTable.tsx b/src/app/(main)/admin/teams/AdminTeamsTable.tsx index e54532583..d7c99a267 100644 --- a/src/app/(main)/admin/teams/AdminTeamsTable.tsx +++ b/src/app/(main)/admin/teams/AdminTeamsTable.tsx @@ -1,11 +1,11 @@ -import { DateDistance } from '@/components/common/DateDistance'; -import { useMessages } from '@/components/hooks'; -import { Edit, Trash } from '@/components/icons'; -import { MenuButton } from '@/components/input/MenuButton'; -import { DataColumn, DataTable, Dialog, Icon, MenuItem, Modal, Row, Text } from '@umami/react-zen'; -import { TeamDeleteForm } from '../../teams/[teamId]/TeamDeleteForm'; -import Link from 'next/link'; import { useState } from 'react'; +import { Row, Text, Icon, DataTable, DataColumn, MenuItem, Modal } from '@umami/react-zen'; +import Link from 'next/link'; +import { Trash } from '@/components/icons'; +import { useMessages } from '@/components/hooks'; +import { Edit } from '@/components/icons'; +import { MenuButton } from '@/components/input/MenuButton'; +import { DateDistance } from '@/components/common/DateDistance'; export function AdminTeamsTable({ data = [], @@ -15,7 +15,7 @@ export function AdminTeamsTable({ showActions?: boolean; }) { const { formatMessage, labels } = useMessages(); - const [deleteTeam, setDeleteTeam] = useState(null); + const [deleteUser, setDeleteUser] = useState(null); return ( <> @@ -60,7 +60,7 @@ export function AdminTeamsTable({ setDeleteTeam(id)} + onAction={() => setDeleteUser(row)} data-test="link-button-delete" > @@ -76,11 +76,7 @@ export function AdminTeamsTable({ )} - - - setDeleteTeam(null)} /> - - + ); } diff --git a/src/app/(main)/admin/users/[userId]/UserEditForm.tsx b/src/app/(main)/admin/users/[userId]/UserEditForm.tsx index 142adaa66..ac7875db0 100644 --- a/src/app/(main)/admin/users/[userId]/UserEditForm.tsx +++ b/src/app/(main)/admin/users/[userId]/UserEditForm.tsx @@ -22,7 +22,6 @@ export function UserEditForm({ userId, onSave }: { userId: string; onSave?: () = await mutateAsync(data, { onSuccess: async () => { toast(formatMessage(messages.saved)); - touch('users'); touch(`user:${user.id}`); onSave?.(); }, diff --git a/src/app/(main)/pixels/[pixelId]/PixelHeader.tsx b/src/app/(main)/pixels/[pixelId]/PixelHeader.tsx index a49729910..7e1a62b87 100644 --- a/src/app/(main)/pixels/[pixelId]/PixelHeader.tsx +++ b/src/app/(main)/pixels/[pixelId]/PixelHeader.tsx @@ -11,7 +11,7 @@ export function PixelHeader() { return ( } marginBottom="3"> - + diff --git a/src/app/(main)/settings/SettingsLayout.tsx b/src/app/(main)/settings/SettingsLayout.tsx index fc7b11e75..787d6c64c 100644 --- a/src/app/(main)/settings/SettingsLayout.tsx +++ b/src/app/(main)/settings/SettingsLayout.tsx @@ -1,10 +1,50 @@ 'use client'; import { PageBody } from '@/components/common/PageBody'; +import { SideMenu } from '@/components/common/SideMenu'; +import { useMessages, useNavigation } from '@/components/hooks'; +import { Settings2, UserCircle, Users } from '@/components/icons'; import { Column, Grid } from '@umami/react-zen'; import { ReactNode } from 'react'; -import { SettingsNav } from './SettingsNav'; export function SettingsLayout({ children }: { children: ReactNode }) { + const { formatMessage, labels } = useMessages(); + const { renderUrl, pathname } = useNavigation(); + + const items = [ + { + label: formatMessage(labels.application), + items: [ + { + id: 'preferences', + label: formatMessage(labels.preferences), + path: renderUrl('/settings/preferences'), + icon: , + }, + ], + }, + { + label: formatMessage(labels.account), + items: [ + { + id: 'profile', + label: formatMessage(labels.profile), + path: renderUrl('/settings/profile'), + icon: , + }, + { + id: 'teams', + label: formatMessage(labels.teams), + path: renderUrl('/settings/teams'), + icon: , + }, + ], + }, + ]; + + const selectedKey = items + .flatMap(e => e.items) + .find(({ path }) => path && pathname.includes(path.split('?')[0]))?.id; + return ( - + {children} diff --git a/src/app/(main)/settings/SettingsNav.tsx b/src/app/(main)/settings/SettingsNav.tsx deleted file mode 100644 index 4b35c82bd..000000000 --- a/src/app/(main)/settings/SettingsNav.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { SideMenu } from '@/components/common/SideMenu'; -import { useMessages, useNavigation } from '@/components/hooks'; -import { Settings2, UserCircle, Users } from '@/components/icons'; - -export function SettingsNav({ onItemClick }: { onItemClick?: () => void }) { - const { formatMessage, labels } = useMessages(); - const { renderUrl, pathname } = useNavigation(); - - const items = [ - { - label: formatMessage(labels.application), - items: [ - { - id: 'preferences', - label: formatMessage(labels.preferences), - path: renderUrl('/settings/preferences'), - icon: , - }, - ], - }, - { - label: formatMessage(labels.account), - items: [ - { - id: 'profile', - label: formatMessage(labels.profile), - path: renderUrl('/settings/profile'), - icon: , - }, - { - id: 'teams', - label: formatMessage(labels.teams), - path: renderUrl('/settings/teams'), - icon: , - }, - ], - }, - ]; - - const selectedKey = items - .flatMap(e => e.items) - .find(({ path }) => path && pathname.includes(path.split('?')[0]))?.id; - - return ( - - ); -} diff --git a/src/app/(main)/teams/[teamId]/TeamDeleteForm.tsx b/src/app/(main)/teams/[teamId]/TeamDeleteForm.tsx index 7adc9b341..cf1ce6188 100644 --- a/src/app/(main)/teams/[teamId]/TeamDeleteForm.tsx +++ b/src/app/(main)/teams/[teamId]/TeamDeleteForm.tsx @@ -19,7 +19,6 @@ export function TeamDeleteForm({ await mutateAsync(null, { onSuccess: async () => { touch('teams'); - touch(`teams:${teamId}`); onSave?.(); onClose?.(); }, diff --git a/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx index e73ce10ef..eff072fde 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx @@ -1,27 +1,23 @@ 'use client'; -import { FieldSelectForm } from '@/app/(main)/websites/[websiteId]/(reports)/breakdown/FieldSelectForm'; -import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls'; -import { Panel } from '@/components/common/Panel'; -import { useDateRange, useMessages, useMobile } from '@/components/hooks'; -import { ListCheck } from '@/components/icons'; -import { DialogButton } from '@/components/input/DialogButton'; -import { Column, Row } from '@umami/react-zen'; import { useState } from 'react'; +import { Button, Column, Box, DialogTrigger, Popover, Dialog, IconLabel } from '@umami/react-zen'; +import { useDateRange, useMessages } from '@/components/hooks'; +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'; export function BreakdownPage({ websiteId }: { websiteId: string }) { const { dateRange: { startDate, endDate }, } = useDateRange(); const [fields, setFields] = useState(['path']); - const { isMobile } = useMobile(); return ( - - - + { const { formatMessage, labels } = useMessages(); return ( - } - label={formatMessage(labels.fields)} - width="800px" - minHeight="300px" - > - {({ close }) => { - return ; - }} - + + + + + + {({ close }) => ( + + )} + + + + ); }; diff --git a/src/app/(main)/websites/[websiteId]/cohorts/CohortAddButton.tsx b/src/app/(main)/websites/[websiteId]/cohorts/CohortAddButton.tsx index 737ab502c..53bab8a15 100644 --- a/src/app/(main)/websites/[websiteId]/cohorts/CohortAddButton.tsx +++ b/src/app/(main)/websites/[websiteId]/cohorts/CohortAddButton.tsx @@ -12,7 +12,7 @@ export function CohortAddButton({ websiteId }: { websiteId: string }) { label={formatMessage(labels.cohort)} variant="primary" width="800px" - height="calc(100dvh - 40px)" + minHeight="300px" > {({ close }) => { return ; diff --git a/src/app/(main)/websites/[websiteId]/cohorts/CohortEditButton.tsx b/src/app/(main)/websites/[websiteId]/cohorts/CohortEditButton.tsx index 48944677d..693f31d77 100644 --- a/src/app/(main)/websites/[websiteId]/cohorts/CohortEditButton.tsx +++ b/src/app/(main)/websites/[websiteId]/cohorts/CohortEditButton.tsx @@ -21,7 +21,7 @@ export function CohortEditButton({ variant="quiet" title={formatMessage(labels.cohort)} width="800px" - height="calc(100dvh - 40px)" + minHeight="300px" > {({ close }) => { return ( diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentAddButton.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentAddButton.tsx index aed63ac68..052d3185b 100644 --- a/src/app/(main)/websites/[websiteId]/segments/SegmentAddButton.tsx +++ b/src/app/(main)/websites/[websiteId]/segments/SegmentAddButton.tsx @@ -12,7 +12,6 @@ export function SegmentAddButton({ websiteId }: { websiteId: string }) { label={formatMessage(labels.segment)} variant="primary" width="800px" - height="calc(100dvh - 40px)" > {({ close }) => { return ; diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentEditButton.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentEditButton.tsx index 8c025772b..6d422c95b 100644 --- a/src/app/(main)/websites/[websiteId]/segments/SegmentEditButton.tsx +++ b/src/app/(main)/websites/[websiteId]/segments/SegmentEditButton.tsx @@ -21,7 +21,6 @@ export function SegmentEditButton({ title={formatMessage(labels.segment)} variant="quiet" width="800px" - height="calc(100dvh - 40px)" > {({ close }) => { return ( diff --git a/src/app/(main)/websites/[websiteId]/settings/WebsiteEditForm.tsx b/src/app/(main)/websites/[websiteId]/settings/WebsiteEditForm.tsx index c7cb3d89f..50598199a 100644 --- a/src/app/(main)/websites/[websiteId]/settings/WebsiteEditForm.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/WebsiteEditForm.tsx @@ -11,7 +11,6 @@ export function WebsiteEditForm({ websiteId, onSave }: { websiteId: string; onSa await mutateAsync(data, { onSuccess: async () => { toast(formatMessage(messages.saved)); - touch('websites'); touch(`website:${website.id}`); onSave?.(); }, diff --git a/src/app/api/links/[linkId]/route.ts b/src/app/api/links/[linkId]/route.ts index 512f39c96..cd93b9c64 100644 --- a/src/app/api/links/[linkId]/route.ts +++ b/src/app/api/links/[linkId]/route.ts @@ -24,9 +24,9 @@ export async function GET(request: Request, { params }: { params: Promise<{ link export async function POST(request: Request, { params }: { params: Promise<{ linkId: string }> }) { const schema = z.object({ - name: z.string().optional(), - url: z.string().optional(), - slug: z.string().min(8).optional(), + name: z.string(), + url: z.string(), + slug: z.string(), }); const { auth, body, error } = await parseRequest(request, schema); diff --git a/src/app/api/pixels/[pixelId]/route.ts b/src/app/api/pixels/[pixelId]/route.ts index 2f547c04f..0788579f1 100644 --- a/src/app/api/pixels/[pixelId]/route.ts +++ b/src/app/api/pixels/[pixelId]/route.ts @@ -24,8 +24,8 @@ export async function GET(request: Request, { params }: { params: Promise<{ pixe export async function POST(request: Request, { params }: { params: Promise<{ pixelId: string }> }) { const schema = z.object({ - name: z.string().optional(), - slug: z.string().min(8).optional(), + name: z.string(), + slug: z.string().min(8), }); const { auth, body, error } = await parseRequest(request, schema); diff --git a/src/app/api/send/route.ts b/src/app/api/send/route.ts index f5e00c8aa..3e5699889 100644 --- a/src/app/api/send/route.ts +++ b/src/app/api/send/route.ts @@ -82,8 +82,6 @@ export async function POST(request: Request) { id, } = payload; - const sourceId = websiteId || pixelId || linkId; - // Cache check let cache: Cache | null = null; @@ -130,13 +128,13 @@ export async function POST(request: Request) { const sessionSalt = hash(startOfMonth(createdAt).toUTCString()); const visitSalt = hash(startOfHour(createdAt).toUTCString()); - const sessionId = id ? uuid(sourceId, id) : uuid(sourceId, ip, userAgent, sessionSalt); + const sessionId = id ? uuid(websiteId, id) : uuid(websiteId, ip, userAgent, sessionSalt); // Create a session if not found if (!clickhouse.enabled && !cache?.sessionId) { await createSession({ id: sessionId, - websiteId: sourceId, + websiteId, browser, os, device, @@ -208,7 +206,7 @@ export async function POST(request: Request) { : EVENT_TYPE.pageView; await saveEvent({ - websiteId: sourceId, + websiteId: websiteId || linkId || pixelId, sessionId, visitId, eventType, @@ -272,9 +270,6 @@ export async function POST(request: Request) { } catch (e) { const error = serializeError(e); - // eslint-disable-next-line no-console - console.log(error); - return serverError({ errorObject: error }); } } diff --git a/src/components/common/LinkButton.tsx b/src/components/common/LinkButton.tsx index 251f77626..ca1baccbc 100644 --- a/src/components/common/LinkButton.tsx +++ b/src/components/common/LinkButton.tsx @@ -8,7 +8,6 @@ export interface LinkButtonProps extends ButtonProps { target?: string; scroll?: boolean; variant?: any; - prefetch?: boolean; children?: ReactNode; } @@ -17,7 +16,6 @@ export function LinkButton({ variant, scroll = true, target, - prefetch, children, ...props }: LinkButtonProps) { @@ -25,7 +23,7 @@ export function LinkButton({ return ( diff --git a/src/components/hooks/useMobile.ts b/src/components/hooks/useMobile.ts index 6b40f3da1..e3afc5ee6 100644 --- a/src/components/hooks/useMobile.ts +++ b/src/components/hooks/useMobile.ts @@ -3,7 +3,6 @@ import { useBreakpoint } from '@umami/react-zen'; export function useMobile() { const breakpoint = useBreakpoint(); const isMobile = ['xs', 'sm', 'md'].includes(breakpoint); - const isPhone = ['xs', 'sm'].includes(breakpoint); - return { breakpoint, isMobile, isPhone }; + return { breakpoint, isMobile }; } diff --git a/src/components/metrics/ListTable.tsx b/src/components/metrics/ListTable.tsx index 303556b01..3aef2b287 100644 --- a/src/components/metrics/ListTable.tsx +++ b/src/components/metrics/ListTable.tsx @@ -42,7 +42,7 @@ export function ListTable({ currency, }: ListTableProps) { const { formatMessage, labels } = useMessages(); - const { isPhone } = useMobile(); + const { isMobile } = useMobile(); const getRow = (row: ListData, index: number) => { const { label, count, percent } = row; @@ -57,7 +57,7 @@ export function ListTable({ showPercentage={showPercentage} change={renderChange ? renderChange(row, index) : null} currency={currency} - isMobile={isPhone} + isMobile={isMobile} /> ); }; diff --git a/src/queries/sql/events/getEventDataValues.ts b/src/queries/sql/events/getEventDataValues.ts index e1975e2e4..ad7dd1a37 100644 --- a/src/queries/sql/events/getEventDataValues.ts +++ b/src/queries/sql/events/getEventDataValues.ts @@ -47,6 +47,7 @@ async function relationalQuery( where event_data.website_id = {{websiteId::uuid}} and event_data.created_at between {{startDate}} and {{endDate}} and event_data.data_key = {{propertyName}} + and website_event.event_name = {{eventName}} ${filterQuery} group by value order by 2 desc