datastake-daf 0.6.830 → 0.6.832

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.
Files changed (39) hide show
  1. package/dist/components/index.js +1538 -1478
  2. package/dist/hooks/index.js +40 -1
  3. package/dist/layouts/index.js +2 -2
  4. package/dist/pages/index.js +1890 -171
  5. package/dist/services/index.js +121 -0
  6. package/dist/utils/index.js +15 -1
  7. package/package.json +1 -1
  8. package/src/@daf/core/components/EditForm/storyConfig2.js +1176 -728
  9. package/src/@daf/core/components/Screens/ConflictManagement/components/KeyIndicators/config.js +106 -0
  10. package/src/@daf/core/components/Screens/ConflictManagement/components/KeyIndicators/index.js +47 -0
  11. package/src/@daf/core/components/Screens/ConflictManagement/components/MineSite/helper.js +3 -0
  12. package/src/@daf/core/components/Screens/ConflictManagement/components/MineSite/index.js +218 -0
  13. package/src/@daf/core/components/Screens/ConflictManagement/components/RisksWidget/components/IncidentsTime/hook.js +32 -0
  14. package/src/@daf/core/components/Screens/ConflictManagement/components/RisksWidget/components/IncidentsTime/index.js +73 -0
  15. package/src/@daf/core/components/Screens/ConflictManagement/components/RisksWidget/components/ProblemSolver/hook.js +86 -0
  16. package/src/@daf/core/components/Screens/ConflictManagement/components/RisksWidget/components/ProblemSolver/index.js +102 -0
  17. package/src/@daf/core/components/Screens/ConflictManagement/components/RisksWidget/components/TerritorialDistribution/config.js +34 -0
  18. package/src/@daf/core/components/Screens/ConflictManagement/components/RisksWidget/components/TerritorialDistribution/index.js +107 -0
  19. package/src/@daf/core/components/Screens/ConflictManagement/components/RisksWidget/config.js +5 -0
  20. package/src/@daf/core/components/Screens/ConflictManagement/components/RisksWidget/index.js +77 -0
  21. package/src/@daf/core/components/Screens/ConflictManagement/index.js +136 -0
  22. package/src/@daf/hooks/useWidgetFetch.js +7 -0
  23. package/src/@daf/layouts/AppLayout/components/MobileDrawer/index.js +1 -1
  24. package/src/@daf/pages/Events/Testimonials/columns.js +1 -1
  25. package/src/@daf/pages/Events/columns.js +2 -3
  26. package/src/@daf/pages/Locations/columns.js +1 -1
  27. package/src/@daf/pages/Summary/hook.js +52 -19
  28. package/src/@daf/services/DashboardService.js +9 -0
  29. package/src/@daf/services/MineSiteService.js +104 -0
  30. package/src/constants/locales/en/translation.js +1 -0
  31. package/src/helpers/user.js +16 -1
  32. package/src/pages.js +4 -1
  33. package/src/services.js +2 -1
  34. package/src/utils.js +1 -1
  35. package/build/favicon.ico +0 -0
  36. package/build/logo192.png +0 -0
  37. package/build/logo512.png +0 -0
  38. package/build/manifest.json +0 -25
  39. package/build/robots.txt +0 -3
