feat: add rudimentary top features box to stat page
This commit is contained in:
@@ -18,12 +18,19 @@ type BackendWord = {
|
|||||||
count: number;
|
count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TopUser = {
|
||||||
|
author: string;
|
||||||
|
source: string;
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
|
||||||
const StatPage = () => {
|
const StatPage = () => {
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
const [postsPerDay, setPostsPerDay] = useState([]);
|
const [postsPerDay, setPostsPerDay] = useState([]);
|
||||||
const [heatmapData, setHeatmapData] = useState([]);
|
const [heatmapData, setHeatmapData] = useState([]);
|
||||||
|
const [topUserData, setTopUserData] = useState<TopUser[]>([]);
|
||||||
const [wordFrequencyData, setWordFrequencyData] = useState([]);
|
const [wordFrequencyData, setWordFrequencyData] = useState([]);
|
||||||
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
@@ -33,13 +40,18 @@ const StatPage = () => {
|
|||||||
|
|
||||||
Promise.all([
|
Promise.all([
|
||||||
axios.get("http://localhost:5000/stats/time"),
|
axios.get("http://localhost:5000/stats/time"),
|
||||||
|
axios.get("http://localhost:5000/stats/user"),
|
||||||
axios.get("http://localhost:5000/stats/content"),
|
axios.get("http://localhost:5000/stats/content"),
|
||||||
])
|
])
|
||||||
.then(([timeRes, wordsRes]) => {
|
.then(([timeRes, userRes, wordsRes]) => {
|
||||||
const eventsPerDay = Array.isArray(timeRes.data?.events_per_day)
|
const eventsPerDay = Array.isArray(timeRes.data?.events_per_day)
|
||||||
? timeRes.data.events_per_day
|
? timeRes.data.events_per_day
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
|
const topUsers = Array.isArray(userRes.data?.top_users)
|
||||||
|
? userRes.data.top_users
|
||||||
|
: [];
|
||||||
|
|
||||||
const weekdayHourHeatmap = Array.isArray(timeRes.data?.weekday_hour_heatmap)
|
const weekdayHourHeatmap = Array.isArray(timeRes.data?.weekday_hour_heatmap)
|
||||||
? timeRes.data.weekday_hour_heatmap
|
? timeRes.data.weekday_hour_heatmap
|
||||||
: [];
|
: [];
|
||||||
@@ -54,6 +66,8 @@ const StatPage = () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
setTopUserData(topUsers);
|
||||||
|
|
||||||
setHeatmapData(weekdayHourHeatmap);
|
setHeatmapData(weekdayHourHeatmap);
|
||||||
|
|
||||||
setWordFrequencyData(
|
setWordFrequencyData(
|
||||||
@@ -62,6 +76,7 @@ const StatPage = () => {
|
|||||||
value: d.count,
|
value: d.count,
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
})
|
})
|
||||||
.catch((e) => setError("Failed to load statistics: " + String(e)));
|
.catch((e) => setError("Failed to load statistics: " + String(e)));
|
||||||
};
|
};
|
||||||
@@ -113,18 +128,18 @@ const StatPage = () => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gridTemplateColumns: "2fr 1fr",
|
gridTemplateColumns: "2fr 2fr 2fr",
|
||||||
gap: 24,
|
gap: 12,
|
||||||
maxWidth: 1100,
|
|
||||||
margin: "0 auto",
|
margin: "0 auto",
|
||||||
width: "100%"
|
width: "100%",
|
||||||
|
height: "100%"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2>Events per Day</h2>
|
<h2>Events per Day</h2>
|
||||||
|
|
||||||
<ResponsiveContainer width={800} height={350}>
|
<ResponsiveContainer width={600} height={350}>
|
||||||
<LineChart data={postsPerDay}>
|
<LineChart data={postsPerDay}>
|
||||||
<CartesianGrid strokeDasharray="3 3" />
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
<XAxis dataKey="date" />
|
<XAxis dataKey="date" />
|
||||||
@@ -151,7 +166,26 @@ const StatPage = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
{topUserData?.length > 0 && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
maxHeight: 450,
|
||||||
|
width: "100%",
|
||||||
|
overflowY: "auto",
|
||||||
|
padding: 12
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<h2>Top Users</h2>
|
||||||
|
{topUserData.map((item) => (
|
||||||
|
<p key={`${item.author}-${item.source}`}>
|
||||||
|
{item.author} ({item.source}): {item.count}
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style={{ width: "100%", height: 320}}>
|
<div style={{ width: "100%", height: 320}}>
|
||||||
<h2>Heatmap</h2>
|
<h2>Heatmap</h2>
|
||||||
|
|||||||
Reference in New Issue
Block a user