@geo2france/api-dashboard 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.MD +192 -0
  2. package/dist/components/Attributions/Attribution.test.d.ts +1 -0
  3. package/dist/components/Attributions/Attribution.test.js +19 -0
  4. package/dist/components/Attributions/Attributions.d.ts +17 -0
  5. package/dist/components/Attributions/Attributions.js +30 -0
  6. package/dist/components/Charts/ChartEcharts.d.ts +7 -0
  7. package/dist/components/Charts/ChartEcharts.js +35 -0
  8. package/dist/components/Charts/Pie.d.ts +10 -0
  9. package/dist/components/Charts/Pie.js +35 -0
  10. package/dist/components/Charts/YearSerie.d.ts +16 -0
  11. package/dist/components/Charts/YearSerie.js +70 -0
  12. package/dist/components/Control/Control.d.ts +21 -0
  13. package/dist/components/Control/Control.js +84 -0
  14. package/dist/components/Control/Radio.d.ts +19 -0
  15. package/dist/components/Control/Radio.js +27 -0
  16. package/dist/components/Control/Select.d.ts +15 -0
  17. package/dist/components/Control/Select.js +25 -0
  18. package/dist/components/DashboardChart/DashboardChart.d.ts +11 -0
  19. package/dist/components/DashboardChart/DashboardChart.js +42 -0
  20. package/dist/components/DashboardElement/DashboardElement.d.ts +21 -0
  21. package/dist/components/DashboardElement/DashboardElement.js +108 -0
  22. package/dist/components/DashboardElement/hooks.d.ts +28 -0
  23. package/dist/components/DashboardElement/hooks.js +29 -0
  24. package/dist/components/DashboardPage/Block.d.ts +15 -0
  25. package/dist/components/DashboardPage/Block.js +40 -0
  26. package/dist/components/DashboardPage/DashboardPage.test.d.ts +1 -0
  27. package/dist/components/DashboardPage/DashboardPage.test.js +40 -0
  28. package/dist/components/DashboardPage/Page.d.ts +42 -0
  29. package/dist/components/DashboardPage/Page.js +80 -0
  30. package/dist/components/Dataset/DataPreview.d.ts +12 -0
  31. package/dist/components/Dataset/DataPreview.js +21 -0
  32. package/dist/components/Dataset/Dataset.d.ts +17 -0
  33. package/dist/components/Dataset/Dataset.js +94 -0
  34. package/dist/components/Dataset/Filter.d.ts +9 -0
  35. package/dist/components/Dataset/Filter.js +7 -0
  36. package/dist/components/Dataset/Join.d.ts +8 -0
  37. package/dist/components/Dataset/Join.js +7 -0
  38. package/dist/components/Dataset/Producer.d.ts +18 -0
  39. package/dist/components/Dataset/Producer.js +27 -0
  40. package/dist/components/Dataset/Provider.d.ts +21 -0
  41. package/dist/components/Dataset/Provider.js +22 -0
  42. package/dist/components/Dataset/Transform.d.ts +6 -0
  43. package/dist/components/Dataset/Transform.js +7 -0
  44. package/dist/components/Dataset/hooks.d.ts +24 -0
  45. package/dist/components/Dataset/hooks.js +19 -0
  46. package/dist/components/Debug/Debug.d.ts +1 -0
  47. package/dist/components/Debug/Debug.js +24 -0
  48. package/dist/components/FlipCard/FlipCard.d.ts +12 -0
  49. package/dist/components/FlipCard/FlipCard.js +38 -0
  50. package/dist/components/FlipCard/FlipCard.test.d.ts +1 -0
  51. package/dist/components/FlipCard/FlipCard.test.js +36 -0
  52. package/dist/components/KeyFigure/KeyFigure.d.ts +18 -0
  53. package/dist/components/KeyFigure/KeyFigure.js +13 -0
  54. package/dist/components/Layout/DashboardApp.d.ts +18 -0
  55. package/dist/components/Layout/DashboardApp.js +46 -0
  56. package/dist/components/Layout/Error.d.ts +2 -0
  57. package/dist/components/Layout/Error.js +6 -0
  58. package/dist/components/Layout/Footer.d.ts +6 -0
  59. package/dist/components/Layout/Footer.js +47 -0
  60. package/dist/components/Layout/Sider.d.ts +9 -0
  61. package/dist/components/Layout/Sider.js +48 -0
  62. package/dist/components/LoadingContainer/LoadingContainer.d.ts +17 -0
  63. package/dist/components/LoadingContainer/LoadingContainer.js +33 -0
  64. package/dist/components/MapLegend/MapLegend.d.ts +12 -0
  65. package/dist/components/MapLegend/MapLegend.js +19 -0
  66. package/dist/components/NextPrevSelect/NextPrevSelect.d.ts +17 -0
  67. package/dist/components/NextPrevSelect/NextPrevSelect.js +49 -0
  68. package/dist/components/Palette/Palette.d.ts +18 -0
  69. package/dist/components/Palette/Palette.js +29 -0
  70. package/dist/data_providers/datafair/datafair.test.d.ts +1 -0
  71. package/dist/data_providers/datafair/datafair.test.js +39 -0
  72. package/dist/data_providers/datafair/index.d.ts +15 -0
  73. package/dist/data_providers/datafair/index.js +33 -0
  74. package/dist/data_providers/datafair/utils/axios.d.ts +2 -0
  75. package/dist/data_providers/datafair/utils/axios.js +13 -0
  76. package/dist/data_providers/datafair/utils/generateFilter.d.ts +1 -0
  77. package/dist/data_providers/datafair/utils/generateFilter.js +40 -0
  78. package/dist/data_providers/datafair/utils/generateSort.d.ts +1 -0
  79. package/dist/data_providers/datafair/utils/generateSort.js +19 -0
  80. package/dist/data_providers/datafair/utils/index.d.ts +4 -0
  81. package/dist/data_providers/datafair/utils/index.js +4 -0
  82. package/dist/data_providers/datafair/utils/mapOperator.d.ts +1 -0
  83. package/dist/data_providers/datafair/utils/mapOperator.js +13 -0
  84. package/dist/data_providers/file/index.d.ts +6 -0
  85. package/dist/data_providers/file/index.js +25 -0
  86. package/dist/data_providers/file/utils/axios.d.ts +2 -0
  87. package/dist/data_providers/file/utils/axios.js +26 -0
  88. package/dist/data_providers/types.d.ts +52 -0
  89. package/dist/data_providers/types.js +2 -0
  90. package/dist/data_providers/wfs/index.d.ts +3 -0
  91. package/dist/data_providers/wfs/index.js +43 -0
  92. package/dist/data_providers/wfs/utils/axios.d.ts +2 -0
  93. package/dist/data_providers/wfs/utils/axios.js +26 -0
  94. package/dist/data_providers/wfs/utils/generateFilter.d.ts +4 -0
  95. package/dist/data_providers/wfs/utils/generateFilter.js +45 -0
  96. package/dist/data_providers/wfs/utils/generateSort.d.ts +1 -0
  97. package/dist/data_providers/wfs/utils/generateSort.js +20 -0
  98. package/dist/data_providers/wfs/utils/index.d.ts +4 -0
  99. package/dist/data_providers/wfs/utils/index.js +4 -0
  100. package/dist/data_providers/wfs/utils/mapOperator.d.ts +1 -0
  101. package/dist/data_providers/wfs/utils/mapOperator.js +36 -0
  102. package/dist/data_providers/wfs/wfs.test.d.ts +1 -0
  103. package/dist/data_providers/wfs/wfs.test.js +60 -0
  104. package/dist/dsl/index.d.ts +19 -0
  105. package/dist/dsl/index.js +19 -0
  106. package/dist/index.d.ts +29 -0
  107. package/dist/index.js +33 -0
  108. package/dist/types.d.ts +15 -0
  109. package/dist/types.js +1 -0
  110. package/dist/utils/baserecordtogeojsonpoint.d.ts +13 -0
  111. package/dist/utils/baserecordtogeojsonpoint.js +17 -0
  112. package/dist/utils/cardStyles.d.ts +2 -0
  113. package/dist/utils/cardStyles.js +12 -0
  114. package/dist/utils/deepmerge.d.ts +2 -0
  115. package/dist/utils/deepmerge.js +24 -0
  116. package/dist/utils/route_utils.d.ts +6 -0
  117. package/dist/utils/route_utils.js +14 -0
  118. package/dist/utils/useApi.d.ts +12 -0
  119. package/dist/utils/useApi.js +14 -0
  120. package/dist/utils/useMapControl.d.ts +8 -0
  121. package/dist/utils/useMapControl.js +24 -0
  122. package/dist/utils/useSearchParamsState.d.ts +11 -0
  123. package/dist/utils/useSearchParamsState.js +18 -0
  124. package/dist/utils/usechartexports.d.ts +17 -0
  125. package/dist/utils/usechartexports.js +39 -0
  126. package/dist/utils/usecharthightlight.d.ts +25 -0
  127. package/dist/utils/usecharthightlight.js +44 -0
  128. package/package.json +98 -0
