diff --git a/backend/db/crud.py b/backend/db/crud.py index 47ae8baaa0976e23045b836ce7a47221c5cb7e40..1d0ed8e9a2e19c5133148f981ed09997a4451c7c 100644 --- a/backend/db/crud.py +++ b/backend/db/crud.py @@ -105,11 +105,11 @@ def get_avg_graph(place: str, db: Session): weekday, current_time = current_date.weekday(), current_date.time() first_timeslot = get_timeslot(place, weekday, True, db) if first_timeslot and current_time <= first_timeslot[1]: - return get_avg_graph_points(place, weekday, first_timeslot[0], first_timeslot[1], timedelta(minutes=5), db), first_timeslot[0], first_timeslot[1] + return get_avg_graph_points(place, weekday, first_timeslot[0], first_timeslot[1], timedelta(minutes=5), db) second_timeslot = get_timeslot(place, weekday, False, db) if second_timeslot and current_time <= second_timeslot[1]: - return get_avg_graph_points(place, weekday, second_timeslot[0], second_timeslot[1], timedelta(minutes=5), db), second_timeslot[0], second_timeslot[1] - return [], None, None + return get_avg_graph_points(place, weekday, second_timeslot[0], second_timeslot[1], timedelta(minutes=5), db) + return [] def get_current_graph_points(place: str, current_date: date, min_time: time, max_time: time, interval: timedelta, db: Session): @@ -173,7 +173,7 @@ def get_current_graph(place: str, db: Session): if second_timeslot and current_time <= second_timeslot[0]: return [], None, None elif second_timeslot and current_time <= second_timeslot[1]: - points = get_current_graph_points(place, day, second_timeslot[0], current_time, timedelta(minutes=5), db), second_timeslot[0], second_timeslot[1] + points = get_current_graph_points(place, day, second_timeslot[0], current_time, timedelta(minutes=5), db) start_time = 60 * second_timeslot[0].hour + second_timeslot[0].minute end_time = 60 * second_timeslot[1].hour + second_timeslot[1].minute return points, start_time, end_time diff --git a/backend/routers/stats.py b/backend/routers/stats.py index d03ec12798a975d364c4b8b5cb651ab9580dfbbb..1ee3c705404f5211a3486f169165722816629970 100644 --- a/backend/routers/stats.py +++ b/backend/routers/stats.py @@ -14,7 +14,7 @@ async def waiting_time(place: str, db: Session = Depends(get_db)): return crud.get_waiting_time(place, db) -@router.get('/{place}/stats/avg_graph', response_model=Tuple[list, int, int]) +@router.get('/{place}/stats/avg_graph', response_model=list) async def stats(place: str, db: Session = Depends(get_db)): return crud.get_avg_graph(place, db) diff --git a/frontend/src/components/Graph.js b/frontend/src/components/Graph.js index 8b7782c29e14aad05696a645be665ed9fdc9d8b4..c2f1f0171680337a8cbc6de8712527d7aa9440a7 100644 --- a/frontend/src/components/Graph.js +++ b/frontend/src/components/Graph.js @@ -1,21 +1,24 @@ import React from "react"; import axios from "axios"; import { - AreaChart, + Line, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, + ComposedChart, } from "recharts"; +import ToggleButton from "react-bootstrap/ToggleButton"; import "../styles/Graph.css"; -const CustomTooltip = ({ active, payload }) => { +const CustomTooltip = ({ active, payload, label }) => { return ( <> {active && payload && payload.length && ( <div className="custom-tooltip"> + <p className="label">{`${formatXAxis(label)}`}</p> <p className="label">{`Temps d'attente : ${payload[0].value} minutes`}</p> </div> )} @@ -24,40 +27,60 @@ const CustomTooltip = ({ active, payload }) => { }; function formatXAxis(value) { + if (value == 0) return ""; return Math.floor(value / 60).toString() + "h" + (value % 60).toString().padStart(2, "0"); } -export default function Graph({ place, type }) { - const [data, setData] = React.useState([]); +export default function Graph({ place }) { + const [checked, setChecked] = React.useState(false); + const [currentData, setCurrentData] = React.useState([[], 0, 0]); React.useEffect(() => { axios .get( - `${process.env.REACT_APP_BASE_URL_BACK}/${encodeURIComponent( - place, - )}/stats/${encodeURIComponent(type)}_graph`, + `${process.env.REACT_APP_BASE_URL_BACK}/${encodeURIComponent(place)}/stats/current_graph`, ) .then((response) => { - setData(response.data[0]); + setCurrentData(response.data); + }); + }, []); + + const [avgData, setAvgData] = React.useState([[], 0, 0]); + + React.useEffect(() => { + axios + .get(`${process.env.REACT_APP_BASE_URL_BACK}/${encodeURIComponent(place)}/stats/avg_graph`) + .then((response) => { + setAvgData(response.data); }); }, []); - console.log(data[0]); return ( <> - {!!data.length && ( + {!!currentData[0].length && ( <div style={{ height: "60%", padding: "3rem" }}> <div className="graph"> <ResponsiveContainer width="100%" height="100%"> - <AreaChart - data={data} + <ComposedChart margin={{ top: 5, right: 30, - left: 20, + left: -10, bottom: 5, }} > + {checked ? ( + <Line + data={avgData} + type="monotone" + dataKey="time" + stroke="#FF0000" + strokeWidth={2} + dot={{ stroke: "#FF0000", strokeWidth: 2, fill: "#fff" }} + /> + ) : ( + <div /> + )} <defs> <linearGradient id="colorGradient" x1="0" y1="0" x2="0" y2="1"> <stop offset="10%" stopColor="#ff0000" stopOpacity={0.55} /> @@ -72,36 +95,53 @@ export default function Graph({ place, type }) { tick={{ fill: "#FFFFFF", fontSize: "18" }} dataKey="name" type="number" - domain={[840, 1020]} + interval="preserveStartEnd" + domain={[currentData[1], currentData[2]]} tickFormatter={formatXAxis} /> <YAxis axisLine={false} tickLine={false} tick={{ fill: "#FFFFFF", fontSize: "18" }} - /*tickInt*/ + tickInt tickCount={10} dataKey="time" type="number" - domain={[0, 50]} - /*domain={[0, (dataMax) => 10 * Math.floor((dataMax + 10) / 10)]}*/ + domain={[0, (dataMax) => 10 * Math.floor((dataMax + 10) / 10)]} allowDecimals={false} name="Temps d'attente" /> <Tooltip content={<CustomTooltip />} /> <Area + data={currentData[0]} type="monotone" dataKey="time" stroke="#FFFFFF" - strokeWidth={1} + strokeWidth={2} fillOpacity={1} fill="url(#colorGradient)" dot={{ stroke: "#0967D2", strokeWidth: 2, fill: "#fff" }} /> - </AreaChart> + </ComposedChart> </ResponsiveContainer> </div> - <div className="graph-title">Temps d'attente estimé depuis l'ouverture</div> + <div className="graph-title"> + Temps d'attente estimé depuis l'ouverture (en minutes) + </div> + <div className="graph-button"> + <ToggleButton + id="toggle-check" + type="checkbox" + variant="primary" + checked={checked} + value="0" + onChange={() => setChecked(!checked)} + > + {checked + ? "Retirer le temps d'attente moyen pour ce créneau" + : "Afficher le temps d'attente moyen pour ce créneau"} + </ToggleButton> + </div> </div> )} </> diff --git a/frontend/src/styles/Graph.css b/frontend/src/styles/Graph.css index c3991fac2cd50dd6ce127b028f0b65ab3ceaeaa9..a02f967bec49522b5bc516f62f0d816c6143fe44 100644 --- a/frontend/src/styles/Graph.css +++ b/frontend/src/styles/Graph.css @@ -7,4 +7,8 @@ height: 100%; width: 100%; display: inline-block; +} + +.graph-button{ + margin-top: 10px; } \ No newline at end of file