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.
@@ -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
- if (!restoredAreaChart || !Array.isArray(restoredAreaChart) || restoredAreaChart.length === 0) {
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: restoredAreaChart,
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
- if (!activitiesTimelineChart || !Array.isArray(activitiesTimelineChart) || activitiesTimelineChart.length === 0) {
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: activitiesTimelineChart,
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("Health and Safety"),
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: 'duosFormed'
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, duosFormed: "null"}, {count: 1, duosFormed: "no"}, {count: 1, duosFormed: "yes"}]
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 duosFormedValue = item.duosFormed;
43858
+ const fieldValue = item[selectedField];
43859
43859
  const count = item.count || 0;
43860
43860
 
43861
- // Map duosFormed values to distribution categories
43862
- if (duosFormedValue === "yes" || duosFormedValue === true) {
43861
+ // Map field values to distribution categories
43862
+ if (fieldValue === "yes" || fieldValue === true) {
43863
43863
  distribution.compliant += count;
43864
- } else if (duosFormedValue === "no" || duosFormedValue === false) {
43864
+ } else if (fieldValue === "no" || fieldValue === false) {
43865
43865
  distribution.notCompliant += count;
43866
- } else if (duosFormedValue === "null" || duosFormedValue === null || duosFormedValue === undefined) {
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
- const getTooltipChildren = React.useCallback(item => getHealthAndSafetyTooltipChildren(item, isEmpty, healthAndSafetyDistributionData, t, renderTooltipJsx), [t, isEmpty, healthAndSafetyDistributionData]);
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 (!jobsData || !Array.isArray(jobsData) || jobsData.length === 0) {
44189
- return [];
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: jobsData,
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datastake-daf",
3
- "version": "0.6.776",
3
+ "version": "0.6.778",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^5.2.5",
6
6
  "@antv/g2": "^5.1.1",
@@ -21,14 +21,15 @@ const JobsTimeline = ({
21
21
  : (dayJobsTimeline?.jobsTimeline || dayJobsTimeline?.jobs || dayJobsTimeline?.timeline || []);
22
22
 
23
23
  const jobsTimelineData = useMemo(() => {
24
- if (!jobsData || !Array.isArray(jobsData) || jobsData.length === 0) {
25
- return [];
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: jobsData,
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("Health and Safety"),
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 HealthAndSafety = ({
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: 'duosFormed' },
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, duosFormed: "null"}, {count: 1, duosFormed: "no"}, {count: 1, duosFormed: "yes"}]
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 duosFormedValue = item.duosFormed;
72
+ const fieldValue = item[selectedField];
63
73
  const count = item.count || 0;
64
-
65
- // Map duosFormed values to distribution categories
66
- if (duosFormedValue === "yes" || duosFormedValue === true) {
74
+
75
+ // Map field values to distribution categories
76
+ if (fieldValue === "yes" || fieldValue === true) {
67
77
  distribution.compliant += count;
68
- } else if (duosFormedValue === "no" || duosFormedValue === false) {
78
+ } else if (fieldValue === "no" || fieldValue === false) {
69
79
  distribution.notCompliant += count;
70
- } else if (duosFormedValue === "null" || duosFormedValue === null || duosFormedValue === undefined) {
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
- // Map activitiesTimelineChart data to ColumnChart format with time filter support
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
- if (!activitiesTimelineChart || !Array.isArray(activitiesTimelineChart) || activitiesTimelineChart.length === 0) {
23
- return [];
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: activitiesTimelineChart,
26
+ mainData: dataToProcess,
29
27
  isCumulative: false,
30
28
  valueField: 'count',
31
29
  });
@@ -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
- if (!restoredAreaChart || !Array.isArray(restoredAreaChart) || restoredAreaChart.length === 0) {
24
- return [];
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: restoredAreaChart,
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) {