@@ -0,0 +1,18 @@
1
+ import { ReactElement } from "react";
2
+ export type ProducerType = {
3
+ nom: string;
4
+ url?: string;
5
+ };
6
+ interface IProducerProps {
7
+ url?: string;
8
+ children: string;
9
+ }
10
+ /**
11
+ * Les props sont récupérées par le parent (Dataset) et enregistrés avec le dataset
12
+ */
13
+ export declare const Producer: React.FC<IProducerProps>;
14
+ interface IProducersFooterProps {
15
+ component: ReactElement;
16
+ }
17
+ export declare const ProducersFooter: React.FC<IProducersFooterProps>;
18
+ export {};
@@ -0,0 +1,27 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useDatasets } from "./hooks";
3
+ import { Typography } from "antd";
4
+ const { Link } = Typography;
5
+ /**
6
+ * Les props sont récupérées par le parent (Dataset) et enregistrés avec le dataset
7
+ */
8
+ export const Producer = () => {
9
+ return _jsx(_Fragment, {});
10
+ };
11
+ /*
12
+ Composant pour afficher les producteurs sous le graphique
13
+ */
14
+ export const ProducersFooter = ({ component }) => {
15
+ // On vérfie si le composant à une props dataset (définie ou non)
16
+ // Afin de ne PAS afficher de producteur sur les élements qui ne font appel à aucun dataset (par exemple les bloc statiques)
17
+ if ('props' in component && 'dataset' in component.props) {
18
+ const dataset_id_arr = Array.isArray(component.props.dataset) ? component.props.dataset : [component.props.dataset];
19
+ const datasets = useDatasets(dataset_id_arr);
20
+ const producers = datasets?.flatMap((dataset) => dataset?.producers?.map((p) => ({ nom: p.nom, url: p.url }))).filter(p => p !== undefined);
21
+ const uniqueProducers = Array.from(new Map(producers?.map(p => [p.nom, p]) // clé unique = nom
22
+ ).values());
23
+ uniqueProducers.sort((a, b) => a.nom.localeCompare(b.nom));
24
+ return datasets ? (_jsxs(_Fragment, { children: ["Source des donn\u00E9es :", " ", uniqueProducers?.map((p, idx, arr) => (_jsxs("span", { children: [_jsx(Link, { href: p.url, children: p.nom }), idx < arr.length - 1 ? ', ' : ''] }, idx)))] })) : null;
25
+ }
26
+ return _jsx(_Fragment, {});
27
+ };
@@ -0,0 +1,21 @@
1
+ import { ReactNode } from "react";
2
+ import { DataProvider } from "../../data_providers/types";
3
+ export declare const DataProviderContext: import("react").Context<DataProvider | undefined>;
4
+ export type ProviderType = "wfs" | "datafair" | "file";
5
+ interface IProviderProps {
6
+ children?: ReactNode;
7
+ type: ProviderType;
8
+ url: string;
9
+ }
10
+ export declare const getProviderFromType: (s: ProviderType) => ((apiUrl: string, httpClient?: import("axios").AxiosInstance) => {
11
+ getList: ({ resource, pagination, filters, sorters, meta }: import("../../data_providers/datafair").GetListParams) => Promise<{
12
+ data: any;
13
+ total: any;
14
+ }>;
15
+ getApiUrl: () => string;
16
+ }) | ((apiUrl: string, httpClient?: import("axios").AxiosInstance) => DataProvider) | ((apiUrl: string, options?: {
17
+ httpClient?: import("axios").AxiosInstance;
18
+ processData?: (data: any) => any[];
19
+ }) => DataProvider);
20
+ export declare const Provider: React.FC<IProviderProps>;
21
+ export {};
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext } from "react";
3
+ import { DatafairProvider, FileProvider, WfsProvider } from "../..";
4
+ export const DataProviderContext = createContext(undefined);
5
+ export const getProviderFromType = (s) => {
6
+ if (s == "datafair") {
7
+ return DatafairProvider;
8
+ }
9
+ else if (s == "wfs") {
10
+ return WfsProvider;
11
+ }
12
+ else if (s == "file") {
13
+ return FileProvider;
14
+ }
15
+ else {
16
+ throw "Unssuported provider";
17
+ }
18
+ };
19
+ export const Provider = ({ children, type: provider_type, url }) => {
20
+ const provider_fn = getProviderFromType(provider_type);
21
+ return (_jsx(DataProviderContext.Provider, { value: provider_fn(url), children: children }));
22
+ };
@@ -0,0 +1,6 @@
1
+ import { SimpleRecord } from "../..";
2
+ interface ITransformProps<T = SimpleRecord[]> {
3
+ children: string | ((data: T) => T);
4
+ }
5
+ export declare const DSL_Transform: React.FC<ITransformProps>;
6
+ export {};
@@ -0,0 +1,7 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ /*
3
+ * Les props sont utilisées dans le Dataset parent pour appliquer une (ou plusieurs fonction de transformation)
4
+ */
5
+ export const DSL_Transform = () => {
6
+ return _jsx(_Fragment, {});
7
+ };
@@ -0,0 +1,24 @@
1
+ export declare const useDataset: (dataset_id?: string) => {
2
+ id: string;
3
+ resource: string;
4
+ data?: import("../..").SimpleRecord[];
5
+ isFetching: boolean;
6
+ isError: boolean;
7
+ producers?: any[];
8
+ } | undefined;
9
+ export declare const useDatasets: (dataset_ids?: string[]) => {
10
+ id: string;
11
+ resource: string;
12
+ data?: import("../..").SimpleRecord[];
13
+ isFetching: boolean;
14
+ isError: boolean;
15
+ producers?: any[];
16
+ }[] | undefined;
17
+ export declare const useAllDatasets: () => {
18
+ id: string;
19
+ resource: string;
20
+ data?: import("../..").SimpleRecord[];
21
+ isFetching: boolean;
22
+ isError: boolean;
23
+ producers?: any[];
24
+ }[] | undefined;
@@ -0,0 +1,19 @@
1
+ import { useContext } from "react";
2
+ import { DatasetContext } from "../DashboardPage/Page";
3
+ export const useDataset = (dataset_id) => {
4
+ const datasetContext = useContext(DatasetContext);
5
+ if (dataset_id) {
6
+ return datasetContext[dataset_id];
7
+ }
8
+ // Retourne le premier dataset si pas d'id
9
+ const firstKey = Object.keys(datasetContext)[0];
10
+ return firstKey ? datasetContext[firstKey] : undefined;
11
+ };
12
+ export const useDatasets = (dataset_ids) => {
13
+ const datasetContext = useContext(DatasetContext);
14
+ return (dataset_ids?.map((dataset_id) => datasetContext[dataset_id]));
15
+ };
16
+ export const useAllDatasets = () => {
17
+ const datasetContext = useContext(DatasetContext);
18
+ return useDatasets(Object.keys(datasetContext));
19
+ };
@@ -0,0 +1 @@
1
+ export declare const Debug: React.FC;
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Badge, Collapse, Divider, FloatButton, Modal, theme, Typography } from "antd";
3
+ import { DataPreview, PalettePreview } from "../../dsl";
4
+ import { useAllDatasets } from "../Dataset/hooks";
5
+ import { AiOutlineBug } from "react-icons/ai";
6
+ import { useState } from "react";
7
+ import { DatasetBadgeStatus } from "../Dataset/DataPreview";
8
+ import { ControlPreview } from "../Control/Control";
9
+ const { useToken } = theme;
10
+ const { Text, Title } = Typography;
11
+ /*
12
+ * Ajoute un float-button permettant d'afficher un panneau de debug listant les jeux de données, les contrôles, etc..
13
+ */
14
+ export const Debug = () => {
15
+ const { token } = useToken();
16
+ const [isModalOpen, setIsModalOpen] = useState(false);
17
+ const datasets = useAllDatasets();
18
+ const items = datasets?.map((dataset) => ({
19
+ key: dataset.id,
20
+ label: _jsxs("span", { children: [_jsx(DatasetBadgeStatus, { isError: dataset?.isError, isFetching: dataset?.isFetching }), " ", dataset.id, " ", " ", _jsxs(Text, { type: "secondary", children: [" ", dataset?.resource, " "] }), " ", _jsx(Badge, { color: token.colorInfo, overflowCount: 9999, count: dataset?.data?.length })] }),
21
+ children: _jsx(DataPreview, { dataset: dataset.id, pageSize: 3 })
22
+ }));
23
+ return (_jsxs(_Fragment, { children: [_jsx(FloatButton, { icon: _jsx(AiOutlineBug, {}), type: "primary", onClick: () => setIsModalOpen(true), style: { top: 5 }, className: "debugFloatButton" }), ";", _jsxs(Modal, { title: "Information concepteur", width: "90%", centered: true, styles: { content: { 'width': "100%", padding: 36 } }, closable: { 'aria-label': 'Custom Close Button' }, open: isModalOpen, onCancel: () => setIsModalOpen(false), footer: null, children: [_jsx(Title, { level: 5, children: "Jeux de donn\u00E9es " }), _jsx(Collapse, { accordion: true, items: items }), _jsx(Divider, {}), _jsx(Title, { level: 5, children: "Contr\u00F4les utilisateur " }), _jsx(ControlPreview, {}), _jsx(Divider, {}), _jsx(Title, { level: 5, children: "Palette " }), _jsx(PalettePreview, {})] })] }));
24
+ };
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { ReactElement } from "react";
3
+ interface FlipCardProps {
4
+ title?: string | ReactElement;
5
+ children: ReactElement | ReactElement[];
6
+ information?: ReactElement | string;
7
+ }
8
+ /**
9
+ * Une card qui peux se retourner et afficher des informations a son verso
10
+ */
11
+ declare const FlipCard: React.FC<FlipCardProps>;
12
+ export default FlipCard;
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef } from 'react';
3
+ import { Button, Card, Typography } from "antd";
4
+ import { useState } from "react";
5
+ import { BsInfoCircle, BsInfoCircleFill } from "react-icons/bs";
6
+ import { cardStyles } from "../../utils/cardStyles";
7
+ const { Text } = Typography;
8
+ /**
9
+ * Une card qui peux se retourner et afficher des informations a son verso
10
+ */
11
+ const FlipCard = ({ title, information, children }) => {
12
+ const [flipped, setFlipped] = useState(false);
13
+ const toggleFlipped = () => setFlipped(!flipped);
14
+ const cardARef = useRef(null);
15
+ const height = cardARef.current ? cardARef.current.clientHeight : undefined; // Forcer la hauteur à celle de la card "Recto"
16
+ const FlipCardStyle = {
17
+ transition: "transform 0.8s",
18
+ backfaceVisibility: "hidden",
19
+ width: "100%",
20
+ };
21
+ const InfoButton = ({ filled = false }) => {
22
+ return (_jsx(Button, { type: "text", shape: "circle", "aria-label": "info", onClick: toggleFlipped, children: filled ? _jsx(BsInfoCircleFill, {}) : _jsx(BsInfoCircle, {}) }));
23
+ };
24
+ return (_jsxs("div", { style: { position: "relative", height: "100%" }, children: [_jsx(Card, { title: title, extra: _jsxs(_Fragment, { children: [information && _jsx(InfoButton, { filled: flipped }), " "] }), style: {
25
+ transform: flipped ? "rotateY(180deg)" : "",
26
+ position: "static",
27
+ height: "100%",
28
+ ...FlipCardStyle,
29
+ }, styles: cardStyles, ref: cardARef, children: children }), _jsx(Card, { title: title, extra: _jsx(InfoButton, { filled: flipped }), style: {
30
+ transform: !flipped ? "rotateY(180deg)" : "",
31
+ height: height,
32
+ top: 0,
33
+ position: "absolute",
34
+ overflow: "auto",
35
+ ...FlipCardStyle,
36
+ }, styles: cardStyles, children: typeof information === "string" ? (_jsx("div", { style: { margin: 10 }, children: _jsx(Text, { italic: true, type: "secondary", children: information }) })) : (_jsx(_Fragment, { children: information })) })] }));
37
+ };
38
+ export default FlipCard;
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { render, screen } from '@testing-library/react';
3
+ import FlipCard from "./FlipCard";
4
+ import '@testing-library/jest-dom';
5
+ import userEvent from '@testing-library/user-event';
6
+ const a_value = "Hello !";
7
+ const b_value = "Ceci est une description";
8
+ describe("FlipCard Component", () => {
9
+ test("initial state", async () => {
10
+ // Génération DOM virtuel et sélection des noeuds
11
+ render(_jsx(FlipCard, { information: b_value, children: _jsx("span", { children: a_value }) }));
12
+ const cardA = screen.getByText(a_value).closest('.ant-card'); // Recto
13
+ const cardB = screen.getByText(b_value).closest('.ant-card'); // Verso
14
+ // Assertions
15
+ expect(screen.queryByText(a_value)).toBeInTheDocument();
16
+ expect(screen.queryByText(b_value)).toBeInTheDocument();
17
+ expect(cardA).not.toHaveStyle('transform: rotateY(180deg)');
18
+ expect(cardB).toHaveStyle('transform: rotateY(180deg)');
19
+ });
20
+ test("flip the card", async () => {
21
+ // initialisation user
22
+ const user = userEvent.setup();
23
+ // Génération DOM virtuel et sélection des noeuds
24
+ render(_jsx(FlipCard, { information: b_value, children: _jsx("span", { children: a_value }) }));
25
+ const cardA = screen.getByText(a_value).closest('.ant-card'); // Recto
26
+ const cardB = screen.getByText(b_value).closest('.ant-card'); // Verso
27
+ const infoButton = screen.getAllByRole('button', { name: "info" }); // Bouton info (2 boutons identiques, un sur chaque face). A améliorer
28
+ // Assertions
29
+ await user.click(infoButton[0]);
30
+ expect(cardA).toHaveStyle('transform: rotateY(180deg)');
31
+ expect(cardB).not.toHaveStyle('transform: rotateY(180deg)');
32
+ await user.click(infoButton[1]);
33
+ expect(cardA).not.toHaveStyle('transform: rotateY(180deg)');
34
+ expect(cardB).toHaveStyle('transform: rotateY(180deg)');
35
+ });
36
+ });
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { ReactElement } from "react";
3
+ export interface KeyFigureProps {
4
+ name?: string;
5
+ description?: string;
6
+ value?: number | string;
7
+ unit?: string;
8
+ sub_value?: number | string;
9
+ icon?: ReactElement;
10
+ digits?: number;
11
+ }
12
+ /**
13
+ * Composant permettant d'afficher un chiffre clé.
14
+ * Si une description est fournie, le composant "flip" pour montrer la description
15
+ * L'utilisateur peut aussi fournir une valeur de référence, généralement la valeur régionale ou nationale
16
+ */
17
+ declare const KeyFigure: React.FC<KeyFigureProps>;
18
+ export default KeyFigure;
@@ -0,0 +1,13 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Typography } from "antd";
3
+ import FlipCard from "../FlipCard/FlipCard";
4
+ const { Text } = Typography;
5
+ /**
6
+ * Composant permettant d'afficher un chiffre clé.
7
+ * Si une description est fournie, le composant "flip" pour montrer la description
8
+ * L'utilisateur peut aussi fournir une valeur de référence, généralement la valeur régionale ou nationale
9
+ */
10
+ const KeyFigure = ({ name, description, value, unit, sub_value, icon, digits }) => {
11
+ return (_jsx(FlipCard, { title: name, information: description, children: _jsxs("div", { style: { textAlign: "center", marginTop: 10 }, children: [_jsxs("span", { style: { fontSize: 24 }, children: [icon, " ", value ? value.toLocaleString(undefined, { maximumFractionDigits: digits }) : '-', " ", unit] }), " ", _jsxs("span", { style: { fontSize: 18 }, children: [_jsx("br", {}), _jsxs(Text, { type: "secondary", children: [sub_value, " "] })] })] }) }));
12
+ };
13
+ export default KeyFigure;
@@ -0,0 +1,18 @@
1
+ import { ThemeConfig } from "antd";
2
+ import { Partner, RouteConfig } from "../../types";
3
+ interface AppContextProps {
4
+ title?: string;
5
+ subtitle?: string;
6
+ logo?: string;
7
+ }
8
+ export declare const AppContext: import("react").Context<AppContextProps>;
9
+ interface DashboardApprProps {
10
+ title?: string;
11
+ subtitle?: string;
12
+ route_config: RouteConfig[];
13
+ theme?: ThemeConfig;
14
+ logo: string;
15
+ brands?: Partner[];
16
+ }
17
+ declare const DashboardApp: React.FC<DashboardApprProps>;
18
+ export default DashboardApp;
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
3
+ import { ConfigProvider, Layout } from "antd";
4
+ import { HashRouter, Outlet, Route, Routes } from "react-router-dom";
5
+ import { generateRoutes } from "../../utils/route_utils";
6
+ import DashboardSider from "./Sider";
7
+ import { Content } from "antd/es/layout/layout";
8
+ import { ErrorComponent } from "./Error";
9
+ import { DasbhoardFooter } from "./Footer";
10
+ import { createContext, useState } from "react";
11
+ import { ControlContext } from "../DashboardPage/Page";
12
+ import { HelmetProvider } from "react-helmet-async";
13
+ //import '../../index.css' //TODO a intégrer en jsx
14
+ const queryClient = new QueryClient();
15
+ const default_theme = {
16
+ token: {
17
+ colorPrimary: "#95c11f",
18
+ linkHoverDecoration: 'underline',
19
+ colorLink: '#0f4496',
20
+ colorLinkHover: '#0D2449',
21
+ borderRadius: 4,
22
+ fontFamily: 'Inter'
23
+ },
24
+ components: {
25
+ Timeline: {
26
+ itemPaddingBottom: 40
27
+ },
28
+ Form: {
29
+ labelColor: 'rgba(0,0,0,0.7)'
30
+ }
31
+ }
32
+ };
33
+ export const AppContext = createContext({});
34
+ const DashboardApp = ({ route_config, theme, logo, brands, title, subtitle }) => {
35
+ const context_values = { title, subtitle, logo };
36
+ /* CONTROLS */
37
+ const [controls, setControles] = useState({});
38
+ const pushControl = (c) => {
39
+ setControles(prev => ({
40
+ ...prev,
41
+ ...c
42
+ }));
43
+ };
44
+ return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ConfigProvider, { theme: theme || default_theme /* Merger plutôt ?*/, children: _jsx(HelmetProvider, { children: _jsx(AppContext.Provider, { value: context_values, children: _jsx(ControlContext.Provider, { value: { values: controls, pushValue: pushControl }, children: _jsx(HashRouter, { children: _jsx(Routes, { children: _jsxs(Route, { element: _jsxs(Layout, { children: [_jsxs(Layout, { children: [_jsx(DashboardSider, { route_config: route_config }), _jsx(Content, { style: { width: "85%" }, children: _jsx(Outlet, {}) })] }), _jsx(DasbhoardFooter, { brands: brands })] }), children: [generateRoutes(route_config), _jsx(Route, { path: "*", element: _jsx(ErrorComponent, {}) })] }) }) }) }) }) }) }) }));
45
+ };
46
+ export default DashboardApp;
@@ -0,0 +1,2 @@
1
+ import React from "react";
2
+ export declare const ErrorComponent: React.FC;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Result, Typography, Space } from "antd";
3
+ const { Text } = Typography;
4
+ export const ErrorComponent = () => {
5
+ return (_jsx(Result, { status: "404", title: "404", extra: _jsx(Space, { direction: "vertical", size: "large", children: _jsx(Space, { children: _jsx(Text, { children: "La page n'existe pas" }) }) }) }));
6
+ };
@@ -0,0 +1,6 @@
1
+ import { Partner } from "../../types";
2
+ interface DbFooterProps {
3
+ brands?: Partner[];
4
+ }
5
+ export declare const DasbhoardFooter: React.FC<DbFooterProps>;
6
+ export {};
@@ -0,0 +1,47 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Layout, Typography } from "antd";
3
+ import { useContext, useState } from "react";
4
+ import { UpOutlined, DownOutlined } from "@ant-design/icons";
5
+ import { AppContext } from "./DashboardApp";
6
+ const { Text, Link } = Typography;
7
+ export const DasbhoardFooter = ({ brands }) => {
8
+ const [isCollapsed, setIsCollapsed] = useState(window.innerWidth < 768 ? true : false);
9
+ const toggleCollapse = () => {
10
+ setIsCollapsed(!isCollapsed);
11
+ };
12
+ const app_context = useContext(AppContext);
13
+ const style_img = {
14
+ height: "60px",
15
+ marginRight: "20px",
16
+ };
17
+ return (_jsxs(Layout.Footer, { style: {
18
+ textAlign: "center",
19
+ color: "#fff",
20
+ backgroundColor: "#fff",
21
+ bottom: "0",
22
+ position: "sticky",
23
+ right: "0",
24
+ width: "100%",
25
+ height: isCollapsed ? "0px" : "150px",
26
+ transition: "height 0.5s ease-in-out",
27
+ overflow: "hidden",
28
+ borderTop: "1px solid #ccc",
29
+ zIndex: 600, // maplibre top zIndex if 500
30
+ }, children: [isCollapsed && (_jsx("div", { style: {
31
+ color: "#000",
32
+ fontSize: "14px",
33
+ marginTop: -15,
34
+ }, children: _jsx(Link, { href: "/", target: "_blank", children: _jsxs(Text, { children: [app_context?.title, " - ", app_context?.subtitle] }) }) })), _jsx("div", { style: { display: isCollapsed ? "none" : "block", padding: "10px 0" }, children: brands?.map((p) => (_jsx("a", { href: p.url, children: _jsx("img", { style: style_img, src: p.logo, alt: p.name }) }, p.name))) }), _jsx("div", { style: {
35
+ position: "absolute",
36
+ bottom: "5px",
37
+ right: "10px",
38
+ cursor: "pointer",
39
+ zIndex: 1001,
40
+ backgroundColor: "#dead8f",
41
+ padding: "5px",
42
+ display: "flex",
43
+ alignItems: "center",
44
+ justifyContent: "center",
45
+ borderRadius: "4px",
46
+ }, onClick: toggleCollapse, children: isCollapsed ? (_jsx(UpOutlined, { style: { fontSize: "16px", color: "#fff" } })) : (_jsx(DownOutlined, { style: { fontSize: "16px", color: "#fff" } })) })] }));
47
+ };
@@ -0,0 +1,9 @@
1
+ import React, { CSSProperties } from "react";
2
+ import { RouteConfig } from "../../types";
3
+ interface DbSiderProps {
4
+ logo?: string;
5
+ route_config?: RouteConfig[];
6
+ style?: CSSProperties;
7
+ }
8
+ declare const DashboardSider: React.FC<DbSiderProps>;
9
+ export default DashboardSider;
@@ -0,0 +1,48 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useContext, useState } from "react";
3
+ import { Layout, Menu, theme, Row, Col, Button, Divider } from "antd";
4
+ import { NavLink, useLocation } from "react-router-dom";
5
+ import { MdOutlineKeyboardDoubleArrowLeft, MdOutlineKeyboardDoubleArrowRight } from "react-icons/md";
6
+ import { generateMenuItems } from "../../utils/route_utils";
7
+ import { AppContext } from "./DashboardApp";
8
+ const style_img = {
9
+ height: 52,
10
+ maxWidth: "100%",
11
+ objectFit: "contain"
12
+ };
13
+ const DashboardSider = ({ style, logo, route_config }) => {
14
+ const { logo: appLogo, title } = useContext(AppContext);
15
+ const { token } = theme.useToken();
16
+ const { pathname: selectedKey } = useLocation();
17
+ const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
18
+ const [collapsed, setCollapsed] = useState(isMobile ? true : false);
19
+ window.addEventListener("resize", () => {
20
+ setIsMobile(window.innerWidth < 768);
21
+ });
22
+ const toggleCollapsed = () => {
23
+ setCollapsed(!collapsed);
24
+ };
25
+ const siderStyle = {
26
+ height: "100vh",
27
+ backgroundColor: token.colorBgContainer,
28
+ zIndex: 2,
29
+ ...style
30
+ };
31
+ return (_jsx(_Fragment, { children: _jsx(Layout.Sider, { theme: "light", collapsible: true, collapsedWidth: isMobile ? 40 : 80, collapsed: collapsed, onCollapse: toggleCollapsed, style: siderStyle, width: isMobile ? '80%' : 220, trigger: null, children: _jsxs(Row, { justify: "center", children: [_jsx(Col, { span: 24, children: _jsxs("div", { style: {
32
+ margin: 4,
33
+ display: "flex",
34
+ justifyContent: "center",
35
+ alignItems: "center",
36
+ backgroundColor: token.colorBgElevated,
37
+ }, children: [_jsx(NavLink, { to: "", style: {
38
+ display: collapsed ? 'none' : undefined,
39
+ marginTop: 8, marginLeft: 8
40
+ }, children: _jsx("img", { style: style_img, src: appLogo, alt: title }) }), _jsx(Divider, { style: { display: collapsed ? 'none' : undefined }, type: "vertical" }), _jsx(Button, { type: "text", onClick: () => setCollapsed(!collapsed), icon: collapsed ? _jsx(MdOutlineKeyboardDoubleArrowRight, {}) : _jsx(MdOutlineKeyboardDoubleArrowLeft, {}), style: {
41
+ fontSize: '28px',
42
+ width: 32,
43
+ height: 32,
44
+ //backgroundColor: token.colorFillSecondary,
45
+ marginTop: 8
46
+ } })] }) }), _jsx(Col, { span: 24, children: _jsx(Menu, { items: route_config && generateMenuItems(route_config), selectedKeys: [selectedKey], mode: "inline", style: { marginTop: "20px", width: "100%" } }) })] }) }) }));
47
+ };
48
+ export default DashboardSider;
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ interface LoadingContainerProps {
3
+ isFetching: boolean;
4
+ noData?: boolean;
5
+ children: React.ReactNode;
6
+ blurRadius?: string;
7
+ delay?: number;
8
+ }
9
+ /**
10
+ * Composant qui ajoute un effet de flou pendant le chargement (si temps de chargement > delay) et affiche un spinner au centre du contenu.
11
+ * @param isLoading Indique si le chargement est en cours ou non
12
+ * @param children Les éléments enfants à afficher dans le composant
13
+ * @param blurRadius Rayon du floutage (par défaut : 10px)
14
+ * @param delay Délai en millisecondes avant d'appliquer le flou lors du chargement (par défaut : 500ms)
15
+ */
16
+ declare const LoadingContainer: React.FC<LoadingContainerProps>;
17
+ export default LoadingContainer;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { Empty, Spin, theme } from 'antd';
4
+ import { PiEmptyFill } from "react-icons/pi";
5
+ /**
6
+ * Composant qui ajoute un effet de flou pendant le chargement (si temps de chargement > delay) et affiche un spinner au centre du contenu.
7
+ * @param isLoading Indique si le chargement est en cours ou non
8
+ * @param children Les éléments enfants à afficher dans le composant
9
+ * @param blurRadius Rayon du floutage (par défaut : 10px)
10
+ * @param delay Délai en millisecondes avant d'appliquer le flou lors du chargement (par défaut : 500ms)
11
+ */
12
+ const LoadingContainer = ({ isFetching, children, blurRadius = '10px', delay = 500, noData }) => {
13
+ const { token } = theme.useToken();
14
+ const [blur, setBlur] = useState(false);
15
+ const timeoutRef = useRef(null); //Le timeout permet que le blur ne s'affiche pas si le chargement est plus court que delay (éviter effet clignotement)
16
+ useEffect(() => {
17
+ if (isFetching) {
18
+ timeoutRef.current = window.setTimeout(() => {
19
+ setBlur(true);
20
+ }, delay);
21
+ }
22
+ else {
23
+ timeoutRef.current && clearTimeout(timeoutRef.current);
24
+ setBlur(false);
25
+ }
26
+ return () => { timeoutRef.current && clearTimeout(timeoutRef.current); };
27
+ }, [isFetching]);
28
+ return (_jsxs(_Fragment, { children: [_jsx("div", { style: {
29
+ filter: blur ? `blur(${blurRadius})` : undefined,
30
+ display: noData ? "none" : undefined
31
+ }, children: children }), noData && _jsx(Empty, { style: { position: "relative", top: "50%", right: "50%", marginBottom: 50, transform: "translate(50%, -50%)" }, description: "Pas de donn\u00E9es disponibles", image: _jsx(PiEmptyFill, { size: 80, color: token.colorPrimary }) }), blur ? _jsx(Spin, { size: "large", style: { position: 'absolute', left: '50%', top: '50%' } }) : _jsx(_Fragment, {})] }));
32
+ };
33
+ export default LoadingContainer;
@@ -0,0 +1,12 @@
1
+ import { CSSProperties } from "react";
2
+ export interface LegendItem {
3
+ color?: string;
4
+ label: string;
5
+ style?: CSSProperties;
6
+ }
7
+ interface MapLegendProps {
8
+ items: LegendItem[];
9
+ style?: CSSProperties;
10
+ }
11
+ declare const MapLegend: React.FC<MapLegendProps>;
12
+ export default MapLegend;
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ const default_style = {
3
+ backgroundColor: 'rgba(256,256,256,0.8)',
4
+ padding: '10px',
5
+ borderRadius: '4px',
6
+ border: '1px solid grey',
7
+ margin: 8
8
+ };
9
+ const MapLegend = ({ items, style }) => {
10
+ const divStyle = { ...default_style, ...style };
11
+ return (_jsx("div", { style: divStyle, children: items.map((item, index) => (_jsxs("div", { style: { display: 'flex', alignItems: 'center', marginBottom: '4px' }, children: [_jsx("div", { style: {
12
+ width: '16px',
13
+ height: '16px',
14
+ backgroundColor: item.color,
15
+ borderRadius: '2px',
16
+ marginRight: '8px'
17
+ } }), _jsx("span", { children: item.label })] }, index))) }));
18
+ };
19
+ export default MapLegend;
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { CSSProperties } from "react";
3
+ type NextPrevSelectProps = {
4
+ options?: {
5
+ label: string | number;
6
+ value: string | number;
7
+ }[] | string[] | number[];
8
+ style?: CSSProperties;
9
+ defaultValue?: string | number;
10
+ value?: string | number;
11
+ onChange?: (value: string | number) => void;
12
+ reverse?: boolean;
13
+ name?: string;
14
+ arrows?: boolean;
15
+ };
16
+ declare const NextPrevSelect: React.FC<NextPrevSelectProps>;
17
+ export default NextPrevSelect;