improve profile page

This commit is contained in:
Carl-Gerhard Lindesvärd
2024-05-07 23:27:31 +02:00
parent bc54801ad3
commit ab367cf4db
14 changed files with 85 additions and 127 deletions

View File

@@ -30,7 +30,7 @@ interface EventListProps {
count: number;
}
export function EventList({ data, count }: EventListProps) {
const { cursor, setCursor } = useCursor();
const { cursor, setCursor, loading } = useCursor();
const [filters] = useEventQueryFilters();
return (
<>
@@ -77,6 +77,7 @@ export function EventList({ data, count }: EventListProps) {
setCursor={setCursor}
count={count}
take={50}
loading={loading}
/>
)}
</div>
@@ -92,6 +93,7 @@ export function EventList({ data, count }: EventListProps) {
setCursor={setCursor}
count={count}
take={50}
loading={loading}
/>
</>
)}

View File

@@ -1,3 +0,0 @@
import FullPageLoadingState from '@/components/full-page-loading-state';
export default FullPageLoadingState;

View File

@@ -1,4 +1,4 @@
import { useMemo } from 'react';
import { Suspense, useMemo } from 'react';
import PageLayout from '@/app/(app)/[organizationSlug]/[projectId]/page-layout';
import { ListPropertiesIcon } from '@/components/events/list-properties-icon';
import { OverviewFiltersButtons } from '@/components/overview/filters/overview-filters-buttons';
@@ -64,12 +64,7 @@ export default async function Page({
};
const startDate = parseAsString.parseServerSide(searchParams.startDate);
const endDate = parseAsString.parseServerSide(searchParams.endDate);
const [profile, events, count, metrics] = await Promise.all([
getProfileById(profileId, projectId),
getEventList(eventListOptions),
getEventsCount(eventListOptions),
getProfileMetrics(profileId, projectId),
]);
const profile = await getProfileById(profileId, projectId);
const pageViewsChart: IChartInput = {
projectId,
@@ -148,11 +143,11 @@ export default async function Page({
return (
<>
<PageLayout organizationSlug={organizationSlug} title={<div />} />
<StickyBelowHeader className="!relative !top-auto !z-0 flex items-center gap-8 p-8">
<StickyBelowHeader className="!relative !top-auto !z-0 flex flex-col gap-8 p-4 md:flex-row md:items-center md:p-8">
<div className="flex flex-1 gap-4">
<ProfileAvatar {...profile} size={'lg'} />
<div className="">
<h1 className="text-2xl font-semibold">
<div className="min-w-0">
<h1 className="max-w-full overflow-hidden text-ellipsis break-words text-lg font-semibold md:max-w-sm md:whitespace-nowrap md:text-2xl">
{getProfileName(profile)}
</h1>
<div className="flex items-center gap-4">
@@ -194,31 +189,19 @@ export default async function Page({
</Widget>
</div>
<div className="mt-8">
<EventList data={events} count={count} />
<Suspense fallback={<div />}>
<EventListServer {...eventListOptions} />
</Suspense>
</div>
</div>
</>
);
}
function ValueRow({ name, value }: { name: string; value?: unknown }) {
if (!value) {
return null;
}
return (
<div className="flex flex-row justify-between">
<div className="font-medium capitalize text-muted-foreground">
{name.replace('_', ' ')}
</div>
<div className="flex items-center gap-2 text-right">
{typeof value === 'string' ? (
<>
<SerieIcon name={value} /> {value}
</>
) : (
<>{value}</>
)}
</div>
</div>
);
async function EventListServer(props: GetEventListOptions) {
const [events, count] = await Promise.all([
getEventList(props),
getEventsCount(props),
]);
return <EventList data={events} count={count} />;
}

View File

@@ -1,4 +1,4 @@
import withLoadingWidget from '@/hocs/with-loading-widget';
import withSuspense from '@/hocs/with-suspense';
import { getProfileMetrics } from '@openpanel/db';
@@ -14,4 +14,4 @@ const ProfileMetricsServer = async ({ projectId, profileId }: Props) => {
return <ProfileMetrics data={data} />;
};
export default withLoadingWidget(ProfileMetricsServer);
export default withSuspense(ProfileMetricsServer, () => null);

View File

@@ -12,52 +12,52 @@ type Props = {
const ProfileMetrics = ({ data }: Props) => {
const number = useNumber();
return (
<div className="flex gap-6">
<div className="rounded-xl text-right">
<div className="flex flex-wrap gap-6 whitespace-nowrap md:justify-end md:text-right">
<div>
<div className="text-xs font-medium text-muted-foreground">
First seen
</div>
<div className="text-xl font-medium">
<div className="text-lg font-semibold">
{formatDistanceToNow(data.firstSeen)}
</div>
</div>
<div className="rounded-xl text-right">
<div>
<div className="text-xs font-medium text-muted-foreground">
Last seen
</div>
<div className="text-xl font-medium">
<div className="text-lg font-semibold">
{formatDistanceToNow(data.lastSeen)}
</div>
</div>
<div className="rounded-xl text-right">
<div>
<div className="text-xs font-medium text-muted-foreground">
Sessions
</div>
<div className="text-xl font-medium">
<div className="text-lg font-semibold">
{number.format(data.sessions)}
</div>
</div>
<div className="rounded-xl text-right">
<div>
<div className="text-xs font-medium text-muted-foreground">
Avg. Session
</div>
<div className="text-xl font-medium">
<div className="text-lg font-semibold">
{number.formatWithUnit(data.durationAvg / 1000, 'min')}
</div>
</div>
<div className="rounded-xl text-right">
<div>
<div className="text-xs font-medium text-muted-foreground">
P90. Session
</div>
<div className="text-xl font-medium">
<div className="text-lg font-semibold">
{number.formatWithUnit(data.durationP90 / 1000, 'min')}
</div>
</div>
<div className="rounded-xl text-right">
<div>
<div className="text-xs font-medium text-muted-foreground">
Page views
</div>
<div className="text-xl font-medium">
<div className="text-lg font-semibold">
{number.format(data.screenViews)}
</div>
</div>

View File

@@ -1,3 +0,0 @@
import FullPageLoadingState from '@/components/full-page-loading-state';
export default FullPageLoadingState;

View File

@@ -11,7 +11,7 @@ interface Props {
filters?: IChartEventFilter[];
}
const limit = 50;
const limit = 40;
async function ProfileListServer({ projectId, cursor, filters }: Props) {
const [profiles, count] = await Promise.all([

View File

@@ -23,7 +23,7 @@ interface ProfileListProps {
}
export function ProfileList({ data, count, limit = 50 }: ProfileListProps) {
const { organizationSlug, projectId } = useAppParams();
const { cursor, setCursor } = useCursor();
const { cursor, setCursor, loading } = useCursor();
return (
<Widget>
<WidgetHead className="flex items-center justify-between">
@@ -32,6 +32,7 @@ export function ProfileList({ data, count, limit = 50 }: ProfileListProps) {
size="sm"
cursor={cursor}
setCursor={setCursor}
loading={loading}
count={count}
take={limit}
/>