datastake-daf 0.6.809 → 0.6.811
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/build/favicon.ico +0 -0
- package/build/logo192.png +0 -0
- package/build/logo512.png +0 -0
- package/build/manifest.json +25 -0
- package/build/robots.txt +3 -0
- package/dist/components/index.js +1513 -1795
- package/dist/hooks/index.js +4 -11
- package/dist/layouts/index.js +484 -460
- package/dist/pages/index.js +1746 -753
- package/dist/services/index.js +5 -19
- package/dist/style/datastake/mapbox-gl.css +330 -0
- package/dist/utils/index.js +489 -484
- package/package.json +1 -1
- package/public/Vegetation/damage-from-insects-default.svg +2 -0
- package/public/Vegetation/dry-or-dead-default.svg +2 -0
- package/public/Vegetation/healthy-default.svg +2 -0
- package/public/Vegetation/yellowing.svg +2 -0
- package/src/@daf/core/components/AuthForm/index.jsx +3 -12
- package/src/@daf/core/components/Icon/configs/Droplets.js +9 -0
- package/src/@daf/core/components/Icon/configs/TrendUp.js +8 -0
- package/src/@daf/core/components/Icon/configs/index.js +4 -0
- package/src/@daf/core/components/Screens/Admin/AdminDashboard/components/UserStatistics/TopContributors/index.jsx +1 -0
- package/src/@daf/core/components/Screens/Admin/AdminDashboard/components/UserStatistics/UserGrowth/hook.js +1 -0
- package/src/@daf/core/components/Screens/Admin/AdminDashboard/components/UserStatistics/UserGrowth/index.jsx +3 -1
- package/src/@daf/core/components/Screens/Admin/AdminModals/CombineLocation/index.jsx +51 -51
- package/src/@daf/core/components/Screens/Admin/AdminModals/CombineSubjects/index.jsx +1 -6
- package/src/@daf/core/components/Screens/Admin/AdminModals/NewAccount/index.jsx +12 -47
- package/src/@daf/core/components/Screens/Admin/AdminModals/NewUser/index.jsx +10 -36
- package/src/@daf/core/components/Screens/Admin/AdminModals/TransferRights/index.jsx +1 -1
- package/src/@daf/core/components/Screens/Admin/AdminScreens/Accounts.jsx +0 -1
- package/src/@daf/core/components/Screens/Admin/AdminScreens/Dashboard.jsx +2 -2
- package/src/@daf/core/components/Screens/Admin/AdminTables/AccountTable/helper.js +30 -22
- package/src/@daf/core/components/Screens/Admin/AdminTables/AccountTable/index.jsx +3 -4
- package/src/@daf/core/components/Screens/Admin/AdminTables/LocationTable/index.jsx +2 -6
- package/src/@daf/core/components/Screens/Admin/AdminTables/SubjectsTable/index.jsx +12 -14
- package/src/@daf/core/components/Screens/Admin/AdminTables/UserTable/index.jsx +1 -0
- package/src/@daf/core/components/Screens/Admin/AdminTables/hook.js +0 -3
- package/src/@daf/core/components/Screens/Admin/AdminViews/components/Edit/index.jsx +9 -12
- package/src/@daf/core/components/Screens/Admin/AdminViews/components/Users/index.jsx +4 -16
- package/src/@daf/core/components/Screens/Admin/AdminViews/components/View/helpers.js +17 -9
- package/src/@daf/core/components/Screens/Admin/AdminViews/index.jsx +8 -9
- package/src/@daf/core/components/Screens/Admin/AppInvitation/index.jsx +99 -124
- package/src/@daf/hooks/useAdminDashboard.js +4 -7
- package/src/@daf/pages/Locations/MineSite/columns.js +18 -1
- package/src/@daf/pages/Locations/MineSite/config.js +2 -2
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/BiodiversityHabitat/InvasiveSpecies.jsx +107 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/BiodiversityHabitat/ObservedFauna.jsx +80 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/BiodiversityHabitat/Stats.jsx +62 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/BiodiversityHabitat/index.jsx +109 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/KeyInformation/index.jsx +8 -4
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/PlantedSpecies.jsx +21 -9
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/SeedlingsHeight.jsx +36 -2
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/Stats.jsx +3 -3
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/VegetationHealth.jsx +19 -8
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/index.jsx +13 -9
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/SoilWaterProfile/SalinityLevels.jsx +100 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/SoilWaterProfile/SoilType.jsx +84 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/SoilWaterProfile/Stats.jsx +72 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/SoilWaterProfile/WaterQuality.jsx +84 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/SoilWaterProfile/index.jsx +101 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/chartHelpers.js +102 -0
- package/src/@daf/pages/Summary/Activities/MonitoringCampaign/index.jsx +8 -2
- package/src/@daf/services/AdminService.js +4 -15
- package/src/@daf/services/DashboardService.js +3 -3
- package/src/@daf/utils/filters.js +15 -13
- package/src/@daf/utils/numbers.js +1 -1
- package/src/constants/locales/en/translation.js +0 -9
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { Widget, RadarChart } from '../../../../../../../../src/index.js';
|
|
3
|
+
|
|
4
|
+
// Define the specific 5 categories to show in radar chart
|
|
5
|
+
const RADAR_CATEGORIES = ['spiders', 'scaleInsects', 'caterpillars', 'ants', 'unidentifiedPests'];
|
|
6
|
+
|
|
7
|
+
// Custom labels for the radar chart
|
|
8
|
+
const RADAR_LABELS = {
|
|
9
|
+
'spiders': 'Spiders',
|
|
10
|
+
'scaleInsects': 'Scale insects',
|
|
11
|
+
'caterpillars': 'Caterpillars',
|
|
12
|
+
'ants': 'Ants',
|
|
13
|
+
'unidentifiedPests': 'Unidentified pests'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const InvasiveSpecies = ({
|
|
17
|
+
invasiveSpeciesChart,
|
|
18
|
+
t = (s) => s,
|
|
19
|
+
options = {}
|
|
20
|
+
}) => {
|
|
21
|
+
|
|
22
|
+
const chartData = useMemo(() => {
|
|
23
|
+
const speciesOptions = options?.invasiveSpecies || [];
|
|
24
|
+
|
|
25
|
+
// Create a map of existing data
|
|
26
|
+
const dataMap = new Map();
|
|
27
|
+
if (invasiveSpeciesChart && Array.isArray(invasiveSpeciesChart)) {
|
|
28
|
+
invasiveSpeciesChart.forEach(item => {
|
|
29
|
+
if (item?.invasiveSpecies) {
|
|
30
|
+
dataMap.set(item.invasiveSpecies, Number(item?.count) || 0);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Create chart data for all 5 radar categories
|
|
36
|
+
const data = RADAR_CATEGORIES.map((categoryValue) => {
|
|
37
|
+
return {
|
|
38
|
+
item: RADAR_LABELS[categoryValue] || categoryValue,
|
|
39
|
+
score: dataMap.get(categoryValue) || 0,
|
|
40
|
+
invasiveSpecies: categoryValue
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return data;
|
|
45
|
+
}, [invasiveSpeciesChart, options]);
|
|
46
|
+
|
|
47
|
+
const maxScore = useMemo(() => {
|
|
48
|
+
if (!chartData || chartData.length === 0) return 100;
|
|
49
|
+
const max = Math.max(...chartData.map(item => item.score || 0));
|
|
50
|
+
return max > 0 ? Math.ceil(max * 1.2) : 100;
|
|
51
|
+
}, [chartData]);
|
|
52
|
+
|
|
53
|
+
const isEmpty = useMemo(() => {
|
|
54
|
+
// Never empty since we always show 5 categories
|
|
55
|
+
return false;
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
58
|
+
console.log('InvasiveSpecies - chartData:', chartData);
|
|
59
|
+
return (
|
|
60
|
+
<Widget
|
|
61
|
+
title={t("Invasive Species")}
|
|
62
|
+
className="with-border-header h-w-btn-header"
|
|
63
|
+
>
|
|
64
|
+
|
|
65
|
+
{isEmpty ? (
|
|
66
|
+
<div style={{
|
|
67
|
+
display: 'flex',
|
|
68
|
+
alignItems: 'center',
|
|
69
|
+
justifyContent: 'center',
|
|
70
|
+
height: '100%',
|
|
71
|
+
color: '#999'
|
|
72
|
+
}}>
|
|
73
|
+
{t("No data available")}
|
|
74
|
+
</div>
|
|
75
|
+
) : (
|
|
76
|
+
<RadarChart
|
|
77
|
+
data={chartData}
|
|
78
|
+
xFieldKey="item"
|
|
79
|
+
yFieldKey="score"
|
|
80
|
+
animated={true}
|
|
81
|
+
height={400}
|
|
82
|
+
score={{
|
|
83
|
+
max: maxScore,
|
|
84
|
+
min: 0
|
|
85
|
+
}}
|
|
86
|
+
renderTooltipContent={(title, data) => {
|
|
87
|
+
if (!data || data.length === 0) return {};
|
|
88
|
+
const item = data[0]?.data || data[0];
|
|
89
|
+
return {
|
|
90
|
+
title: title,
|
|
91
|
+
items: [
|
|
92
|
+
{
|
|
93
|
+
label: t("Sightings"),
|
|
94
|
+
value: item?.score || 0,
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
}}
|
|
99
|
+
/>
|
|
100
|
+
)}
|
|
101
|
+
|
|
102
|
+
</Widget>
|
|
103
|
+
);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export default InvasiveSpecies;
|
|
107
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { Widget, BarChart } from '../../../../../../../../src/index.js';
|
|
3
|
+
import { calculateNiceAxisConfig, mergeDefaultCategories } from '../chartHelpers.js';
|
|
4
|
+
|
|
5
|
+
const ObservedFauna = ({
|
|
6
|
+
observedFaunaChart,
|
|
7
|
+
t = (s) => s,
|
|
8
|
+
options = {}
|
|
9
|
+
}) => {
|
|
10
|
+
const chartData = useMemo(() => {
|
|
11
|
+
const allFaunaTypes = options?.faunaObserved || [];
|
|
12
|
+
|
|
13
|
+
if (allFaunaTypes.length === 0) {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const mergedData = mergeDefaultCategories(
|
|
18
|
+
observedFaunaChart,
|
|
19
|
+
allFaunaTypes,
|
|
20
|
+
'fauna',
|
|
21
|
+
'count',
|
|
22
|
+
'label',
|
|
23
|
+
'value'
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
// Rename 'label' to 'type' for BarChart compatibility
|
|
27
|
+
return mergedData.map(item => ({
|
|
28
|
+
type: item.label,
|
|
29
|
+
value: item.value,
|
|
30
|
+
fauna: item.fauna
|
|
31
|
+
}));
|
|
32
|
+
}, [observedFaunaChart, options]);
|
|
33
|
+
|
|
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
|
+
);
|
|
45
|
+
}, [chartData]);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<Widget
|
|
49
|
+
title={t("Observed Fauna")}
|
|
50
|
+
className="with-border-header h-w-btn-header"
|
|
51
|
+
>
|
|
52
|
+
<BarChart
|
|
53
|
+
data={chartData}
|
|
54
|
+
yFieldKey="type"
|
|
55
|
+
xFieldKey="value"
|
|
56
|
+
animated={true}
|
|
57
|
+
color="#00AEB1"
|
|
58
|
+
xAxisConfig={xAxisConfig}
|
|
59
|
+
renderTooltipContent={(title, data) => {
|
|
60
|
+
if (!data || data.length === 0) return {};
|
|
61
|
+
const item = data[0]?.data || data[0];
|
|
62
|
+
return {
|
|
63
|
+
title: title,
|
|
64
|
+
subTitle: t("Sightings"),
|
|
65
|
+
items: [
|
|
66
|
+
{
|
|
67
|
+
label: t("Count"),
|
|
68
|
+
value: item?.value || 0,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
}}
|
|
73
|
+
/>
|
|
74
|
+
|
|
75
|
+
</Widget>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export default ObservedFauna;
|
|
80
|
+
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
faunaSightings,
|
|
7
|
+
invasiveSpeciesSightings,
|
|
8
|
+
t = (s) => s
|
|
9
|
+
}) => {
|
|
10
|
+
const faunaSightingsChange = useMemo(() => {
|
|
11
|
+
if (!faunaSightings) return null;
|
|
12
|
+
return calculateStatChange(
|
|
13
|
+
{
|
|
14
|
+
current: Number(faunaSightings.current) || 0,
|
|
15
|
+
previous: Number(faunaSightings.previous) || 0,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
tooltipText: t("In comparison to last period"),
|
|
19
|
+
format: 'absolute',
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
}, [faunaSightings, t]);
|
|
23
|
+
|
|
24
|
+
const invasiveSpeciesSightingsChange = useMemo(() => {
|
|
25
|
+
if (!invasiveSpeciesSightings) return null;
|
|
26
|
+
return calculateStatChange(
|
|
27
|
+
{
|
|
28
|
+
current: Number(invasiveSpeciesSightings.current) || 0,
|
|
29
|
+
previous: Number(invasiveSpeciesSightings.previous) || 0,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
tooltipText: t("In comparison to last period"),
|
|
33
|
+
format: 'absolute',
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
}, [invasiveSpeciesSightings, t]);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div style={{ display: "flex", gap: "24px", marginBottom: "24px" }}>
|
|
40
|
+
<section style={{ flex: 1 }}>
|
|
41
|
+
<StatCard
|
|
42
|
+
title={t("Fauna Sightings")}
|
|
43
|
+
value={faunaSightings ? Number(faunaSightings.current).toLocaleString() : "0"}
|
|
44
|
+
icon="Fish"
|
|
45
|
+
change={faunaSightingsChange}
|
|
46
|
+
/>
|
|
47
|
+
</section>
|
|
48
|
+
|
|
49
|
+
<section style={{ flex: 1 }}>
|
|
50
|
+
<StatCard
|
|
51
|
+
title={t("Invasive Species Sightings")}
|
|
52
|
+
value={invasiveSpeciesSightings ? Number(invasiveSpeciesSightings.current).toLocaleString() : "0"}
|
|
53
|
+
icon="Ant"
|
|
54
|
+
change={invasiveSpeciesSightingsChange}
|
|
55
|
+
/>
|
|
56
|
+
</section>
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default Stats;
|
|
62
|
+
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { Widget } from '../../../../../../../../src/index.js';
|
|
3
|
+
import { useWidgetFetch } from '../../../../../../hooks/useWidgetFetch.js';
|
|
4
|
+
import Stats from './Stats.jsx';
|
|
5
|
+
import ObservedFauna from './ObservedFauna.jsx';
|
|
6
|
+
import InvasiveSpecies from './InvasiveSpecies.jsx';
|
|
7
|
+
|
|
8
|
+
const BiodiversityHabitat = ({
|
|
9
|
+
id,
|
|
10
|
+
getSummaryDetail,
|
|
11
|
+
loading = false,
|
|
12
|
+
t = (s) => s,
|
|
13
|
+
options = {}
|
|
14
|
+
}) => {
|
|
15
|
+
const defaultConfig = useMemo(
|
|
16
|
+
() => ({
|
|
17
|
+
basepath: "events/monitoring-campaign-summary",
|
|
18
|
+
url: `/summary/${id}/biodiversity-habitat`,
|
|
19
|
+
stop: !id,
|
|
20
|
+
}),
|
|
21
|
+
[id],
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const customGetData = useMemo(() => {
|
|
25
|
+
if (getSummaryDetail && id) {
|
|
26
|
+
return ({ url, params = {} }) => {
|
|
27
|
+
const match = url.match(/\/summary\/[^/]+\/(.+)/);
|
|
28
|
+
if (match) {
|
|
29
|
+
const [, type] = match;
|
|
30
|
+
return getSummaryDetail(id, type, params);
|
|
31
|
+
}
|
|
32
|
+
throw new Error(`Invalid URL format: ${url}`);
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}, [getSummaryDetail, id]);
|
|
37
|
+
|
|
38
|
+
const { loading: outcomesLoading, data: outcomesData } = useWidgetFetch({
|
|
39
|
+
config: defaultConfig,
|
|
40
|
+
getData: customGetData
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const {
|
|
44
|
+
faunaSightings,
|
|
45
|
+
invasiveSpecies,
|
|
46
|
+
previousCycleFaunaSightings,
|
|
47
|
+
previousCycleInvasiveSpecies,
|
|
48
|
+
observedFauna
|
|
49
|
+
} = outcomesData || {};
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
const transformedFaunaSightings = useMemo(() => {
|
|
53
|
+
const current = Array.isArray(faunaSightings) && faunaSightings.length > 0
|
|
54
|
+
? faunaSightings.reduce((sum, item) => sum + (Number(item?.count) || 0), 0)
|
|
55
|
+
: 0;
|
|
56
|
+
const previous = Array.isArray(previousCycleFaunaSightings) && previousCycleFaunaSightings.length > 0
|
|
57
|
+
? previousCycleFaunaSightings.reduce((sum, item) => sum + (Number(item?.count) || 0), 0)
|
|
58
|
+
: 0;
|
|
59
|
+
return { current, previous };
|
|
60
|
+
}, [faunaSightings, previousCycleFaunaSightings]);
|
|
61
|
+
|
|
62
|
+
const transformedInvasiveSpecies = useMemo(() => {
|
|
63
|
+
const current = Array.isArray(invasiveSpecies) && invasiveSpecies.length > 0
|
|
64
|
+
? invasiveSpecies.reduce((sum, item) => sum + (Number(item?.count) || 0), 0)
|
|
65
|
+
: 0;
|
|
66
|
+
const previous = Array.isArray(previousCycleInvasiveSpecies) && previousCycleInvasiveSpecies.length > 0
|
|
67
|
+
? previousCycleInvasiveSpecies.reduce((sum, item) => sum + (Number(item?.count) || 0), 0)
|
|
68
|
+
: 0;
|
|
69
|
+
return { current, previous };
|
|
70
|
+
}, [invasiveSpecies, previousCycleInvasiveSpecies]);
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<section>
|
|
75
|
+
<Widget
|
|
76
|
+
title={t("Biodiversity & Habitat")}
|
|
77
|
+
loading={loading || outcomesLoading}
|
|
78
|
+
className="with-border-header h-w-btn-header"
|
|
79
|
+
>
|
|
80
|
+
<Stats
|
|
81
|
+
faunaSightings={transformedFaunaSightings}
|
|
82
|
+
invasiveSpeciesSightings={transformedInvasiveSpecies}
|
|
83
|
+
t={t}
|
|
84
|
+
/>
|
|
85
|
+
|
|
86
|
+
<div style={{ display: "flex", gap: "24px" }}>
|
|
87
|
+
<section style={{ flex: 1 }}>
|
|
88
|
+
<ObservedFauna
|
|
89
|
+
observedFaunaChart={observedFauna}
|
|
90
|
+
t={t}
|
|
91
|
+
options={options}
|
|
92
|
+
/>
|
|
93
|
+
</section>
|
|
94
|
+
|
|
95
|
+
<InvasiveSpecies
|
|
96
|
+
invasiveSpeciesChart={invasiveSpecies}
|
|
97
|
+
t={t}
|
|
98
|
+
options={options}
|
|
99
|
+
/>
|
|
100
|
+
|
|
101
|
+
</div>
|
|
102
|
+
</Widget>
|
|
103
|
+
|
|
104
|
+
</section>
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export default BiodiversityHabitat;
|
|
109
|
+
|
package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/KeyInformation/index.jsx
CHANGED
|
@@ -7,8 +7,8 @@ const KeyInformation = ({ id, t = () => { }, getSummaryDetail, loading = false }
|
|
|
7
7
|
|
|
8
8
|
const defaultConfig = useMemo(
|
|
9
9
|
() => ({
|
|
10
|
-
basepath: "events/monitoring-campaign",
|
|
11
|
-
url:
|
|
10
|
+
basepath: "events/monitoring-campaign-summary",
|
|
11
|
+
url: `/${id}/key-information`,
|
|
12
12
|
stop: !id,
|
|
13
13
|
}),
|
|
14
14
|
[id],
|
|
@@ -16,10 +16,14 @@ const KeyInformation = ({ id, t = () => { }, getSummaryDetail, loading = false }
|
|
|
16
16
|
|
|
17
17
|
const customGetData = useMemo(() => {
|
|
18
18
|
if (getSummaryDetail && id) {
|
|
19
|
-
return (
|
|
20
|
-
const
|
|
19
|
+
return (rest) => {
|
|
20
|
+
const { url, filters: restFilters } = rest;
|
|
21
|
+
const match = url.match(/\/[^/]+\/(.+)/);
|
|
21
22
|
if (match) {
|
|
22
23
|
const [, type] = match;
|
|
24
|
+
const params = {
|
|
25
|
+
...(restFilters || {}),
|
|
26
|
+
};
|
|
23
27
|
return getSummaryDetail(id, type, params);
|
|
24
28
|
}
|
|
25
29
|
throw new Error(`Invalid URL format: ${url}`);
|
|
@@ -2,28 +2,40 @@ import React, { useMemo, useCallback } from 'react';
|
|
|
2
2
|
import { Widget, PieChart } from '../../../../../../../../src/index.js';
|
|
3
3
|
import { renderTooltipJsx } from '../../../../../../utils/tooltip.js';
|
|
4
4
|
|
|
5
|
-
const COLORS = ['#
|
|
5
|
+
const COLORS = ['#6AD99E', '#F5C2AC', '#F0A888', '#DF571E', '#C04B19', '#9B3D14', '#7A2F0F'];
|
|
6
6
|
|
|
7
7
|
const PlantedSpecies = ({
|
|
8
8
|
plantedSpeciesChart,
|
|
9
|
-
t = (s) => s
|
|
9
|
+
t = (s) => s,
|
|
10
|
+
options = {}
|
|
10
11
|
}) => {
|
|
12
|
+
|
|
13
|
+
const optionsMap = useMemo(() => {
|
|
14
|
+
if (!options || !Array.isArray(options)) return {};
|
|
15
|
+
return options.reduce((acc, option) => {
|
|
16
|
+
if (option?.value) {
|
|
17
|
+
acc[option.value] = option.label;
|
|
18
|
+
}
|
|
19
|
+
return acc;
|
|
20
|
+
}, {});
|
|
21
|
+
}, [options]);
|
|
22
|
+
|
|
11
23
|
const pieData = useMemo(() => {
|
|
12
24
|
const data = plantedSpeciesChart || [];
|
|
13
|
-
const total = data.reduce((sum, item) => sum + (Number(item?.
|
|
25
|
+
const total = data.reduce((sum, item) => sum + (Number(item?.count) || 0), 0);
|
|
14
26
|
|
|
15
27
|
return data.map((item, index) => ({
|
|
16
|
-
value: Number(item?.
|
|
17
|
-
percent: total > 0 ? (Number(item?.
|
|
28
|
+
value: Number(item?.count) || 0,
|
|
29
|
+
percent: total > 0 ? (Number(item?.count) || 0) / total : 0,
|
|
18
30
|
color: COLORS[index % COLORS.length],
|
|
19
|
-
label: item?.
|
|
20
|
-
key: item?.
|
|
31
|
+
label: optionsMap[item?.name] || item?.name || '',
|
|
32
|
+
key: item?.name || `item-${index}`,
|
|
21
33
|
}));
|
|
22
|
-
}, [plantedSpeciesChart]);
|
|
34
|
+
}, [plantedSpeciesChart, optionsMap]);
|
|
23
35
|
|
|
24
36
|
const isEmpty = useMemo(() => {
|
|
25
37
|
return !plantedSpeciesChart || plantedSpeciesChart.length === 0 ||
|
|
26
|
-
plantedSpeciesChart.every(item => !item?.
|
|
38
|
+
plantedSpeciesChart.every(item => !item?.count || Number(item.count) === 0);
|
|
27
39
|
}, [plantedSpeciesChart]);
|
|
28
40
|
|
|
29
41
|
const getTooltipChildren = useCallback(
|
|
@@ -1,10 +1,43 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
2
|
import { Widget, ColumnChart } from '../../../../../../../../src/index.js';
|
|
3
|
+
import { calculateNiceAxisConfig, mergeDefaultCategories } from '../chartHelpers.js';
|
|
4
|
+
|
|
5
|
+
// Default height ranges to always display
|
|
6
|
+
const DEFAULT_HEIGHT_RANGES = [
|
|
7
|
+
{ value: '0-10', label: '0-10 cm' },
|
|
8
|
+
{ value: '11-20', label: '11-20 cm' },
|
|
9
|
+
{ value: '21-30', label: '21-30 cm' },
|
|
10
|
+
{ value: '30+', label: '30+ cm' }
|
|
11
|
+
];
|
|
3
12
|
|
|
4
13
|
const SeedlingsHeight = ({
|
|
5
14
|
seedlingsHeightChart,
|
|
6
15
|
t = (s) => s
|
|
7
16
|
}) => {
|
|
17
|
+
const chartData = useMemo(() => {
|
|
18
|
+
return mergeDefaultCategories(
|
|
19
|
+
seedlingsHeightChart,
|
|
20
|
+
DEFAULT_HEIGHT_RANGES,
|
|
21
|
+
'range',
|
|
22
|
+
'count',
|
|
23
|
+
'label',
|
|
24
|
+
'value'
|
|
25
|
+
);
|
|
26
|
+
}, [seedlingsHeightChart]);
|
|
27
|
+
|
|
28
|
+
const yAxisConfig = useMemo(() => {
|
|
29
|
+
return calculateNiceAxisConfig(
|
|
30
|
+
chartData,
|
|
31
|
+
'value',
|
|
32
|
+
2, // multiplier: double the max value
|
|
33
|
+
{
|
|
34
|
+
min: 0,
|
|
35
|
+
max: 20,
|
|
36
|
+
tickMethod: () => [0, 5, 10, 15, 20]
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
}, [chartData]);
|
|
40
|
+
|
|
8
41
|
return (
|
|
9
42
|
<Widget
|
|
10
43
|
title={t("Seedlings Height")}
|
|
@@ -13,12 +46,13 @@ const SeedlingsHeight = ({
|
|
|
13
46
|
<div className="flex flex-1 flex-column justify-content-center">
|
|
14
47
|
<div className="flex justify-content-center w-full">
|
|
15
48
|
<ColumnChart
|
|
16
|
-
data={
|
|
49
|
+
data={chartData}
|
|
17
50
|
xFieldKey="label"
|
|
18
51
|
yFieldKey="value"
|
|
19
52
|
animated={true}
|
|
20
53
|
height={200}
|
|
21
54
|
color="#016C6E"
|
|
55
|
+
yAxis={yAxisConfig}
|
|
22
56
|
renderTooltipContent={(title, data) => {
|
|
23
57
|
if (!data || data.length === 0) return {};
|
|
24
58
|
const item = data[0]?.data || data[0];
|
package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/Stats.jsx
CHANGED
|
@@ -56,7 +56,7 @@ const Stats = ({
|
|
|
56
56
|
<StatCard
|
|
57
57
|
title={t("Survival Rate")}
|
|
58
58
|
value={survivalRate ? Number(survivalRate.current).toLocaleString() : "0"}
|
|
59
|
-
icon="
|
|
59
|
+
icon="TrendUp"
|
|
60
60
|
change={survivalRateChange}
|
|
61
61
|
/>
|
|
62
62
|
</section>
|
|
@@ -65,7 +65,7 @@ const Stats = ({
|
|
|
65
65
|
<StatCard
|
|
66
66
|
title={t("Average Height")}
|
|
67
67
|
value={averageHeight ? Number(averageHeight.current).toLocaleString() + " cm" : "0 cm"}
|
|
68
|
-
icon="
|
|
68
|
+
icon="SpacingHeight"
|
|
69
69
|
change={averageHeightChange}
|
|
70
70
|
/>
|
|
71
71
|
</section>
|
|
@@ -74,7 +74,7 @@ const Stats = ({
|
|
|
74
74
|
<StatCard
|
|
75
75
|
title={t("Average Diameter")}
|
|
76
76
|
value={averageDiameter ? Number(averageDiameter.current).toLocaleString() + " mm" : "0 mm"}
|
|
77
|
-
icon="
|
|
77
|
+
icon="Tree"
|
|
78
78
|
change={averageDiameterChange}
|
|
79
79
|
/>
|
|
80
80
|
</section>
|
|
@@ -6,24 +6,35 @@ const COLORS = ['#016C6E', '#F5C2AC', '#F0A888', '#DF571E', '#C04B19', '#9B3D14'
|
|
|
6
6
|
|
|
7
7
|
const VegetationHealth = ({
|
|
8
8
|
vegetationHealthChart,
|
|
9
|
-
t = (s) => s
|
|
9
|
+
t = (s) => s,
|
|
10
|
+
options = {}
|
|
10
11
|
}) => {
|
|
12
|
+
const optionsMap = useMemo(() => {
|
|
13
|
+
if (!options || !Array.isArray(options)) return {};
|
|
14
|
+
return options.reduce((acc, option) => {
|
|
15
|
+
if (option?.value) {
|
|
16
|
+
acc[option.value] = option.label;
|
|
17
|
+
}
|
|
18
|
+
return acc;
|
|
19
|
+
}, {});
|
|
20
|
+
}, [options]);
|
|
21
|
+
|
|
11
22
|
const pieData = useMemo(() => {
|
|
12
23
|
const data = vegetationHealthChart || [];
|
|
13
|
-
const total = data.reduce((sum, item) => sum + (Number(item?.
|
|
24
|
+
const total = data.reduce((sum, item) => sum + (Number(item?.count) || 0), 0);
|
|
14
25
|
|
|
15
26
|
return data.map((item, index) => ({
|
|
16
|
-
value: Number(item?.
|
|
17
|
-
percent: total > 0 ? (Number(item?.
|
|
27
|
+
value: Number(item?.count) || 0,
|
|
28
|
+
percent: total > 0 ? (Number(item?.count) || 0) / total : 0,
|
|
18
29
|
color: COLORS[index % COLORS.length],
|
|
19
|
-
label: item?.
|
|
20
|
-
key: item?.
|
|
30
|
+
label: optionsMap[item?.name] || item?.name || '',
|
|
31
|
+
key: item?.name || `item-${index}`,
|
|
21
32
|
}));
|
|
22
|
-
}, [vegetationHealthChart]);
|
|
33
|
+
}, [vegetationHealthChart, optionsMap]);
|
|
23
34
|
|
|
24
35
|
const isEmpty = useMemo(() => {
|
|
25
36
|
return !vegetationHealthChart || vegetationHealthChart.length === 0 ||
|
|
26
|
-
vegetationHealthChart.every(item => !item?.
|
|
37
|
+
vegetationHealthChart.every(item => !item?.count || Number(item.count) === 0);
|
|
27
38
|
}, [vegetationHealthChart]);
|
|
28
39
|
|
|
29
40
|
const getTooltipChildren = useCallback(
|
package/src/@daf/pages/Summary/Activities/MonitoringCampaign/components/MangroveGrowth/index.jsx
CHANGED
|
@@ -10,12 +10,13 @@ const MangroveGrowth = ({
|
|
|
10
10
|
id,
|
|
11
11
|
getSummaryDetail,
|
|
12
12
|
loading = false,
|
|
13
|
-
t = (s) => s
|
|
13
|
+
t = (s) => s,
|
|
14
|
+
options = {}
|
|
14
15
|
}) => {
|
|
15
16
|
const defaultConfig = useMemo(
|
|
16
17
|
() => ({
|
|
17
|
-
basepath: "events/monitoring-campaign",
|
|
18
|
-
url: `/summary/${id}/
|
|
18
|
+
basepath: "events/monitoring-campaign-summary",
|
|
19
|
+
url: `/summary/${id}/mangrove-growth`,
|
|
19
20
|
stop: !id,
|
|
20
21
|
}),
|
|
21
22
|
[id],
|
|
@@ -44,9 +45,9 @@ const MangroveGrowth = ({
|
|
|
44
45
|
survivalRate,
|
|
45
46
|
averageHeight,
|
|
46
47
|
averageDiameter,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
vegetationHealth,
|
|
49
|
+
seedlingsTimelineChart,
|
|
50
|
+
plantedSpecies
|
|
50
51
|
} = outcomesData || {};
|
|
51
52
|
|
|
52
53
|
return (
|
|
@@ -66,20 +67,23 @@ const MangroveGrowth = ({
|
|
|
66
67
|
<div style={{ display: "flex", gap: "24px" }}>
|
|
67
68
|
<section style={{ flex: 1 }}>
|
|
68
69
|
<VegetationHealth
|
|
69
|
-
vegetationHealthChart={
|
|
70
|
+
vegetationHealthChart={vegetationHealth}
|
|
70
71
|
t={t}
|
|
72
|
+
options={options.growthObservations}
|
|
71
73
|
/>
|
|
72
74
|
</section>
|
|
73
75
|
<section style={{ flex: 1 }}>
|
|
74
76
|
<SeedlingsHeight
|
|
75
|
-
seedlingsHeightChart={
|
|
77
|
+
seedlingsHeightChart={seedlingsTimelineChart}
|
|
76
78
|
t={t}
|
|
79
|
+
options={options.seedlingsHeight}
|
|
77
80
|
/>
|
|
78
81
|
</section>
|
|
79
82
|
<section style={{ flex: 1 }}>
|
|
80
83
|
<PlantedSpecies
|
|
81
|
-
plantedSpeciesChart={
|
|
84
|
+
plantedSpeciesChart={plantedSpecies}
|
|
82
85
|
t={t}
|
|
86
|
+
options={options.mangroveSpecies}
|
|
83
87
|
/>
|
|
84
88
|
</section>
|
|
85
89
|
</div>
|