@hisptz/dhis2-analytics 1.0.51 → 1.0.52

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 (117) hide show
  1. package/LICENSE +29 -0
  2. package/package.json +4 -4
  3. package/.gitignore +0 -5
  4. package/d2.config.js +0 -8
  5. package/i18n/en.pot +0 -439
  6. package/src/components/ChartAnalytics/ChartAnalytics.test.tsx +0 -51
  7. package/src/components/ChartAnalytics/components/DownloadMenu/components/Menu.tsx +0 -48
  8. package/src/components/ChartAnalytics/components/DownloadMenu/constants/menu.ts +0 -38
  9. package/src/components/ChartAnalytics/components/DownloadMenu/index.tsx +0 -65
  10. package/src/components/ChartAnalytics/components/DownloadMenu/interfaces/menu.ts +0 -1
  11. package/src/components/ChartAnalytics/hooks/useChart.ts +0 -35
  12. package/src/components/ChartAnalytics/index.tsx +0 -28
  13. package/src/components/ChartAnalytics/models/bar.ts +0 -20
  14. package/src/components/ChartAnalytics/models/column.ts +0 -52
  15. package/src/components/ChartAnalytics/models/index.ts +0 -111
  16. package/src/components/ChartAnalytics/models/line.ts +0 -31
  17. package/src/components/ChartAnalytics/models/multi-series.ts +0 -115
  18. package/src/components/ChartAnalytics/models/pie.ts +0 -54
  19. package/src/components/ChartAnalytics/services/export.ts +0 -38
  20. package/src/components/ChartAnalytics/styles/custom-highchart.css +0 -48
  21. package/src/components/ChartAnalytics/types/props.tsx +0 -48
  22. package/src/components/ChartAnalytics/utils/chart.ts +0 -128
  23. package/src/components/CircularProgressDashboard/CircularProgressIndicator.test.tsx +0 -9
  24. package/src/components/CircularProgressDashboard/index.tsx +0 -36
  25. package/src/components/CircularProgressDashboard/types/props.tsx +0 -17
  26. package/src/components/CustomPivotTable/components/Table/index.tsx +0 -23
  27. package/src/components/CustomPivotTable/components/TableBody/TableBody.module.css +0 -12
  28. package/src/components/CustomPivotTable/components/TableBody/index.tsx +0 -96
  29. package/src/components/CustomPivotTable/components/TableHeaders/TableHeaders.module.css +0 -10
  30. package/src/components/CustomPivotTable/components/TableHeaders/index.tsx +0 -94
  31. package/src/components/CustomPivotTable/index.tsx +0 -63
  32. package/src/components/CustomPivotTable/interfaces/index.ts +0 -1
  33. package/src/components/CustomPivotTable/services/engine.ts +0 -102
  34. package/src/components/CustomPivotTable/state/engine.tsx +0 -22
  35. package/src/components/Map/components/EarthEngineLayerConfiguration/EarthEngineLayerConfigModal.stories.tsx +0 -28
  36. package/src/components/Map/components/EarthEngineLayerConfiguration/EarthEngineLayerConfiguration.stories.tsx +0 -34
  37. package/src/components/Map/components/EarthEngineLayerConfiguration/index.tsx +0 -412
  38. package/src/components/Map/components/MapArea/index.tsx +0 -83
  39. package/src/components/Map/components/MapArea/interfaces/index.ts +0 -39
  40. package/src/components/Map/components/MapControls/components/CustomControl/index.tsx +0 -24
  41. package/src/components/Map/components/MapControls/components/DownloadControl/index.tsx +0 -11
  42. package/src/components/Map/components/MapControls/components/FullscreenControl/index.tsx +0 -7
  43. package/src/components/Map/components/MapControls/index.tsx +0 -24
  44. package/src/components/Map/components/MapLayer/components/BoundaryLayer/hooks/useBoundaryData.ts +0 -7
  45. package/src/components/Map/components/MapLayer/components/BoundaryLayer/index.tsx +0 -55
  46. package/src/components/Map/components/MapLayer/components/GoogleEngineLayer/components/EarthEngineLegend.tsx +0 -74
  47. package/src/components/Map/components/MapLayer/components/GoogleEngineLayer/constants/index.ts +0 -430
  48. package/src/components/Map/components/MapLayer/components/GoogleEngineLayer/hooks/index.ts +0 -34
  49. package/src/components/Map/components/MapLayer/components/GoogleEngineLayer/index.tsx +0 -185
  50. package/src/components/Map/components/MapLayer/components/GoogleEngineLayer/interfaces/index.ts +0 -56
  51. package/src/components/Map/components/MapLayer/components/GoogleEngineLayer/services/api.js +0 -34241
  52. package/src/components/Map/components/MapLayer/components/GoogleEngineLayer/services/engine.ts +0 -431
  53. package/src/components/Map/components/MapLayer/components/GoogleEngineLayer/utils/index.ts +0 -105
  54. package/src/components/Map/components/MapLayer/components/LegendArea/LegendArea.module.css +0 -12
  55. package/src/components/Map/components/MapLayer/components/LegendArea/components/LegendCardHeader/index.tsx +0 -17
  56. package/src/components/Map/components/MapLayer/components/LegendArea/index.tsx +0 -167
  57. package/src/components/Map/components/MapLayer/components/PointLayer/components/PointLegend/index.tsx +0 -44
  58. package/src/components/Map/components/MapLayer/components/PointLayer/hooks/index.ts +0 -8
  59. package/src/components/Map/components/MapLayer/components/PointLayer/index.tsx +0 -36
  60. package/src/components/Map/components/MapLayer/components/ThematicLayer/components/Bubble/components/BubbleLegend/components/Bubble.tsx +0 -48
  61. package/src/components/Map/components/MapLayer/components/ThematicLayer/components/Bubble/components/BubbleLegend/components/Bubbles.tsx +0 -150
  62. package/src/components/Map/components/MapLayer/components/ThematicLayer/components/Bubble/components/BubbleLegend/index.tsx +0 -39
  63. package/src/components/Map/components/MapLayer/components/ThematicLayer/components/Bubble/index.tsx +0 -57
  64. package/src/components/Map/components/MapLayer/components/ThematicLayer/components/Choropleth/components/ChoroplethLegend.tsx +0 -43
  65. package/src/components/Map/components/MapLayer/components/ThematicLayer/components/Choropleth/index.tsx +0 -38
  66. package/src/components/Map/components/MapLayer/components/ThematicLayer/components/CustomTooltip/index.tsx +0 -26
  67. package/src/components/Map/components/MapLayer/components/ThematicLayer/hooks/config.ts +0 -10
  68. package/src/components/Map/components/MapLayer/components/ThematicLayer/index.tsx +0 -46
  69. package/src/components/Map/components/MapLayer/components/ThematicLayer/styles/legends.css +0 -62
  70. package/src/components/Map/components/MapLayer/index.tsx +0 -32
  71. package/src/components/Map/components/MapLayer/interfaces/index.ts +0 -139
  72. package/src/components/Map/components/MapProvider/components/MapLayerProvider/hooks/index.tsx +0 -368
  73. package/src/components/Map/components/MapProvider/components/MapLayerProvider/index.tsx +0 -105
  74. package/src/components/Map/components/MapProvider/hooks/index.ts +0 -14
  75. package/src/components/Map/components/MapProvider/index.tsx +0 -93
  76. package/src/components/Map/components/MapUpdater/index.tsx +0 -8
  77. package/src/components/Map/components/ThematicLayerConfiguration/ThematicLayerConfigModal.stories.tsx +0 -28
  78. package/src/components/Map/components/ThematicLayerConfiguration/ThematicLayerConfiguration.stories.tsx +0 -34
  79. package/src/components/Map/components/ThematicLayerConfiguration/components/ColorScaleSelect/components/ColorScale/index.tsx +0 -24
  80. package/src/components/Map/components/ThematicLayerConfiguration/components/ColorScaleSelect/constants/colors.ts +0 -433
  81. package/src/components/Map/components/ThematicLayerConfiguration/components/ColorScaleSelect/index.tsx +0 -50
  82. package/src/components/Map/components/ThematicLayerConfiguration/components/ColorScaleSelect/styles/ColorScale.module.css +0 -15
  83. package/src/components/Map/components/ThematicLayerConfiguration/components/ColorScaleSelect/styles/ColorScaleSelect.module.css +0 -12
  84. package/src/components/Map/components/ThematicLayerConfiguration/components/ColorScaleSelect/utils/colors.ts +0 -91
  85. package/src/components/Map/components/ThematicLayerConfiguration/components/CustomLegend/index.tsx +0 -45
  86. package/src/components/Map/components/ThematicLayerConfiguration/components/IndicatorSelectorModal/index.tsx +0 -47
  87. package/src/components/Map/components/ThematicLayerConfiguration/components/LegendSetSelector/index.tsx +0 -57
  88. package/src/components/Map/components/ThematicLayerConfiguration/index.tsx +0 -248
  89. package/src/components/Map/constants/colors.ts +0 -434
  90. package/src/components/Map/constants/legendSet.ts +0 -19
  91. package/src/components/Map/hooks/map.ts +0 -47
  92. package/src/components/Map/index.tsx +0 -65
  93. package/src/components/Map/interfaces/index.ts +0 -57
  94. package/src/components/Map/state/index.tsx +0 -31
  95. package/src/components/Map/utils/colors.ts +0 -95
  96. package/src/components/Map/utils/helpers.ts +0 -15
  97. package/src/components/Map/utils/map.ts +0 -150
  98. package/src/components/SingleValueContainer/SingleValueContainer.test.tsx +0 -24
  99. package/src/components/SingleValueContainer/components/SingleValueItem/SingleValueItem.tsx +0 -46
  100. package/src/components/SingleValueContainer/components/SingleValueItem/SingleValuePercentage.tsx +0 -12
  101. package/src/components/SingleValueContainer/index.tsx +0 -37
  102. package/src/components/SingleValueContainer/styles/SingleValueContainer.module.css +0 -39
  103. package/src/components/SingleValueContainer/types/props.tsx +0 -16
  104. package/src/components/Visualization/components/AnalyticsDataProvider/index.tsx +0 -76
  105. package/src/components/Visualization/components/DimensionsProvider/index.tsx +0 -51
  106. package/src/components/Visualization/components/LayoutProvider/index.tsx +0 -34
  107. package/src/components/Visualization/components/VisualizationDimensionSelector/index.tsx +0 -59
  108. package/src/components/Visualization/components/VisualizationProvider/index.tsx +0 -31
  109. package/src/components/Visualization/components/VisualizationSelector/index.tsx +0 -157
  110. package/src/components/Visualization/components/VisualizationTypeProvider/index.tsx +0 -40
  111. package/src/components/Visualization/components/VisualizationTypeSelector/index.tsx +0 -46
  112. package/src/components/Visualization/index.tsx +0 -103
  113. package/src/index.ts +0 -6
  114. package/src/locales/en/translations.json +0 -138
  115. package/src/locales/index.js +0 -16
  116. package/tsconfig.build.json +0 -46
  117. package/tsconfig.json +0 -51