@@ -0,0 +1,106 @@
1
+ import React from "react";
2
+ import CustomIcon from "../../../../../components/Icon/CustomIcon.jsx";
3
+
4
+ const renderNumber = (number, locale = 'en') => {
5
+ return new Intl.NumberFormat(locale).format(number);
6
+ }
7
+
8
+ export const getRowConfig = ({ t, data = {}, goTo, getRedirectLink, theme = {} }) => [
9
+ {
10
+ label: (
11
+ <div className="flex">
12
+ <div className="flex-1">{t("Identified Armed Groups")}</div>
13
+ <div
14
+ className="cursor-pointer"
15
+ onClick={() => goTo(getRedirectLink("/app/armed-groups"))}
16
+ >
17
+ <CustomIcon
18
+ name="LinkNewTab"
19
+ width={16}
20
+ height={16}
21
+ color={theme.colorPrimary}
22
+ />
23
+ </div>
24
+ </div>
25
+ ),
26
+ render: () => {
27
+ return <span>{renderNumber(data.armedGroups ?? 0, "en")}</span>;
28
+ },
29
+ },
30
+ {
31
+ label: (
32
+ <div className="flex">
33
+ <div className="flex-1">{t("Reported Incidents")}</div>
34
+ <div
35
+ className="cursor-pointer"
36
+ onClick={() => goTo(getRedirectLink("/app/incident"))}
37
+ >
38
+ <CustomIcon
39
+ name="LinkNewTab"
40
+ width={16}
41
+ height={16}
42
+ color={theme.colorPrimary}
43
+ />
44
+ </div>
45
+ </div>
46
+ ),
47
+ render: () => <span>{renderNumber(data?.incidents ?? 0, "en")}</span>,
48
+ },
49
+ {
50
+ label: (
51
+ <div className="flex">
52
+ <div className="flex-1">{t("Monitored Locations")}</div>
53
+ <div
54
+ className="cursor-pointer"
55
+ onClick={() => goTo(getRedirectLink("/app/locations"))}
56
+ >
57
+ <CustomIcon
58
+ name="LinkNewTab"
59
+ width={16}
60
+ height={16}
61
+ color={theme.colorPrimary}
62
+ />
63
+ </div>
64
+ </div>
65
+ ),
66
+ render: () => <span>{renderNumber(data.locations ?? 0, "en")}</span>,
67
+ },
68
+ {
69
+ label: (
70
+ <div className="flex">
71
+ <div className="flex-1">{t("Testimonials")}</div>
72
+ <div
73
+ className="cursor-pointer"
74
+ onClick={() => goTo(getRedirectLink("/app/testimonials"))}
75
+ >
76
+ <CustomIcon
77
+ name="LinkNewTab"
78
+ width={16}
79
+ height={16}
80
+ color={theme.colorPrimary}
81
+ />
82
+ </div>
83
+ </div>
84
+ ),
85
+ render: () => <span>{renderNumber(data.testimonials ?? 0, "en")}</span>,
86
+ },
87
+ {
88
+ label: (
89
+ <div className="flex">
90
+ <div className="flex-1">{t("Information Sources")}</div>
91
+ <div
92
+ className="cursor-pointer"
93
+ onClick={() => goTo(getRedirectLink("/app/partners"))}
94
+ >
95
+ <CustomIcon
96
+ name="LinkNewTab"
97
+ width={16}
98
+ height={16}
99
+ color={theme.colorPrimary}
100
+ />
101
+ </div>
102
+ </div>
103
+ ),
104
+ render: () => <span>{renderNumber(data.partners ?? 0, "en")}</span>,
105
+ },
106
+ ];
@@ -0,0 +1,47 @@
1
+ import React, { useMemo } from "react";
2
+ import KeyIndicatorsWidget from "../../../../Dashboard/Widget/KeyIndicators/index.jsx";
3
+ import { getRowConfig } from "./config.js";
4
+ import {useWidgetFetch} from "../../../../../../hooks/useWidgetFetch.js";
5
+
6
+ export const defaultFetchConfig = {
7
+ url: "/informations",
8
+ filters: {},
9
+ basepath: "dashboard/conflict-management"
10
+ };
11
+
12
+ export default function KeyIndicators({ selectedPartners = {}, partners = 0, t = (s) => s, goTo = () => {}, getRedirectLink = (s) => s, theme = {} }) {
13
+ const fetchConfig = useMemo(
14
+ () => ({
15
+ ...defaultFetchConfig,
16
+ filters: {
17
+ sources: selectedPartners?.partners || [],
18
+ },
19
+ stop: selectedPartners?.loading,
20
+ }),
21
+ [selectedPartners],
22
+ );
23
+
24
+ const { data, loading } = useWidgetFetch({ config: fetchConfig });
25
+
26
+ const config = useMemo(
27
+ () =>
28
+ getRowConfig({
29
+ t,
30
+ data: { ...data, partners },
31
+ goTo,
32
+ getRedirectLink,
33
+ theme,
34
+ }),
35
+ [t, data, goTo, getRedirectLink, partners, theme],
36
+ );
37
+
38
+ return (
39
+ <KeyIndicatorsWidget
40
+ t={t}
41
+ config={config}
42
+ loading={loading}
43
+ title={t("Key Information")}
44
+ className="small-content"
45
+ />
46
+ );
47
+ }
@@ -0,0 +1,3 @@
1
+ const areaColors = ["#6698E4", "#B37FEB", "#FF9C6E", "#95DE64", "#FF85C0"];
2
+
3
+ export { areaColors };
@@ -0,0 +1,218 @@
1
+ import React, { useEffect, useMemo, useState } from "react";
2
+ // import { useSelector } from "react-redux";
3
+ import MineSiteMap from "../../../../Dashboard/Map/index.jsx";
4
+ import Widget from "../../../../Dashboard/Widget/index.jsx";
5
+ import { areaColors } from "./helper.js";
6
+ import {useWidgetFetch} from "../../../../../../hooks/useWidgetFetch.js";
7
+
8
+
9
+ const TERRITORY_MAP = "territory";
10
+ const EVENT_MAP = "event";
11
+
12
+ export default function MineSites({ selectedPartners = {} ,t = (s) => s,goTo = () => {},getRedirectLink = (s) => s, theme = {}, APP , options = {}, user = {}}) {
13
+
14
+ const tabs = useMemo(
15
+ () => [
16
+ { value: TERRITORY_MAP, label: t("Armed Groups") },
17
+ { value: EVENT_MAP, label: t("Incidents") },
18
+ ],
19
+ [t],
20
+ );
21
+
22
+ const [filters, setFilters] = useState({});
23
+ const [activeTab, setActiveTab] = useState(tabs[0].value);
24
+
25
+ // useEffect(() => {
26
+ // setFilters({});
27
+ // }, [activeTab]);
28
+
29
+ const defaultFetchConfig = useMemo(
30
+ () => ({
31
+ basepath: "analytics",
32
+ url: "/widgets/gps-monitoring",
33
+ filters: {
34
+ activeTab,
35
+ sources: selectedPartners?.partners || [],
36
+ ...filters,
37
+ ...(activeTab === 'event' ? { eventTypes: ['incident'] } : {})
38
+ },
39
+ defaultData: [],
40
+ stop: selectedPartners?.loading,
41
+ }),
42
+ [activeTab, selectedPartners, filters],
43
+ );
44
+
45
+ const { data, loading } = useWidgetFetch({ config: defaultFetchConfig });
46
+ // const { user } = useSelector((state) => state.authentication);
47
+
48
+ const filtersConfig = useMemo(() => {
49
+ if (activeTab === EVENT_MAP) {
50
+ return [
51
+ {
52
+ label: t("Location type"),
53
+ placeholder: t("Select"),
54
+ key: "category",
55
+ type: "select",
56
+ value: filters?.category || "all",
57
+ options: [
58
+ { label: t("All"), value: "all" },
59
+ ...(options?.locationCategories || []),
60
+ ],
61
+ },
62
+ ];
63
+ }
64
+ }, [activeTab, filters, t, options.locationCategories]);
65
+
66
+ const onFilterChange = (filters) => {
67
+ setFilters((p) => ({ ...p, ...filters }));
68
+ };
69
+
70
+ const renderTooltip = (data) => {
71
+ if (activeTab === TERRITORY_MAP) {
72
+ return [
73
+ {
74
+ label: t("Members"),
75
+ value: data.numberOfMembers || "--",
76
+ },
77
+ {
78
+ label: t("Location"),
79
+ value: data?.headquarters || "--",
80
+ },
81
+ ];
82
+ } else {
83
+ return [
84
+ {
85
+ label: t("Major Incidents"),
86
+ color: "#F04438",
87
+ value: data?.totals?.major,
88
+ },
89
+ {
90
+ label: t("Moderate Incidents"),
91
+ color: "#FF7A45",
92
+ value: data?.totals?.moderate,
93
+ },
94
+ {
95
+ label: t("Minor Incidents"),
96
+ color: "#FFC069",
97
+ value: data?.totals?.minor,
98
+ },
99
+ ];
100
+ }
101
+ };
102
+
103
+ const onClickLink = (data) => {
104
+ const sourceId = data?.authorId;
105
+ const getLink = (link) => getRedirectLink(sourceId && sourceId !== user?.company?.id ? `${link}?sourceId=${sourceId}` : link);
106
+ if (activeTab === TERRITORY_MAP) {
107
+ goTo(`/app/view/armed-groups/${data?.datastakeId}`);
108
+ } else {
109
+ switch (data?.category) {
110
+ case "mineSite":
111
+ return goTo(getLink(`/app/mine-summary/${data?.datastakeId}`));
112
+ case "area":
113
+ return goTo(getLink(`/app/view/conflict-areas/${data?.datastakeId}`));
114
+ default:
115
+ goTo(getLink(`/app/view/locations/${data?.datastakeId}`));
116
+ }
117
+ }
118
+ };
119
+
120
+ const mapData = useMemo(() => {
121
+ if (activeTab === TERRITORY_MAP) {
122
+ const safeData = Array.isArray(data) ? data : [];
123
+
124
+ if (safeData.length === 0) return [];
125
+
126
+ return safeData.map((d, index) => {
127
+ return {
128
+ ...d,
129
+ area: d?.areaOfInfluence?.areaOfInfluence || {},
130
+ gps: {
131
+ latitude: 7,
132
+ longitude: 1,
133
+ },
134
+ color: areaColors[index % areaColors.length],
135
+ };
136
+ });
137
+ } else {
138
+ const safeData = Array.isArray(data) ? data : [];
139
+
140
+ if (safeData.length === 0) return [];
141
+
142
+ const locations = {};
143
+
144
+ data.filter((d) => d?.location).forEach((d) => {
145
+ const { location, ...rest } = d;
146
+
147
+ const event = {
148
+ ...rest,
149
+ type: rest.severity ? `${rest.severity}_incident` : "",
150
+ };
151
+
152
+ if (locations[location.datastakeId]) {
153
+ locations[location.datastakeId].data.push(event);
154
+ } else {
155
+ locations[location.datastakeId] = {
156
+ gps: location.gps,
157
+ name: location.name,
158
+ datastakeId: location.datastakeId,
159
+ authorId: location?.authorId,
160
+ data: [event],
161
+ type: options.locationCategories.find((c) => c.value === location.category)
162
+ ?.label,
163
+ category: location.category,
164
+ };
165
+ }
166
+ });
167
+
168
+ return Object.values(locations).map((d) => {
169
+ const sources = [];
170
+
171
+ d.data.forEach((d) => {
172
+ if (Array.isArray(d.sources)) {
173
+ d.sources.forEach((s) => {
174
+ if (!sources.includes(s)) {
175
+ sources.push(s);
176
+ }
177
+ });
178
+ }
179
+ });
180
+
181
+ return {
182
+ ...d,
183
+ total: d.data.length || 0,
184
+ };
185
+ });
186
+ }
187
+ }, [activeTab, data.length, data, options.locationCategory, filters.type]);
188
+
189
+ const _mapData = useMemo(() => {
190
+ return mapData?.filter((d) => d?.gps)
191
+ }, [activeTab, mapData])
192
+
193
+ return (
194
+ <Widget
195
+ loading={loading}
196
+ title={t("Conflict Map")}
197
+ className="v2-widget no-px no-pb-body h-w-btn-header"
198
+ tabsConfig={{ tabs, value: activeTab, onChange: setActiveTab }}
199
+ >
200
+ <MineSiteMap
201
+ t={t}
202
+ app={APP}
203
+ showSider={false}
204
+ user={user}
205
+ data={_mapData}
206
+ mapConfig={{ maxZoom: 10 }}
207
+ primaryLink
208
+ type={activeTab}
209
+ onFilterChange={onFilterChange}
210
+ filtersConfig={activeTab === TERRITORY_MAP ? undefined : filtersConfig}
211
+ renderTooltip={renderTooltip}
212
+ onClickLink={onClickLink}
213
+ link={true}
214
+ key={activeTab}
215
+ />
216
+ </Widget>
217
+ );
218
+ }
@@ -0,0 +1,32 @@
1
+ import { useMemo, useState } from "react";
2
+
3
+ export default function useIncidentsTimeline({ t=()=>{}, options = {} }) {
4
+ const [filters, setFilters] = useState({ severity: "all" });
5
+
6
+ const filtersConfig = useMemo(
7
+ () => ({
8
+ filtersConfig: {
9
+ severity: {
10
+ type: "select",
11
+ label: "",
12
+ placeholder: (t) => t(""),
13
+ style: { flex: 1 },
14
+ labelStyle: { flex: 1 },
15
+ },
16
+ },
17
+ onApply: (val) => setFilters(val),
18
+ options: {
19
+ severity: [{ value: "all", label: t("All") }, ...(options?.severityOptions || [])],
20
+ },
21
+ selectedFilters: filters,
22
+ type: "small",
23
+ t,
24
+ }),
25
+ [t, filters, options?.severityOptions],
26
+ );
27
+
28
+ return {
29
+ filters,
30
+ filtersConfig,
31
+ };
32
+ }
@@ -0,0 +1,73 @@
1
+ import { useCallback, useMemo } from "react";
2
+ import StackChart from "../../../../../../Charts/StackChart/index.jsx";
3
+ import Widget from "../../../../../../Dashboard/Widget/index.jsx";
4
+ import PropTypes from 'prop-types';
5
+ import useIncidentsTimeline from "./hook.js";
6
+
7
+ export default function IncidentsTime({ selectedRange, selectedPartners = {} ,t=()=>{},goTo=(s)=>s,getRedirectLink=(s)=>s, theme = {}, APP , options = {}}) {
8
+ const { filters, filtersConfig } = useIncidentsTimeline({ t, options });
9
+ const { user } = useSelector((state) => state.authentication);
10
+
11
+ const getSourceParam = useCallback((sourceId) => {
12
+ if (user?.company?.id !== sourceId) {
13
+ return `?sourceId=${sourceId}`;
14
+ }
15
+
16
+ return "";
17
+ }, [user?.company?.id]);
18
+
19
+ const defaultFetchConfig = useMemo(
20
+ () => ({
21
+ url: `/incidents-timeline`,
22
+ filters: {
23
+ ...filters,
24
+ severity: filters.severity ? filters.severity : "all",
25
+ period: selectedRange,
26
+ sources: selectedPartners?.partners || [],
27
+ },
28
+ defaultData: [],
29
+ stop: selectedPartners?.loading,
30
+ }),
31
+ [filters, selectedRange, selectedPartners],
32
+ );
33
+ const renderSeverity = (val) => {
34
+ const colors = getColors("INCIDENTS", app);
35
+
36
+ switch (val) {
37
+ case "major":
38
+ return <span style={{ color: colors.major }}>{t("Major")}</span>;
39
+ case "minor":
40
+ return <span style={{ color: colors.minor }}>{t("Minor")}</span>;
41
+ case "moderate":
42
+ return <span style={{ color: colors.moderate }}>{t("Moderate")}</span>;
43
+ default:
44
+ return null;
45
+ }
46
+ };
47
+
48
+ const chartConfig = {}; const { data, loading } = useWidgetFetch(defaultFetchConfig);
49
+
50
+
51
+ return (
52
+ <Widget
53
+ loading={loading}
54
+ filtersConfig={filtersConfig}
55
+ title={t("Incidents Timeline")}
56
+ className="with-border-header"
57
+ t={t}
58
+ >
59
+ <StackChart {...chartConfig} height="400px" t={t} />
60
+ </Widget>
61
+ );
62
+ }
63
+
64
+ IncidentsTime.propTypes = {
65
+ selectedRange: PropTypes.string,
66
+ selectedPartners: PropTypes.object,
67
+ t: PropTypes.func,
68
+ goTo: PropTypes.func,
69
+ getRedirectLink: PropTypes.func,
70
+ theme: PropTypes.object,
71
+ APP: PropTypes.string,
72
+ options: PropTypes.object,
73
+ };
@@ -0,0 +1,86 @@
1
+ import { useEffect, useMemo, useState } from "react";
2
+ import DashboardService from "../../../../../../../../services/DashboardService.js";
3
+
4
+
5
+ export default function useProblemSolvers(t = () => {}) {
6
+ const [filters, setFilters] = useState({
7
+ administrativeLevel1: "all",
8
+ });
9
+
10
+ const [filterOptions, setFilterOptions] = useState([]);
11
+
12
+ useEffect(() => {
13
+ async function fetchOptions() {
14
+ try {
15
+ const { data } = await DashboardService.getWidget({
16
+ url: "/problem-solvers",
17
+ });
18
+
19
+
20
+ const rawOptions = Object.keys(data)
21
+ .map((agentKey) => {
22
+ const actions = data[agentKey]?.actions || [];
23
+
24
+ return actions
25
+ .map((action) => {
26
+ const lvl1 = action?.location?.administrativeLevel1;
27
+ const name =
28
+ action?.location?.name ||
29
+ action?.location?.administrativeLevel1 ||
30
+ null;
31
+
32
+ if (!lvl1 || !name) return undefined;
33
+
34
+ return {
35
+ label: name,
36
+ value: lvl1,
37
+ };
38
+ })
39
+ .filter(Boolean);
40
+ })
41
+ .flat();
42
+
43
+ const unique = [
44
+ ...new Map(rawOptions.map((item) => [item.value, item])).values(),
45
+ ];
46
+
47
+ setFilterOptions(unique);
48
+ } catch (err) {
49
+ console.error("Problem Solvers fetch failed:", err);
50
+ }
51
+ }
52
+
53
+ fetchOptions();
54
+ }, []);
55
+
56
+
57
+ const filtersConfig = useMemo(
58
+ () => ({
59
+ filtersConfig: {
60
+ administrativeLevel1: {
61
+ type: "select",
62
+ label: "",
63
+ placeholder: t("Select"),
64
+ style: { flex: 1 },
65
+ labelStyle: { flex: 1 },
66
+ },
67
+ },
68
+ onApply: (val) => setFilters(val),
69
+ options: {
70
+ administrativeLevel1: [
71
+ { label: t("All"), value: "all" },
72
+ ...filterOptions,
73
+ ],
74
+ },
75
+ selectedFilters: filters,
76
+ type: "small",
77
+ t,
78
+ }),
79
+ [t, filters, filterOptions]
80
+ );
81
+
82
+ return {
83
+ filters,
84
+ filtersConfig,
85
+ };
86
+ }
@@ -0,0 +1,102 @@
1
+ import React, { useMemo, useCallback } from 'react'
2
+ import PropTypes from 'prop-types';
3
+ import { renderTooltipJsx } from '../../../../../../../../utils/tooltip.js';
4
+ import Widget from '../../../../../../../../core/components/Dashboard/Widget/index.jsx';
5
+ import Chart from '../../../../../../../../core/components/Charts/PieChart/chart.jsx';
6
+ import {useWidgetFetch} from '../../../../../../../../hooks/useWidgetFetch.js';
7
+ import useProblemSolvers from './hook.js';
8
+
9
+ const distributionColors = ["#3061A8", "#6698E4", "#A6C3EF", "#D6E3F8", "#E6EEFB"];
10
+
11
+ function ProblemSolvers({ selectedPartners = {}, loading: parentLoading = false, t=()=>{}, theme = {}, selectedRange ,goTo = () => {}, getRedirectLink = () => {}}) {
12
+ const { filters, filtersConfig } = useProblemSolvers();
13
+
14
+ const defaultFetchConfig = useMemo(
15
+ () => ({
16
+ basepath: "conflict-management",
17
+ url: "/problem-solvers",
18
+ filters: {
19
+ ...filters,
20
+ period: selectedRange,
21
+ sources: selectedPartners?.partners || [],
22
+ },
23
+ defaultData: [],
24
+ stop: selectedPartners?.loading,
25
+ }),
26
+ [filters, selectedRange, selectedPartners],
27
+ );
28
+
29
+
30
+ const { data, loading } = useWidgetFetch({ config: defaultFetchConfig });
31
+
32
+ const pieData = useMemo(() => {
33
+ if (!data || Array.isArray(data)) return [];
34
+ const all = Object.keys(data);
35
+ const totalActions = all.reduce((acc, key) => acc + (data[key]?.actions?.length || 0), 0);
36
+
37
+ return all
38
+ .sort((a, b) => (data[b]?.actions?.length || 0) - (data[a]?.actions?.length || 0))
39
+ .map((key, index) => {
40
+ const item = data[key];
41
+ return {
42
+ value: item?.actions?.length,
43
+ label: item?.implementerData?.name,
44
+ implementerData: item?.implementerData,
45
+ color: distributionColors[index % distributionColors.length],
46
+ percent: totalActions ? (item?.actions?.length / totalActions) : 0,
47
+ }
48
+ });
49
+ }, [data]);
50
+
51
+ const isEmpty = !pieData.length;
52
+
53
+ const getTooltipChildren = useCallback((items) => {
54
+ const item = items[0];
55
+
56
+ return renderTooltipJsx({
57
+ title: item?.label || t("Undetermined"),
58
+ link: true,
59
+ onClickLink: () => {
60
+ goTo("/app/corrective-actions");
61
+ },
62
+ items: [
63
+ {
64
+ label: t("Number of actions"),
65
+ value: item?.value,
66
+ },
67
+ ],
68
+ });
69
+ }, [t, goTo]);
70
+
71
+ return (
72
+ <Widget
73
+ loading={loading || parentLoading}
74
+ title={t("Problem Solvers")}
75
+ filtersConfig={filtersConfig}
76
+ className="with-border-header"
77
+ >
78
+ <Chart
79
+ mouseXOffset={10}
80
+ mouseYOffset={10}
81
+ changeOpacityOnHover={false}
82
+ data={pieData}
83
+ doConstraints={false}
84
+ isPie
85
+ t={t}
86
+ isEmpty={isEmpty}
87
+ getTooltipChildren={getTooltipChildren}
88
+ />
89
+ </Widget>
90
+ );
91
+ }
92
+
93
+ ProblemSolvers.propTypes = {
94
+ selectedPartners: PropTypes.object,
95
+ loading: PropTypes.bool,
96
+ t: PropTypes.func,
97
+ theme: PropTypes.object,
98
+ selectedRange: PropTypes.string,
99
+ }
100
+
101
+ export default ProblemSolvers;
102
+
@@ -0,0 +1,34 @@
1
+
2
+ import { useMemo, useState } from "react";
3
+
4
+ export default function useTerritorialDistribution({ t = (s)=>{s}, options = {} }) {
5
+ const [filters, setFilters] = useState({ filter1: 'all', filter2: 'all' });
6
+
7
+ const filtersConfig = useMemo((t) => ({
8
+ onApply: (val) => setFilters(val),
9
+ options: {
10
+ filter1: [{ label: t('All'), value: 'all' }],
11
+ filter2: [{ label: t('All'), value: 'all' }],
12
+ },
13
+ selectedFilters: filters,
14
+ type: 'small',
15
+ t,
16
+ }), [t, filters]);
17
+
18
+ return {
19
+ filters,
20
+ filtersConfig,
21
+ setFilters,
22
+ t,
23
+ };
24
+ }
25
+
26
+ export const getColors = (theme) => {
27
+ return [
28
+ theme.colorPrimary8,
29
+ theme.colorPrimary7,
30
+ theme.colorPrimary5,
31
+ theme.colorPrimary6,
32
+ theme.colorPrimary4,
33
+ ]
34
+ }