wip event list
This commit is contained in:
@@ -173,7 +173,6 @@ export function EventListItem({
|
||||
{profile && (
|
||||
<KeyValueSubtle
|
||||
name="Profile"
|
||||
// icon={<ProfileAvatar size="xs" {...(profile ?? {})} />}
|
||||
value={getProfileName(profile)}
|
||||
href={`/${params.organizationId}/${params.projectId}/profiles/${profile.id}`}
|
||||
/>
|
||||
@@ -191,28 +190,36 @@ export function EventListItem({
|
||||
}
|
||||
image={<EventIcon name={name} />}
|
||||
>
|
||||
{propertiesList.length > 0 && (
|
||||
<div className="p-4 flex flex-col gap-4">
|
||||
<div className="font-medium">Your properties</div>
|
||||
<div className="flex flex-wrap gap-x-4 gap-y-2">
|
||||
{propertiesList.map((item) => (
|
||||
<KeyValue key={item.name} name={item.name} value={item.value} />
|
||||
))}
|
||||
<div className="p-2">
|
||||
<div className="bg-gradient-to-tr from-slate-100 to-white rounded-md">
|
||||
{propertiesList.length > 0 && (
|
||||
<div className="p-4 flex flex-col gap-4">
|
||||
<div className="font-medium">Your properties</div>
|
||||
<div className="flex flex-wrap gap-x-4 gap-y-2">
|
||||
{propertiesList.map((item) => (
|
||||
<KeyValue
|
||||
key={item.name}
|
||||
name={item.name}
|
||||
value={item.value}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="p-4 flex flex-col gap-4">
|
||||
<div className="font-medium">Properties</div>
|
||||
<div className="flex flex-wrap gap-x-4 gap-y-2">
|
||||
{keyValueList.map((item) => (
|
||||
<KeyValue
|
||||
onClick={() => item.onClick?.()}
|
||||
key={item.name}
|
||||
name={item.name}
|
||||
value={item.value}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="p-4 flex flex-col gap-4">
|
||||
<div className="font-medium">Properties</div>
|
||||
<div className="flex flex-wrap gap-x-4 gap-y-2">
|
||||
{keyValueList.map((item) => (
|
||||
<KeyValue
|
||||
onClick={item.onClick}
|
||||
key={item.name}
|
||||
name={item.name}
|
||||
value={item.value}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</ExpandableListItem>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
'use client';
|
||||
|
||||
import { FullPageEmptyState } from '@/components/FullPageEmptyState';
|
||||
import { Pagination } from '@/components/Pagination';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useCursor } from '@/hooks/useCursor';
|
||||
import { GanttChartIcon } from 'lucide-react';
|
||||
import { last } from 'ramda';
|
||||
|
||||
import { IServiceCreateEventPayload } from '@mixan/db';
|
||||
|
||||
import { EventListItem } from './event-list-item';
|
||||
|
||||
interface EventListProps {
|
||||
data: IServiceCreateEventPayload[];
|
||||
}
|
||||
export function EventList({ data }: EventListProps) {
|
||||
const { cursor, setCursor } = useCursor();
|
||||
return (
|
||||
<>
|
||||
<div className="p-4">
|
||||
{data.length === 0 ? (
|
||||
<FullPageEmptyState title="No events here" icon={GanttChartIcon}>
|
||||
{/* {filterEvents.length ? (
|
||||
<p>Could not find any events with your filter</p>
|
||||
) : (
|
||||
<p>We have not recieved any events yet</p>
|
||||
)} */}
|
||||
<p>We have not recieved any events yet</p>
|
||||
</FullPageEmptyState>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex flex-col gap-4">
|
||||
{data.map((item) => (
|
||||
<EventListItem
|
||||
key={item.createdAt.toString() + item.name + item.profileId}
|
||||
{...item}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setCursor(last(data)?.createdAt ?? null)}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { useMemo, useState } from 'react';
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { StickyBelowHeader } from '@/app/(app)/[organizationId]/[projectId]/layout-sticky-below-header';
|
||||
import { FullPageEmptyState } from '@/components/FullPageEmptyState';
|
||||
import { Pagination, usePagination } from '@/components/Pagination';
|
||||
import { ComboboxAdvanced } from '@/components/ui/combobox-advanced';
|
||||
import { GanttChartIcon } from 'lucide-react';
|
||||
import { parseAsArrayOf, parseAsString, useQueryState } from 'nuqs';
|
||||
|
||||
import { EventListItem } from './event-list-item';
|
||||
|
||||
interface ListEventsProps {
|
||||
projectId: string;
|
||||
}
|
||||
export function ListEvents({ projectId }: ListEventsProps) {
|
||||
const pagination = usePagination();
|
||||
const [eventFilters, setEventFilters] = useQueryState(
|
||||
'events',
|
||||
parseAsArrayOf(parseAsString).withDefault([])
|
||||
);
|
||||
const eventsQuery = api.event.list.useQuery({
|
||||
events: eventFilters,
|
||||
projectId: projectId,
|
||||
...pagination,
|
||||
});
|
||||
const events = useMemo(() => eventsQuery.data ?? [], [eventsQuery]);
|
||||
|
||||
const filterEventsQuery = api.chart.events.useQuery({
|
||||
projectId: projectId,
|
||||
});
|
||||
|
||||
const filterEvents = (filterEventsQuery.data ?? []).map((item) => ({
|
||||
value: item.name,
|
||||
label: item.name,
|
||||
}));
|
||||
|
||||
return (
|
||||
<>
|
||||
<StickyBelowHeader className="p-4 flex justify-between">
|
||||
<div>
|
||||
<ComboboxAdvanced
|
||||
items={filterEvents}
|
||||
value={eventFilters}
|
||||
onChange={setEventFilters}
|
||||
placeholder="Filter by event"
|
||||
/>
|
||||
</div>
|
||||
</StickyBelowHeader>
|
||||
<div className="p-4">
|
||||
{events.length === 0 ? (
|
||||
<FullPageEmptyState title="No events here" icon={GanttChartIcon}>
|
||||
{eventFilters.length ? (
|
||||
<p>Could not find any events with your filter</p>
|
||||
) : (
|
||||
<p>We have not recieved any events yet</p>
|
||||
)}
|
||||
</FullPageEmptyState>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex flex-col gap-4">
|
||||
{events.map((item) => (
|
||||
<EventListItem key={item.createdAt.toString()} {...item} />
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<Pagination {...pagination} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,22 +1,39 @@
|
||||
import { Suspense } from 'react';
|
||||
import PageLayout from '@/app/(app)/[organizationId]/[projectId]/page-layout';
|
||||
import { OverviewFiltersDrawer } from '@/components/overview/filters/overview-filters-drawer';
|
||||
import { getExists } from '@/server/pageExists';
|
||||
|
||||
import { ListEvents } from './list-events';
|
||||
import { getEventList, getEvents } from '@mixan/db';
|
||||
|
||||
import { StickyBelowHeader } from '../layout-sticky-below-header';
|
||||
import { EventList } from './event-list';
|
||||
|
||||
interface PageProps {
|
||||
params: {
|
||||
projectId: string;
|
||||
organizationId: string;
|
||||
};
|
||||
searchParams: {
|
||||
cursor?: string;
|
||||
};
|
||||
}
|
||||
export default async function Page({
|
||||
params: { projectId, organizationId },
|
||||
searchParams: { cursor },
|
||||
}: PageProps) {
|
||||
await getExists(organizationId, projectId);
|
||||
const events = await getEventList({
|
||||
cursor,
|
||||
projectId,
|
||||
take: 50,
|
||||
});
|
||||
|
||||
return (
|
||||
<PageLayout title="Events" organizationSlug={organizationId}>
|
||||
<ListEvents projectId={projectId} />
|
||||
<StickyBelowHeader className="p-4 flex justify-between">
|
||||
<OverviewFiltersDrawer projectId={projectId} />
|
||||
</StickyBelowHeader>
|
||||
<EventList data={events} />
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { Suspense } from 'react';
|
||||
import { WidgetHead } from '@/components/overview/overview-widget';
|
||||
import { useOverviewOptions } from '@/components/overview/useOverviewOptions';
|
||||
import { Chart } from '@/components/report/chart';
|
||||
import { ChartLoading } from '@/components/report/chart/ChartLoading';
|
||||
import { MetricCardLoading } from '@/components/report/chart/MetricCard';
|
||||
import { Widget, WidgetBody } from '@/components/Widget';
|
||||
import { useEventFilters } from '@/hooks/useEventQueryFilters';
|
||||
import type { IChartInput } from '@/types';
|
||||
import { cn } from '@/utils/cn';
|
||||
|
||||
@@ -15,8 +13,8 @@ interface OverviewMetricsProps {
|
||||
}
|
||||
|
||||
export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
||||
const { previous, range, interval, metric, setMetric, filters } =
|
||||
useOverviewOptions();
|
||||
const { previous, range, interval, metric, setMetric } = useOverviewOptions();
|
||||
const filters = useEventFilters();
|
||||
|
||||
const reports = [
|
||||
{
|
||||
|
||||
@@ -2,26 +2,8 @@
|
||||
|
||||
import { useOverviewOptions } from '@/components/overview/useOverviewOptions';
|
||||
import { ReportRange } from '@/components/report/ReportRange';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { SheetTrigger } from '@/components/ui/sheet';
|
||||
import { FilterIcon } from 'lucide-react';
|
||||
|
||||
export function OverviewReportRange() {
|
||||
const { previous, range, setRange, interval, metric, setMetric, filters } =
|
||||
useOverviewOptions();
|
||||
|
||||
const { range, setRange } = useOverviewOptions();
|
||||
return <ReportRange value={range} onChange={(value) => setRange(value)} />;
|
||||
}
|
||||
|
||||
export function OverviewFilterSheetTrigger() {
|
||||
const { previous, range, setRange, interval, metric, setMetric, filters } =
|
||||
useOverviewOptions();
|
||||
|
||||
return (
|
||||
<SheetTrigger asChild>
|
||||
<Button variant="outline" responsive icon={FilterIcon}>
|
||||
Filters
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import PageLayout from '@/app/(app)/[organizationId]/[projectId]/page-layout';
|
||||
import { OverviewFiltersButtons } from '@/components/overview/filters/overview-filters-buttons';
|
||||
import { OverviewFiltersDrawer } from '@/components/overview/filters/overview-filters-drawer';
|
||||
import ServerLiveCounter from '@/components/overview/live-counter';
|
||||
import { OverviewFilters } from '@/components/overview/overview-filters';
|
||||
import { OverviewFiltersButtons } from '@/components/overview/overview-filters-buttons';
|
||||
import { OverviewLiveHistogram } from '@/components/overview/overview-live-histogram';
|
||||
import { OverviewShare } from '@/components/overview/overview-share';
|
||||
import OverviewTopDevices from '@/components/overview/overview-top-devices';
|
||||
@@ -9,17 +9,13 @@ import OverviewTopEvents from '@/components/overview/overview-top-events';
|
||||
import OverviewTopGeo from '@/components/overview/overview-top-geo';
|
||||
import OverviewTopPages from '@/components/overview/overview-top-pages';
|
||||
import OverviewTopSources from '@/components/overview/overview-top-sources';
|
||||
import { Sheet, SheetContent } from '@/components/ui/sheet';
|
||||
import { getExists } from '@/server/pageExists';
|
||||
|
||||
import { db } from '@mixan/db';
|
||||
|
||||
import { StickyBelowHeader } from './layout-sticky-below-header';
|
||||
import OverviewMetrics from './overview-metrics';
|
||||
import {
|
||||
OverviewFilterSheetTrigger,
|
||||
OverviewReportRange,
|
||||
} from './overview-sticky-header';
|
||||
import { OverviewReportRange } from './overview-sticky-header';
|
||||
|
||||
interface PageProps {
|
||||
params: {
|
||||
@@ -42,37 +38,32 @@ export default async function Page({
|
||||
|
||||
return (
|
||||
<PageLayout title="Overview" organizationSlug={organizationId}>
|
||||
<Sheet>
|
||||
<StickyBelowHeader>
|
||||
<div className="p-4 flex gap-2 justify-between">
|
||||
<div className="flex gap-2">
|
||||
<OverviewReportRange />
|
||||
<OverviewFilterSheetTrigger />
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<ServerLiveCounter projectId={projectId} />
|
||||
<OverviewShare data={share} />
|
||||
</div>
|
||||
<StickyBelowHeader>
|
||||
<div className="p-4 flex gap-2 justify-between">
|
||||
<div className="flex gap-2">
|
||||
<OverviewReportRange />
|
||||
<OverviewFiltersDrawer projectId={projectId} />
|
||||
</div>
|
||||
<OverviewFiltersButtons />
|
||||
</StickyBelowHeader>
|
||||
<div className="p-4 grid gap-4 grid-cols-6">
|
||||
<div className="col-span-6">
|
||||
<OverviewLiveHistogram projectId={projectId} />
|
||||
</div>
|
||||
<OverviewMetrics projectId={projectId} />
|
||||
<OverviewTopSources projectId={projectId} />
|
||||
<OverviewTopPages projectId={projectId} />
|
||||
<OverviewTopDevices projectId={projectId} />
|
||||
<OverviewTopEvents projectId={projectId} />
|
||||
<div className="col-span-6">
|
||||
<OverviewTopGeo projectId={projectId} />
|
||||
<div className="flex gap-2">
|
||||
<ServerLiveCounter projectId={projectId} />
|
||||
<OverviewShare data={share} />
|
||||
</div>
|
||||
</div>
|
||||
<SheetContent className="!max-w-lg w-full" side="right">
|
||||
<OverviewFilters projectId={projectId} />
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
<OverviewFiltersButtons />
|
||||
</StickyBelowHeader>
|
||||
<div className="p-4 grid gap-4 grid-cols-6">
|
||||
<div className="col-span-6">
|
||||
<OverviewLiveHistogram projectId={projectId} />
|
||||
</div>
|
||||
<OverviewMetrics projectId={projectId} />
|
||||
<OverviewTopSources projectId={projectId} />
|
||||
<OverviewTopPages projectId={projectId} />
|
||||
<OverviewTopDevices projectId={projectId} />
|
||||
<OverviewTopEvents projectId={projectId} />
|
||||
<div className="col-span-6">
|
||||
<OverviewTopGeo projectId={projectId} />
|
||||
</div>
|
||||
</div>
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user