datastake-daf 0.6.815 → 0.6.816

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 (30) hide show
  1. package/dist/components/index.js +1703 -1578
  2. package/dist/pages/index.js +344 -685
  3. package/dist/style/datastake/mapbox-gl.css +330 -0
  4. package/dist/utils/index.js +0 -28
  5. package/package.json +1 -1
  6. package/src/@daf/core/components/Charts/RadarChart/index.jsx +12 -3
  7. package/src/@daf/core/components/Charts/style.js +2 -1
  8. package/src/@daf/core/components/Dashboard/Map/ChainIcon/index.js +104 -123
  9. package/src/@daf/core/components/Dashboard/Widget/VegetationWidget/index.jsx +0 -4
  10. package/src/@daf/core/components/Table/index.jsx +6 -11
  11. package/src/@daf/pages/Events/Activities/columns.js +11 -15
  12. package/src/@daf/pages/Events/Incidents/columns.js +11 -15
  13. package/src/@daf/pages/Events/columns.js +3 -7
  14. package/src/@daf/pages/Locations/MineSite/columns.js +11 -16
  15. package/src/@daf/pages/Locations/columns.js +3 -7
  16. package/src/@daf/pages/Stakeholders/Operators/columns.js +12 -16
  17. package/src/@daf/pages/Stakeholders/Workers/columns.js +12 -16
  18. package/src/@daf/pages/Stakeholders/columns.js +4 -8
  19. package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/BiodiversityHabitat/ObservedFauna.jsx +6 -11
  20. package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/PlantedSpecies.jsx +25 -10
  21. package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/SeedlingsHeight.jsx +10 -13
  22. package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/VegetationHealth.jsx +19 -4
  23. package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/SoilWaterProfile/SoilType.jsx +22 -10
  24. package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/SoilWaterProfile/WaterQuality.jsx +26 -10
  25. package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/chartHelpers.js +74 -0
  26. package/src/@daf/pages/TablePage/helper.js +0 -15
  27. package/src/helpers/errorHandling.js +74 -142
  28. package/src/utils.js +1 -1
  29. package/src/@daf/pages/Events/Testimonials/columns.js +0 -173
  30. package/src/@daf/pages/Events/Testimonials/config.js +0 -175
@@ -1,5 +1,4 @@
1
1
  import { useMemo, useEffect, useRef, useState } from "react";
