datastake-daf 0.6.776 → 0.6.778
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 +2269 -2391
- package/dist/pages/index.js +66 -42
- package/package.json +1 -1
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CommunityParticipation/JobsTimeline/index.jsx +5 -4
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleIndicators/HealthAndSafety/helper.js +3 -2
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleIndicators/HealthAndSafety/index.jsx +54 -22
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleOutcomes/PlantingActivitiesTimeline.jsx +5 -7
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleOutcomes/RestoredArea.jsx +4 -8
- package/src/@daf/utils/timeFilterUtils.js +3 -6
package/dist/pages/index.js
CHANGED
|
@@ -5322,7 +5322,7 @@ const getMetaPlaceholer = (inputMeta, t) => inputMeta.notApplicable ? t("Not app
|
|
|
5322
5322
|
* @param {string} [filterCond=null] - Filter condition.
|
|
5323
5323
|
* @returns {Object[]} - Filtered options.
|
|
5324
5324
|
*/
|
|
5325
|
-
function filterOptions(options, filters, formsValue = {}, repeatValues = {}, filterCond = null) {
|
|
5325
|
+
function filterOptions$1(options, filters, formsValue = {}, repeatValues = {}, filterCond = null) {
|
|
5326
5326
|
const isOrCond = filterCond !== "and";
|
|
5327
5327
|
const objFilter = {};
|
|
5328
5328
|
filters.forEach(f => {
|
|
@@ -27265,7 +27265,7 @@ const inputTypeComponent = {
|
|
|
27265
27265
|
opts = JSON.parse(JSON.stringify(opts));
|
|
27266
27266
|
opts = opts.map(o => getSelectOptions(o, formsValue));
|
|
27267
27267
|
if (optionsFilter && Array.isArray(optionsFilter)) {
|
|
27268
|
-
opts = filterOptions(opts, optionsFilter, formsValue, repeatValues, filterCond);
|
|
27268
|
+
opts = filterOptions$1(opts, optionsFilter, formsValue, repeatValues, filterCond);
|
|
27269
27269
|
}
|
|
27270
27270
|
if (propHasValue(value)) {
|
|
27271
27271
|
const selectOption = opts.find(o => o.value === value);
|
|
@@ -27384,7 +27384,7 @@ const inputTypeComponent = {
|
|
|
27384
27384
|
opts = JSON.parse(JSON.stringify(opts));
|
|
27385
27385
|
opts = opts.map(o => getSelectOptions(o, formsValue));
|
|
27386
27386
|
if (optionsFilter && Array.isArray(optionsFilter)) {
|
|
27387
|
-
opts = filterOptions(opts, optionsFilter, formsValue, repeatValues, filterCond);
|
|
27387
|
+
opts = filterOptions$1(opts, optionsFilter, formsValue, repeatValues, filterCond);
|
|
27388
27388
|
}
|
|
27389
27389
|
if (propHasValue(value) && Array.isArray(value) && value.length > 0 && !tags) {
|
|
27390
27390
|
try {
|
|
@@ -42957,11 +42957,9 @@ const processChartDateData = ({
|
|
|
42957
42957
|
isCumulative = false,
|
|
42958
42958
|
valueField = 'total'
|
|
42959
42959
|
}) => {
|
|
42960
|
-
if (!mainData || !Array.isArray(mainData) || mainData.length === 0) {
|
|
42961
|
-
return [];
|
|
42962
|
-
}
|
|
42963
42960
|
const timeQuantity = getTimeQuantity(filter);
|
|
42964
|
-
const dates = mainData;
|
|
42961
|
+
const dates = mainData || [];
|
|
42962
|
+
const isEmpty = !mainData || !Array.isArray(mainData) || mainData.length === 0;
|
|
42965
42963
|
const _data = [];
|
|
42966
42964
|
let end = filters?.timeframe?.endDate || dayjs__default["default"]();
|
|
42967
42965
|
let start = filters?.timeframe?.startDate || dayjs__default["default"]().add(-12, timeQuantity);
|
|
@@ -42993,7 +42991,7 @@ const processChartDateData = ({
|
|
|
42993
42991
|
let currentDate = start.clone();
|
|
42994
42992
|
while (currentDate.isBefore(end) || currentDate.isSame(end, filter === "daily" ? "day" : filter === "weekly" ? "week" : "month")) {
|
|
42995
42993
|
// Filter data points that fall within this period
|
|
42996
|
-
const score = dates.filter(d => {
|
|
42994
|
+
const score = isEmpty ? 0 : dates.filter(d => {
|
|
42997
42995
|
if (!d.date) return false;
|
|
42998
42996
|
switch (filter) {
|
|
42999
42997
|
case "daily":
|
|
@@ -43139,19 +43137,12 @@ const RestoredArea = ({
|
|
|
43139
43137
|
} = useTimeFilter({
|
|
43140
43138
|
defaultFilter: 'monthly'
|
|
43141
43139
|
});
|
|
43142
|
-
|
|
43143
|
-
// Map restoredAreaChart data to LineChart format with time filter support
|
|
43144
|
-
// Y-axis: total/cumulated value
|
|
43145
|
-
// X-axis: date (formatted based on timeFilter)
|
|
43146
|
-
// Fill all periods in the range, even if empty
|
|
43147
43140
|
const restoredAreaChartData = React.useMemo(() => {
|
|
43148
|
-
|
|
43149
|
-
return [];
|
|
43150
|
-
}
|
|
43141
|
+
const dataToProcess = !restoredAreaChart || !Array.isArray(restoredAreaChart) || restoredAreaChart.length === 0 ? [] : restoredAreaChart;
|
|
43151
43142
|
|
|
43152
43143
|
// Process data with cumulative calculation (for restored area)
|
|
43153
43144
|
return processChartDateData({
|
|
43154
|
-
mainData:
|
|
43145
|
+
mainData: dataToProcess,
|
|
43155
43146
|
isCumulative: true,
|
|
43156
43147
|
valueField: 'total'
|
|
43157
43148
|
});
|
|
@@ -43289,18 +43280,12 @@ const PlantingActivitiesTimeline = ({
|
|
|
43289
43280
|
} = useTimeFilter({
|
|
43290
43281
|
defaultFilter: 'monthly'
|
|
43291
43282
|
});
|
|
43292
|
-
|
|
43293
|
-
// Map activitiesTimelineChart data to ColumnChart format with time filter support
|
|
43294
|
-
// Data structure: [{count: 2, date: "2025-11-03"}]
|
|
43295
|
-
// Fill all periods in the range, even if empty
|
|
43296
43283
|
const activitiesTimelineData = React.useMemo(() => {
|
|
43297
|
-
|
|
43298
|
-
return [];
|
|
43299
|
-
}
|
|
43284
|
+
const dataToProcess = !activitiesTimelineChart || !Array.isArray(activitiesTimelineChart) || activitiesTimelineChart.length === 0 ? [] : activitiesTimelineChart;
|
|
43300
43285
|
|
|
43301
43286
|
// Process data without cumulative calculation (for activities timeline)
|
|
43302
43287
|
return processChartDateData({
|
|
43303
|
-
mainData:
|
|
43288
|
+
mainData: dataToProcess,
|
|
43304
43289
|
isCumulative: false,
|
|
43305
43290
|
valueField: 'count'
|
|
43306
43291
|
});
|
|
@@ -43746,9 +43731,10 @@ const calculateHealthAndSafetyPieData = (healthAndSafetyDistributionData, t) =>
|
|
|
43746
43731
|
* @param {Object} healthAndSafetyDistributionData - Distribution object
|
|
43747
43732
|
* @param {Function} t - Translation function
|
|
43748
43733
|
* @param {Function} renderTooltipJsx - Function to render tooltip JSX
|
|
43734
|
+
* @param {string} tooltipTitle - Title to display in the tooltip (defaults to "Health and Safety")
|
|
43749
43735
|
* @returns {JSX.Element|null} Tooltip content or null
|
|
43750
43736
|
*/
|
|
43751
|
-
const getHealthAndSafetyTooltipChildren = (item, isEmpty, healthAndSafetyDistributionData, t, renderTooltipJsx) => {
|
|
43737
|
+
const getHealthAndSafetyTooltipChildren = (item, isEmpty, healthAndSafetyDistributionData, t, renderTooltipJsx, tooltipTitle = "Health and Safety") => {
|
|
43752
43738
|
// If empty or no data, return null to display nothing
|
|
43753
43739
|
if (isEmpty || !Object.keys(healthAndSafetyDistributionData).length) {
|
|
43754
43740
|
return null;
|
|
@@ -43785,25 +43771,39 @@ const getHealthAndSafetyTooltipChildren = (item, isEmpty, healthAndSafetyDistrib
|
|
|
43785
43771
|
|
|
43786
43772
|
// Show all items with their percentages
|
|
43787
43773
|
return renderTooltipJsx({
|
|
43788
|
-
title: t(
|
|
43774
|
+
title: t(tooltipTitle),
|
|
43789
43775
|
items: itemsWithData
|
|
43790
43776
|
});
|
|
43791
43777
|
};
|
|
43792
43778
|
|
|
43779
|
+
const filterOptions = [{
|
|
43780
|
+
value: 'aidKitAccessible',
|
|
43781
|
+
label: 'Aid kit availability'
|
|
43782
|
+
}, {
|
|
43783
|
+
value: 'hsTrainingConfirmation',
|
|
43784
|
+
label: 'H&S training delivery'
|
|
43785
|
+
}, {
|
|
43786
|
+
value: 'duosFormed',
|
|
43787
|
+
label: 'Workers safe pairing'
|
|
43788
|
+
}, {
|
|
43789
|
+
value: 'presenceOfChildren',
|
|
43790
|
+
label: 'No children'
|
|
43791
|
+
}];
|
|
43793
43792
|
const HealthAndSafety = ({
|
|
43794
43793
|
id,
|
|
43795
43794
|
getSummaryDetail,
|
|
43796
43795
|
loading = false,
|
|
43797
43796
|
t = s => s
|
|
43798
43797
|
}) => {
|
|
43798
|
+
const [selectedField, setSelectedField] = React.useState('aidKitAccessible');
|
|
43799
43799
|
const defaultConfig = React.useMemo(() => ({
|
|
43800
43800
|
basepath: "planting-cycle",
|
|
43801
43801
|
url: `/summary/${id}/filtered-piechart`,
|
|
43802
43802
|
filters: {
|
|
43803
|
-
field:
|
|
43803
|
+
field: selectedField
|
|
43804
43804
|
},
|
|
43805
43805
|
stop: !id
|
|
43806
|
-
}), [id]);
|
|
43806
|
+
}), [id, selectedField]);
|
|
43807
43807
|
const customGetData = React.useMemo(() => {
|
|
43808
43808
|
if (getSummaryDetail && id) {
|
|
43809
43809
|
return rest => {
|
|
@@ -43834,7 +43834,7 @@ const HealthAndSafety = ({
|
|
|
43834
43834
|
});
|
|
43835
43835
|
|
|
43836
43836
|
// Process the fetched pie chart data
|
|
43837
|
-
// The API returns data in format: [{count: 1,
|
|
43837
|
+
// The API returns data in format: [{count: 1, [field]: "null"}, {count: 1, [field]: "no"}, {count: 1, [field]: "yes"}]
|
|
43838
43838
|
const healthAndSafetyDistributionData = React.useMemo(() => {
|
|
43839
43839
|
if (!pieChartData) return {
|
|
43840
43840
|
compliant: 0,
|
|
@@ -43847,7 +43847,7 @@ const HealthAndSafety = ({
|
|
|
43847
43847
|
return pieChartData;
|
|
43848
43848
|
}
|
|
43849
43849
|
|
|
43850
|
-
// If it's an array, process it
|
|
43850
|
+
// If it's an array, process it using the selected field
|
|
43851
43851
|
if (Array.isArray(pieChartData)) {
|
|
43852
43852
|
const distribution = {
|
|
43853
43853
|
compliant: 0,
|
|
@@ -43855,15 +43855,15 @@ const HealthAndSafety = ({
|
|
|
43855
43855
|
empty: 0
|
|
43856
43856
|
};
|
|
43857
43857
|
pieChartData.forEach(item => {
|
|
43858
|
-
const
|
|
43858
|
+
const fieldValue = item[selectedField];
|
|
43859
43859
|
const count = item.count || 0;
|
|
43860
43860
|
|
|
43861
|
-
// Map
|
|
43862
|
-
if (
|
|
43861
|
+
// Map field values to distribution categories
|
|
43862
|
+
if (fieldValue === "yes" || fieldValue === true) {
|
|
43863
43863
|
distribution.compliant += count;
|
|
43864
|
-
} else if (
|
|
43864
|
+
} else if (fieldValue === "no" || fieldValue === false) {
|
|
43865
43865
|
distribution.notCompliant += count;
|
|
43866
|
-
} else if (
|
|
43866
|
+
} else if (fieldValue === "null" || fieldValue === null || fieldValue === undefined) {
|
|
43867
43867
|
distribution.empty += count;
|
|
43868
43868
|
}
|
|
43869
43869
|
});
|
|
@@ -43872,16 +43872,41 @@ const HealthAndSafety = ({
|
|
|
43872
43872
|
|
|
43873
43873
|
// Fallback: try to extract from activityData-like structure
|
|
43874
43874
|
return getHealthAndSafetyDistributionData(pieChartData);
|
|
43875
|
-
}, [pieChartData]);
|
|
43875
|
+
}, [pieChartData, selectedField]);
|
|
43876
43876
|
const isEmpty = React.useMemo(() => isHealthAndSafetyDistributionEmpty(healthAndSafetyDistributionData), [healthAndSafetyDistributionData]);
|
|
43877
43877
|
const pieData = React.useMemo(() => calculateHealthAndSafetyPieData(healthAndSafetyDistributionData, t), [healthAndSafetyDistributionData, t]);
|
|
43878
|
-
|
|
43878
|
+
|
|
43879
|
+
// Get the label for the selected field to use as tooltip title
|
|
43880
|
+
const selectedFieldLabel = React.useMemo(() => {
|
|
43881
|
+
const selectedOption = filterOptions.find(opt => opt.value === selectedField);
|
|
43882
|
+
return selectedOption ? selectedOption.label : 'Health and Safety';
|
|
43883
|
+
}, [selectedField]);
|
|
43884
|
+
const getTooltipChildren = React.useCallback(item => getHealthAndSafetyTooltipChildren(item, isEmpty, healthAndSafetyDistributionData, t, renderTooltipJsx, selectedFieldLabel), [t, isEmpty, healthAndSafetyDistributionData, selectedFieldLabel]);
|
|
43885
|
+
const handleFilterChange = React.useCallback(value => {
|
|
43886
|
+
setSelectedField(value);
|
|
43887
|
+
}, []);
|
|
43879
43888
|
return /*#__PURE__*/jsxRuntime.jsx(Widget, {
|
|
43880
43889
|
loading: loading || pieChartLoading,
|
|
43881
43890
|
title: /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
43882
43891
|
children: t("Health and Safety")
|
|
43883
43892
|
}),
|
|
43884
43893
|
className: "with-border-header h-w-btn-header ",
|
|
43894
|
+
addedHeader: /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
43895
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
43896
|
+
className: "flex-1"
|
|
43897
|
+
}), /*#__PURE__*/jsxRuntime.jsx(antd.Select, {
|
|
43898
|
+
value: selectedField,
|
|
43899
|
+
style: {
|
|
43900
|
+
width: 180
|
|
43901
|
+
},
|
|
43902
|
+
onChange: handleFilterChange,
|
|
43903
|
+
options: filterOptions.map(opt => ({
|
|
43904
|
+
...opt,
|
|
43905
|
+
label: t(opt.label)
|
|
43906
|
+
})),
|
|
43907
|
+
popupMatchSelectWidth: 180
|
|
43908
|
+
})]
|
|
43909
|
+
}),
|
|
43885
43910
|
children: /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
43886
43911
|
style: {
|
|
43887
43912
|
marginTop: "auto",
|
|
@@ -44185,14 +44210,13 @@ const JobsTimeline = ({
|
|
|
44185
44210
|
});
|
|
44186
44211
|
const jobsData = Array.isArray(dayJobsTimeline) ? dayJobsTimeline : dayJobsTimeline?.jobsTimeline || dayJobsTimeline?.jobs || dayJobsTimeline?.timeline || [];
|
|
44187
44212
|
const jobsTimelineData = React.useMemo(() => {
|
|
44188
|
-
if
|
|
44189
|
-
|
|
44190
|
-
}
|
|
44213
|
+
// Always process data, even if empty, to generate default date range for x-axis
|
|
44214
|
+
const dataToProcess = !jobsData || !Array.isArray(jobsData) || jobsData.length === 0 ? [] : jobsData;
|
|
44191
44215
|
|
|
44192
44216
|
// Process data without cumulative calculation (for jobs timeline)
|
|
44193
44217
|
// Try to find value in total, count, jobs, or value fields
|
|
44194
44218
|
return processChartDateData({
|
|
44195
|
-
mainData:
|
|
44219
|
+
mainData: dataToProcess,
|
|
44196
44220
|
isCumulative: false,
|
|
44197
44221
|
valueField: 'total' // Will fallback to count/jobs/value if total doesn't exist
|
|
44198
44222
|
});
|
package/package.json
CHANGED
|
@@ -21,14 +21,15 @@ const JobsTimeline = ({
|
|
|
21
21
|
: (dayJobsTimeline?.jobsTimeline || dayJobsTimeline?.jobs || dayJobsTimeline?.timeline || []);
|
|
22
22
|
|
|
23
23
|
const jobsTimelineData = useMemo(() => {
|
|
24
|
-
if
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
// Always process data, even if empty, to generate default date range for x-axis
|
|
25
|
+
const dataToProcess = (!jobsData || !Array.isArray(jobsData) || jobsData.length === 0)
|
|
26
|
+
? []
|
|
27
|
+
: jobsData;
|
|
27
28
|
|
|
28
29
|
// Process data without cumulative calculation (for jobs timeline)
|
|
29
30
|
// Try to find value in total, count, jobs, or value fields
|
|
30
31
|
return processChartDateData({
|
|
31
|
-
mainData:
|
|
32
|
+
mainData: dataToProcess,
|
|
32
33
|
isCumulative: false,
|
|
33
34
|
valueField: 'total', // Will fallback to count/jobs/value if total doesn't exist
|
|
34
35
|
});
|
|
@@ -87,9 +87,10 @@ export const calculateHealthAndSafetyPieData = (healthAndSafetyDistributionData,
|
|
|
87
87
|
* @param {Object} healthAndSafetyDistributionData - Distribution object
|
|
88
88
|
* @param {Function} t - Translation function
|
|
89
89
|
* @param {Function} renderTooltipJsx - Function to render tooltip JSX
|
|
90
|
+
* @param {string} tooltipTitle - Title to display in the tooltip (defaults to "Health and Safety")
|
|
90
91
|
* @returns {JSX.Element|null} Tooltip content or null
|
|
91
92
|
*/
|
|
92
|
-
export const getHealthAndSafetyTooltipChildren = (item, isEmpty, healthAndSafetyDistributionData, t, renderTooltipJsx) => {
|
|
93
|
+
export const getHealthAndSafetyTooltipChildren = (item, isEmpty, healthAndSafetyDistributionData, t, renderTooltipJsx, tooltipTitle = "Health and Safety") => {
|
|
93
94
|
// If empty or no data, return null to display nothing
|
|
94
95
|
if (isEmpty || !Object.keys(healthAndSafetyDistributionData).length) {
|
|
95
96
|
return null;
|
|
@@ -129,7 +130,7 @@ export const getHealthAndSafetyTooltipChildren = (item, isEmpty, healthAndSafety
|
|
|
129
130
|
|
|
130
131
|
// Show all items with their percentages
|
|
131
132
|
return renderTooltipJsx({
|
|
132
|
-
title: t(
|
|
133
|
+
title: t(tooltipTitle),
|
|
133
134
|
items: itemsWithData,
|
|
134
135
|
});
|
|
135
136
|
};
|
|
@@ -1,23 +1,33 @@
|
|
|
1
|
-
import React, { useMemo, useCallback } from 'react';
|
|
1
|
+
import React, { useMemo, useCallback, useState } from 'react';
|
|
2
2
|
import { Widget, PieChart } from '../../../../../../../../index.js';
|
|
3
|
+
import { Select } from 'antd';
|
|
3
4
|
import { getHealthAndSafetyDistributionData, isHealthAndSafetyDistributionEmpty, calculateHealthAndSafetyPieData, getHealthAndSafetyTooltipChildren } from './helper';
|
|
4
5
|
import { renderTooltipJsx } from '../../../../../../../../utils';
|
|
5
6
|
import { useWidgetFetch } from '../../../../../../../hooks/useWidgetFetch.js';
|
|
6
7
|
|
|
7
|
-
const
|
|
8
|
+
const filterOptions = [
|
|
9
|
+
{ value: 'aidKitAccessible', label: 'Aid kit availability' },
|
|
10
|
+
{ value: 'hsTrainingConfirmation', label: 'H&S training delivery' },
|
|
11
|
+
{ value: 'duosFormed', label: 'Workers safe pairing' },
|
|
12
|
+
{ value: 'presenceOfChildren', label: 'No children' },
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const HealthAndSafety = ({
|
|
8
16
|
id,
|
|
9
17
|
getSummaryDetail,
|
|
10
|
-
loading = false,
|
|
11
|
-
t = (s) => s
|
|
18
|
+
loading = false,
|
|
19
|
+
t = (s) => s
|
|
12
20
|
}) => {
|
|
21
|
+
const [selectedField, setSelectedField] = useState('aidKitAccessible');
|
|
22
|
+
|
|
13
23
|
const defaultConfig = useMemo(
|
|
14
24
|
() => ({
|
|
15
25
|
basepath: "planting-cycle",
|
|
16
26
|
url: `/summary/${id}/filtered-piechart`,
|
|
17
|
-
filters: { field:
|
|
27
|
+
filters: { field: selectedField },
|
|
18
28
|
stop: !id,
|
|
19
29
|
}),
|
|
20
|
-
[id],
|
|
30
|
+
[id, selectedField],
|
|
21
31
|
);
|
|
22
32
|
|
|
23
33
|
const customGetData = useMemo(() => {
|
|
@@ -45,53 +55,75 @@ const HealthAndSafety = ({
|
|
|
45
55
|
});
|
|
46
56
|
|
|
47
57
|
// Process the fetched pie chart data
|
|
48
|
-
// The API returns data in format: [{count: 1,
|
|
58
|
+
// The API returns data in format: [{count: 1, [field]: "null"}, {count: 1, [field]: "no"}, {count: 1, [field]: "yes"}]
|
|
49
59
|
const healthAndSafetyDistributionData = useMemo(() => {
|
|
50
60
|
if (!pieChartData) return { compliant: 0, notCompliant: 0, empty: 0 };
|
|
51
|
-
|
|
61
|
+
|
|
52
62
|
// If it's already a distribution object
|
|
53
63
|
if (pieChartData.compliant !== undefined || pieChartData.notCompliant !== undefined) {
|
|
54
64
|
return pieChartData;
|
|
55
65
|
}
|
|
56
|
-
|
|
57
|
-
// If it's an array, process it
|
|
66
|
+
|
|
67
|
+
// If it's an array, process it using the selected field
|
|
58
68
|
if (Array.isArray(pieChartData)) {
|
|
59
69
|
const distribution = { compliant: 0, notCompliant: 0, empty: 0 };
|
|
60
|
-
|
|
70
|
+
|
|
61
71
|
pieChartData.forEach(item => {
|
|
62
|
-
const
|
|
72
|
+
const fieldValue = item[selectedField];
|
|
63
73
|
const count = item.count || 0;
|
|
64
|
-
|
|
65
|
-
// Map
|
|
66
|
-
if (
|
|
74
|
+
|
|
75
|
+
// Map field values to distribution categories
|
|
76
|
+
if (fieldValue === "yes" || fieldValue === true) {
|
|
67
77
|
distribution.compliant += count;
|
|
68
|
-
} else if (
|
|
78
|
+
} else if (fieldValue === "no" || fieldValue === false) {
|
|
69
79
|
distribution.notCompliant += count;
|
|
70
|
-
} else if (
|
|
80
|
+
} else if (fieldValue === "null" || fieldValue === null || fieldValue === undefined) {
|
|
71
81
|
distribution.empty += count;
|
|
72
82
|
}
|
|
73
83
|
});
|
|
74
|
-
|
|
84
|
+
|
|
75
85
|
return distribution;
|
|
76
86
|
}
|
|
77
|
-
|
|
87
|
+
|
|
78
88
|
// Fallback: try to extract from activityData-like structure
|
|
79
89
|
return getHealthAndSafetyDistributionData(pieChartData);
|
|
80
|
-
}, [pieChartData]);
|
|
90
|
+
}, [pieChartData, selectedField]);
|
|
81
91
|
|
|
82
92
|
const isEmpty = useMemo(() => isHealthAndSafetyDistributionEmpty(healthAndSafetyDistributionData), [healthAndSafetyDistributionData]);
|
|
83
93
|
const pieData = useMemo(() => calculateHealthAndSafetyPieData(healthAndSafetyDistributionData, t), [healthAndSafetyDistributionData, t]);
|
|
84
94
|
|
|
95
|
+
// Get the label for the selected field to use as tooltip title
|
|
96
|
+
const selectedFieldLabel = useMemo(() => {
|
|
97
|
+
const selectedOption = filterOptions.find(opt => opt.value === selectedField);
|
|
98
|
+
return selectedOption ? selectedOption.label : 'Health and Safety';
|
|
99
|
+
}, [selectedField]);
|
|
100
|
+
|
|
85
101
|
const getTooltipChildren = useCallback(
|
|
86
|
-
(item) => getHealthAndSafetyTooltipChildren(item, isEmpty, healthAndSafetyDistributionData, t, renderTooltipJsx),
|
|
87
|
-
[t, isEmpty, healthAndSafetyDistributionData],
|
|
102
|
+
(item) => getHealthAndSafetyTooltipChildren(item, isEmpty, healthAndSafetyDistributionData, t, renderTooltipJsx, selectedFieldLabel),
|
|
103
|
+
[t, isEmpty, healthAndSafetyDistributionData, selectedFieldLabel],
|
|
88
104
|
);
|
|
89
105
|
|
|
106
|
+
const handleFilterChange = useCallback((value) => {
|
|
107
|
+
setSelectedField(value);
|
|
108
|
+
}, []);
|
|
109
|
+
|
|
90
110
|
return (
|
|
91
111
|
<Widget
|
|
92
112
|
loading={loading || pieChartLoading}
|
|
93
113
|
title={<div>{t("Health and Safety")}</div>}
|
|
94
114
|
className="with-border-header h-w-btn-header "
|
|
115
|
+
addedHeader={
|
|
116
|
+
<>
|
|
117
|
+
<div className="flex-1" />
|
|
118
|
+
<Select
|
|
119
|
+
value={selectedField}
|
|
120
|
+
style={{ width: 180 }}
|
|
121
|
+
onChange={handleFilterChange}
|
|
122
|
+
options={filterOptions.map(opt => ({ ...opt, label: t(opt.label) }))}
|
|
123
|
+
popupMatchSelectWidth={180}
|
|
124
|
+
/>
|
|
125
|
+
</>
|
|
126
|
+
}
|
|
95
127
|
>
|
|
96
128
|
<div
|
|
97
129
|
style={{
|
|
@@ -15,17 +15,15 @@ const PlantingActivitiesTimeline = ({
|
|
|
15
15
|
}) => {
|
|
16
16
|
const { timeFilter, setTimeFilter, formatDateAxis, processChartDateData } = useTimeFilter({ defaultFilter: 'monthly' });
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
// Data structure: [{count: 2, date: "2025-11-03"}]
|
|
20
|
-
// Fill all periods in the range, even if empty
|
|
18
|
+
|
|
21
19
|
const activitiesTimelineData = useMemo(() => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
const dataToProcess = (!activitiesTimelineChart || !Array.isArray(activitiesTimelineChart) || activitiesTimelineChart.length === 0)
|
|
21
|
+
? []
|
|
22
|
+
: activitiesTimelineChart;
|
|
25
23
|
|
|
26
24
|
// Process data without cumulative calculation (for activities timeline)
|
|
27
25
|
return processChartDateData({
|
|
28
|
-
mainData:
|
|
26
|
+
mainData: dataToProcess,
|
|
29
27
|
isCumulative: false,
|
|
30
28
|
valueField: 'count',
|
|
31
29
|
});
|
package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleOutcomes/RestoredArea.jsx
CHANGED
|
@@ -15,18 +15,14 @@ const RestoredArea = ({
|
|
|
15
15
|
}) => {
|
|
16
16
|
const { timeFilter, setTimeFilter, formatDateAxis, processChartDateData } = useTimeFilter({ defaultFilter: 'monthly' });
|
|
17
17
|
|
|
18
|
-
// Map restoredAreaChart data to LineChart format with time filter support
|
|
19
|
-
// Y-axis: total/cumulated value
|
|
20
|
-
// X-axis: date (formatted based on timeFilter)
|
|
21
|
-
// Fill all periods in the range, even if empty
|
|
22
18
|
const restoredAreaChartData = useMemo(() => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
const dataToProcess = (!restoredAreaChart || !Array.isArray(restoredAreaChart) || restoredAreaChart.length === 0)
|
|
20
|
+
? []
|
|
21
|
+
: restoredAreaChart;
|
|
26
22
|
|
|
27
23
|
// Process data with cumulative calculation (for restored area)
|
|
28
24
|
return processChartDateData({
|
|
29
|
-
mainData:
|
|
25
|
+
mainData: dataToProcess,
|
|
30
26
|
isCumulative: true,
|
|
31
27
|
valueField: 'total',
|
|
32
28
|
});
|
|
@@ -99,12 +99,9 @@ export const processChartDateData = ({
|
|
|
99
99
|
isCumulative = false,
|
|
100
100
|
valueField = 'total'
|
|
101
101
|
}) => {
|
|
102
|
-
if (!mainData || !Array.isArray(mainData) || mainData.length === 0) {
|
|
103
|
-
return [];
|
|
104
|
-
}
|
|
105
|
-
|
|
106
102
|
const timeQuantity = getTimeQuantity(filter);
|
|
107
|
-
const dates = mainData;
|
|
103
|
+
const dates = mainData || [];
|
|
104
|
+
const isEmpty = !mainData || !Array.isArray(mainData) || mainData.length === 0;
|
|
108
105
|
|
|
109
106
|
const _data = [];
|
|
110
107
|
let end = filters?.timeframe?.endDate || dayjs();
|
|
@@ -140,7 +137,7 @@ export const processChartDateData = ({
|
|
|
140
137
|
let currentDate = start.clone();
|
|
141
138
|
while (currentDate.isBefore(end) || currentDate.isSame(end, filter === "daily" ? "day" : filter === "weekly" ? "week" : "month")) {
|
|
142
139
|
// Filter data points that fall within this period
|
|
143
|
-
const score = dates
|
|
140
|
+
const score = isEmpty ? 0 : dates
|
|
144
141
|
.filter((d) => {
|
|
145
142
|
if (!d.date) return false;
|
|
146
143
|
switch (filter) {
|