Skip to content

Commit 5a42aa8

Browse files
committed
feat: activity scatter charts, user rank
1 parent d3ae103 commit 5a42aa8

File tree

15 files changed

+890
-357
lines changed

15 files changed

+890
-357
lines changed

app/(protected)/admin/dashboard/page.tsx

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@ import {
77
BreadcrumbSeparator,
88
} from '@/components/ui/breadcrumb'
99

10-
import { MonthlyRevenueChart } from '@/components/dashboard/MonthlyRevenueChart'
11-
import { MostBorrowedBookChart } from '@/components/dashboard/MostBorrowedBookChart'
12-
import { MontlyBorrowChart } from '@/components/dashboard/MontlyBorrowChart'
13-
import { TopMembershipChart } from '@/components/dashboard/TopMembershipChart'
14-
import { getAnalysis, getBorrowingHeatmapAnalysis } from '@/lib/api/analysis'
1510
import { SITE_NAME } from '@/lib/consts'
1611
import type { Metadata } from 'next'
1712
import { LibrarySelector } from '@/components/dashboard/LibrarySelector'
@@ -23,7 +18,17 @@ import { getListLibraries } from '@/lib/api/library'
2318
import { DateRange } from 'react-day-picker'
2419
import { cookies } from 'next/headers'
2520
import { Suspense } from 'react'
26-
import { BorrowHeatmapChart } from '@/components/dashboard/BorrowHeatmapChart'
21+
import { AnalysisChartsWrapper } from '@/components/dashboard/AnalysisChartsWrapper'
22+
import {
23+
BorrowHeatmapWrapper,
24+
ReturnHeatmapWrapper,
25+
} from '@/components/dashboard/HeatmapWrapper'
26+
import { PowerUsersWrapper } from '@/components/dashboard/PowerUsersWrapper'
27+
import {
28+
AnalysisChartsLoading,
29+
HeatmapChartLoading,
30+
PowerUsersLoading,
31+
} from '@/components/dashboard/ChartLoadingComponents'
2732

2833
export const metadata: Metadata = {
2934
title: `Dashboard · ${SITE_NAME}`,
@@ -50,7 +55,7 @@ export default async function DashboardPage({
5055
redirect('/', RedirectType.replace)
5156
}
5257

53-
const { from, to, limit = 5, skip = 0 } = await searchParams
58+
const { from, to, skip, limit = 5 } = await searchParams
5459

5560
const cookieStore = await cookies()
5661
const cookieName = process.env.LIBRARY_COOKIE_NAME as string
@@ -67,25 +72,8 @@ export default async function DashboardPage({
6772
redirect('?' + sp.toString(), RedirectType.replace)
6873
}
6974

70-
const [res, libsRes, heatmapRes] = await Promise.all([
71-
getAnalysis({
72-
skip,
73-
limit,
74-
from: startOfDay(parse(from, 'dd-MM-yyyy', new Date())).toJSON(),
75-
to: endOfDay(parse(to, 'dd-MM-yyyy', new Date())).toJSON(),
76-
library_id: libID!,
77-
}),
78-
getListLibraries({ limit: 5 }),
79-
getBorrowingHeatmapAnalysis({
80-
library_id: libID!,
81-
start: startOfDay(parse(from, 'dd-MM-yyyy', new Date())).toJSON(),
82-
end: endOfDay(parse(to, 'dd-MM-yyyy', new Date())).toJSON(),
83-
}),
84-
])
85-
86-
if ('error' in res) {
87-
return <div>{res.error}</div>
88-
}
75+
const libsRes = await getListLibraries({ limit: 5 })
76+
8977
if ('error' in libsRes) {
9078
return <div>{libsRes.error}</div>
9179
}
@@ -117,6 +105,9 @@ export default async function DashboardPage({
117105
redirect('./?' + sp.toString(), RedirectType.replace)
118106
}
119107

108+
const start = startOfDay(parse(from, 'dd-MM-yyyy', new Date())).toJSON()
109+
const end = endOfDay(parse(to, 'dd-MM-yyyy', new Date())).toJSON()
110+
120111
return (
121112
<div>
122113
<h1 className="text-2xl font-semibold">Libraries</h1>
@@ -147,15 +138,30 @@ export default async function DashboardPage({
147138
range={{ from: fromDate, to: toDate }}
148139
onChangeAction={onDateRangeChange}
149140
/>
150-
<MostBorrowedBookChart data={res.data.book} />
151-
<TopMembershipChart data={res.data.membership} />
152-
<MontlyBorrowChart data={res.data.borrowing} />
153-
<MonthlyRevenueChart data={res.data.revenue} />
154-
{'error' in heatmapRes ? (
155-
<div>{heatmapRes.error}</div>
156-
) : (
157-
<BorrowHeatmapChart data={heatmapRes.data} />
158-
)}
141+
<Suspense fallback={<AnalysisChartsLoading />}>
142+
<AnalysisChartsWrapper
143+
libraryId={libID!}
144+
from={start}
145+
to={end}
146+
limit={5}
147+
skip={0}
148+
/>
149+
</Suspense>
150+
<Suspense fallback={<HeatmapChartLoading />}>
151+
<BorrowHeatmapWrapper libraryId={libID!} start={start} end={end} />
152+
</Suspense>
153+
<Suspense fallback={<HeatmapChartLoading />}>
154+
<ReturnHeatmapWrapper libraryId={libID!} start={start} end={end} />
155+
</Suspense>
156+
<Suspense fallback={<PowerUsersLoading />}>
157+
<PowerUsersWrapper
158+
libraryId={libID!}
159+
from={start}
160+
to={end}
161+
limit={limit}
162+
skip={skip}
163+
/>
164+
</Suspense>
159165
</div>
160166
</div>
161167
)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { MonthlyRevenueChart } from './MonthlyRevenueChart'
2+
import { MostBorrowedBookChart } from './MostBorrowedBookChart'
3+
import { MontlyBorrowChart } from './MontlyBorrowChart'
4+
import { TopMembershipChart } from './TopMembershipChart'
5+
import { getAnalysis } from '@/lib/api/analysis'
6+
7+
type AnalysisChartsWrapperProps = {
8+
libraryId: string
9+
from: string
10+
to: string
11+
limit?: number
12+
skip?: number
13+
}
14+
15+
export async function AnalysisChartsWrapper({
16+
libraryId,
17+
from,
18+
to,
19+
limit = 5,
20+
skip = 0,
21+
}: AnalysisChartsWrapperProps) {
22+
const res = await getAnalysis({
23+
skip,
24+
limit,
25+
from,
26+
to,
27+
library_id: libraryId,
28+
})
29+
30+
if ('error' in res) {
31+
return (
32+
<>
33+
<div className="col-span-2 p-4 border border-destructive/80 rounded-lg bg-destructive/20">
34+
<p className="text-destructive/">Error loading charts: {res.error}</p>
35+
</div>
36+
</>
37+
)
38+
}
39+
40+
return (
41+
<>
42+
<MostBorrowedBookChart data={res.data.book} />
43+
<TopMembershipChart data={res.data.membership} />
44+
<MontlyBorrowChart data={res.data.borrowing} />
45+
<MonthlyRevenueChart data={res.data.revenue} />
46+
</>
47+
)
48+
}

components/dashboard/BorrowHeatmapChart.tsx

Lines changed: 0 additions & 109 deletions
This file was deleted.

0 commit comments

Comments
 (0)