2
- import { createPortal } from "react-dom";
3
2
  import {
4
3
  isMineSite,
5
4
  getStakeholderPosition,
@@ -11,6 +10,7 @@ import {
11
10
  import MineSiteMarker from "./Markers/SVG/MinesiteMarker.js";
12
11
  import VillageMarker from "./Markers/SVG/VillageMarker.js";
13
12
  import StakeholderIcon from "./Markers/StakeholderMarker.js";
13
+ import { createRoot } from "react-dom/client";
14
14
  import * as L from "leaflet";
15
15
  import { Popover } from "antd";
16
16
  import { renderTooltipJsx } from "../../../../../utils/tooltip.js";
@@ -32,8 +32,8 @@ export default function LocationIcon({
32
32
  activeMarker,
33
33
  setActiveMarker,
34
34
  }) {
35
- const markersRef = useRef([]);
36
- const [portalContainers, setPortalContainers] = useState([]);
35
+ const rootsMapRef = useRef(new Map());
36
+ const markersRef = useRef([])
37
37
  const isSelected = selectedMarkersId.includes(data.datastakeId);
38
38
  const Marker = useMemo(() => {
39
39
  if (isMineSite(data.type)) {
@@ -114,31 +114,25 @@ export default function LocationIcon({
114
114
  }, [JSON.stringify(allData), JSON.stringify(data.links), JSON.stringify(data.stakeholders), zoom]);
115
115
 
116
116
  const stakeholdersOfLocation = useMemo(() => {
117
- return (data?.stakeholders || []).filter(stakeholder => {
118
- if (!stakeholder.links || stakeholder.links.length === 0) {
119
- return true;
120
- }
121
-
122
- const locationsWithThisStakeholder = allData
123
- .filter(loc =>
124
- loc.stakeholders?.some(s => s.datastakeId === stakeholder.datastakeId)
125
- )
126
- .map(loc => loc.datastakeId);
127
-
128
- const primaryLocation = locationsWithThisStakeholder.sort()[0];
129
- return data.datastakeId === primaryLocation;
130
- });
131
- }, [data.stakeholders, data.datastakeId, allData, zoom]);
117
+ return data?.stakeholders || [];
118
+ }, [data.stakeholders, zoom]);
132
119
 
133
120
  useEffect(() => {
134
- markersRef.current.forEach(marker => {
135
- if (mapRef && mapRef.hasLayer(marker)) {
121
+ const currentRoots = rootsMapRef.current;
122
+ const currentMarkers = markersRef.current;
123
+
124
+ currentMarkers.forEach(marker => {
125
+ if (mapRef.hasLayer(marker)) {
136
126
  mapRef.removeLayer(marker);
137
127
  }
138
128
  });
129
+ currentRoots.forEach(root => {
130
+ root.unmount();
131
+ });
132
+ currentRoots.clear();
139
133
  markersRef.current = [];
140
- setPortalContainers([]);
141
134
 
135
+ // Only create stakeholder markers if this location or any of its stakeholders are selected
142
136
  const shouldShowStakeholders = isSelected || stakeholdersOfLocation.some(stk =>
143
137
  selectedMarkersId.includes(stk.datastakeId)
144
138
  );
@@ -147,11 +141,9 @@ export default function LocationIcon({
147
141
  return;
148
142
  }
149
143
 
150
- // Create markers and store their container references
151
- const containers = [];
152
-
144
+ // Create new markers only when selected
153
145
  stakeholdersOfLocation.forEach((stakeholder, index) => {
154
- const markerId = `${data.datastakeId}-${stakeholder.datastakeId}`;
146
+ const markerId = `${stakeholder.datastakeId}`;
155
147
  const { x, y, radius, center } = getStakeholderPosition({
156
148
  zoom,
157
149
  totalMarkers: stakeholdersOfLocation.length,
@@ -170,30 +162,46 @@ export default function LocationIcon({
170
162
  const isForceOpen = activeMarker?.datastakeId === data.datastakeId;
171
163
  const iconSize = isSmallMarker(zoom) || isExtraSmallMarker(zoom) ? [11, 11] : [25, 25];
172
164
 
173
- // Create container div
174
- const containerDiv = document.createElement('div');
175
- containerDiv.id = markerId;
176
-
177
165
  const marker = L.marker(stakeholderLatLng, {
178
166
  icon: L.divIcon({
179
- html: containerDiv.outerHTML,
167
+ html: `<div id="${markerId}"></div>`,
180
168
  className: "marker-chain",
181
169
  iconSize: iconSize,
182
170
  }),
183
171
  }).addTo(mapRef);
184
172
 
185
173
  markersRef.current.push(marker);
186
-
187
- // Store container info for portal rendering
188
- containers.push({
189
- markerId,
190
- stakeholder,
191
- x,
192
- y,
193
- radius,
194
- index,
195
- isForceOpen,
196
- });
174
+
175
+ setTimeout(() => {
176
+ const div = document.getElementById(markerId);
177
+ if (div && !rootsMapRef.current.has(markerId)) {
178
+ const root = createRoot(div);
179
+ rootsMapRef.current.set(markerId, root);
180
+
181
+ root.render(
182
+ <StakeholderIcon
183
+ data={stakeholder}
184
+ zoom={zoom}
185
+ allData={allData}
186
+ link={link}
187
+ parentId={data.datastakeId}
188
+ renderTooltip={renderTooltip}
189
+ onClickLink={onClickLink}
190
+ selectedMarkersId={selectedMarkersId}
191
+ handleSelectMarker={handleSelectMarker}
192
+ mapRef={mapRef}
193
+ radius={radius}
194
+ index={index}
195
+ x={x}
196
+ y={y}
197
+ openPopupIdRef={openPopupIdRef}
198
+ polylinesRef={polylinesRef}
199
+ isForceOpen={isForceOpen}
200
+ activeMarker={activeMarker}
201
+ />,
202
+ );
203
+ }
204
+ }, 0);
197
205
 
198
206
  setMapMarkers((prev) => {
199
207
  const array = [
@@ -228,23 +236,21 @@ export default function LocationIcon({
228
236
  isForceOpen,
229
237
  listOfPolylines: polylinesRef.current,
230
238
  stakeholderType: stakeholder.type,
231
- animated: true,
239
+ animated: true,
232
240
  });
233
241
  });
234
242
 
235
- // Update portal containers after markers are created
236
- setTimeout(() => {
237
- setPortalContainers(containers);
238
- }, 0);
239
-
240
243
  return () => {
241
244
  markersRef.current.forEach(marker => {
242
- if (mapRef && mapRef.hasLayer(marker)) {
245
+ if (mapRef.hasLayer(marker)) {
243
246
  mapRef.removeLayer(marker);
244
247
  }
245
248
  });
249
+ rootsMapRef.current.forEach(root => {
250
+ root.unmount();
251
+ });
252
+ rootsMapRef.current.clear();
246
253
  markersRef.current = [];
247
- setPortalContainers([]);
248
254
  };
249
255
  }, [stakeholdersOfLocation, selectedMarkersId, activeMarker, zoom]);
250
256
 
@@ -338,81 +344,56 @@ useEffect(() => {
338
344
  }, [linkedNodesData, selectedMarkersId, zoom, stakeholdersOfLocation, isSelected]);
339
345
 
340
346
  return (
341
- <>
342
- <Popover
343
- content={renderTooltipJsx({
344
- title: data.name,
345
- subTitle: data.subTitle,
346
- total: data.sources,
347
- className: "pt-0 pb-0",
348
- items: renderTooltip(data),
349
- link,
350
- onClickLink: () => onClickLink(data),
351
- isNewTab: true,
352
- })}
353
- getPopupContainer={(triggerNode) => {
354
- const mapElement = document.getElementById("map");
355
- return mapElement || triggerNode.parentElement || document.body;
356
- }}
357
- >
358
- <div style={{ position: "relative", display: "inline-block" }}>
359
- {(isSelected || selectedMarkersId.length === 0) && (
360
- <div
361
- style={{
362
- position: "absolute",
363
- bottom: "0",
364
- left: "50%",
365
- transform: "translateX(-50%)",
366
- width: "12px",
367
- height: "6px",
368
- background: "rgba(0,0,0,0.15)",
369
- borderRadius: "50%",
370
- filter: "blur(3px)",
371
- }}
372
- />
373
- )}
374
- <Marker
375
- isSelected={isSelected}
376
- onClick={() => {
377
- handleSelectMarker(data);
378
- setActiveMarker(isSelected ? null : data);
347
+ <Popover
348
+ content={renderTooltipJsx({
349
+ title: data.name,
350
+ subTitle: data.subTitle,
351
+ total: data.sources,
352
+ className: "pt-0 pb-0",
353
+ items: renderTooltip(data),
354
+ link,
355
+ onClickLink: () => onClickLink(data),
356
+ isNewTab: true,
357
+ })}
358
+ // open={
359
+ // (!openPopupIdRef.current || openPopupIdRef.current === data.datastakeId) &&
360
+ // isHovering
361
+ // }
362
+ getPopupContainer={(triggerNode) => {
363
+ const mapElement = document.getElementById("map");
364
+ return mapElement || triggerNode.parentElement || document.body;
365
+ }}
366
+ >
367
+ <div style={{ position: "relative", display: "inline-block" }}>
368
+ {(isSelected || selectedMarkersId.length === 0) && (
369
+ <div
370
+ style={{
371
+ position: "absolute",
372
+ bottom: "0",
373
+ left: "50%",
374
+ transform: "translateX(-50%)",
375
+ width: "12px",
376
+ height: "6px",
377
+ background: "rgba(0,0,0,0.15)",
378
+ borderRadius: "50%",
379
+ filter: "blur(3px)",
379
380
  }}
380
- zoom={zoom}
381
- selectedMarkersId={selectedMarkersId}
382
381
  />
383
- </div>
384
- </Popover>
385
-
386
- {/* Render stakeholder icons via portals */}
387
- {portalContainers.map(({markerId, stakeholder, x, y, radius, index, isForceOpen}) => {
388
- const container = document.getElementById(markerId);
389
- if (!container) return null;
390
-
391
- return createPortal(
392
- <StakeholderIcon
393
- key={markerId}
394
- data={stakeholder}
395
- zoom={zoom}
396
- allData={allData}
397
- link={link}
398
- parentId={data.datastakeId}
399
- renderTooltip={renderTooltip}
400
- onClickLink={onClickLink}
401
- selectedMarkersId={selectedMarkersId}
402
- handleSelectMarker={handleSelectMarker}
403
- mapRef={mapRef}
404
- radius={radius}
405
- index={index}
406
- x={x}
407
- y={y}
408
- openPopupIdRef={openPopupIdRef}
409
- polylinesRef={polylinesRef}
410
- isForceOpen={isForceOpen}
411
- activeMarker={activeMarker}
412
- />,
413
- container
414
- );
415
- })}
416
- </>
382
+ )}
383
+ <Marker
384
+ isSelected={isSelected}
385
+ onClick={() => {
386
+ handleSelectMarker(data);
387
+ setActiveMarker(isSelected ? null : data);
388
+ }}
389
+ zoom={zoom}
390
+ onMouseEnter={() => setIsHovering(true)}
391
+ onMouseLeave={() => {
392
+ setIsHovering(false);
393
+ }}
394
+ selectedMarkersId={selectedMarkersId}
395
+ />
396
+ </div>
397
+ </Popover>
417
398
  );
418
399
  }
@@ -16,16 +16,12 @@ export default function VegetationWidget({
16
16
  }) {
17
17
  let vegetationConfig = getVegetationConfig();
18
18
 
19
- // Get all VEGETATION_KEYS values before filtering (needed for mapping check)
20
19
  const allVegetationKeys = vegetationConfig.map(item => item.key);
21
20
 
22
- // Filter to show only specific keys if filterKeys is provided
23
21
  if (filterKeys && Array.isArray(filterKeys)) {
24
22
  vegetationConfig = vegetationConfig.filter(item => filterKeys.includes(item.key));
25
23
  }
26
24
 
27
- // Map growthObservations to VEGETATION_KEYS
28
- // Handle both formats: growthObservations keys (e.g., "yellowing_leaves") and VEGETATION_KEYS (e.g., "yellowing")
29
25
  const mappedGrowthObservations = Array.isArray(growthObservations)
30
26
  ? growthObservations
31
27
  .map(obs => {
@@ -36,12 +36,7 @@ export default function DAFTable({
36
36
  doEmptyRows,
37
37
  ...rest
38
38
  }) {
39
- const source = useMemo(() => {
40
- if (data && Array.isArray(data)) {
41
- return data;
42
- }
43
- return [];
44
- }, [data]);
39
+ const [source, setSource] = useState([]);
45
40
  const projectData = (projects || []).find(p => p.id === selectedProject);
46
41
  const [filtersInit, setFiltersInit] = useState(!loading);
47
42
 
@@ -90,11 +85,11 @@ export default function DAFTable({
90
85
  } : filtersConfig;
91
86
  }, [sourcesKey, sources, filtersConfig, t]);
92
87
 
93
- // useEffect(() => {
94
- // if (data && Array.isArray(data)) {
95
- // setSource(data);
96
- // }
97
- // }, [data, data.length]);
88
+ useEffect(() => {
89
+ if (data && Array.isArray(data)) {
90
+ setSource(data);
91
+ }
92
+ }, [data, data.length]);
98
93
 
99
94
  const paginationPageSize = pagination?.pageSize;
100
95
  const dataSource = useMemo(() => {
@@ -117,23 +117,19 @@ export const getColumns = ({t, goTo, user, options, activeTab, getRedirectLink,
117
117
  },
118
118
  },
119
119
  {
120
- title: t("Sources"),
121
- dataIndex: "sources",
122
- key: "sources",
123
- show: activeTab !== "own",
124
- render: (val, all) => {
125
- if (all.empty) {
126
- return <div className="daf-default-cell" />;
127
- }
128
-
129
- if (!val || val?.length === 0) {
130
- return "-";
131
- }
120
+ title: t("Sources"),
121
+ dataIndex: "sources",
122
+ key: "sources",
123
+ show: activeTab !== "own",
124
+ render: (val, all) => {
125
+ if (all.empty) {
126
+ return <div className="daf-default-cell" />;
127
+ }
132
128
 
133
- const sources = sourceAvatarConfig(val, user, applications);
129
+ const sources = sourceAvatarConfig(val, user, applications);
134
130
 
135
- return <AvatarGroup items={sources} />;
136
- },
131
+ return <AvatarGroup items={sources}></AvatarGroup>;
132
+ },
137
133
  },
138
134
  {
139
135
  title: t("Status"),
@@ -117,23 +117,19 @@ export const getColumns = ({t, goTo, user, options, activeTab, getRedirectLink,
117
117
  },
118
118
  },
119
119
  {
120
- title: t("Sources"),
121
- dataIndex: "sources",
122
- key: "sources",
123
- show: activeTab !== "own",
124
- render: (val, all) => {
125
- if (all.empty) {
126
- return <div className="daf-default-cell" />;
127
- }
128
-
129
- if (!val || val?.length === 0) {
130
- return "-";
131
- }
120
+ title: t("Sources"),
121
+ dataIndex: "sources",
122
+ key: "sources",
123
+ show: activeTab !== "own",
124
+ render: (val, all) => {
125
+ if (all.empty) {
126
+ return <div className="daf-default-cell" />;
127
+ }
132
128
 
133
- const sources = sourceAvatarConfig(val, user, applications);
129
+ const sources = sourceAvatarConfig(val, user, applications);
134
130
 
135
- return <AvatarGroup items={sources} />;
136
- },
131
+ return <AvatarGroup items={sources}></AvatarGroup>;
132
+ },
137
133
  },
138
134
  {
139
135
  title: t("Status"),
@@ -147,17 +147,13 @@ export const getColumns = ({ t, goTo, user, options, activeTab, getRedirectLink,
147
147
  key: "sources",
148
148
  show: activeTab !== "own",
149
149
  render: (val, all) => {
150
- if (all.empty) {
151
- return <div className="daf-default-cell" />;
152
- }
153
-
154
- if (!val || val?.length === 0) {
155
- return "-";
150
+ if (all.empty) {
151
+ return <div className="daf-default-cell" />;
156
152
  }
157
153
 
158
154
  const sources = sourceAvatarConfig(val, user, applications);
159
155
 
160
- return <AvatarGroup items={sources} />;
156
+ return <AvatarGroup items={sources}></AvatarGroup>;
161
157
  },
162
158
  },
163
159
  {
@@ -145,25 +145,20 @@ export const getColumns = ({t, goTo, user, options, activeTab, getRedirectLink,
145
145
  return renderStatusTag({ value: _val, t });
146
146
  },
147
147
  },
148
- {
149
- title: t("Sources"),
150
- dataIndex: "sources",
151
- key: "sources",
152
- show: activeTab !== "own",
153
- render: (val, all) => {
148
+
149
+ {
150
+ title: t("Sources"),
151
+ dataIndex: 'sources',
152
+ ellipsis: true,
153
+ show: activeTab !== "own",
154
+ render: (v, all) => {
154
155
  if (all.empty) {
155
- return <div className="daf-default-cell" />;
156
+ return <div className="daf-default-cell" />
156
157
  }
157
-
158
- if (!val || val?.length === 0) {
159
- return "-";
160
- }
161
-
162
- const sources = sourceAvatarConfig(val, user, applications);
163
-
164
- return <AvatarGroup items={sources} />;
158
+ const sources = sourceAvatarConfig(v, user, applications);
159
+ return <AvatarGroup items={sources}></AvatarGroup>;
160
+ },
165
161
  },
166
- },
167
162
  {
168
163
  id: 'actions',
169
164
  title: "",
@@ -105,15 +105,11 @@ export const getColumns = ({t, goTo, user, options, activeTab, getRedirectLink,
105
105
  return <div className="daf-default-cell" />;
106
106
  }
107
107
 
108
- if (!val || val?.length === 0) {
109
- return "-";
110
- }
111
-
112
- const sources = sourceAvatarConfig(val, user, applications);
108
+ const sources = sourceAvatarConfig(val, user, applications);
113
109
 
114
- return <AvatarGroup items={sources} />;
110
+ return <AvatarGroup items={sources}></AvatarGroup>;
115
111
  },
116
- },
112
+ },
117
113
  {
118
114
  title: t("Last Update"),
119
115
  dataIndex: "updatedAt",
@@ -116,25 +116,21 @@ export const getColumns = ({t, goTo, user, options, activeTab, getRedirectLink,
116
116
  },
117
117
  ellipsis: true,
118
118
  },
119
- {
120
- title: t("Sources"),
121
- dataIndex: "sources",
122
- key: "sources",
123
- show: activeTab !== "own",
124
- render: (val, all) => {
125
- if (all.empty) {
126
- return <div className="daf-default-cell" />;
127
- }
128
-
129
- if (!val || val?.length === 0) {
130
- return "-";
131
- }
119
+ {
120
+ title: t("Sources"),
121
+ dataIndex: "sources",
122
+ key: "sources",
123
+ show: activeTab !== "own",
124
+ render: (val, all) => {
125
+ if (all.empty) {
126
+ return <div className="daf-default-cell" />;
127
+ }
132
128
 
133
- const sources = sourceAvatarConfig(val, user, applications);
129
+ const sources = sourceAvatarConfig(val, user, applications);
134
130
 
135
- return <AvatarGroup items={sources} />;
131
+ return <AvatarGroup items={sources}></AvatarGroup>;
132
+ },
136
133
  },
137
- },
138
134
  {
139
135
  title: t("Status"),
140
136
  dataIndex: 'status',
@@ -101,24 +101,20 @@ export const getColumns = ({t, goTo, user, options, activeTab, getRedirectLink,
101
101
  ellipsis: true,
102
102
  },
103
103
  {
104
- title: t("Sources"),
105
- dataIndex: "sources",
106
- key: "sources",
107
- show: activeTab !== "own",
108
- render: (val, all) => {
109
- if (all.empty) {
110
- return <div className="daf-default-cell" />;
111
- }
112
-
113
- if (!val || val?.length === 0) {
114
- return "-";
115
- }
104
+ title: t("Sources"),
105
+ dataIndex: "sources",
106
+ key: "sources",
107
+ show: activeTab !== "own",
108
+ render: (val, all) => {
109
+ if (all.empty) {
110
+ return <div className="daf-default-cell" />;
111
+ }
116
112
 
117
- const sources = sourceAvatarConfig(val, user, applications);
113
+ const sources = sourceAvatarConfig(val, user, applications);
118
114
 
119
- return <AvatarGroup items={sources} />;
120
- },
121
- },
115
+ return <AvatarGroup items={sources}></AvatarGroup>;
116
+ },
117
+ },
122
118
  {
123
119
  title: t("Status"),
124
120
  dataIndex: "status",
@@ -43,9 +43,7 @@ export const getColumns = ({t, goTo, user, options, activeTab, getRedirectLink,
43
43
  return <div className="daf-default-cell" />
44
44
  }
45
45
 
46
- const categoriesOptions = [...(options?.categoriesOptions || []), ...(options?.category || [])]
47
-
48
- const category = findOptions(v, categoriesOptions);
46
+ const category = findOptions(v, options?.categoriesOptions);
49
47
 
50
48
  return category ? <Tooltip title={category}>{category}</Tooltip> : '-';
51
49
  },
@@ -60,9 +58,7 @@ export const getColumns = ({t, goTo, user, options, activeTab, getRedirectLink,
60
58
  return <div className="daf-default-cell" />
61
59
  }
62
60
 
63
- const subCategoriesOptions = [...(options?.subCategoriesOptions || []), ...(options?.subCategory || [])];
64
-
65
- const subCategory = findOptions(v, subCategoriesOptions);
61
+ const subCategory = findOptions(v, options?.subCategoriesOptions);
66
62
 
67
63
  return subCategory ? <Tooltip title={subCategory}>{subCategory}</Tooltip> : '-';
68
64
  },
@@ -93,12 +89,12 @@ export const getColumns = ({t, goTo, user, options, activeTab, getRedirectLink,
93
89
  return <div className="daf-default-cell" />;
94
90
  }
95
91
  if (!val || val?.length === 0) {
96
- return "-";
92
+ return "--";
97
93
  }
98
94
 
99
95
  const sources = sourceAvatarConfig(val, user, applications);
100
96
 
101
- return <AvatarGroup items={sources} />;
97
+ return <AvatarGroup items={sources}></AvatarGroup>;
102
98
  },
103
99
  },
104
100
  {
@@ -1,6 +1,6 @@
1
1
  import React, { useMemo } from 'react';
2
2
  import { Widget, BarChart } from '../../../../../../../../src/index.js';
3
- import { calculateNiceAxisConfig, mergeDefaultCategories } from '../chartHelpers.js';
3
+ import { calculateNaturalAxisConfig, mergeDefaultCategories } from '../chartHelpers.js';
4
4
 
5
5
  const ObservedFauna = ({
6
6
  observedFaunaChart,
@@ -32,16 +32,11 @@ const ObservedFauna = ({
32
32
  }, [observedFaunaChart, options]);
33
33
 
34
34
  const xAxisConfig = useMemo(() => {
35
- return calculateNiceAxisConfig(
36
- chartData,
37
- 'value',
38
- 1.2, // multiplier: 20% padding
39
- {
40
- min: 0,
41
- max: 10,
42
- tickMethod: () => [0, 2, 4, 6, 8, 10]
43
- }
44
- );
35
+ const maxValue = chartData && chartData.length > 0
36
+ ? Math.max(...chartData.map(item => Number(item?.value) || 0))
37
+ : 0;
38
+
39
+ return calculateNaturalAxisConfig(maxValue);
45
40
  }, [chartData]);
46
41
 
47
42
  return (