@@ -1,46 +0,0 @@
1
- import {last} from "lodash";
2
- import React from "react";
3
- import {LayerGroup, LayersControl, Pane} from "react-leaflet";
4
- import {CustomBubbleLayer} from "../../interfaces";
5
- import Bubble from "./components/Bubble";
6
- import Choropleth from "./components/Choropleth";
7
- import useThematicLayer from "./hooks/config";
8
-
9
- export default function ThematicLayer({ layerId, index }: { layerId: string; index: number }) {
10
- const layer = useThematicLayer(layerId);
11
-
12
- if (!layer) {
13
- return null;
14
- }
15
-
16
- const { type, dataItem, name, data, enabled, legends } = layer ?? {};
17
- const uniqueName = name ?? dataItem.displayName;
18
- return (
19
- <>
20
- <LayersControl.Overlay checked={enabled} name={uniqueName}>
21
- <Pane
22
- style={{
23
- zIndex: type === "bubble" ? 500 : 500 - (index + 1),
24
- }}
25
- name={uniqueName}>
26
- <LayerGroup>
27
- {data?.map((datum) =>
28
- type === "choropleth" ? <Choropleth legends={legends ?? []} data={datum} key={`${datum?.dataItem?.id}-${datum?.orgUnit?.id}-layer`} /> : null
29
- )}
30
- {data?.map((datum) =>
31
- type === "bubble" ? (
32
- <Bubble
33
- radius={(layer as CustomBubbleLayer)?.radius}
34
- legends={legends ?? []}
35
- highestData={last(data)?.data ?? 1}
36
- data={datum}
37
- key={`${datum?.dataItem?.id}-${datum?.orgUnit?.id}-layer`}
38
- />
39
- ) : null
40
- )}
41
- </LayerGroup>
42
- </Pane>
43
- </LayersControl.Overlay>
44
- </>
45
- );
46
- }
@@ -1,62 +0,0 @@
1
- .legend-card {
2
- display: flex;
3
- flex-direction: column;
4
- justify-content: center;
5
- align-items: center;
6
- height: 100%;
7
- padding: 0.5rem;
8
- border-radius: 0.2rem;
9
- background-color: #fff;
10
- box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.1);
11
- border: 2px solid rgba(0, 0, 0, 0.2);
12
- }
13
-
14
- .legend-card.collapsed {
15
- padding: 0 !important;
16
- float: right;
17
- }
18
-
19
- .legend-header {
20
- font-weight: bold;
21
- margin-bottom: 0.5rem;
22
- }
23
-
24
- .legend-item {
25
- display: flex;
26
- flex-direction: row;
27
- align-items: center;
28
- justify-content: start;
29
- padding: 0 1rem;
30
- gap: 16px;
31
- width: 100%;
32
- }
33
-
34
- .legend-item-color {
35
- width: 1rem;
36
- height: 1rem;
37
- border-radius: 1px;
38
- }
39
-
40
- .legend-item-label {
41
- }
42
-
43
- .source-url {
44
- background: none !important;
45
- line-height: inherit !important;
46
- text-align: inherit !important;
47
- width: auto !important;
48
- height: auto !important;
49
- text-decoration: underline !important;
50
- color: #0078A8 !important;
51
- }
52
-
53
- .legend-list {
54
- display: flex;
55
- flex-direction: column;
56
- justify-content: flex-start;
57
- align-items: center;
58
- width: 100%;
59
- height: 100%;
60
- background-color: #fff;
61
- gap: 4px;
62
- }
@@ -1,32 +0,0 @@
1
- import React from "react";
2
- import BoundaryLayer from "./components/BoundaryLayer";
3
- import GoogleEngineLayer from "./components/GoogleEngineLayer";
4
- import {PointLayer} from "./components/PointLayer";
5
- import ThematicLayer from "./components/ThematicLayer";
6
- import {CustomBoundaryLayer, CustomGoogleEngineLayer, CustomPointLayer, CustomThematicLayer} from "./interfaces";
7
-
8
- export default function MapLayer({
9
- layer,
10
- index,
11
- }: {
12
- layer: CustomThematicLayer | CustomBoundaryLayer | CustomPointLayer | CustomGoogleEngineLayer;
13
- index: number;
14
- }) {
15
- switch (layer.type) {
16
- case "overlay":
17
- case "basemap":
18
- return <BoundaryLayer {...layer} />;
19
- case "bubble":
20
- case "choropleth":
21
- return <ThematicLayer layerId={layer.id} index={index} />;
22
- case "point":
23
- return <PointLayer />;
24
- case "population":
25
- case "elevation":
26
- case "footprints":
27
- case "landCover":
28
- return <GoogleEngineLayer layerId={layer.id} />;
29
- default:
30
- return null;
31
- }
32
- }
@@ -1,139 +0,0 @@
1
- import type {Legend} from "@hisptz/dhis2-utils";
2
- import {MapOrgUnit, PointOrgUnit} from "../../../interfaces";
3
- import {LegendColorScale} from "../../../utils/colors";
4
- import {EarthEngineOptions} from "../components/GoogleEngineLayer/interfaces";
5
- import {EarthEngine} from "../components/GoogleEngineLayer/services/engine";
6
-
7
- export type BoundaryLayerType = "basemap" | "overlay";
8
- export type ThematicLayerType = "choropleth" | "bubble";
9
-
10
- export const SUPPORTED_EARTH_ENGINE_LAYERS = ["population", "footprints", "elevation", "landCover"];
11
-
12
- export type GoogleEngineLayerType = "population" | "footprints" | "elevation" | "landCover";
13
-
14
- export interface CustomBoundaryLayer extends CustomMapLayer {
15
- id: string;
16
- type: BoundaryLayerType;
17
- enabled: boolean;
18
- }
19
-
20
- export interface EarthEngineLayerConfig extends CustomMapLayer {
21
- type: GoogleEngineLayerType;
22
- aggregations?: string[];
23
- name?: string;
24
- filters?: {
25
- period: string;
26
- };
27
- params?: {
28
- min: number;
29
- max: number;
30
- palette?: string;
31
- };
32
- }
33
-
34
- export interface CustomGoogleEngineLayer extends CustomMapLayer {
35
- type: GoogleEngineLayerType;
36
- options: EarthEngineOptions;
37
- aggregations?: string[];
38
- name: string;
39
- url: string;
40
- engine?: EarthEngine;
41
- }
42
-
43
- export interface CustomPointLayer extends CustomMapLayer {
44
- id: string;
45
- type: "point";
46
- label?: string;
47
- level?: string | number;
48
- group?: string;
49
- style?: {
50
- icon?: string;
51
- groupSet?: string;
52
- orgUnitGroups?: Array<{ name: string; symbol: string }>;
53
- };
54
- points?: Array<PointOrgUnit>;
55
- }
56
-
57
- export type DataItemType = "dataElement" | "indicator" | "programIndicator";
58
-
59
- export interface ThematicLayerDataItem {
60
- id: string;
61
- displayName: string;
62
- type: DataItemType;
63
- legendSet?: string;
64
- legendConfig?: {
65
- colorClass: LegendColorScale;
66
- scale: number;
67
- };
68
- }
69
-
70
- export interface ThematicLayerControl {
71
- position: "topleft" | "topright" | "bottomleft" | "bottomright";
72
- enabled: boolean;
73
- }
74
-
75
- export interface ThematicLayerData {
76
- orgUnit: MapOrgUnit;
77
- data?: number;
78
- dataItem: ThematicLayerDataItem;
79
- }
80
-
81
- export interface ThematicLayerRawData {
82
- orgUnit: string;
83
- data?: number;
84
- dataItem: string;
85
- }
86
-
87
- export interface CustomChoroplethLayer extends CustomMapLayer {
88
- enabled: boolean;
89
- name?: string;
90
- data: ThematicLayerData[];
91
- dataItem: ThematicLayerDataItem;
92
- type: "choropleth";
93
- control?: ThematicLayerControl;
94
- legends?: Legend[];
95
- }
96
-
97
- export interface CustomBubbleLayer extends CustomMapLayer {
98
- enabled: boolean;
99
- name?: string;
100
- data: ThematicLayerData[];
101
- dataItem: ThematicLayerDataItem;
102
- type: "bubble";
103
- control?: ThematicLayerControl;
104
- legends?: Legend[];
105
- radius?: {
106
- min: number;
107
- max: number;
108
- };
109
- }
110
-
111
- export type CustomThematicLayer = CustomBubbleLayer | CustomChoroplethLayer;
112
-
113
- export interface ThematicLayerConfig {
114
- id: string;
115
- data?: ThematicLayerRawData[];
116
- enabled: boolean;
117
- name?: string;
118
- dataItem: ThematicLayerDataItem;
119
- type: ThematicLayerType;
120
- control?: ThematicLayerControl;
121
- radius?: {
122
- min: number;
123
- max: number;
124
- };
125
- }
126
-
127
- export interface CustomMapLayer {
128
- id: string;
129
- type: string;
130
- enabled: boolean;
131
- }
132
-
133
- export type MapLayer = CustomBoundaryLayer | ThematicLayerConfig | CustomPointLayer | CustomGoogleEngineLayer;
134
-
135
- export interface MapLayerProps {
136
- enabled: boolean;
137
- type: "boundary" | "thematic" | "external" | "point" | "earthEngine";
138
- layer: MapLayer;
139
- }
@@ -1,368 +0,0 @@
1
- import {compact, differenceBy, find, head, isEmpty, last, sortBy} from "lodash";
2
- import {useMapOrganisationUnit, useMapPeriods} from "../../../hooks";
3
- import {useCallback, useMemo, useState} from "react";
4
- import {
5
- generateLegends,
6
- getOrgUnitsSelection,
7
- sanitizeDate,
8
- sanitizeOrgUnits,
9
- toGeoJson
10
- } from "../../../../../utils/map";
11
- import {useDataEngine} from "@dhis2/app-runtime";
12
- import {
13
- CustomGoogleEngineLayer,
14
- CustomPointLayer,
15
- CustomThematicLayer,
16
- EarthEngineLayerConfig,
17
- ThematicLayerConfig
18
- } from "../../../../MapLayer/interfaces";
19
- import {MapOrgUnit, PointOrgUnit} from "../../../../../interfaces";
20
- import {asyncify, map} from "async-es";
21
- import {LegendSet} from "@hisptz/dhis2-utils";
22
- import {defaultClasses, defaultColorScaleName} from "../../../../../utils/colors";
23
- import {useGoogleEngineToken} from "../../../../MapLayer/components/GoogleEngineLayer/hooks";
24
- import {useBoundaryData} from "../../../../MapLayer/components/BoundaryLayer/hooks/useBoundaryData";
25
- import {EarthEngine} from "../../../../MapLayer/components/GoogleEngineLayer/services/engine";
26
- import {EARTH_ENGINE_LAYERS} from "../../../../MapLayer/components/GoogleEngineLayer/constants";
27
- import {EarthEngineOptions} from "../../../../MapLayer/components/GoogleEngineLayer/interfaces";
28
-
29
- const analyticsQuery = {
30
- analytics: {
31
- resource: "analytics",
32
- params: ({ou, pe, dx, startDate, endDate}: any) => {
33
- const peDimension = !isEmpty(pe) ? `pe:${pe?.join(";")}` : undefined;
34
- const ouDimension = !isEmpty(ou) ? `ou:${ou?.join(";")}` : undefined;
35
- const dxDimension = !isEmpty(dx) ? `dx:${dx?.join(";")}` : undefined;
36
-
37
- return {
38
- dimension: compact([dxDimension, peDimension, ouDimension]),
39
- startDate,
40
- endDate,
41
- displayProperty: "NAME",
42
- };
43
- },
44
- },
45
- };
46
- const query = {
47
- layer: {
48
- resource: "geoFeatures",
49
- params: ({ous}: any) => ({
50
- ou: `ou:${ous.join(";")}`,
51
- }),
52
- },
53
- analytics: {
54
- resource: "analytics",
55
- params: ({ous}: any) => ({
56
- dimension: [`ou:${ous.join(";")}`, `pe:${new Date().getFullYear()}`],
57
- skipData: true,
58
- hierarchyMeta: true,
59
- }),
60
- },
61
- };
62
- const groupSetQuery = {
63
- groupSet: {
64
- resource: "organisationUnitGroupSets",
65
- id: ({groupSet}: any) => groupSet,
66
- params: {
67
- fields: ["organisationUnitGroups[name,color,symbol,organisationUnits[id]]"],
68
- },
69
- },
70
- };
71
- const legendSetsQuery = {
72
- legendSets: {
73
- resource: "legendSets",
74
- id: ({id}: any) => id,
75
- params: {
76
- fields: ["id", "displayName", "legends[id,code,startValue,endValue,color]"],
77
- },
78
- },
79
- };
80
-
81
- export function useThematicLayers(): any {
82
- const engine = useDataEngine();
83
- const [loading, setLoading] = useState(false);
84
- const {orgUnits, orgUnitSelection} = useMapOrganisationUnit();
85
- const {periods, range} = useMapPeriods() ?? {};
86
- const ou = useMemo(() => getOrgUnitsSelection(orgUnitSelection), [orgUnitSelection]);
87
- const pe = useMemo(() => periods?.map((pe: any) => pe.id), [periods]);
88
-
89
- const {startDate, endDate} = useMemo(() => {
90
- if (!range) {
91
- return {
92
- startDate: undefined,
93
- endDate: undefined,
94
- };
95
- }
96
- return {
97
- startDate: sanitizeDate(range.start.toDateString()),
98
- endDate: sanitizeDate(range.end.toDateString()),
99
- };
100
- }, [range]);
101
- const sanitizeData = (data: any, layer: ThematicLayerConfig) => {
102
- if (data) {
103
- const {analytics} = data as any;
104
- const rows = analytics?.rows;
105
- const ouIndex = analytics.headers.findIndex((header: any) => header.name === "ou");
106
- const dxIndex = analytics.headers.findIndex((header: any) => header.name === "dx");
107
- const valueIndex = analytics.headers.findIndex((header: any) => header.name === "value");
108
-
109
- if (!isEmpty(rows)) {
110
- return sortBy(
111
- orgUnits?.map((ou: MapOrgUnit) => {
112
- const row = rows.find((row: any) => row[ouIndex] === ou.id && row[dxIndex] === layer.dataItem.id);
113
- return {
114
- orgUnit: ou,
115
- data: row ? parseFloat(row[valueIndex]) : undefined,
116
- dataItem: {
117
- ...layer.dataItem,
118
- },
119
- };
120
- }),
121
- ["data"]
122
- );
123
- }
124
- return [];
125
- }
126
- return [];
127
- };
128
-
129
- const sanitizeLegends = async (layers: CustomThematicLayer[]): Promise<CustomThematicLayer[]> => {
130
- return (await map(
131
- layers,
132
- asyncify(async (layer: CustomThematicLayer) => {
133
- try {
134
- const legends = [];
135
- if (layer.dataItem.legendSet) {
136
- const legendSetData = await engine.query(legendSetsQuery, {
137
- variables: {
138
- id: layer.dataItem.legendSet,
139
- },
140
- });
141
- const legendSet: LegendSet = legendSetData?.legendSets as LegendSet;
142
- if (legendSet) {
143
- legends.push(...legendSet.legends);
144
- }
145
- } else {
146
- const {scale, colorClass} = layer.dataItem.legendConfig ?? {
147
- scale: defaultClasses,
148
- colorClass: defaultColorScaleName,
149
- };
150
- const sortedData = sortBy(layer.data.filter((datum) => !!datum.data), "data");
151
- const autoLegends = generateLegends(last(sortedData)?.data ?? 0, head(sortedData)?.data ?? 0, {
152
- classesCount: scale,
153
- colorClass,
154
- });
155
- legends.push(...autoLegends);
156
- }
157
- return {
158
- ...layer,
159
- legends,
160
- };
161
- } catch (e) {
162
- return layer;
163
- }
164
- })
165
- )) as CustomThematicLayer[];
166
- };
167
-
168
- const sanitizeLayers = async (layers: ThematicLayerConfig[]): Promise<CustomThematicLayer[]> => {
169
- try {
170
- setLoading(true);
171
- const layersWithoutData = layers?.filter((layer) => !layer.data);
172
- const layersWithData = differenceBy(layers, layersWithoutData, "id");
173
- const dx = layersWithoutData.map((layer) => layer.dataItem.id);
174
- let sanitizedLayersWithData: any = [];
175
-
176
- console.log({layersWithoutData})
177
-
178
- if (!isEmpty(dx)) {
179
- const data = await engine.query(analyticsQuery, {
180
- variables: {
181
- dx,
182
- ou,
183
- pe,
184
- startDate,
185
- endDate,
186
- },
187
- });
188
- sanitizedLayersWithData = layersWithoutData.map((layer) => ({
189
- ...layer,
190
- name: layer?.name ?? layer?.dataItem?.displayName ?? layer.id,
191
- data: sanitizeData(data, layer),
192
- }));
193
- }
194
- const sanitizedLayersWithOrgUnits = layersWithData.map((layer) => ({
195
- ...layer,
196
- data: layer.data?.map((datum) => ({
197
- ...datum,
198
- orgUnit: find(orgUnits, ["id", datum.orgUnit]) as MapOrgUnit,
199
- dataItem: layer.dataItem,
200
- name: layer?.name ?? layer?.dataItem?.displayName ?? layer.id,
201
- })),
202
- }));
203
- setLoading(false);
204
- return await sanitizeLegends([...sanitizedLayersWithData, ...sanitizedLayersWithOrgUnits]);
205
- } catch (e: any) {
206
- console.error(`Error getting thematic layers`, e.details);
207
- setLoading(false);
208
- return [];
209
- }
210
- };
211
-
212
- return {
213
- sanitizeLayers,
214
- loading,
215
- };
216
- }
217
-
218
- export function usePointLayer() {
219
- const engine = useDataEngine();
220
- const {orgUnitSelection} = useMapOrganisationUnit();
221
- const [loading, setLoading] = useState(false);
222
-
223
- const sanitizePointData = useCallback((orgUnitData: any, groupSetData: any): PointOrgUnit[] => {
224
- const {analytics, layer} = (orgUnitData as any) ?? {};
225
- const rawOrgUnits = sanitizeOrgUnits(analytics?.metaData);
226
- const geoJSONObjects = toGeoJson(layer?.filter((bound: any) => bound.co));
227
- return compact(
228
- rawOrgUnits.map((orgUnit: any) => {
229
- const geoJSONObject: any = geoJSONObjects?.find((geoJSON: any) => geoJSON.properties.id === orgUnit.id);
230
- const orgUnitGroups: any = (groupSetData?.groupSet as any)?.organisationUnitGroups ?? [];
231
- const ouGroup = find(orgUnitGroups, (ouGroup) => !!find(ouGroup?.organisationUnits ?? [], ["id", orgUnit.id]));
232
-
233
- if (!geoJSONObject || geoJSONObject.properties.type !== "Point") {
234
- return;
235
- }
236
- return {
237
- ...orgUnit,
238
- geoJSON: geoJSONObject,
239
- level: geoJSONObject.properties.level,
240
- icon: {
241
- type: "groupIcon",
242
- icon: ouGroup?.symbol,
243
- },
244
- };
245
- })
246
- );
247
- }, []);
248
-
249
- const sanitizeLayer = useCallback(async (layer: CustomPointLayer): Promise<CustomPointLayer | undefined> => {
250
- try {
251
- if (!layer.level && !layer.group) {
252
- return;
253
- }
254
- setLoading(true);
255
- const level = layer.level ? `LEVEL-${layer.level}` : undefined;
256
- const group = layer.group ? `OU_GROUP-${layer.group}` : undefined;
257
- const ous = [...getOrgUnitsSelection(orgUnitSelection), level, group];
258
-
259
- const pointData = await engine.query(query, {
260
- variables: {
261
- ous,
262
- },
263
- });
264
- const groupSetData = await engine.query(groupSetQuery, {
265
- variables: {
266
- groupSet: layer.style?.groupSet,
267
- },
268
- });
269
- const sanitizedOrgUnitData = sanitizePointData(pointData, groupSetData);
270
-
271
- const orgUnitGroups = (groupSetData?.groupSet as any)?.organisationUnitGroups ?? [];
272
-
273
- const sanitizedOrgUnitGroups = orgUnitGroups.map((ouGroup: any) => ({
274
- ...ouGroup,
275
- organisationUnits: undefined,
276
- }));
277
- setLoading(false);
278
- return {
279
- ...layer,
280
- points: sanitizedOrgUnitData,
281
- style: {
282
- ...layer.style,
283
- orgUnitGroups: sanitizedOrgUnitGroups,
284
- },
285
- };
286
- } catch (e: any) {
287
- setLoading(false);
288
- console.error(`Error getting point layer`, e.details);
289
- return;
290
- }
291
- }, []);
292
-
293
- return {
294
- loading,
295
- sanitizeLayer,
296
- };
297
- }
298
-
299
- export function useGoogleEngineLayers() {
300
- const {refresh} = useGoogleEngineToken();
301
- const orgUnits = useBoundaryData();
302
-
303
- async function getImageUrl(earthEngine: EarthEngine, {filters}: EarthEngineLayerConfig): Promise<string | undefined> {
304
- if (earthEngine.initialized) {
305
- try {
306
- earthEngine.setOrgUnits(orgUnits ?? []);
307
- const period = filters?.period;
308
- if (period) {
309
- earthEngine.setPeriod(period);
310
- }
311
- return earthEngine.url();
312
- } catch (e) {
313
- console.error(e);
314
- }
315
- }
316
- }
317
-
318
- const sanitizeLayers = useCallback(
319
- async (layers: EarthEngineLayerConfig[]): Promise<CustomGoogleEngineLayer[]> => {
320
- if (isEmpty(layers)) {
321
- return [];
322
- }
323
- try {
324
- const {token} = await refresh();
325
- if (!token) {
326
- console.error(`Google token not available in this instance`);
327
- return [];
328
- }
329
- await EarthEngine.setToken(token, refresh);
330
- return map(
331
- layers,
332
- asyncify(async (layer: EarthEngineLayerConfig) => {
333
- try {
334
- const defaultOptions: any = find(EARTH_ENGINE_LAYERS, ["id", layer.type]) ?? {};
335
- const options: EarthEngineOptions = {
336
- ...defaultOptions,
337
- aggregations: layer.aggregations ?? defaultOptions?.aggregations,
338
- params: layer.params ?? defaultOptions?.params,
339
- };
340
- const updatedLayer = {
341
- ...layer,
342
- options,
343
- };
344
- const earthEngine = new EarthEngine({options});
345
- const url = await getImageUrl(earthEngine, updatedLayer);
346
- return {
347
- ...updatedLayer,
348
- engine: earthEngine,
349
- url,
350
- };
351
- } catch (e) {
352
- console.error(e);
353
- return;
354
- }
355
- })
356
- );
357
- } catch (e: any) {
358
- console.error(`Error getting thematic layers`, e.details);
359
- return [];
360
- }
361
- },
362
- [refresh]
363
- );
364
-
365
- return {
366
- sanitizeLayers,
367
- };
368
- }