diff --git a/app/Http/Controllers/RainfallController.php b/app/Http/Controllers/RainfallController.php index 71b08c3..2a278cf 100644 --- a/app/Http/Controllers/RainfallController.php +++ b/app/Http/Controllers/RainfallController.php @@ -110,4 +110,27 @@ class RainfallController extends Controller return response()->json(array_values($results)); } + + public function lastMonths(Request $request) + { + $result = []; + for ($i = 12; $i >= 0; $i--) { + $date = now()->subMonths($i); + $firstOfMonth = now()->subMonths($i)->firstOfMonth(); + $lastOfMonth = now()->subMonths($i)->lastOfMonth(); + $rainfalls = $request->user() + ->rainfalls() + ->whereBetween('date', [$firstOfMonth, $lastOfMonth]) + ->sum('value'); + + $result[] = [ + 'year' => $date->year, + 'month' => $date->month, + 'label' => $date->monthName.' '.$date->year, + 'values' => (int) $rainfalls, + ]; + } + + return response()->json($result); + } } diff --git a/resources/js/components/rainfall/RainfallGraph.tsx b/resources/js/components/rainfall/RainfallGraph.tsx deleted file mode 100644 index 9e19c29..0000000 --- a/resources/js/components/rainfall/RainfallGraph.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import * as d3 from "d3" -import React, {FC, useEffect, useRef} from "react" -import {rainfallGraphData} from "../../types" - -const RainfallGraph: FC = ({width, height, data, start_date, end_date}) => { - - const svgRef = useRef(null) - - useEffect(() => { - renderSVG() - }, [width, height, data]) - - const renderSVG = () => { - const margin = {top: 10, right: 30, bottom: 30, left: 20} - const gWidth = width - margin.left - margin.right - const gHeight = height - margin.top - margin.bottom - - d3.select(svgRef.current).selectAll("*").remove() - const svg = d3.select(svgRef.current) - .attr('id', 'rain-graph') - .attr('width', gWidth + margin.left + margin.right) - .attr('height', gHeight + margin.top + margin.bottom) - .attr('class', 'relative') - .append('g') - .attr('transform', "translate(" + margin.left + "," + margin.top + ")") - - const yMax = data.reduce((result, item) => item.value > result ? item.value : result, 0) - const y = d3.scaleLinear() - .domain([0, yMax + 10]) - .range([gHeight, 0]) - - const x = d3.scaleUtc() - .domain([(new Date(start_date)), (new Date()).setDate((new Date(end_date)).getDate())]) - .range([margin.left, width - margin.right]) - - const yAxis = svg.append('g') - .attr('transform', `translate(${margin.left},0)`) - .call(d3.axisLeft(y).ticks(height / 80)) - .call(g => g.select('.domain').remove()) - - .call(g => g.append('text') - .attr('x', -margin.left) - .attr('y', 10) - .attr('fill', 'currentColor') - .attr('text-anchor', 'start') - ) - - svg.append("g") - .attr("transform", "translate(0," + gHeight + ")") - .call(d3.axisBottom(x) - .ticks(8) - .tickFormat( - // @ts-expect-error change time format - d3.timeFormat("%d/%m/%Y") - ) - , 0) - - if (data.length === 0) { - // no values text - const titleBox = svg.append("g") - .attr("x", (width)) - .attr("y", height) - - titleBox.append("text") - .attr("x", (width / 2)) - .attr("y", height / 2) - .attr("text-anchor", "middle") - .style("font-size", "20px") - .text('Aucune Donnée') - } else { - yAxis.call(g => g.selectAll(".tick line").clone() - .attr("x2", width - margin.left - margin.right) - .attr("stroke-opacity", 0.1)) - } - - - const showDetails = (event: Event, data: rainfallGraphData) => { - const toolTip = document.getElementById('tooltip') - if (toolTip) { - toolTip.style.opacity = '1' - toolTip.innerText = `${data.label} : ${data.value}` - } - } - - const diffDays = Math.round(Math.abs(((new Date(start_date)).getTime() - (new Date(end_date)).getTime()) / (24 * 60 * 60 * 1000))) + 1 - const dayWidth = (width - 44) / diffDays - svg.selectAll(".bar") - .data(data) - .enter() - .append("rect") - .attr("class", "bar") - .attr("fill", "steelblue") - .attr("x", d => x(new Date(d.start)) + 1.5) - .attr("y", d => y(d.value)) - .attr("width", d => (dayWidth * d.days - 3)) - .attr("height", d => height - margin.bottom - 10 - y(d.value)) - .on('click', showDetails) - .append('title') - .text(d => `${d.label} : ${d.value}`) - } - - return
- -
-
-} - -export default RainfallGraph - -interface RainfallGraphProps { - width: number, - height: number, - data: rainfallGraphData[], - start_date: string, - end_date: string, -} diff --git a/resources/js/components/rainfall/YearRainfaill.tsx b/resources/js/components/rainfall/YearRainfaill.tsx new file mode 100644 index 0000000..1fe84a7 --- /dev/null +++ b/resources/js/components/rainfall/YearRainfaill.tsx @@ -0,0 +1,52 @@ +import React, {useState, useEffect} from "react" +import Card from "../Card" +import useAxiosTools from "../../hooks/AxiosTools" +import {AxiosError} from "axios" +import {monthlyRainfall} from "../../types" + +const YearRainfall = () => { + + const {errorCatch, errorLabel, setError, axiosGet} = useAxiosTools() + const [data, setData] = useState([]) + const months = Array(13) + .reduce((result, item, index) => { + const date = new Date() + console.log(item, index, date) + return item + }, []) + console.log(months) + + useEffect(() => { + fetchData() + }, []) + + const fetchData = async () => { + try { + const res = await axiosGet('/api/rainfalls/last-months') + setData(res.data) + } catch (e) { + if (e instanceof AxiosError) { + setError(e.message) + } else { + errorCatch(e) + } + } + } + + return
+ +

Précipitations des derniers mois

+ {errorLabel()} + + + {data.map(line => + + + )} + +
{line.label}{line.values}
+
+
+} + +export default YearRainfall diff --git a/resources/js/hooks/DimensionHook.tsx b/resources/js/hooks/DimensionHook.tsx index a9e7ded..caca778 100644 --- a/resources/js/hooks/DimensionHook.tsx +++ b/resources/js/hooks/DimensionHook.tsx @@ -4,7 +4,7 @@ const useDimension = () => { const RESET_TIMEOUT = 300 let movement_timer: number|undefined = undefined - const targetRef = useRef() + const targetRef = useRef() const [dimensions, setDimensions] = useState({ width:0, height: 0 }) useEffect(() => { diff --git a/resources/js/pages/Home.tsx b/resources/js/pages/Home.tsx index 14ea1d7..63b5826 100644 --- a/resources/js/pages/Home.tsx +++ b/resources/js/pages/Home.tsx @@ -1,6 +1,7 @@ import React from "react" import useAuthUser from "../hooks/AuthUser" -import Rainfall from "./Rainfall" +import YearRainfall from "../components/rainfall/YearRainfaill" +import PageLayout from "../components/PageLayout" const Home = () => { @@ -8,7 +9,9 @@ const Home = () => { return
{authUser - ? + ? + + :

Application pour enregistrer sa pluviométrie

Un compte est nécessaire mais les inscriptions ne sont pas ouvertes.

diff --git a/resources/js/pages/Rainfall.tsx b/resources/js/pages/Rainfall/RainfallGraph.tsx similarity index 85% rename from resources/js/pages/Rainfall.tsx rename to resources/js/pages/Rainfall/RainfallGraph.tsx index a5576c9..36b0ea1 100644 --- a/resources/js/pages/Rainfall.tsx +++ b/resources/js/pages/Rainfall/RainfallGraph.tsx @@ -1,14 +1,14 @@ import React, {useEffect, useState} from "react" -import PageLayout from "../components/PageLayout" -import LastFiveMesure from "../components/rainfall/LastFiveMesure" -import AddRainfall from "../components/rainfall/AddRainfall" -import useAxiosTools from "../hooks/AxiosTools" -import {rainfallGraphData} from "../types" -import Field from "../components/Field" -import useDimension from "../hooks/DimensionHook" -import RainFallEcharts from "../components/rainfall/RainFallEcharts" +import PageLayout from "../../components/PageLayout" +import LastFiveMesure from "../../components/rainfall/LastFiveMesure" +import AddRainfall from "../../components/rainfall/AddRainfall" +import useAxiosTools from "../../hooks/AxiosTools" +import {rainfallGraphData} from "../../types" +import Field from "../../components/Field" +import useDimension from "../../hooks/DimensionHook" +import RainFallEcharts from "../../components/rainfall/RainFallEcharts" -const Rainfall = () => { +const RainfallGraph = () => { const [loadedAt, reload] = useState(new Date) const [graphData, setGraphData] = useState([]) @@ -77,4 +77,4 @@ const Rainfall = () => { } -export default Rainfall +export default RainfallGraph diff --git a/resources/js/pages/Router.tsx b/resources/js/pages/Router.tsx index 7855b26..56e1697 100644 --- a/resources/js/pages/Router.tsx +++ b/resources/js/pages/Router.tsx @@ -9,7 +9,7 @@ const Home = lazy(() => import('./Home')) const Login = lazy(() => import('./Auth/Login')) const Profile = lazy(() => import('./Auth/Profile')) const Reset = lazy(() => import('./Auth/Reset')) -const Rainfall = lazy(() => import('./Rainfall')) +const Rainfall = lazy(() => import('./Rainfall/RainfallGraph')) const RainfallIndex = lazy(() => import('./Rainfall/RainfallIndex')) const Router = () => { diff --git a/resources/js/types.ts b/resources/js/types.ts index 32798eb..4367e20 100644 --- a/resources/js/types.ts +++ b/resources/js/types.ts @@ -14,6 +14,13 @@ export interface rainfallGraphData { value: number, } +export interface monthlyRainfall { + year: number, + month: number, + label: string, + values: number, +} + export interface WeatherRequest { list: WeatherValue[], } diff --git a/routes/api.php b/routes/api.php index 73cbd3e..d34becf 100644 --- a/routes/api.php +++ b/routes/api.php @@ -28,6 +28,7 @@ Route::middleware('auth:sanctum')->group(function () { Route::post('/locations', [LocationController::class, 'store'])->name('location.store'); + Route::get('/rainfalls/last-months', [RainfallController::class, 'lastMonths'])->name('rainfalls.last'); Route::get('/rainfalls/last', [RainfallController::class, 'lastRainfalls'])->name('rainfalls.last'); Route::get('/rainfalls/graph', [RainfallController::class, 'graphValue'])->name('rainfalls.graph');