import { ReportChartShortcut } from '@/components/report-chart/shortcut'; import { useEventQueryFilters, useEventQueryNamesFilter, } from '@/hooks/use-event-query-filters'; import { ProjectLink } from '@/components/links'; import { WidgetButtons, WidgetHead, } from '@/components/overview/overview-widget'; import { SerieIcon } from '@/components/report-chart/common/serie-icon'; import { Button } from '@/components/ui/button'; import { FieldValue, KeyValueGrid } from '@/components/ui/key-value-grid'; import { Widget, WidgetBody } from '@/components/widget'; import { fancyMinutes } from '@/hooks/use-numer-formatter'; import { useTRPC } from '@/integrations/trpc/react'; import { cn } from '@/utils/cn'; import { getProfileName } from '@/utils/getters'; import type { IClickhouseEvent, IServiceEvent } from '@openpanel/db'; import { useSuspenseQuery } from '@tanstack/react-query'; import { FilterIcon, XIcon } from 'lucide-react'; import { omit } from 'ramda'; import { Suspense, useState } from 'react'; import { popModal } from '.'; import { ModalContent } from './Modal/Container'; interface Props { id: string; createdAt?: Date; projectId: string; } const filterable: Partial> = { name: 'name', referrer: 'referrer', referrerName: 'referrer_name', referrerType: 'referrer_type', brand: 'brand', model: 'model', browser: 'browser', browserVersion: 'browser_version', os: 'os', osVersion: 'os_version', city: 'city', region: 'region', country: 'country', device: 'device', properties: 'properties', path: 'path', origin: 'origin', }; export default function EventDetails(props: Props) { return ( }> ); } function EventDetailsContent({ id, createdAt, projectId }: Props) { const [, setEvents] = useEventQueryNamesFilter(); const [, setFilter] = useEventQueryFilters(); const TABS = { essentials: { id: 'essentials', title: 'Essentials', }, detailed: { id: 'detailed', title: 'Detailed', }, }; const [widget, setWidget] = useState(TABS.essentials); const trpc = useTRPC(); const query = useSuspenseQuery( trpc.event.details.queryOptions({ id, projectId, createdAt, }), ); const { event, session } = query.data; const profile = event.profile; const data = (() => { const data: { name: keyof IServiceEvent | string; value: any; event: IServiceEvent; }[] = [ { name: 'createdAt', value: event.createdAt, }, { name: 'name', value: event.name, }, { name: 'origin', value: event.origin, }, { name: 'path', value: event.path, }, { name: 'country', value: event.country, }, { name: 'region', value: event.region, }, { name: 'city', value: event.city, }, { name: 'referrer', value: event.referrer, }, { name: 'referrerName', value: event.referrerName, }, { name: 'referrerType', value: event.referrerType, }, { name: 'brand', value: event.brand, }, { name: 'model', value: event.model, }, ].map((item) => ({ ...item, event })); if (widget.id === TABS.detailed.id) { data.length = 0; Object.entries(omit(['properties', 'profile', 'meta'], event)).forEach( ([name, value]) => { if (!name.startsWith('__')) { data.push({ name: name as keyof IServiceEvent, value: value as any, event, }); } }, ); } return data.filter((item) => { if (widget.id === TABS.essentials.id) { return !!item.value; } return true; }); })(); const properties = Object.entries(event.properties) .filter(([name]) => !name.startsWith('__')) .map(([name, value]) => ({ name, value, event, })); return ( <>
{event.name}
{/* */}
{Object.entries(TABS).map(([, tab]) => ( ))}
{profile && ( popModal()} href={`/profiles/${profile.id}`} className="card p-4 py-2 col gap-2 hover:bg-def-100" >
{profile.avatar && ( )}
{getProfileName(profile, false)}
{event.referrerName || event.referrer}
{!!session && (
This session has {session.screenViewCount} screen views and{' '} {session.eventCount} events. Visit duration is{' '} {fancyMinutes(session.duration / 1000)}.
)}
)} {properties.length > 0 && (
Properties
(
{String(item.value)}
)} onItemClick={(item) => { popModal(); setFilter(`properties.${item.name}`, item.value as any); }} />
)}
Information
{ const isFilterable = item.value && (filterable as any)[item.name]; if (isFilterable) { return (
); } return ( ); }} onItemClick={(item) => { const isFilterable = item.value && (filterable as any)[item.name]; if (isFilterable) { popModal(); setFilter(item.name as keyof IServiceEvent, item.value); } }} />
All events for {event.name}
); } function EventDetailsSkeleton() { return ( <>
{/* Profile skeleton */}
{/* Properties skeleton */}
{Array.from({ length: 3 }).map((_, i) => (
))}
{/* Information skeleton */}
{Array.from({ length: 6 }).map((_, i) => (
))}
{/* Chart skeleton */}
); }