datastake-daf 0.6.774 → 0.6.775
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 +2384 -2252
- package/dist/pages/index.js +1802 -820
- package/dist/style/datastake/mapbox-gl.css +330 -0
- package/package.json +1 -1
- package/src/@daf/hooks/useTimeFilter.js +56 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/AssociatedInformation/config.js +548 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/AssociatedInformation/index.jsx +137 -24
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CommunityParticipation/JobsTimeline/index.jsx +33 -102
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleIndicators/HealthAndSafety/helper.js +8 -6
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleIndicators/HealthAndSafety/index.jsx +73 -4
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleIndicators/index.jsx +1 -1
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleOutcomes/PlantingActivitiesTimeline.jsx +148 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleOutcomes/RestoredArea.jsx +150 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleOutcomes/index.jsx +11 -390
- package/src/@daf/pages/Summary/Activities/PlantingCycle/index.jsx +3 -4
- package/src/@daf/utils/timeFilterUtils.js +226 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import { capitalize } from '../../helpers/StringHelper.js';
|
|
3
|
+
import { renderNumber } from './numbers.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Formats a date based on the time filter
|
|
7
|
+
* @param {dayjs.Dayjs} date - The date to format
|
|
8
|
+
* @param {boolean} breakLine - Whether to add a line break (for tooltips)
|
|
9
|
+
* @param {string} timeFilter - The time filter ('daily', 'weekly', 'monthly')
|
|
10
|
+
* @returns {string} Formatted date string
|
|
11
|
+
*/
|
|
12
|
+
export const getFormatDate = (date, breakLine = false, timeFilter = 'monthly') => {
|
|
13
|
+
switch (timeFilter) {
|
|
14
|
+
case "daily":
|
|
15
|
+
return date.format("DD/MM");
|
|
16
|
+
case "weekly" :
|
|
17
|
+
return `W${renderNumber(date.week())}`;
|
|
18
|
+
default:
|
|
19
|
+
// Monthly format: "Dec 24", "Jan 25", etc.
|
|
20
|
+
|
|
21
|
+
return breakLine
|
|
22
|
+
? `${capitalize(date.format("MMM"))}\n${date.format("YY")}`
|
|
23
|
+
: `${capitalize(date.format("MMM"))} ${date.format("YY")}`;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Gets the time quantity string for dayjs operations
|
|
29
|
+
* @param {string} timeFilter - The time filter ('daily', 'weekly', 'monthly')
|
|
30
|
+
* @returns {string} Time quantity string ('days', 'weeks', 'months')
|
|
31
|
+
*/
|
|
32
|
+
export const getTimeQuantity = (timeFilter = 'monthly') => {
|
|
33
|
+
return timeFilter === "monthly"
|
|
34
|
+
? "months"
|
|
35
|
+
: timeFilter === "daily"
|
|
36
|
+
? "days"
|
|
37
|
+
: "weeks";
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Gets previous cumulative score from data before start date
|
|
42
|
+
* @param {Array} dates - Array of data objects with date field
|
|
43
|
+
* @param {dayjs.Dayjs} startDate - The start date
|
|
44
|
+
* @param {string} timeFilter - The time filter
|
|
45
|
+
* @param {string} valueField - The field name to extract value from (default: 'total')
|
|
46
|
+
* @returns {Object} Object with hasPreviousData, previousCumulativeScore, previousMaxScore
|
|
47
|
+
*/
|
|
48
|
+
export const getPreviousGraphData = (dates, startDate, timeFilter, valueField = 'total') => {
|
|
49
|
+
let previousCumulativeScore = 0;
|
|
50
|
+
let previousMaxScore = 0;
|
|
51
|
+
let hasPreviousData = false;
|
|
52
|
+
|
|
53
|
+
dates.forEach((d) => {
|
|
54
|
+
const date = dayjs(d.date, "YYYY-MM-DD");
|
|
55
|
+
if (!date.isValid()) return;
|
|
56
|
+
|
|
57
|
+
let isBeforeStart = false;
|
|
58
|
+
switch (timeFilter) {
|
|
59
|
+
case "daily":
|
|
60
|
+
isBeforeStart = date.isBefore(startDate, 'day');
|
|
61
|
+
break;
|
|
62
|
+
case "weekly":
|
|
63
|
+
isBeforeStart = date.isBefore(startDate, 'week');
|
|
64
|
+
break;
|
|
65
|
+
default:
|
|
66
|
+
isBeforeStart = date.isBefore(startDate, 'month');
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (isBeforeStart) {
|
|
71
|
+
hasPreviousData = true;
|
|
72
|
+
const value = Number(d[valueField] || d.count || d.jobs || d.value || 0) || 0;
|
|
73
|
+
previousCumulativeScore += value;
|
|
74
|
+
previousMaxScore = Math.max(previousMaxScore, value);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
hasPreviousData,
|
|
80
|
+
previousCumulativeScore,
|
|
81
|
+
previousMaxScore,
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Processes chart data with time filtering support
|
|
87
|
+
* @param {Object} params - Parameters object
|
|
88
|
+
* @param {Array} params.mainData - Array of data objects with date and value fields
|
|
89
|
+
* @param {string} params.timeFilter - Time filter ('daily', 'weekly', 'monthly')
|
|
90
|
+
* @param {Object} params.filters - Optional filters object with timeframe
|
|
91
|
+
* @param {boolean} params.isCumulative - Whether to calculate cumulative values (default: false)
|
|
92
|
+
* @param {string} params.valueField - Field name to extract value from (default: 'total', also checks 'count', 'jobs', 'value')
|
|
93
|
+
* @returns {Array} Processed chart data array
|
|
94
|
+
*/
|
|
95
|
+
export const processChartDateData = ({
|
|
96
|
+
mainData,
|
|
97
|
+
timeFilter: filter,
|
|
98
|
+
filters = {},
|
|
99
|
+
isCumulative = false,
|
|
100
|
+
valueField = 'total'
|
|
101
|
+
}) => {
|
|
102
|
+
if (!mainData || !Array.isArray(mainData) || mainData.length === 0) {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const timeQuantity = getTimeQuantity(filter);
|
|
107
|
+
const dates = mainData;
|
|
108
|
+
|
|
109
|
+
const _data = [];
|
|
110
|
+
let end = filters?.timeframe?.endDate || dayjs();
|
|
111
|
+
let start = filters?.timeframe?.startDate || dayjs().add(-12, timeQuantity);
|
|
112
|
+
|
|
113
|
+
// Normalize start and end to period boundaries
|
|
114
|
+
if (filter === "daily") {
|
|
115
|
+
start = start.startOf('day');
|
|
116
|
+
end = end.startOf('day');
|
|
117
|
+
} else if (filter === "weekly") {
|
|
118
|
+
start = start.startOf('week');
|
|
119
|
+
end = end.startOf('week');
|
|
120
|
+
} else {
|
|
121
|
+
start = start.startOf('month');
|
|
122
|
+
end = end.startOf('month');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let i = 0;
|
|
126
|
+
let cumulativeScore = 0;
|
|
127
|
+
|
|
128
|
+
// Calculate initial cumulative value if needed
|
|
129
|
+
if (isCumulative) {
|
|
130
|
+
const { hasPreviousData, previousCumulativeScore } = getPreviousGraphData(
|
|
131
|
+
dates,
|
|
132
|
+
start,
|
|
133
|
+
filter,
|
|
134
|
+
valueField
|
|
135
|
+
);
|
|
136
|
+
cumulativeScore = hasPreviousData ? previousCumulativeScore : 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Loop until we reach the end date
|
|
140
|
+
let currentDate = start.clone();
|
|
141
|
+
while (currentDate.isBefore(end) || currentDate.isSame(end, filter === "daily" ? "day" : filter === "weekly" ? "week" : "month")) {
|
|
142
|
+
// Filter data points that fall within this period
|
|
143
|
+
const score = dates
|
|
144
|
+
.filter((d) => {
|
|
145
|
+
if (!d.date) return false;
|
|
146
|
+
switch (filter) {
|
|
147
|
+
case "daily":
|
|
148
|
+
return d.date === currentDate.format("YYYY-MM-DD");
|
|
149
|
+
case "weekly":
|
|
150
|
+
return dayjs(d.date, "YYYY-MM-DD").week() === currentDate.week() &&
|
|
151
|
+
dayjs(d.date, "YYYY-MM-DD").year() === currentDate.year();
|
|
152
|
+
default:
|
|
153
|
+
return (
|
|
154
|
+
dayjs(d.date, "YYYY-MM-DD").format("YYYY-MM") ===
|
|
155
|
+
currentDate.format("YYYY-MM")
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
.reduce((a, b) => {
|
|
160
|
+
const value = Number(b[valueField] || b.count || b.jobs || b.value || 0) || 0;
|
|
161
|
+
return a + value;
|
|
162
|
+
}, 0);
|
|
163
|
+
|
|
164
|
+
if (isCumulative) {
|
|
165
|
+
cumulativeScore += score;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
_data.push({
|
|
169
|
+
date: getFormatDate(currentDate, false, filter),
|
|
170
|
+
value: isCumulative ? cumulativeScore : score,
|
|
171
|
+
period: score, // Period value for tooltip
|
|
172
|
+
jobs: score, // For compatibility with jobs field
|
|
173
|
+
month: currentDate.format('YYYY-MM-DD'), // For compatibility
|
|
174
|
+
key: i,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
currentDate = currentDate.add(1, timeQuantity);
|
|
178
|
+
i++;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return _data;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Formats date axis labels, checking if already formatted
|
|
186
|
+
* @param {string} label - The label to format
|
|
187
|
+
* @param {Function} getFormatDateFn - Function to format dates
|
|
188
|
+
* @returns {string} Formatted date string
|
|
189
|
+
*/
|
|
190
|
+
export const formatDateAxis = (label, getFormatDateFn) => {
|
|
191
|
+
if (!label) return label;
|
|
192
|
+
|
|
193
|
+
// Check if label is already in the correct format (MMM YY, DD/MM, or W#)
|
|
194
|
+
// If it matches our format patterns, return as-is
|
|
195
|
+
if (typeof label === 'string') {
|
|
196
|
+
// Check for MMM YY format (e.g., "Dec 24", "Jan 25")
|
|
197
|
+
if (/^[A-Z][a-z]{2} \d{2}$/.test(label)) {
|
|
198
|
+
return label;
|
|
199
|
+
}
|
|
200
|
+
// Check for DD/MM format (e.g., "03/11")
|
|
201
|
+
if (/^\d{2}\/\d{2}$/.test(label)) {
|
|
202
|
+
return label;
|
|
203
|
+
}
|
|
204
|
+
// Check for W# format (e.g., "W1", "W12")
|
|
205
|
+
if (/^W\d+$/.test(label)) {
|
|
206
|
+
return label;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Otherwise, try to parse and format it
|
|
211
|
+
let date = dayjs(label);
|
|
212
|
+
|
|
213
|
+
// If first attempt fails, try parsing as ISO date string
|
|
214
|
+
if (!date.isValid() && typeof label === 'string') {
|
|
215
|
+
date = dayjs(label, ['YYYY-MM-DD', 'YYYY-MM', 'MMM YY', 'MMM YYYY', 'DD/MM'], true);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// If it's a valid date, format it using getFormatDate
|
|
219
|
+
if (date.isValid() && getFormatDateFn) {
|
|
220
|
+
return getFormatDateFn(date, false);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Return as-is if we can't parse it
|
|
224
|
+
return label;
|
|
225
|
+
};
|
|
226
|
+
|