datastake-daf 0.6.784 → 0.6.785
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.
- package/dist/components/index.js +99 -99
- package/dist/pages/index.js +846 -65
- package/dist/style/datastake/mapbox-gl.css +330 -0
- package/dist/utils/index.js +58 -0
- package/package.json +1 -1
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/KeyInformation/index.jsx +48 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/PlantedSpecies.jsx +73 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/SeedlingsHeight.jsx +44 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/Stats.jsx +86 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/VegetationHealth.jsx +73 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/index.jsx +92 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MonitoringScopeAndFindings/index.jsx +348 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/config.js +35 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/index.jsx +30 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CommunityParticipation/CommunityStats/helper.js +1 -1
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleIndicators/index.jsx +1 -1
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleOutcomes/index.jsx +1 -1
- package/src/@daf/pages/Summary/Activities/PlantingCycle/helper.js +0 -56
- package/src/@daf/utils/numbers.js +57 -0
- package/src/pages.js +1 -0
- package/src/utils.js +1 -1
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/* Isolated Mapbox GL CSS - Scoped to prevent Leaflet conflicts */
|
|
2
|
+
|
|
3
|
+
/* Mapbox GL Core Styles - Scoped with .mapbox-gl-scope */
|
|
4
|
+
.mapbox-gl-scope .mapboxgl-map {
|
|
5
|
+
font: 12px/20px Helvetica Neue, Arial, Helvetica, sans-serif;
|
|
6
|
+
overflow: hidden;
|
|
7
|
+
position: relative;
|
|
8
|
+
-webkit-tap-highlight-color: rgb(0 0 0/0);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.mapbox-gl-scope .mapboxgl-canvas {
|
|
12
|
+
left: 0;
|
|
13
|
+
position: absolute;
|
|
14
|
+
top: 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.mapbox-gl-scope .mapboxgl-map:-webkit-full-screen {
|
|
18
|
+
height: 100%;
|
|
19
|
+
width: 100%;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.mapbox-gl-scope .mapboxgl-canary {
|
|
23
|
+
background-color: salmon;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-interactive,
|
|
27
|
+
.mapbox-gl-scope .mapboxgl-ctrl-group button.mapboxgl-ctrl-compass {
|
|
28
|
+
cursor: grab;
|
|
29
|
+
-webkit-user-select: none;
|
|
30
|
+
user-select: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-interactive.mapboxgl-track-pointer {
|
|
34
|
+
cursor: pointer;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-interactive:active,
|
|
38
|
+
.mapbox-gl-scope .mapboxgl-ctrl-group button.mapboxgl-ctrl-compass:active {
|
|
39
|
+
cursor: grabbing;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate,
|
|
43
|
+
.mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate .mapboxgl-canvas {
|
|
44
|
+
touch-action: pan-x pan-y;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-touch-drag-pan,
|
|
48
|
+
.mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-touch-drag-pan .mapboxgl-canvas {
|
|
49
|
+
touch-action: pinch-zoom;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate.mapboxgl-touch-drag-pan,
|
|
53
|
+
.mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate.mapboxgl-touch-drag-pan .mapboxgl-canvas {
|
|
54
|
+
touch-action: none;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Control positioning */
|
|
58
|
+
.mapbox-gl-scope .mapboxgl-ctrl-bottom,
|
|
59
|
+
.mapbox-gl-scope .mapboxgl-ctrl-bottom-left,
|
|
60
|
+
.mapbox-gl-scope .mapboxgl-ctrl-bottom-right,
|
|
61
|
+
.mapbox-gl-scope .mapboxgl-ctrl-left,
|
|
62
|
+
.mapbox-gl-scope .mapboxgl-ctrl-right,
|
|
63
|
+
.mapbox-gl-scope .mapboxgl-ctrl-top,
|
|
64
|
+
.mapbox-gl-scope .mapboxgl-ctrl-top-left,
|
|
65
|
+
.mapbox-gl-scope .mapboxgl-ctrl-top-right {
|
|
66
|
+
pointer-events: none;
|
|
67
|
+
position: absolute;
|
|
68
|
+
z-index: 2;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.mapbox-gl-scope .mapboxgl-ctrl-top-left {
|
|
72
|
+
left: 0;
|
|
73
|
+
top: 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.mapbox-gl-scope .mapboxgl-ctrl-top {
|
|
77
|
+
left: 50%;
|
|
78
|
+
top: 0;
|
|
79
|
+
transform: translateX(-50%);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.mapbox-gl-scope .mapboxgl-ctrl-top-right {
|
|
83
|
+
right: 0;
|
|
84
|
+
top: 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.mapbox-gl-scope .mapboxgl-ctrl-right {
|
|
88
|
+
right: 0;
|
|
89
|
+
top: 50%;
|
|
90
|
+
transform: translateY(-50%);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.mapbox-gl-scope .mapboxgl-ctrl-bottom-right {
|
|
94
|
+
bottom: 0;
|
|
95
|
+
right: 0;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.mapbox-gl-scope .mapboxgl-ctrl-bottom {
|
|
99
|
+
bottom: 0;
|
|
100
|
+
left: 50%;
|
|
101
|
+
transform: translateX(-50%);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.mapbox-gl-scope .mapboxgl-ctrl-bottom-left {
|
|
105
|
+
bottom: 0;
|
|
106
|
+
left: 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.mapbox-gl-scope .mapboxgl-ctrl-left {
|
|
110
|
+
left: 0;
|
|
111
|
+
top: 50%;
|
|
112
|
+
transform: translateY(-50%);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.mapbox-gl-scope .mapboxgl-ctrl {
|
|
116
|
+
clear: both;
|
|
117
|
+
pointer-events: auto;
|
|
118
|
+
transform: translate(0);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.mapbox-gl-scope .mapboxgl-ctrl-top-left .mapboxgl-ctrl {
|
|
122
|
+
float: left;
|
|
123
|
+
margin: 10px 0 0 10px;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.mapbox-gl-scope .mapboxgl-ctrl-top .mapboxgl-ctrl {
|
|
127
|
+
float: left;
|
|
128
|
+
margin: 10px 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.mapbox-gl-scope .mapboxgl-ctrl-top-right .mapboxgl-ctrl {
|
|
132
|
+
float: right;
|
|
133
|
+
margin: 10px 10px 0 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.mapbox-gl-scope .mapboxgl-ctrl-bottom-right .mapboxgl-ctrl,
|
|
137
|
+
.mapbox-gl-scope .mapboxgl-ctrl-right .mapboxgl-ctrl {
|
|
138
|
+
float: right;
|
|
139
|
+
margin: 0 10px 10px 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.mapbox-gl-scope .mapboxgl-ctrl-bottom .mapboxgl-ctrl {
|
|
143
|
+
float: left;
|
|
144
|
+
margin: 10px 0;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.mapbox-gl-scope .mapboxgl-ctrl-bottom-left .mapboxgl-ctrl,
|
|
148
|
+
.mapbox-gl-scope .mapboxgl-ctrl-left .mapboxgl-ctrl {
|
|
149
|
+
float: left;
|
|
150
|
+
margin: 0 0 10px 10px;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* Control group styling */
|
|
154
|
+
.mapbox-gl-scope .mapboxgl-ctrl-group {
|
|
155
|
+
background: #fff;
|
|
156
|
+
border-radius: 4px;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.mapbox-gl-scope .mapboxgl-ctrl-group:not(:empty) {
|
|
160
|
+
box-shadow: 0 0 0 2px #0000001a;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.mapbox-gl-scope .mapboxgl-ctrl-group button {
|
|
164
|
+
background-color: initial;
|
|
165
|
+
border: 0;
|
|
166
|
+
box-sizing: border-box;
|
|
167
|
+
cursor: pointer;
|
|
168
|
+
display: block;
|
|
169
|
+
height: 29px;
|
|
170
|
+
outline: none;
|
|
171
|
+
overflow: hidden;
|
|
172
|
+
padding: 0;
|
|
173
|
+
width: 29px;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.mapbox-gl-scope .mapboxgl-ctrl-group button+button {
|
|
177
|
+
border-top: 1px solid #ddd;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.mapbox-gl-scope .mapboxgl-ctrl button .mapboxgl-ctrl-icon {
|
|
181
|
+
background-position: 50%;
|
|
182
|
+
background-repeat: no-repeat;
|
|
183
|
+
display: block;
|
|
184
|
+
height: 100%;
|
|
185
|
+
width: 100%;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.mapbox-gl-scope .mapboxgl-ctrl-attrib-button:focus,
|
|
189
|
+
.mapbox-gl-scope .mapboxgl-ctrl-group button:focus {
|
|
190
|
+
box-shadow: 0 0 2px 2px #0096ff;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.mapbox-gl-scope .mapboxgl-ctrl button:disabled {
|
|
194
|
+
cursor: not-allowed;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.mapbox-gl-scope .mapboxgl-ctrl button:disabled .mapboxgl-ctrl-icon {
|
|
198
|
+
opacity: .25;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.mapbox-gl-scope .mapboxgl-ctrl-group button:first-child {
|
|
202
|
+
border-radius: 4px 4px 0 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.mapbox-gl-scope .mapboxgl-ctrl-group button:last-child {
|
|
206
|
+
border-radius: 0 0 4px 4px;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.mapbox-gl-scope .mapboxgl-ctrl-group button:only-child {
|
|
210
|
+
border-radius: inherit;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.mapbox-gl-scope .mapboxgl-ctrl button:not(:disabled):hover {
|
|
214
|
+
background-color: #0000000d;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/* Marker styles */
|
|
218
|
+
.mapbox-gl-scope .mapboxgl-marker {
|
|
219
|
+
position: absolute;
|
|
220
|
+
z-index: 1;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.mapbox-gl-scope .mapboxgl-marker svg {
|
|
224
|
+
display: block;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/* Popup styles */
|
|
228
|
+
.mapbox-gl-scope .mapboxgl-popup {
|
|
229
|
+
position: absolute;
|
|
230
|
+
text-align: center;
|
|
231
|
+
margin-bottom: 20px;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.mapbox-gl-scope .mapboxgl-popup-content-wrapper {
|
|
235
|
+
padding: 1px;
|
|
236
|
+
text-align: left;
|
|
237
|
+
border-radius: 12px;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.mapbox-gl-scope .mapboxgl-popup-content {
|
|
241
|
+
margin: 13px 24px 13px 20px;
|
|
242
|
+
line-height: 1.3;
|
|
243
|
+
font-size: 13px;
|
|
244
|
+
min-height: 1px;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.mapbox-gl-scope .mapboxgl-popup-content p {
|
|
248
|
+
margin: 17px 0;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.mapbox-gl-scope .mapboxgl-popup-tip-container {
|
|
252
|
+
width: 40px;
|
|
253
|
+
height: 20px;
|
|
254
|
+
position: absolute;
|
|
255
|
+
left: 50%;
|
|
256
|
+
margin-top: -1px;
|
|
257
|
+
margin-left: -20px;
|
|
258
|
+
overflow: hidden;
|
|
259
|
+
pointer-events: none;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.mapbox-gl-scope .mapboxgl-popup-tip {
|
|
263
|
+
width: 17px;
|
|
264
|
+
height: 17px;
|
|
265
|
+
padding: 1px;
|
|
266
|
+
margin: -10px auto 0;
|
|
267
|
+
pointer-events: auto;
|
|
268
|
+
-webkit-transform: rotate(45deg);
|
|
269
|
+
-moz-transform: rotate(45deg);
|
|
270
|
+
-ms-transform: rotate(45deg);
|
|
271
|
+
transform: rotate(45deg);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.mapbox-gl-scope .mapboxgl-popup-content-wrapper,
|
|
275
|
+
.mapbox-gl-scope .mapboxgl-popup-tip {
|
|
276
|
+
background: white;
|
|
277
|
+
color: #333;
|
|
278
|
+
box-shadow: 0 3px 14px rgba(0, 0, 0, 0.4);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.mapbox-gl-scope .mapboxgl-popup-close-button {
|
|
282
|
+
position: absolute;
|
|
283
|
+
top: 0;
|
|
284
|
+
right: 0;
|
|
285
|
+
border: none;
|
|
286
|
+
text-align: center;
|
|
287
|
+
width: 24px;
|
|
288
|
+
height: 24px;
|
|
289
|
+
font: 16px/24px Tahoma, Verdana, sans-serif;
|
|
290
|
+
color: #757575;
|
|
291
|
+
text-decoration: none;
|
|
292
|
+
background: transparent;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.mapbox-gl-scope .mapboxgl-popup-close-button:hover,
|
|
296
|
+
.mapbox-gl-scope .mapboxgl-popup-close-button:focus {
|
|
297
|
+
color: #585858;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* Attribution */
|
|
301
|
+
.mapbox-gl-scope .mapboxgl-ctrl-attribution {
|
|
302
|
+
background: #fff;
|
|
303
|
+
background: rgba(255, 255, 255, 0.8);
|
|
304
|
+
margin: 0;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.mapbox-gl-scope .mapboxgl-ctrl-attribution,
|
|
308
|
+
.mapbox-gl-scope .mapboxgl-ctrl-scale-line {
|
|
309
|
+
padding: 0 5px;
|
|
310
|
+
color: #333;
|
|
311
|
+
line-height: 1.4;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.mapbox-gl-scope .mapboxgl-ctrl-attribution a {
|
|
315
|
+
text-decoration: none;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.mapbox-gl-scope .mapboxgl-ctrl-attribution a:hover,
|
|
319
|
+
.mapbox-gl-scope .mapboxgl-ctrl-attribution a:focus {
|
|
320
|
+
text-decoration: underline;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/* Hide attribution by default */
|
|
324
|
+
.mapbox-gl-scope .mapboxgl-ctrl-attribution {
|
|
325
|
+
display: none !important;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.mapbox-gl-scope .mapboxgl-ctrl-logo {
|
|
329
|
+
display: none !important;
|
|
330
|
+
}
|
package/dist/utils/index.js
CHANGED
|
@@ -13134,6 +13134,63 @@ const renderPercentage = val => {
|
|
|
13134
13134
|
return val + "%";
|
|
13135
13135
|
};
|
|
13136
13136
|
|
|
13137
|
+
/**
|
|
13138
|
+
* Calculates stat change object for StatCard component based on current and previous values
|
|
13139
|
+
* @param {Object} data - Object with current and previous values
|
|
13140
|
+
* @param {number} data.current - Current value
|
|
13141
|
+
* @param {number} data.previous - Previous value
|
|
13142
|
+
* @param {Object} options - Optional configuration
|
|
13143
|
+
* @param {string} options.tooltipText - Custom tooltip text
|
|
13144
|
+
* @param {string} options.format - Format type: 'percentage' (default) or 'absolute'
|
|
13145
|
+
* @param {number} options.decimalPlaces - Number of decimal places for percentage (default: 1)
|
|
13146
|
+
* @returns {Object|null} Change object for StatCard or null if data is invalid
|
|
13147
|
+
*/
|
|
13148
|
+
const calculateStatChange = (data, options = {}) => {
|
|
13149
|
+
if (!data || typeof data !== 'object') {
|
|
13150
|
+
return null;
|
|
13151
|
+
}
|
|
13152
|
+
const {
|
|
13153
|
+
current,
|
|
13154
|
+
previous
|
|
13155
|
+
} = data;
|
|
13156
|
+
|
|
13157
|
+
// Validate that both values are numbers
|
|
13158
|
+
if (typeof current !== 'number' || typeof previous !== 'number') {
|
|
13159
|
+
return null;
|
|
13160
|
+
}
|
|
13161
|
+
|
|
13162
|
+
// If previous is 0, we can't calculate percentage change
|
|
13163
|
+
if (previous === 0) {
|
|
13164
|
+
return null;
|
|
13165
|
+
}
|
|
13166
|
+
const {
|
|
13167
|
+
tooltipText,
|
|
13168
|
+
format = 'percentage',
|
|
13169
|
+
decimalPlaces = 1
|
|
13170
|
+
} = options;
|
|
13171
|
+
|
|
13172
|
+
// Calculate the difference
|
|
13173
|
+
const difference = current - previous;
|
|
13174
|
+
const isPositive = difference >= 0;
|
|
13175
|
+
const direction = isPositive ? 'up' : 'down';
|
|
13176
|
+
|
|
13177
|
+
// Format the value
|
|
13178
|
+
let value;
|
|
13179
|
+
if (format === 'absolute') {
|
|
13180
|
+
// Show absolute difference
|
|
13181
|
+
value = Math.abs(difference).toLocaleString();
|
|
13182
|
+
} else {
|
|
13183
|
+
// Show percentage change
|
|
13184
|
+
const percentageChange = Math.abs(difference) / previous * 100;
|
|
13185
|
+
value = `${percentageChange.toFixed(decimalPlaces)}%`;
|
|
13186
|
+
}
|
|
13187
|
+
return {
|
|
13188
|
+
value,
|
|
13189
|
+
direction,
|
|
13190
|
+
tooltipText: tooltipText || undefined
|
|
13191
|
+
};
|
|
13192
|
+
};
|
|
13193
|
+
|
|
13137
13194
|
/**
|
|
13138
13195
|
* Enum for message types used with Ant Design message component
|
|
13139
13196
|
* @enum {string}
|
|
@@ -14908,6 +14965,7 @@ exports.buildBreadCrumbsHelper = buildBreadCrumbs;
|
|
|
14908
14965
|
exports.buildBreadcrumbs = buildBreadcrumbs;
|
|
14909
14966
|
exports.buildKeyIndicatorsConfig = buildKeyIndicatorsConfig;
|
|
14910
14967
|
exports.buildQueryString = buildQueryString;
|
|
14968
|
+
exports.calculateStatChange = calculateStatChange;
|
|
14911
14969
|
exports.camelCaseToTitle = camelCaseToTitle;
|
|
14912
14970
|
exports.capitalize = capitalize;
|
|
14913
14971
|
exports.capitalizeAll = capitalizeAll;
|
package/package.json
CHANGED
package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/KeyInformation/index.jsx
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { KeyIndicators } from '../../../../../../../../src/index.js';
|
|
3
|
+
import { getKeyIndicatorsRowConfig } from '../../config';
|
|
4
|
+
import { useWidgetFetch } from '../../../../../../hooks/useWidgetFetch.js';
|
|
5
|
+
|
|
6
|
+
const KeyInformation = ({ id, t = () => { }, getSummaryDetail, loading = false }) => {
|
|
7
|
+
|
|
8
|
+
const defaultConfig = useMemo(
|
|
9
|
+
() => ({
|
|
10
|
+
basepath: "events/monitoring-campaign",
|
|
11
|
+
url: `/summary/${id}/key-information`,
|
|
12
|
+
stop: !id,
|
|
13
|
+
}),
|
|
14
|
+
[id],
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const customGetData = useMemo(() => {
|
|
18
|
+
if (getSummaryDetail && id) {
|
|
19
|
+
return ({ url, params = {} }) => {
|
|
20
|
+
const match = url.match(/\/summary\/[^/]+\/(.+)/);
|
|
21
|
+
if (match) {
|
|
22
|
+
const [, type] = match;
|
|
23
|
+
return getSummaryDetail(id, type, params);
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`Invalid URL format: ${url}`);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}, [getSummaryDetail, id]);
|
|
30
|
+
|
|
31
|
+
const { loading: keyInformationLoading, data: keyInformationData } = useWidgetFetch({
|
|
32
|
+
config: defaultConfig,
|
|
33
|
+
getData: customGetData
|
|
34
|
+
});
|
|
35
|
+
const keyIndicatorsConfig = useMemo(() => getKeyIndicatorsRowConfig({ t, data: keyInformationData }), [t, keyInformationData]);
|
|
36
|
+
return (
|
|
37
|
+
<section>
|
|
38
|
+
<KeyIndicators
|
|
39
|
+
title={t("Key Information")}
|
|
40
|
+
config={keyIndicatorsConfig}
|
|
41
|
+
loading={loading || keyInformationLoading}
|
|
42
|
+
/>
|
|
43
|
+
</section>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default KeyInformation;
|
|
48
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React, { useMemo, useCallback } from 'react';
|
|
2
|
+
import { Widget, PieChart } from '../../../../../../../../src/index.js';
|
|
3
|
+
import { renderTooltipJsx } from '../../../../../../utils/tooltip.js';
|
|
4
|
+
|
|
5
|
+
const COLORS = ['#016C6E', '#F5C2AC', '#F0A888', '#DF571E', '#C04B19', '#9B3D14', '#7A2F0F'];
|
|
6
|
+
|
|
7
|
+
const PlantedSpecies = ({
|
|
8
|
+
plantedSpeciesChart,
|
|
9
|
+
t = (s) => s
|
|
10
|
+
}) => {
|
|
11
|
+
const pieData = useMemo(() => {
|
|
12
|
+
const data = plantedSpeciesChart || [];
|
|
13
|
+
const total = data.reduce((sum, item) => sum + (Number(item?.value) || 0), 0);
|
|
14
|
+
|
|
15
|
+
return data.map((item, index) => ({
|
|
16
|
+
value: Number(item?.value) || 0,
|
|
17
|
+
percent: total > 0 ? (Number(item?.value) || 0) / total : 0,
|
|
18
|
+
color: COLORS[index % COLORS.length],
|
|
19
|
+
label: item?.type || '',
|
|
20
|
+
key: item?.type || `item-${index}`,
|
|
21
|
+
}));
|
|
22
|
+
}, [plantedSpeciesChart]);
|
|
23
|
+
|
|
24
|
+
const isEmpty = useMemo(() => {
|
|
25
|
+
return !plantedSpeciesChart || plantedSpeciesChart.length === 0 ||
|
|
26
|
+
plantedSpeciesChart.every(item => !item?.value || Number(item.value) === 0);
|
|
27
|
+
}, [plantedSpeciesChart]);
|
|
28
|
+
|
|
29
|
+
const getTooltipChildren = useCallback(
|
|
30
|
+
(item) => {
|
|
31
|
+
if (isEmpty) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return renderTooltipJsx({
|
|
36
|
+
title: t("Planted Species"),
|
|
37
|
+
items: [
|
|
38
|
+
{
|
|
39
|
+
color: item.color,
|
|
40
|
+
label: item.label || '',
|
|
41
|
+
value: item.value || 0,
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
[t, isEmpty]
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Widget
|
|
51
|
+
title={t("Planted Species")}
|
|
52
|
+
className="with-border-header h-w-btn-header"
|
|
53
|
+
>
|
|
54
|
+
<div className="flex flex-1 flex-column justify-content-center">
|
|
55
|
+
<div className="flex justify-content-center w-full">
|
|
56
|
+
<PieChart
|
|
57
|
+
data={pieData}
|
|
58
|
+
isPie
|
|
59
|
+
isEmpty={isEmpty}
|
|
60
|
+
getTooltipChildren={getTooltipChildren}
|
|
61
|
+
mouseXOffset={10}
|
|
62
|
+
mouseYOffset={10}
|
|
63
|
+
changeOpacityOnHover={false}
|
|
64
|
+
doConstraints={false}
|
|
65
|
+
/>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</Widget>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export default PlantedSpecies;
|
|
73
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Widget, ColumnChart } from '../../../../../../../../src/index.js';
|
|
3
|
+
|
|
4
|
+
const SeedlingsHeight = ({
|
|
5
|
+
seedlingsHeightChart,
|
|
6
|
+
t = (s) => s
|
|
7
|
+
}) => {
|
|
8
|
+
return (
|
|
9
|
+
<Widget
|
|
10
|
+
title={t("Seedlings Height")}
|
|
11
|
+
className="with-border-header h-w-btn-header"
|
|
12
|
+
>
|
|
13
|
+
<div className="flex flex-1 flex-column justify-content-center">
|
|
14
|
+
<div className="flex justify-content-center w-full">
|
|
15
|
+
<ColumnChart
|
|
16
|
+
data={seedlingsHeightChart || []}
|
|
17
|
+
xFieldKey="label"
|
|
18
|
+
yFieldKey="value"
|
|
19
|
+
animated={true}
|
|
20
|
+
height={200}
|
|
21
|
+
color="#016C6E"
|
|
22
|
+
renderTooltipContent={(title, data) => {
|
|
23
|
+
if (!data || data.length === 0) return {};
|
|
24
|
+
const item = data[0]?.data || data[0];
|
|
25
|
+
return {
|
|
26
|
+
title: t("Seedlings Height"),
|
|
27
|
+
subTitle: title,
|
|
28
|
+
items: [
|
|
29
|
+
{
|
|
30
|
+
label: t("Count"),
|
|
31
|
+
value: item?.value || 0,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
}}
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</Widget>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default SeedlingsHeight;
|
|
44
|
+
|
package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/Stats.jsx
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { StatCard } from '../../../../../../../../src/index.js';
|
|
3
|
+
import { calculateStatChange } from '../../../../../../utils/numbers.js';
|
|
4
|
+
|
|
5
|
+
const Stats = ({
|
|
6
|
+
survivalRate,
|
|
7
|
+
averageHeight,
|
|
8
|
+
averageDiameter,
|
|
9
|
+
t = (s) => s
|
|
10
|
+
}) => {
|
|
11
|
+
const survivalRateChange = useMemo(() => {
|
|
12
|
+
if (!survivalRate) return null;
|
|
13
|
+
return calculateStatChange(
|
|
14
|
+
{
|
|
15
|
+
current: Number(survivalRate.current) || 0,
|
|
16
|
+
previous: Number(survivalRate.previous) || 0,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
tooltipText: t("In comparison to last period"),
|
|
20
|
+
format: 'absolute',
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
}, [survivalRate, t]);
|
|
24
|
+
|
|
25
|
+
const averageHeightChange = useMemo(() => {
|
|
26
|
+
if (!averageHeight) return null;
|
|
27
|
+
return calculateStatChange(
|
|
28
|
+
{
|
|
29
|
+
current: Number(averageHeight.current) || 0,
|
|
30
|
+
previous: Number(averageHeight.previous) || 0,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
tooltipText: t("In comparison to last period"),
|
|
34
|
+
format: 'absolute',
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
}, [averageHeight, t]);
|
|
38
|
+
|
|
39
|
+
const averageDiameterChange = useMemo(() => {
|
|
40
|
+
if (!averageDiameter) return null;
|
|
41
|
+
return calculateStatChange(
|
|
42
|
+
{
|
|
43
|
+
current: Number(averageDiameter.current) || 0,
|
|
44
|
+
previous: Number(averageDiameter.previous) || 0,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
tooltipText: t("In comparison to last period"),
|
|
48
|
+
format: 'absolute',
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
}, [averageDiameter, t]);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<div style={{ display: "flex", gap: "24px", marginBottom: "24px" }}>
|
|
55
|
+
<section style={{ flex: 1 }}>
|
|
56
|
+
<StatCard
|
|
57
|
+
title={t("Survival Rate")}
|
|
58
|
+
value={survivalRate ? Number(survivalRate.current).toLocaleString() : "0"}
|
|
59
|
+
icon="EventCalendar"
|
|
60
|
+
change={survivalRateChange}
|
|
61
|
+
/>
|
|
62
|
+
</section>
|
|
63
|
+
|
|
64
|
+
<section style={{ flex: 1 }}>
|
|
65
|
+
<StatCard
|
|
66
|
+
title={t("Average Height")}
|
|
67
|
+
value={averageHeight ? Number(averageHeight.current).toLocaleString() + " cm" : "0 cm"}
|
|
68
|
+
icon="ProjectLocation"
|
|
69
|
+
change={averageHeightChange}
|
|
70
|
+
/>
|
|
71
|
+
</section>
|
|
72
|
+
|
|
73
|
+
<section style={{ flex: 1 }}>
|
|
74
|
+
<StatCard
|
|
75
|
+
title={t("Average Diameter")}
|
|
76
|
+
value={averageDiameter ? Number(averageDiameter.current).toLocaleString() + " mm" : "0 mm"}
|
|
77
|
+
icon="Activity"
|
|
78
|
+
change={averageDiameterChange}
|
|
79
|
+
/>
|
|
80
|
+
</section>
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export default Stats;
|
|
86
|
+
|