datastake-daf 0.6.768 → 0.6.769
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 +767 -551
- package/dist/layouts/index.js +495 -459
- package/dist/pages/index.js +2808 -738
- package/dist/style/datastake/mapbox-gl.css +330 -0
- package/dist/utils/index.js +481 -457
- package/package.json +1 -1
- package/src/@daf/core/components/Charts/ColumnChart/index.jsx +10 -0
- package/src/@daf/core/components/Charts/LineChart/index.jsx +14 -0
- package/src/@daf/core/components/Dashboard/Widget/ActivityIndicators/index.jsx +2 -0
- package/src/@daf/core/components/Dashboard/Widget/StatCard/StatCard.stories.js +226 -0
- package/src/@daf/core/components/Dashboard/Widget/StatCard/index.js +103 -0
- package/src/@daf/core/components/Dashboard/Widget/StatCard/style.js +83 -0
- package/src/@daf/core/components/Icon/configs/Down.js +8 -0
- package/src/@daf/core/components/Icon/configs/Up.js +8 -0
- package/src/@daf/core/components/Icon/configs/index.js +4 -0
- package/src/@daf/core/components/Icon/configs/partnerIcon.js +1 -1
- package/src/@daf/core/components/Sidenav/Menu.jsx +4 -4
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/AssociatedInformation/index.jsx +43 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CommunityParticipation/CommunityStats/helper.js +60 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CommunityParticipation/CommunityStats/index.jsx +36 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CommunityParticipation/GenderDistribution/helper.js +117 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CommunityParticipation/GenderDistribution/index.jsx +49 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CommunityParticipation/JobsTimeline/index.jsx +212 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CommunityParticipation/index.jsx +72 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleIndicators/CyclePartners/helper.js +91 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleIndicators/CyclePartners/index.jsx +50 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleIndicators/HealthAndSafety/helper.js +134 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleIndicators/HealthAndSafety/index.jsx +49 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleIndicators/index.jsx +112 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/CycleOutcomes/index.jsx +498 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/KeyInformation/index.jsx +49 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/components/PlantingLocations/index.jsx +120 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/config.js +5 -10
- package/src/@daf/pages/Summary/Activities/PlantingCycle/helper.js +218 -0
- package/src/@daf/pages/Summary/Activities/PlantingCycle/index.jsx +22 -32
- package/src/@daf/pages/Summary/Activities/Restoration/components/ActivityImagery/index.jsx +29 -0
- package/src/@daf/pages/Summary/Activities/Restoration/components/ActivityLocation/index.jsx +94 -0
- package/src/@daf/pages/Summary/Activities/Restoration/components/WorkersDistribution/index.jsx +49 -0
- package/src/@daf/pages/Summary/Activities/Restoration/index.jsx +16 -138
- package/src/index.js +1 -0
|
@@ -4,36 +4,31 @@ export const getKeyIndicatorsRowConfig = ({ t, data = {} }) => [
|
|
|
4
4
|
{
|
|
5
5
|
label: t('Region'),
|
|
6
6
|
render: () => {
|
|
7
|
-
|
|
8
|
-
return <div>{ '-'}</div>;
|
|
7
|
+
return <div>{ data?.region || '-'}</div>;
|
|
9
8
|
}
|
|
10
9
|
},
|
|
11
10
|
{
|
|
12
11
|
label: t('Associated Plots'),
|
|
13
12
|
render: () => {
|
|
14
|
-
|
|
15
|
-
return <div>{'0'}</div>
|
|
13
|
+
return <div>{data?.associatedPlotsCount || '0'}</div>
|
|
16
14
|
}
|
|
17
15
|
},
|
|
18
16
|
{
|
|
19
17
|
label: t('Implementation Partners'),
|
|
20
18
|
render: () => {
|
|
21
|
-
|
|
22
|
-
return <div>{'0'}</div>
|
|
19
|
+
return <div>{data?.partnersCount || '0'}</div>
|
|
23
20
|
}
|
|
24
21
|
},
|
|
25
22
|
{
|
|
26
23
|
label: t('Total Activities'),
|
|
27
24
|
render: () => {
|
|
28
|
-
|
|
29
|
-
return <div>{'0'}</div>
|
|
25
|
+
return <div>{data?.activitiesCount || '0'}</div>
|
|
30
26
|
}
|
|
31
27
|
},
|
|
32
28
|
{
|
|
33
29
|
label: t('Information Sources'),
|
|
34
30
|
render: () => {
|
|
35
|
-
|
|
36
|
-
return <div>{'0'}</div>
|
|
31
|
+
return <div>{data?.informationSourcesCount || '0'}</div>
|
|
37
32
|
}
|
|
38
33
|
},
|
|
39
34
|
];
|
|
@@ -120,3 +120,221 @@ export const getMapDataFromActivity = (activityData, t) => {
|
|
|
120
120
|
return mapData;
|
|
121
121
|
};
|
|
122
122
|
|
|
123
|
+
const PARTNER_COLORS = ['#016C6E', '#00AEB1', '#FF7A45', '#52C41A', '#1890FF', '#722ED1', '#FA8C16', '#EB2F96'];
|
|
124
|
+
|
|
125
|
+
export const getPartnersDistributionData = (activityData) => {
|
|
126
|
+
// Handle object format: { "Partner 1": count1, "Partner 2": count2 }
|
|
127
|
+
if (activityData?.partnersDistribution && typeof activityData.partnersDistribution === 'object') {
|
|
128
|
+
return activityData.partnersDistribution;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (Array.isArray(activityData?.partners)) {
|
|
132
|
+
const distribution = {};
|
|
133
|
+
activityData.partners.forEach(partner => {
|
|
134
|
+
const name = partner?.name || partner?.nickName || partner?.label || 'Unknown';
|
|
135
|
+
const count = partner?.count || partner?.value || 1;
|
|
136
|
+
distribution[name] = (distribution[name] || 0) + count;
|
|
137
|
+
});
|
|
138
|
+
return distribution;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Default empty object
|
|
142
|
+
return {};
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export const isPartnersDistributionEmpty = (partnersDistributionData) => {
|
|
146
|
+
return Object.values(partnersDistributionData).every(val => !val || val === 0);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export const calculatePartnersPieData = (partnersDistributionData) => {
|
|
150
|
+
const total = Object.values(partnersDistributionData).reduce((all, val) => all + (val || 0), 0);
|
|
151
|
+
|
|
152
|
+
return Object.keys(partnersDistributionData).map((key, index) => {
|
|
153
|
+
const color = PARTNER_COLORS[index % PARTNER_COLORS.length];
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
value: partnersDistributionData[key] || 0,
|
|
157
|
+
percent: total > 0 ? (partnersDistributionData[key] || 0) / total : 0,
|
|
158
|
+
color: color,
|
|
159
|
+
label: key,
|
|
160
|
+
key: key,
|
|
161
|
+
};
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export const getPartnersTooltipChildren = (item, isEmpty, partnersDistributionData, t, renderTooltipJsx) => {
|
|
166
|
+
if (isEmpty) {
|
|
167
|
+
if (!Object.keys(partnersDistributionData).length) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return renderTooltipJsx({
|
|
172
|
+
title: t("Partners"),
|
|
173
|
+
items: Object.keys(partnersDistributionData).map((k) => ({
|
|
174
|
+
label: k,
|
|
175
|
+
value: 0,
|
|
176
|
+
})),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return renderTooltipJsx({
|
|
181
|
+
title: t("Partners"),
|
|
182
|
+
items: [
|
|
183
|
+
{
|
|
184
|
+
color: item.color,
|
|
185
|
+
label: item.label,
|
|
186
|
+
value: `${item.value || 0}`,
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const HEALTH_SAFETY_COLORS = {
|
|
193
|
+
compliant: '#52C41A',
|
|
194
|
+
notCompliant: '#FF4D4F',
|
|
195
|
+
empty: '#D9D9D9',
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const getIndicatorType = (value) => {
|
|
199
|
+
if (value === "yes" || value === true) return "compliant";
|
|
200
|
+
if (value === "no" || value === false) return "notCompliant";
|
|
201
|
+
if (value === null || value === undefined) return "empty";
|
|
202
|
+
return "empty";
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
export const getHealthAndSafetyDistributionData = (activityData) => {
|
|
206
|
+
// Define health and safety indicator fields
|
|
207
|
+
const indicators = [
|
|
208
|
+
{ field: 'aidKitAccessible', label: 'Aid kit availability' },
|
|
209
|
+
{ field: 'hsTrainingConfirmation', label: 'H&S training delivery' },
|
|
210
|
+
{ field: 'duosFormed', label: 'Workers safe pairing' },
|
|
211
|
+
{ field: 'presenceOfChildren', label: 'No children' },
|
|
212
|
+
{ field: 'focalPointPresent', label: 'Security presence' },
|
|
213
|
+
{ field: 'relayPresent', label: 'Relay presence' },
|
|
214
|
+
];
|
|
215
|
+
|
|
216
|
+
const distribution = {
|
|
217
|
+
compliant: 0,
|
|
218
|
+
notCompliant: 0,
|
|
219
|
+
empty: 0,
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
indicators.forEach(({ field }) => {
|
|
223
|
+
const value = activityData?.[field];
|
|
224
|
+
const type = getIndicatorType(value);
|
|
225
|
+
distribution[type] = (distribution[type] || 0) + 1;
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
return distribution;
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
export const isHealthAndSafetyDistributionEmpty = (healthAndSafetyDistributionData) => {
|
|
232
|
+
return Object.values(healthAndSafetyDistributionData).every(val => !val || val === 0);
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export const calculateHealthAndSafetyPieData = (healthAndSafetyDistributionData, t) => {
|
|
236
|
+
const total = Object.values(healthAndSafetyDistributionData).reduce((all, val) => all + (val || 0), 0);
|
|
237
|
+
|
|
238
|
+
const labels = {
|
|
239
|
+
compliant: t("Compliant"),
|
|
240
|
+
notCompliant: t("Not Compliant"),
|
|
241
|
+
empty: t("Not Set"),
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
return Object.keys(healthAndSafetyDistributionData).map((key) => {
|
|
245
|
+
const color = HEALTH_SAFETY_COLORS[key] || '#D9D9D9';
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
value: healthAndSafetyDistributionData[key] || 0,
|
|
249
|
+
percent: total > 0 ? (healthAndSafetyDistributionData[key] || 0) / total : 0,
|
|
250
|
+
color: color,
|
|
251
|
+
label: labels[key] || key,
|
|
252
|
+
key: key,
|
|
253
|
+
};
|
|
254
|
+
});
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
export const getHealthAndSafetyTooltipChildren = (item, isEmpty, healthAndSafetyDistributionData, t, renderTooltipJsx) => {
|
|
258
|
+
if (isEmpty) {
|
|
259
|
+
if (!Object.keys(healthAndSafetyDistributionData).length) {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return renderTooltipJsx({
|
|
264
|
+
title: t("Health and Safety"),
|
|
265
|
+
items: Object.keys(healthAndSafetyDistributionData).map((k) => ({
|
|
266
|
+
label: k === 'compliant' ? t("Compliant") : k === 'notCompliant' ? t("Not Compliant") : t("Not Set"),
|
|
267
|
+
value: 0,
|
|
268
|
+
})),
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return renderTooltipJsx({
|
|
273
|
+
title: t("Health and Safety"),
|
|
274
|
+
items: [
|
|
275
|
+
{
|
|
276
|
+
color: item.color,
|
|
277
|
+
label: item.label,
|
|
278
|
+
value: `${item.value || 0}`,
|
|
279
|
+
},
|
|
280
|
+
],
|
|
281
|
+
});
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Calculates stat change object for StatCard component based on current and previous values
|
|
286
|
+
* @param {Object} data - Object with current and previous values
|
|
287
|
+
* @param {number} data.current - Current value
|
|
288
|
+
* @param {number} data.previous - Previous value
|
|
289
|
+
* @param {Object} options - Optional configuration
|
|
290
|
+
* @param {string} options.tooltipText - Custom tooltip text
|
|
291
|
+
* @param {string} options.format - Format type: 'percentage' (default) or 'absolute'
|
|
292
|
+
* @param {number} options.decimalPlaces - Number of decimal places for percentage (default: 1)
|
|
293
|
+
* @returns {Object|null} Change object for StatCard or null if data is invalid
|
|
294
|
+
*/
|
|
295
|
+
export const calculateStatChange = (data, options = {}) => {
|
|
296
|
+
if (!data || typeof data !== 'object') {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const { current, previous } = data;
|
|
301
|
+
|
|
302
|
+
// Validate that both values are numbers
|
|
303
|
+
if (typeof current !== 'number' || typeof previous !== 'number') {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// If previous is 0, we can't calculate percentage change
|
|
308
|
+
if (previous === 0) {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const {
|
|
313
|
+
tooltipText,
|
|
314
|
+
format = 'percentage',
|
|
315
|
+
decimalPlaces = 1,
|
|
316
|
+
} = options;
|
|
317
|
+
|
|
318
|
+
// Calculate the difference
|
|
319
|
+
const difference = current - previous;
|
|
320
|
+
const isPositive = difference >= 0;
|
|
321
|
+
const direction = isPositive ? 'up' : 'down';
|
|
322
|
+
|
|
323
|
+
// Format the value
|
|
324
|
+
let value;
|
|
325
|
+
if (format === 'absolute') {
|
|
326
|
+
// Show absolute difference
|
|
327
|
+
value = Math.abs(difference).toLocaleString();
|
|
328
|
+
} else {
|
|
329
|
+
// Show percentage change
|
|
330
|
+
const percentageChange = (Math.abs(difference) / previous) * 100;
|
|
331
|
+
value = `${percentageChange.toFixed(decimalPlaces)}%`;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
value,
|
|
336
|
+
direction,
|
|
337
|
+
tooltipText: tooltipText || undefined,
|
|
338
|
+
};
|
|
339
|
+
};
|
|
340
|
+
|
|
@@ -1,44 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import { DashboardLayout, Header } from '../../../../../../src/index.js'
|
|
2
|
+
import PlantingLocations from './components/PlantingLocations/index.jsx';
|
|
3
|
+
import CycleOutcomes from './components/CycleOutcomes/index.jsx';
|
|
4
|
+
import CycleIndicators from './components/CycleIndicators/index.jsx';
|
|
5
|
+
import CommunityParticipation from './components/CommunityParticipation/index.jsx';
|
|
6
|
+
import AssociatedInformation from './components/AssociatedInformation/index.jsx';
|
|
7
|
+
import KeyInformation from './components/KeyInformation/index.jsx';
|
|
4
8
|
|
|
5
|
-
const PlantingCycleSummary = ({
|
|
6
|
-
const keyIndicatorsConfig = useMemo(() => getKeyIndicatorsRowConfig({ t, data: {} }), [t]);
|
|
9
|
+
const PlantingCycleSummary = ({ header, activityData, loading = false, id, t = () => { }, getSummaryDetail }) => {
|
|
7
10
|
|
|
8
11
|
return (
|
|
9
12
|
<DashboardLayout
|
|
10
13
|
header={
|
|
11
14
|
<Header
|
|
12
|
-
title={
|
|
13
|
-
supportText={supportText || ''}
|
|
14
|
-
onDownload={onDownload}
|
|
15
|
-
downloadDisabled={downloadDisabled}
|
|
16
|
-
actionButtons={actionButtons}
|
|
17
|
-
breadcrumbs={breadcrumbs}
|
|
18
|
-
goBackTo={goBackTo}
|
|
19
|
-
loading={loading}
|
|
15
|
+
title={header?.title || ''}
|
|
16
|
+
supportText={header?.supportText || ''}
|
|
17
|
+
onDownload={header?.onDownload}
|
|
18
|
+
downloadDisabled={header?.downloadDisabled}
|
|
19
|
+
actionButtons={header?.actionButtons}
|
|
20
|
+
breadcrumbs={header?.breadcrumbs}
|
|
21
|
+
goBackTo={header?.goBackTo}
|
|
22
|
+
loading={header?.loading}
|
|
20
23
|
/>
|
|
21
24
|
}
|
|
22
25
|
>
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
title={t("Planting Locations")}
|
|
30
|
-
className="no-px h-w-btn-header no-pt-body no-p-body no-pb-body"
|
|
31
|
-
style={{ height: '100%', display: 'flex', flexDirection: 'column' }}
|
|
32
|
-
>
|
|
33
|
-
<MineSiteMap
|
|
34
|
-
loading={loading}
|
|
35
|
-
t={t}
|
|
36
|
-
isSatellite
|
|
37
|
-
data={[]}
|
|
38
|
-
/>
|
|
39
|
-
</Widget>
|
|
40
|
-
|
|
41
|
-
</section>
|
|
26
|
+
<KeyInformation id={id} t={t} getSummaryDetail={getSummaryDetail} loading={loading} />
|
|
27
|
+
<PlantingLocations id={id} getSummaryDetail={getSummaryDetail} loading={loading} t={t} />
|
|
28
|
+
<CycleOutcomes id={id} getSummaryDetail={getSummaryDetail} loading={loading} t={t} />
|
|
29
|
+
<CycleIndicators id={id} getSummaryDetail={getSummaryDetail} loading={loading} t={t} />
|
|
30
|
+
<CommunityParticipation id={id} getSummaryDetail={getSummaryDetail} loading={loading} t={t} />
|
|
31
|
+
<AssociatedInformation id={id} getSummaryDetail={getSummaryDetail} loading={loading} t={t} />
|
|
42
32
|
</DashboardLayout>
|
|
43
33
|
)
|
|
44
34
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { ImageCarousel } from '../../../../../../../../src/index.js';
|
|
3
|
+
import { getActivityImages } from '../../helper';
|
|
4
|
+
import { useResizeContext } from '../../../../../../../../src/context';
|
|
5
|
+
|
|
6
|
+
const ActivityImagery = ({
|
|
7
|
+
activityData,
|
|
8
|
+
loading = false,
|
|
9
|
+
t = (s) => s
|
|
10
|
+
}) => {
|
|
11
|
+
const { isCollapsed, isNestedSidebarCollapsed } = useResizeContext();
|
|
12
|
+
const images = useMemo(() => getActivityImages(activityData), [activityData]);
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div style={{ maxWidth: "70%", width: "calc(100% - 405px)" }}>
|
|
16
|
+
<ImageCarousel
|
|
17
|
+
loading={loading}
|
|
18
|
+
images={images}
|
|
19
|
+
title={t("straatos::activity-imagery")}
|
|
20
|
+
key={`${isCollapsed}-${isNestedSidebarCollapsed}`}
|
|
21
|
+
customArrows={true}
|
|
22
|
+
activeDotColor="#003435"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default ActivityImagery;
|
|
29
|
+
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { Widget, MineSiteMap } from '../../../../../../../../src/index.js';
|
|
3
|
+
import { getMapDataFromActivity } from '../../helper';
|
|
4
|
+
import { convertDMS } from '../../../../../../../../src/helpers/Map';
|
|
5
|
+
import CustomIcon from '../../../../../../../../src/@daf/core/components/Icon/CustomIcon.jsx';
|
|
6
|
+
|
|
7
|
+
const ActivityLocation = ({
|
|
8
|
+
activityData,
|
|
9
|
+
loading = false,
|
|
10
|
+
t = (s) => s
|
|
11
|
+
}) => {
|
|
12
|
+
const mapData = useMemo(() => getMapDataFromActivity(activityData, t), [activityData, t]);
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<section>
|
|
16
|
+
<Widget
|
|
17
|
+
title={t("Activity Location")}
|
|
18
|
+
className="no-px h-w-btn-header no-pt-body no-p-body no-pb-body"
|
|
19
|
+
style={{ height: '100%', display: 'flex', flexDirection: 'column' }}
|
|
20
|
+
>
|
|
21
|
+
<div style={{ flex: 1, minHeight: 0 }}>
|
|
22
|
+
<MineSiteMap
|
|
23
|
+
loading={loading}
|
|
24
|
+
t={t}
|
|
25
|
+
isSatellite={true}
|
|
26
|
+
app={"straatos"}
|
|
27
|
+
type={'location-territory'}
|
|
28
|
+
showSider={false}
|
|
29
|
+
user={null}
|
|
30
|
+
data={mapData}
|
|
31
|
+
maxZoom={18}
|
|
32
|
+
primaryLink={true}
|
|
33
|
+
style={{ height: '100%', width: '100%' }}
|
|
34
|
+
renderTooltipForLocation={(data) => {
|
|
35
|
+
const coordinates = data.gps?.latitude && data.gps?.longitude
|
|
36
|
+
? convertDMS(data.gps.latitude, data.gps.longitude)
|
|
37
|
+
: null;
|
|
38
|
+
|
|
39
|
+
if (!coordinates) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const isActivityEnd = data.name === t("Activity End") || data.id?.includes('-departure');
|
|
44
|
+
const iconColor = isActivityEnd ? "#FF7A45" : "#016C6E";
|
|
45
|
+
|
|
46
|
+
return [
|
|
47
|
+
{
|
|
48
|
+
label: t("Coordinates"),
|
|
49
|
+
|
|
50
|
+
value: (
|
|
51
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '6px', flexWrap: 'nowrap' }}>
|
|
52
|
+
{/* Latitude icon (vertical) */}
|
|
53
|
+
<div style={{ display: 'flex', alignItems: 'center' }}>
|
|
54
|
+
<CustomIcon
|
|
55
|
+
name="SpacingHeight"
|
|
56
|
+
width={14}
|
|
57
|
+
height={14}
|
|
58
|
+
color={iconColor}
|
|
59
|
+
/>
|
|
60
|
+
<span style={{ fontWeight: 600, marginLeft: '4px' }}>{coordinates[0]}</span>
|
|
61
|
+
</div>
|
|
62
|
+
{/* Longitude icon (horizontal) */}
|
|
63
|
+
<div style={{ display: 'flex', alignItems: 'center' }}>
|
|
64
|
+
<CustomIcon
|
|
65
|
+
name="SpacingWidth"
|
|
66
|
+
width={14}
|
|
67
|
+
height={14}
|
|
68
|
+
color={iconColor}
|
|
69
|
+
/>
|
|
70
|
+
<span style={{ fontWeight: 600, marginLeft: '4px' }}>{coordinates[1]}</span>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
),
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
}}
|
|
77
|
+
renderTooltipForTerritory={(data) => {
|
|
78
|
+
return [
|
|
79
|
+
{
|
|
80
|
+
label: t("Plot Name"),
|
|
81
|
+
value: data.plotName || data.name || "--",
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
}}
|
|
85
|
+
link={true}
|
|
86
|
+
/>
|
|
87
|
+
</div>
|
|
88
|
+
</Widget>
|
|
89
|
+
</section>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export default ActivityLocation;
|
|
94
|
+
|
package/src/@daf/pages/Summary/Activities/Restoration/components/WorkersDistribution/index.jsx
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React, { useMemo, useCallback } from 'react';
|
|
2
|
+
import { Widget, PieChart } from '../../../../../../../../src/index.js';
|
|
3
|
+
import { getGenderDistributionData, isGenderDistributionEmpty, calculateGenderPieData, getGenderTooltipChildren } from '../../helper';
|
|
4
|
+
import { renderTooltipJsx } from '../../../../../../../../src/utils';
|
|
5
|
+
|
|
6
|
+
const WorkersDistribution = ({
|
|
7
|
+
activityData,
|
|
8
|
+
loading = false,
|
|
9
|
+
t = (s) => s
|
|
10
|
+
}) => {
|
|
11
|
+
const genderDistributionData = useMemo(() => getGenderDistributionData(activityData), [activityData]);
|
|
12
|
+
const isEmpty = useMemo(() => isGenderDistributionEmpty(genderDistributionData), [genderDistributionData]);
|
|
13
|
+
const pieData = useMemo(() => calculateGenderPieData(genderDistributionData), [genderDistributionData]);
|
|
14
|
+
|
|
15
|
+
const getTooltipChildren = useCallback(
|
|
16
|
+
(item) => getGenderTooltipChildren(item, isEmpty, genderDistributionData, t, renderTooltipJsx),
|
|
17
|
+
[t, isEmpty, genderDistributionData],
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Widget
|
|
22
|
+
loading={loading}
|
|
23
|
+
title={<div>{t("Workers Distribution")}</div>}
|
|
24
|
+
className="with-border-header h-w-btn-header "
|
|
25
|
+
>
|
|
26
|
+
<div
|
|
27
|
+
style={{
|
|
28
|
+
marginTop: "auto",
|
|
29
|
+
marginBottom: "auto",
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
<PieChart
|
|
33
|
+
mouseXOffset={10}
|
|
34
|
+
mouseYOffset={10}
|
|
35
|
+
changeOpacityOnHover={false}
|
|
36
|
+
data={pieData}
|
|
37
|
+
doConstraints={false}
|
|
38
|
+
isPie
|
|
39
|
+
t={t}
|
|
40
|
+
isEmpty={isEmpty}
|
|
41
|
+
getTooltipChildren={getTooltipChildren}
|
|
42
|
+
/>
|
|
43
|
+
</div>
|
|
44
|
+
</Widget>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default WorkersDistribution;
|
|
49
|
+
|