Files
crosspost/frontend/src/pages/Stats.tsx

174 lines
4.9 KiB
TypeScript

import { useEffect, useState, useRef } from "react";
import axios from "axios";
import StatsStyling from "../styles/stats_styling";
import SummaryStats from "../components/SummaryStats";
import EmotionalStats from "../components/EmotionalStats";
import InteractionStats from "../components/UserStats";
import {
type SummaryResponse,
type UserAnalysisResponse,
type TimeAnalysisResponse,
type ContentAnalysisResponse
} from '../types/ApiTypes'
const styles = StatsStyling;
const StatPage = () => {
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const [activeView, setActiveView] = useState<"summary" | "emotional" | "interaction">("summary");
const [userData, setUserData] = useState<UserAnalysisResponse | null>(null);
const [timeData, setTimeData] = useState<TimeAnalysisResponse | null>(null);
const [contentData, setContentData] = useState<ContentAnalysisResponse | null>(null);
const [summary, setSummary] = useState<SummaryResponse | null>(null);
const searchInputRef = useRef<HTMLInputElement>(null);
const beforeDateRef = useRef<HTMLInputElement>(null);
const afterDateRef = useRef<HTMLInputElement>(null);
const getStats = () => {
setError("");
setLoading(true);
Promise.all([
axios.get<TimeAnalysisResponse>("http://localhost:5000/stats/time"),
axios.get<UserAnalysisResponse>("http://localhost:5000/stats/user"),
axios.get<ContentAnalysisResponse>("http://localhost:5000/stats/content"),
axios.get<SummaryResponse>(`http://localhost:5000/stats/summary`),
])
.then(([timeRes, userRes, contentRes, summaryRes]) => {
setUserData(userRes.data || null);
setTimeData(timeRes.data || null);
setContentData(contentRes.data || null);
setSummary(summaryRes.data || null);
})
.catch((e) => setError("Failed to load statistics: " + String(e)))
.finally(() => setLoading(false));
};
const onSubmitFilters = () => {
const query = searchInputRef.current?.value ?? "";
Promise.all([
axios.post("http://localhost:5000/filter/search", {
query: query
}),
])
.then(() => {
getStats();
})
.catch(e => {
setError("Failed to load filters: " + e.response);
})
};
const resetFilters = () => {
axios.get("http://localhost:5000/filter/reset")
.then(() => {
getStats();
})
.catch(e => {
setError(e);
})
};
useEffect(() => {
setError("");
getStats();
}, [])
if (loading) return <p style={{...styles.page, minWidth: "100vh", minHeight: "100vh"}}>Loading insights</p>;
if (error) return <p style={{...styles.page}}>{error}</p>;
return (
<div style={styles.page}>
<div style={{ ...styles.container, ...styles.card, ...styles.headerBar }}>
<div style={styles.controls}>
<input
type="text"
id="query"
ref={searchInputRef}
placeholder="Search events..."
style={styles.input}
/>
<input
type="date"
ref={beforeDateRef}
placeholder="Search before date"
style={styles.input}
/>
<input
type="date"
ref={afterDateRef}
placeholder="Search before date"
style={styles.input}
/>
<button onClick={onSubmitFilters} style={styles.buttonPrimary}>
Search
</button>
<button onClick={resetFilters} style={styles.buttonSecondary}>
Reset
</button>
</div>
<div style={{ fontSize: 13, color: "#6b7280" }}>Analytics Dashboard</div>
</div>
<div style={{ ...styles.container, display: "flex", gap: 8, marginTop: 12 }}>
<button
onClick={() => setActiveView("summary")}
style={activeView === "summary" ? styles.buttonPrimary : styles.buttonSecondary}
>
Summary
</button>
<button
onClick={() => setActiveView("emotional")}
style={activeView === "emotional" ? styles.buttonPrimary : styles.buttonSecondary}
>
Emotional
</button>
<button
onClick={() => setActiveView("interaction")}
style={activeView === "interaction" ? styles.buttonPrimary : styles.buttonSecondary}
>
Interaction
</button>
</div>
{activeView === "summary" && (
<SummaryStats
userData={userData}
timeData={timeData}
contentData={contentData}
summary={summary}
/>
)}
{activeView === "emotional" && contentData && (
<EmotionalStats contentData={contentData} />
)}
{activeView === "emotional" && !contentData && (
<div style={{ ...styles.container, ...styles.card, marginTop: 16 }}>
No emotional data available.
</div>
)}
{activeView === "interaction" && userData && (
<InteractionStats data={userData} />
)}
</div>
);
}
export default StatPage;