diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 07076976..59f9e3b7 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -371,9 +371,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -391,9 +388,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -2698,9 +2692,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2715,9 +2706,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2732,9 +2720,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2749,9 +2734,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2766,9 +2748,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2783,9 +2762,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2800,9 +2776,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2817,9 +2790,6 @@ "ppc64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2834,9 +2804,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2851,9 +2818,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2868,9 +2832,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3118,9 +3079,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3138,9 +3096,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4129,9 +4084,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -4153,9 +4105,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ diff --git a/webapp/src/app/providers/ApiProvider.tsx b/webapp/src/app/providers/ApiProvider.tsx index 7a478aaa..69c89604 100644 --- a/webapp/src/app/providers/ApiProvider.tsx +++ b/webapp/src/app/providers/ApiProvider.tsx @@ -2,13 +2,15 @@ import { type ReactNode, useMemo } from "react"; import { createApiClient } from "@shared/api/client"; import { ApiContext } from "@shared/contexts/ApiContext"; +import { useAuth } from "@features/auth/useAuth"; interface ApiProviderProps { children: ReactNode; } export function ApiProvider({ children }: ApiProviderProps) { - const api = useMemo(() => createApiClient(), []); + const {token} = useAuth() + const api = useMemo(() => createApiClient(token), []); return {children}; } diff --git a/webapp/src/app/routes/AppRouter.tsx b/webapp/src/app/routes/AppRouter.tsx index 87bd06f9..499f1db3 100644 --- a/webapp/src/app/routes/AppRouter.tsx +++ b/webapp/src/app/routes/AppRouter.tsx @@ -7,6 +7,7 @@ import { MapProvider } from "@app/providers"; import { MainPage } from "@pages/MainPage"; import { AdminRoute } from "./lib/AdminRoute"; +import { DashboardPage } from "@pages/dashboard/DashboardPage"; const AdminPage = lazy(() => import("@pages/admin")); const LoginPage = lazy(() => import("@pages/login")); @@ -44,6 +45,9 @@ export function AppRouter() { path="admin" /> + } + path="dashboard" /> ); diff --git a/webapp/src/pages/dashboard/DashboardPage.tsx b/webapp/src/pages/dashboard/DashboardPage.tsx new file mode 100644 index 00000000..433fa31a --- /dev/null +++ b/webapp/src/pages/dashboard/DashboardPage.tsx @@ -0,0 +1,272 @@ +import { useEffect, useState } from "react"; +import { useApi } from "@shared/hooks/useApi"; +import type { ApiClient } from "@shared/api/client"; + +import { Header } from "@widgets/header"; +import { DashBoardHead } from "@widgets/dashboard/head"; +import { ChartForestPotential } from "@features/charts/biodiversity/chart-forest-potential"; + +// request API pour récupérer les données du back, utilisée dans useEffect [window.onload] à terme +async function request(api:ApiClient) { + const data = await api.getDashboardData(); + return data +} + +function twoDecimals(data: Record) { + return Object.fromEntries( + Object.entries(data).map(([key, { value, error }]) => [ + key, + { + value: value === null || value === undefined ? 0 : Number(parseFloat(value).toFixed(2)), + error: error === null || value === undefined ? 0 : Number(parseFloat(error).toFixed(2)) , + }, + ]) + ); +} + +type DataField = { value: number | null; error: number | null }; + +type RawData = { + biomass_volume: DataField; + tree_density: DataField; + richness: DataField; + epf_tree_density: DataField; + epf_necromass_pied: DataField; + epf_necromass_sol: DataField; + epf_necro_biomass_ratio: DataField; + epf_tree_diversity: DataField; + epf_spatial_distribution: DataField; + epf_diameter_distribution: DataField; + epf_vertical_distribution: DataField; + epf_dominant_height: DataField; + epf_microhabitats: DataField; + soil_structure: DataField; + soil_composition: DataField; + ero_rainfall_and_wind: DataField; + ero_couv_slope_and_cover: DataField; + ero_soil_stability: DataField; + ero_water_seepage: DataField; + soil_fauna_density: DataField; + soil_fauna_diversity: DataField; + soil_fauna_abundance_tax1: DataField; + soil_fauna_abundance_tax2: DataField; + soil_fauna_abundance_tax3: DataField; + surface_fauna_density: DataField; + surface_fauna_diversity: DataField; + surface_fauna_abundance_tax1: DataField; + surface_fauna_abundance_tax2: DataField; + surface_fauna_abundance_tax3: DataField; +}; + +const emptyField: DataField = { value: 0, error: 0 }; + +type ChartPotential = { + density: number; + diversity: number; + diameterDistribution: number; + dominantHeight: number; + microHabitat: number; + ratioDeathmassBiomass: number; + spatialDistribution: number; + verticalDistribution: number; +}; + +const fakeData: RawData = { + "biomass_volume": { + "value": null, + "error": null + }, + "tree_density": { + "value": 191.095576570167, + "error": 165.238402454365 + }, + "richness": { + "value": 4.07712393017746, + "error": 2.5814518750596 + }, + "epf_tree_density": { + "value": 1.91095576570167, + "error": 1.65238402454365 + }, + "epf_necromass_pied": { + "value": null, + "error": null + }, + "epf_necromass_sol": { + "value": 208.501348435867, + "error": 151.298726015167 + }, + "epf_necro_biomass_ratio": { + "value": null, + "error": null + }, + "epf_tree_diversity": { + "value": 1.58786308798239, + "error": 1.18239125654929 + }, + "epf_spatial_distribution": { + "value": 3.79432407709241, + "error": 1.91339763493866 + }, + "epf_diameter_distribution": { + "value": null, + "error": null + }, + "epf_vertical_distribution": { + "value": 1.87197322382213, + "error": 0.850973739884704 + }, + "epf_dominant_height": { + "value": 2.77146680888316, + "error": 1.04807137228201 + }, + "epf_microhabitats": { + "value": 2.45796262269716, + "error": 1.2825137863247 + }, + "soil_structure": { + "value": null, + "error": null + }, + "soil_composition": { + "value": 1, + "error": 0 + }, + "ero_rainfall_and_wind": { + "value": null, + "error": null + }, + "ero_couv_slope_and_cover": { + "value": null, + "error": null + }, + "ero_soil_stability": { + "value": 3.61301785316609, + "error": 1.03530203632118 + }, + "ero_water_seepage": { + "value": 0.0105773064537853, + "error": 0.0190876236808545 + }, + "soil_fauna_density": { + "value": 35.4364475369042, + "error": 54.1157337750946 + }, + "soil_fauna_diversity": { + "value": 1.11305062617862, + "error": 0.322854726031543 + }, + "soil_fauna_abundance_tax1": { + "value": null, + "error": null + }, + "soil_fauna_abundance_tax2": { + "value": null, + "error": null + }, + "soil_fauna_abundance_tax3": { + "value": null, + "error": null + }, + "surface_fauna_density": { + "value": 233487.710287447, + "error": 187362.916231765 + }, + "surface_fauna_diversity": { + "value": 2.27261737826991, + "error": 1.84248681478387 + }, + "surface_fauna_abundance_tax1": { + "value": null, + "error": null + }, + "surface_fauna_abundance_tax2": { + "value": null, + "error": null + }, + "surface_fauna_abundance_tax3": { + "value": null, + "error": null + } +} + + +export function DashboardPage() { + const [data, setData] = useState({ + biomass_volume: emptyField, + tree_density: emptyField, + richness: emptyField, + epf_tree_density: emptyField, + epf_necromass_pied: emptyField, + epf_necromass_sol: emptyField, + epf_necro_biomass_ratio: emptyField, + epf_tree_diversity: emptyField, + epf_spatial_distribution: emptyField, + epf_diameter_distribution: emptyField, + epf_vertical_distribution: emptyField, + epf_dominant_height: emptyField, + epf_microhabitats: emptyField, + soil_structure: emptyField, + soil_composition: emptyField, + ero_rainfall_and_wind: emptyField, + ero_couv_slope_and_cover: emptyField, + ero_soil_stability: emptyField, + ero_water_seepage: emptyField, + soil_fauna_density: emptyField, + soil_fauna_diversity: emptyField, + soil_fauna_abundance_tax1: emptyField, + soil_fauna_abundance_tax2: emptyField, + soil_fauna_abundance_tax3: emptyField, + surface_fauna_density: emptyField, + surface_fauna_diversity: emptyField, + surface_fauna_abundance_tax1: emptyField, + surface_fauna_abundance_tax2: emptyField, + surface_fauna_abundance_tax3: emptyField, +}); + + const [benefChartPotential, setBenefChartPotential] = useState({ + density: 0, + diversity: 0, + diameterDistribution: 0, + dominantHeight: 0, + microHabitat: 0, + ratioDeathmassBiomass: 0, + spatialDistribution: 0, + verticalDistribution: 0 +}); + + const api = useApi(); + + useEffect (() => { + // setData(twoDecimals(fakeData)); + const rawData = request(api); + setData(twoDecimals(rawData)); + }, []) + + useEffect (() => { + console.log("Data:", data); + setBenefChartPotential({ + density: data.epf_tree_density.value || 0, + diversity: data.epf_tree_diversity.value || 0, + diameterDistribution: data.epf_diameter_distribution.value || 0, + dominantHeight: data.epf_dominant_height.value || 0, + microHabitat: data.epf_microhabitats.value || 0, + ratioDeathmassBiomass: data.epf_necro_biomass_ratio.value || 0, + spatialDistribution: data.epf_spatial_distribution.value || 0, + verticalDistribution: data.epf_vertical_distribution.value || 0 + }) + }, [data]) + + return ( +
+
+
+ +
+ +
+
+ +
+ ); +} diff --git a/webapp/src/shared/api/client.ts b/webapp/src/shared/api/client.ts index cc6794cd..f00ca147 100644 --- a/webapp/src/shared/api/client.ts +++ b/webapp/src/shared/api/client.ts @@ -39,6 +39,9 @@ export const fetchJSONWithAuth = async ( authToken: string | null, ) => (await fetchWithAuth(endpoint, options, authToken)).json(); -export const createApiClient = () => ({}); +export const createApiClient = (authToken: string | null) => ({ + // Bases + getDashboardData: () => fetchJSONWithAuth('/maps/dashboard/inventaire', {}, authToken), +}); export type ApiClient = ReturnType; diff --git a/webapp/src/shared/i18n/translations/fr/translations.json b/webapp/src/shared/i18n/translations/fr/translations.json index 95923dd5..54876b04 100644 --- a/webapp/src/shared/i18n/translations/fr/translations.json +++ b/webapp/src/shared/i18n/translations/fr/translations.json @@ -209,5 +209,9 @@ "typePlant": "Type de plant" } } + }, + "buttonHeader": { + "toDashboard": "Montrer le dashboard", + "toHome": "Montrer la carte" } } diff --git a/webapp/src/shared/urls.ts b/webapp/src/shared/urls.ts index 36fcfa3c..d777235c 100644 --- a/webapp/src/shared/urls.ts +++ b/webapp/src/shared/urls.ts @@ -1,3 +1,5 @@ export const URLS = { + HOME: "/", LOGIN: "/login", + DASHBOARD: "/dashboard" } as const; diff --git a/webapp/src/widgets/dashboard/head.tsx b/webapp/src/widgets/dashboard/head.tsx new file mode 100644 index 00000000..38557553 --- /dev/null +++ b/webapp/src/widgets/dashboard/head.tsx @@ -0,0 +1,21 @@ +export function DashBoardHead() { + return ( +
+
+
+

Bonjour, Liam Gallagher ! 👋

+

Que recherchez-vous aujourd'hui ?

+
+

⚠ Filtre

+
+ +
+

Catalogue des graphiques

+
+

⚠ 2024

+

⚠ Bénéficiaire

+
+
+
+ ) +} diff --git a/webapp/src/widgets/header/index.tsx b/webapp/src/widgets/header/index.tsx index 3f8c507e..66c38a75 100644 --- a/webapp/src/widgets/header/index.tsx +++ b/webapp/src/widgets/header/index.tsx @@ -1,8 +1,31 @@ -import { DashboardPopover } from "@widgets/DashboardPopover"; +// import { DashboardPopover } from "@widgets/DashboardPopover"; import { UserMenu } from "./user-menu"; +import { Button } from "@shared/ui/button"; +import { URLS } from "@shared/urls"; +import { useNavigate, useLocation } from "react-router-dom"; +import { useTranslation } from "@shared/i18n"; +import { useEffect, useState } from "react"; export function Header() { + const navigate = useNavigate(); + const location = useLocation(); + const path = location.pathname; + const { t } = useTranslation("translations"); + const [buttonText, setButtonText] = useState("") + + function navDashboard() { + if (path === "/") { + navigate(URLS.DASHBOARD); + } else if (path === "/dashboard") { + navigate(URLS.HOME) + } + } + + useEffect(() => { + path === "/" ? setButtonText(t("buttonHeader.toDashboard")) : setButtonText(t("buttonHeader.toHome")); + }) + return (
@@ -14,7 +37,9 @@ export function Header() { />
- +
diff --git a/webapp/src/widgets/map/Map.tsx b/webapp/src/widgets/map/Map.tsx index ac18c178..587ae177 100644 --- a/webapp/src/widgets/map/Map.tsx +++ b/webapp/src/widgets/map/Map.tsx @@ -20,6 +20,7 @@ import { useMap } from "@shared/hooks/useMap"; import pictoInventaire from "./assets/inventaire-icon.svg"; import pictoSocioEco from "./assets/socio-eco-icon.svg"; + function getIconSize({ assetSize, targetSize, @@ -36,9 +37,14 @@ function getIconSize({ const TARGET_SIZE = 48; const SVG_SIZE = 72; + + export const WidgetMap: FC = () => { const { isReady, mapApiRef, forests, mapContainerRef } = useMap(); + + + useEffect(() => { if (!isReady || !mapApiRef.current) return;