forked from
rocksky.app/rocksky
A decentralized music tracking and discovery platform built on AT Protocol 馃幍
1import { useParams, useRouter } from "@tanstack/react-router";
2import { LabelMedium } from "baseui/typography";
3import dayjs from "dayjs";
4import numeral from "numeral";
5import { useEffect, useState } from "react";
6import { Area, AreaChart, Tooltip, TooltipProps, XAxis } from "recharts";
7import useChart from "../../hooks/useChart";
8
9const CustomTooltip = ({
10 active,
11 payload,
12 label,
13}: TooltipProps<number, string>) => {
14 if (active && payload && payload.length) {
15 return (
16 <div className="bg-[#fff] border-[1px] border-[#ccc] p-[5px]">
17 <span className="text-[#808080]">
18 {dayjs(label).format("dddd DD MMMM YYYY")}:
19 </span>
20 <span className="text-[#710de4]">
21 {" "}
22 {numeral(payload[0].value).format("0,0")}
23 </span>
24 </div>
25 );
26 }
27
28 return null;
29};
30const formatXAxis = (tickItem: string) => dayjs(tickItem).format("MMM D");
31
32function ScrobblesAreaChart() {
33 const {
34 getScrobblesChart,
35 getAlbumChart,
36 getArtistChart,
37 getSongChart,
38 getProfileChart,
39 } = useChart();
40 const {
41 state: {
42 location: { pathname },
43 },
44 } = useRouter();
45 const { did, rkey } = useParams({ strict: false });
46 const [data, setData] = useState<
47 {
48 date: string;
49 count: number;
50 }[]
51 >([]);
52
53 useEffect(() => {
54 const fetchScrobblesChart = async () => {
55 if (pathname === "/") {
56 return;
57 }
58
59 if (pathname.startsWith("/profile")) {
60 const charts = await getProfileChart(did!);
61 setData(charts);
62 return;
63 }
64
65 if (pathname.includes("/artist/")) {
66 const charts = await getArtistChart(
67 `at://${did}/app.rocksky.artist/${rkey}`,
68 );
69 setData(charts);
70 return;
71 }
72
73 if (pathname.includes("/album/")) {
74 const charts = await getAlbumChart(
75 `at://${did}/app.rocksky.album/${rkey}`,
76 );
77 setData(charts);
78 return;
79 }
80
81 if (pathname.includes("/song/")) {
82 const charts = await getSongChart(
83 `at://${did}/app.rocksky.song/${rkey}`,
84 );
85 setData(charts);
86 return;
87 }
88
89 if (pathname.includes("/scrobble/")) {
90 const charts = await getSongChart(
91 `at://${did}/app.rocksky.scrobble/${rkey}`,
92 );
93 setData(charts);
94 return;
95 }
96 };
97 fetchScrobblesChart();
98 // eslint-disable-next-line react-hooks/exhaustive-deps
99 }, [pathname]);
100
101 const chartData =
102 pathname === "/" ||
103 pathname.startsWith("/dropbox") ||
104 (pathname.startsWith("/googledrive") && getScrobblesChart().length > 0)
105 ? getScrobblesChart()
106 : data;
107
108 return (
109 <>
110 {!pathname.includes("/playlist/") && (
111 <>
112 <LabelMedium
113 marginBottom={"20px"}
114 className="!text-[var(--color-text)]"
115 >
116 Scrobble Stats
117 </LabelMedium>
118 <AreaChart
119 width={300}
120 height={120}
121 data={chartData}
122 className="top-[5px] right-[0px] left-[0px] bottom-[5px]"
123 >
124 <XAxis
125 dataKey="date"
126 axisLine={{ stroke: "#ccc", strokeWidth: 1 }}
127 tick={{ fontSize: 10, color: "var(--color-text-muted)" }}
128 tickFormatter={formatXAxis}
129 />
130 <Tooltip
131 content={<CustomTooltip />}
132 labelFormatter={(label) => dayjs(label).format("YYYY-MM-DD")}
133 />
134 <Area
135 type="monotone"
136 dataKey="count"
137 stroke="#710de4"
138 fill="#9754e463"
139 />
140 </AreaChart>
141 </>
142 )}
143 </>
144 );
145}
146
147export default ScrobblesAreaChart;