From 4936ba1d40db32301ac58d54723099eb2602c20e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl-Gerhard=20Lindesva=CC=88rd?= Date: Wed, 8 May 2024 10:32:45 +0200 Subject: [PATCH] add suspense for project cards --- .../src/app/(app)/[organizationSlug]/page.tsx | 2 +- apps/dashboard/src/components/fade-in.tsx | 27 +++++ .../src/components/projects/project-card.tsx | 111 ++++++++++-------- 3 files changed, 93 insertions(+), 47 deletions(-) create mode 100644 apps/dashboard/src/components/fade-in.tsx diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/page.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/page.tsx index 10f4371b..fe8df846 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/page.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/page.tsx @@ -1,6 +1,6 @@ import { FullPageEmptyState } from '@/components/full-page-empty-state'; import FullWidthNavbar from '@/components/full-width-navbar'; -import { ProjectCard } from '@/components/projects/project-card'; +import ProjectCard from '@/components/projects/project-card'; import SignOutButton from '@/components/sign-out-button'; import { redirect } from 'next/navigation'; diff --git a/apps/dashboard/src/components/fade-in.tsx b/apps/dashboard/src/components/fade-in.tsx new file mode 100644 index 00000000..fb1deaad --- /dev/null +++ b/apps/dashboard/src/components/fade-in.tsx @@ -0,0 +1,27 @@ +'use client'; + +import { useEffect, useRef } from 'react'; +import { cn } from '@/utils/cn'; + +type Props = { + className?: string; + children: React.ReactNode; +}; + +export function FadeIn({ className, children }: Props) { + const ref = useRef(null); + useEffect(() => { + if (ref.current) { + ref.current.classList.remove('opacity-0'); + ref.current.classList.add('opacity-100'); + } + }, []); + return ( +
+ {children} +
+ ); +} diff --git a/apps/dashboard/src/components/projects/project-card.tsx b/apps/dashboard/src/components/projects/project-card.tsx index 6ea49797..035df73e 100644 --- a/apps/dashboard/src/components/projects/project-card.tsx +++ b/apps/dashboard/src/components/projects/project-card.tsx @@ -1,36 +1,17 @@ +import { Suspense } from 'react'; +import withSuspense from '@/hocs/with-suspense'; import { shortNumber } from '@/hooks/useNumerFormatter'; +import { Fallback } from '@radix-ui/react-avatar'; +import { endOfMonth, startOfMonth } from 'date-fns'; import { escape } from 'sqlstring'; import type { IServiceProject } from '@openpanel/db'; import { chQuery } from '@openpanel/db'; import { ChartSSR } from '../chart-ssr'; +import { FadeIn } from '../fade-in'; -export async function ProjectCard({ - id, - name, - organizationSlug, -}: IServiceProject) { - const [chart, [data]] = await Promise.all([ - chQuery<{ value: number; date: string }>( - `SELECT countDistinct(profile_id) as value, toStartOfDay(created_at) as date FROM events WHERE project_id = ${escape(id)} AND name = 'session_start' AND created_at >= now() - interval '1 month' GROUP BY date ORDER BY date ASC` - ), - chQuery<{ total: number; month: number; day: number }>( - ` - SELECT - ( - SELECT count(DISTINCT profile_id) as count FROM events WHERE project_id = ${escape(id)} - ) as total, - ( - SELECT count(DISTINCT profile_id) as count FROM events WHERE project_id = ${escape(id)} AND created_at >= now() - interval '1 month' - ) as month, - ( - SELECT count(DISTINCT profile_id) as count FROM events WHERE project_id = ${escape(id)} AND created_at >= now() - interval '1 day' - ) as day - ` - ), - ]); - +function ProjectCard({ id, name, organizationSlug }: IServiceProject) { // For some unknown reason I get when navigating back to this page when using // Should be solved: https://github.com/vercel/next.js/issues/61336 // But still get the error @@ -41,31 +22,69 @@ export async function ProjectCard({ >
{name}
- ({ ...d, date: new Date(d.date) }))} /> + + +
Visitors
-
-
-
Total
- - {shortNumber('en')(data?.total)} - -
-
-
Month
- - {shortNumber('en')(data?.month)} - -
-
-
24h
- - {shortNumber('en')(data?.day)} - -
-
+ + + +
); } + +async function ProjectChart({ id }: { id: string }) { + const chart = await chQuery<{ value: number; date: string }>( + `SELECT countDistinct(profile_id) as value, toStartOfDay(created_at) as date FROM events WHERE project_id = ${escape(id)} AND name = 'session_start' AND created_at >= now() - interval '1 month' GROUP BY date ORDER BY date ASC` + ); + + return ( + + ({ ...d, date: new Date(d.date) }))} /> + + ); +} + +function Metric({ value, label }: { value: React.ReactNode; label: string }) { + return ( +
+
{label}
+ {value} +
+ ); +} + +async function ProjectMetrics({ id }: { id: string }) { + const [metrics] = await chQuery<{ + total: number; + month: number; + day: number; + }>( + ` + SELECT + ( + SELECT count(DISTINCT profile_id) as count FROM events WHERE project_id = ${escape(id)} + ) as total, + ( + SELECT count(DISTINCT profile_id) as count FROM events WHERE project_id = ${escape(id)} AND created_at >= now() - interval '1 month' + ) as month, + ( + SELECT count(DISTINCT profile_id) as count FROM events WHERE project_id = ${escape(id)} AND created_at >= now() - interval '1 day' + ) as day + ` + ); + + return ( + + + + + + ); +} + +export default ProjectCard;