datastake-daf 0.6.765 → 0.6.767
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 +482 -245
- package/dist/layouts/index.js +0 -3
- package/dist/pages/index.js +299 -241
- package/dist/services/index.js +18 -0
- package/dist/utils/index.js +328 -5
- package/package.json +4 -2
- package/src/@daf/core/components/Charts/BarChart/index.jsx +4 -0
- package/src/@daf/core/components/Dashboard/Map/ChainIcon/Markers/StakeholderMarker.js +1 -1
- package/src/@daf/core/components/Dashboard/Map/ChainIcon/index.js +1 -9
- package/src/@daf/core/components/Dashboard/Map/StakeholderIcon/index.js +3 -0
- package/src/@daf/core/components/Dashboard/Map/hook.js +31 -1
- package/src/@daf/core/components/Graphs/StakeholderMappings/index.jsx +0 -2
- package/src/@daf/core/components/Graphs/TradeRelationship/index.jsx +49 -11
- package/src/@daf/core/components/Graphs/components/BaseGraph.jsx +10 -7
- package/src/@daf/core/components/Screens/Admin/AdminDashboard/components/KeyIndicatorsWidget/config.js +2 -2
- package/src/@daf/core/components/Screens/Admin/AdminDashboard/components/KeyIndicatorsWidget/index.jsx +1 -1
- package/src/@daf/core/components/Screens/Admin/AdminDashboard/components/UserStatistics/UserActivity/helper.js +4 -1
- package/src/@daf/core/components/Screens/Admin/AdminDashboard/components/UserStatistics/UserActivity/index.jsx +5 -0
- package/src/@daf/core/components/Screens/Admin/AdminDashboard/components/UserStatistics/UserGrowth/index.jsx +1 -0
- package/src/@daf/core/components/Screens/Admin/AdminDashboard/components/UserStatistics/index.jsx +34 -26
- package/src/@daf/core/components/Screens/Admin/AdminDashboard/index.jsx +56 -52
- package/src/@daf/core/components/Screens/Admin/AdminScreens/Dashboard.jsx +52 -67
- package/src/@daf/core/components/Screens/Admin/AdminScreens/Location.jsx +96 -0
- package/src/@daf/core/components/Screens/Admin/AdminScreens/Subjects.jsx +96 -0
- package/src/@daf/core/components/Screens/Admin/AdminScreens/index.js +2 -1
- package/src/@daf/core/components/Screens/Admin/adminRoutes.js +116 -89
- package/src/@daf/core/components/Screens/TableScreen/TableWithTabsAndCreate/create.jsx +106 -0
- package/src/@daf/core/components/Screens/TableScreen/TableWithTabsAndCreate/index.jsx +115 -0
- package/src/@daf/core/components/Table/MoreTags/index.jsx +17 -5
- package/src/@daf/hooks/useMapHelper.js +5 -0
- package/src/@daf/layouts/AuthLayout/components/Navbar/index.jsx +0 -1
- package/src/@daf/pages/Dashboards/SupplyChain/components/ChartsContainer/components/Identification/hook.js +10 -10
- package/src/@daf/pages/Dashboards/SupplyChain/components/SupplyChainMap/index.js +11 -5
- package/src/@daf/pages/Dashboards/UserDashboard/components/ContributionsGraph/helper.js +1 -14
- package/src/@daf/pages/Dashboards/UserDashboard/components/ContributionsGraph/hook.js +12 -5
- package/src/@daf/pages/Dashboards/UserDashboard/components/MineSites/index.jsx +1 -1
- package/src/@daf/pages/Dashboards/UserDashboard/components/Triangulation/hook.js +1 -1
- package/src/@daf/pages/Data/Channels/columns.js +175 -0
- package/src/@daf/pages/Data/Channels/config.js +0 -0
- package/src/@daf/pages/Data/Channels/create.jsx +0 -0
- package/src/@daf/pages/Data/Channels/index.jsx +0 -0
- package/src/@daf/pages/Events/Activities/columns.js +1 -4
- package/src/@daf/pages/Events/helper.js +2 -2
- package/src/@daf/pages/Events/index.jsx +1 -1
- package/src/@daf/pages/Locations/MineSite/columns.js +6 -4
- package/src/@daf/pages/Stakeholders/Operators/columns.js +4 -2
- package/src/@daf/pages/Summary/Activities/PlantingCycle/index.jsx +1 -0
- package/src/@daf/pages/Summary/Minesite/components/StakeholderMapping/config.js +2 -2
- package/src/@daf/pages/Summary/Minesite/components/StakeholderMapping/helper.js +7 -7
- package/src/@daf/pages/Summary/Minesite/components/StakeholderMapping/index.js +3 -2
- package/src/@daf/pages/Summary/Minesite/index.jsx +3 -1
- package/src/@daf/pages/Summary/Operator/components/Governance/index.js +0 -1
- package/src/@daf/pages/Summary/Operator/components/KeyInformation/config.js +33 -21
- package/src/@daf/pages/Summary/Operator/components/TradeRelationships/helper.js +13 -13
- package/src/@daf/pages/Summary/Operator/components/TradeRelationships/hook.js +8 -8
- package/src/@daf/pages/Summary/Operator/components/TradeRelationships/index.js +10 -3
- package/src/@daf/pages/Summary/Operator/index.jsx +3 -0
- package/src/@daf/pages/Summary/components/InformationAvailability/index.js +4 -3
- package/src/@daf/services/AdminService.js +14 -0
- package/src/constants/locales/en/translation.js +109 -2
- package/src/constants/locales/fr/translation.js +109 -1
- package/src/constants/locales/sp/translation.js +104 -1
- package/src/index.js +2 -0
- package/dist/style/datastake/mapbox-gl.css +0 -330
|
@@ -21,6 +21,7 @@ function TradeRelationship({
|
|
|
21
21
|
onFilterChange = () => {},
|
|
22
22
|
renderTooltipItems = () => [],
|
|
23
23
|
getTotal = () => 0,
|
|
24
|
+
onRenderComplete = () => {},
|
|
24
25
|
}) {
|
|
25
26
|
const reactFlowWrapper = useRef(null);
|
|
26
27
|
const [nodes, setNodes] = useNodesState([]);
|
|
@@ -30,6 +31,27 @@ function TradeRelationship({
|
|
|
30
31
|
// const [initCenter, setInitCenter] = useState(true);
|
|
31
32
|
const [associatedNodes, setAssociatedNodes] = useState(null);
|
|
32
33
|
|
|
34
|
+
const isFullyRenderedRef = useRef(false);
|
|
35
|
+
const [isFullyRendered, setIsFullyRendered] = useState(false);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
isFullyRenderedRef.current = false;
|
|
39
|
+
setIsFullyRendered(false);
|
|
40
|
+
setActiveNode(null);
|
|
41
|
+
}, [data]);
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (nodes.length > 0 && edges.length > 0 && !isFullyRenderedRef.current) {
|
|
45
|
+
const timeoutId = setTimeout(() => {
|
|
46
|
+
isFullyRenderedRef.current = true;
|
|
47
|
+
setIsFullyRendered(true);
|
|
48
|
+
onRenderComplete(true);
|
|
49
|
+
}, 200);
|
|
50
|
+
|
|
51
|
+
return () => clearTimeout(timeoutId);
|
|
52
|
+
}
|
|
53
|
+
}, [nodes.length, edges.length, associatedNodes]);
|
|
54
|
+
|
|
33
55
|
useEffect(() => {
|
|
34
56
|
setActiveNode(null);
|
|
35
57
|
}, [data]);
|
|
@@ -58,7 +80,7 @@ function TradeRelationship({
|
|
|
58
80
|
[edges, activeNode, associatedNodes]
|
|
59
81
|
);
|
|
60
82
|
|
|
61
|
-
useEffect(() => {
|
|
83
|
+
useEffect(() => {
|
|
62
84
|
let yInit = 0;
|
|
63
85
|
let xInit = 0;
|
|
64
86
|
const isBilateral = data?.sources?.length >= 1;
|
|
@@ -71,10 +93,9 @@ function TradeRelationship({
|
|
|
71
93
|
setEdges([]);
|
|
72
94
|
return;
|
|
73
95
|
}
|
|
74
|
-
|
|
75
96
|
const _nodes = [
|
|
76
97
|
{
|
|
77
|
-
id: data.id,
|
|
98
|
+
id: data.id?.toString(),
|
|
78
99
|
type: "expandedNode",
|
|
79
100
|
position: {
|
|
80
101
|
x: xInit,
|
|
@@ -89,10 +110,10 @@ function TradeRelationship({
|
|
|
89
110
|
if (isBilateral) {
|
|
90
111
|
(data.sources || []).forEach((source) => {
|
|
91
112
|
const hasPrev = false;
|
|
92
|
-
|
|
113
|
+
const edge = {
|
|
93
114
|
id: `e-${data.id}-${source}`,
|
|
94
|
-
source: source,
|
|
95
|
-
type: "
|
|
115
|
+
source: source?.toString(),
|
|
116
|
+
type: "defaultEdge",
|
|
96
117
|
target: data?.id?.toString(),
|
|
97
118
|
sourceHandle: "left",
|
|
98
119
|
targetHandle: "right",
|
|
@@ -106,7 +127,8 @@ function TradeRelationship({
|
|
|
106
127
|
tooltipTitle,
|
|
107
128
|
moreLeft: false,
|
|
108
129
|
},
|
|
109
|
-
}
|
|
130
|
+
};
|
|
131
|
+
_edges.push(edge);
|
|
110
132
|
});
|
|
111
133
|
}
|
|
112
134
|
|
|
@@ -164,7 +186,7 @@ function TradeRelationship({
|
|
|
164
186
|
? false
|
|
165
187
|
: true;
|
|
166
188
|
|
|
167
|
-
|
|
189
|
+
const edge = {
|
|
168
190
|
id: `e-${ch.id}-${source}`,
|
|
169
191
|
source: hasPrev ? source : ch?.id?.toString(),
|
|
170
192
|
type: isCustom ? "verticalPath" : "defaultEdge",
|
|
@@ -182,7 +204,8 @@ function TradeRelationship({
|
|
|
182
204
|
tooltipTitle,
|
|
183
205
|
moreLeft: prevChildren.length > children.length,
|
|
184
206
|
},
|
|
185
|
-
}
|
|
207
|
+
};
|
|
208
|
+
_edges.push(edge);
|
|
186
209
|
|
|
187
210
|
if (isCustom) {
|
|
188
211
|
customIndex += 1;
|
|
@@ -230,11 +253,25 @@ function TradeRelationship({
|
|
|
230
253
|
maxHeight: 0,
|
|
231
254
|
});
|
|
232
255
|
|
|
256
|
+
// Check for potential ID mismatches
|
|
257
|
+
const nodeIds = _nodes.map(n => n.id);
|
|
258
|
+
const edgeIssues = _edges.filter(e => {
|
|
259
|
+
const sourceExists = nodeIds.includes(e.source);
|
|
260
|
+
const targetExists = nodeIds.includes(e.target);
|
|
261
|
+
return !sourceExists || !targetExists;
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Set nodes first
|
|
233
265
|
setNodes(_nodes);
|
|
234
|
-
|
|
266
|
+
|
|
267
|
+
const timeoutId = setTimeout(() => {
|
|
268
|
+
setEdges(_edges);
|
|
269
|
+
}, 100); // 100ms is imperceptible to users but ensures React Flow is ready
|
|
270
|
+
|
|
271
|
+
// Cleanup to prevent memory leaks if component unmounts quickly
|
|
272
|
+
return () => clearTimeout(timeoutId);
|
|
235
273
|
}, [data, activeNode]);
|
|
236
274
|
|
|
237
|
-
// Used to find associated nodes, when a node is selected
|
|
238
275
|
useEffect(() => {
|
|
239
276
|
if (activeNode) {
|
|
240
277
|
let _associatedNodesRight = [activeNode];
|
|
@@ -293,6 +330,7 @@ function TradeRelationship({
|
|
|
293
330
|
|
|
294
331
|
return (
|
|
295
332
|
<BaseGraph
|
|
333
|
+
key={JSON.stringify(nodes) + JSON.stringify(edges)}
|
|
296
334
|
nodes={mappedNodes}
|
|
297
335
|
edges={mappedEdges}
|
|
298
336
|
maxZoom={maxZoom}
|
|
@@ -33,7 +33,6 @@ const BaseGraph = forwardRef(function BaseGraph(
|
|
|
33
33
|
withDuration = true,
|
|
34
34
|
onFilterChange,
|
|
35
35
|
isPdf,
|
|
36
|
-
zoomOutTransition = false,
|
|
37
36
|
...props
|
|
38
37
|
},
|
|
39
38
|
ref,
|
|
@@ -50,18 +49,22 @@ const BaseGraph = forwardRef(function BaseGraph(
|
|
|
50
49
|
return result;
|
|
51
50
|
}, [nodes.length, mandatoryNodesToFit?.length, mandatoryNodesToFit]);
|
|
52
51
|
|
|
52
|
+
// In BaseGraph.jsx, replace the useEffect with:
|
|
53
53
|
useEffect(() => {
|
|
54
54
|
if (nodesToFit.length === 0) return;
|
|
55
55
|
|
|
56
|
-
requestAnimationFrame
|
|
56
|
+
// Use setTimeout instead of requestAnimationFrame to ensure nodes are rendered
|
|
57
|
+
const timer = setTimeout(() => {
|
|
57
58
|
fitView({
|
|
58
59
|
padding: 0.4,
|
|
59
60
|
nodes: [...nodesToFit],
|
|
60
|
-
duration: withDuration ? 300 : undefined,
|
|
61
|
-
maxZoom: 0.
|
|
61
|
+
// duration: withDuration ? 300 : undefined,
|
|
62
|
+
maxZoom: 0.9,
|
|
62
63
|
});
|
|
63
|
-
});
|
|
64
|
-
|
|
64
|
+
}, 100); // Small delay to ensure nodes are rendered
|
|
65
|
+
|
|
66
|
+
return () => clearTimeout(timer);
|
|
67
|
+
}, [nodesToFit.length, nodesToFit.map(n => `${n.id}-${n.width}-${n.height}`).join(','), withDuration]);
|
|
65
68
|
|
|
66
69
|
return (
|
|
67
70
|
<ComponentWithFocus>
|
|
@@ -87,7 +90,7 @@ const BaseGraph = forwardRef(function BaseGraph(
|
|
|
87
90
|
fitView={true} // zoom out on default
|
|
88
91
|
fitViewOptions={{
|
|
89
92
|
padding: 0.2, //zoom out on default
|
|
90
|
-
|
|
93
|
+
duration: withDuration ? 300 : undefined,
|
|
91
94
|
}}
|
|
92
95
|
{...props}
|
|
93
96
|
>
|
|
@@ -8,7 +8,7 @@ export function getConfig(data, goTo, t) {
|
|
|
8
8
|
return {
|
|
9
9
|
label: (
|
|
10
10
|
<div className="flex">
|
|
11
|
-
<div className="flex-1">{t(
|
|
11
|
+
<div className="flex-1">{t(`${item.title}`)}</div>
|
|
12
12
|
<div className="cursor-pointer" onClick={() => goTo(item.goToPath)}>
|
|
13
13
|
<CustomIcon name="LinkNewTab" width={16} height={16} color={iconColor} />
|
|
14
14
|
</div>
|
|
@@ -17,4 +17,4 @@ export function getConfig(data, goTo, t) {
|
|
|
17
17
|
render: () => <span>{renderNumber(item.valueToShow)}</span>,
|
|
18
18
|
};
|
|
19
19
|
});
|
|
20
|
-
}
|
|
20
|
+
}
|
|
@@ -53,6 +53,9 @@ export const getColor = (users, items) => {
|
|
|
53
53
|
|
|
54
54
|
export function useConfig(data) {
|
|
55
55
|
const config = useMemo(() => {
|
|
56
|
+
// Ensure data is an array to prevent "data.find is not a function" error
|
|
57
|
+
const safeData = Array.isArray(data) ? data : [];
|
|
58
|
+
|
|
56
59
|
const start = moment().add(-1, "years").format("MMM YY");
|
|
57
60
|
let now = moment(start, "MMM YY");
|
|
58
61
|
const _config = [];
|
|
@@ -65,7 +68,7 @@ export function useConfig(data) {
|
|
|
65
68
|
while (true) {
|
|
66
69
|
DAYS.forEach((d) => {
|
|
67
70
|
if (d === nowMonth.format("dd") && now.format("MMM YY") === nowMonth.format("MMM YY")) {
|
|
68
|
-
const users =
|
|
71
|
+
const users = safeData.find((d) => d._id === nowMonth.format("YYYY-MM-DD"))?.count || 0;
|
|
69
72
|
conf.push({ date: nowMonth.format("DD MMM YY"), active: true, users: users });
|
|
70
73
|
nowMonth.add(1, "days");
|
|
71
74
|
} else {
|
|
@@ -10,8 +10,13 @@ const DAYS = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
|
|
|
10
10
|
|
|
11
11
|
export default function UserActivity({ loading, data = [], t }) {
|
|
12
12
|
const config = useConfig(data);
|
|
13
|
+
|
|
13
14
|
const { isCollapsed } = useResizeContext();
|
|
14
15
|
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
// console.log("userActivityyyyy",data);
|
|
19
|
+
|
|
15
20
|
return (
|
|
16
21
|
<Widget
|
|
17
22
|
title={t(`admin::user-activity`)}
|
package/src/@daf/core/components/Screens/Admin/AdminDashboard/components/UserStatistics/index.jsx
CHANGED
|
@@ -4,32 +4,40 @@ import TopContributors from "./TopContributors/index.jsx";
|
|
|
4
4
|
import Widget from "../../../../../Dashboard/Widget/index.jsx";
|
|
5
5
|
|
|
6
6
|
export default function UserStatistics({
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
fetchUserGrowth,
|
|
8
|
+
loading,
|
|
9
|
+
loadingUserGrowth,
|
|
10
|
+
data,
|
|
11
|
+
t,
|
|
12
|
+
translationKeys,
|
|
13
13
|
}) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<UserActivity loading={loading} data={data.userActivityData} t={t} />
|
|
14
|
+
// console.log("UserStatistics:loading", loading);
|
|
15
|
+
// console.log("UserStatistics:loadingUserGrowth", loadingUserGrowth);
|
|
16
|
+
// console.log("UserStatistics:data", data);
|
|
17
|
+
// console.log("UserStatistics:userActivityData", data?.userActivityData);
|
|
18
|
+
// console.log("UserStatistics:topContributorsData", data?.topContributorsData);
|
|
19
|
+
// console.log("UserStatistics:userGrowthData", data?.userGrowthData);
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Widget
|
|
24
|
+
title={t(`${translationKeys}-admin::usage-statistics`)}
|
|
25
|
+
className="with-border-header"
|
|
26
|
+
>
|
|
27
|
+
<div className="flex flex-column gap-6">
|
|
28
|
+
<UserActivity loading={loading} data={data.userActivityData || []} t={t} />
|
|
29
|
+
|
|
30
|
+
<div className="flex flex-row flex-col-mobile gap-6">
|
|
31
|
+
<TopContributors data={data.topContributorsData || []} loading={loading} t={t} />
|
|
32
|
+
<UserGrowth
|
|
33
|
+
t={t}
|
|
34
|
+
loading={loadingUserGrowth}
|
|
35
|
+
data={data.userGrowthData || []}
|
|
36
|
+
fetchUserGrowth={fetchUserGrowth}
|
|
37
|
+
translationKeys={translationKeys}
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</Widget>
|
|
42
|
+
);
|
|
35
43
|
}
|
|
@@ -5,60 +5,64 @@ import KeyIndicatorsWidget from "./components/KeyIndicatorsWidget/index.jsx";
|
|
|
5
5
|
import UserStatistics from "./components/UserStatistics/index.jsx";
|
|
6
6
|
|
|
7
7
|
export default function AdminDashboard({
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
actionWidgetConfig,
|
|
9
|
+
loading,
|
|
10
|
+
data,
|
|
11
|
+
goTo,
|
|
12
|
+
adminTranslationIdentifier,
|
|
13
|
+
t,
|
|
14
|
+
loadingUserGrowth,
|
|
15
|
+
fetchUserGrowth = () => {},
|
|
16
|
+
userGrowthData,
|
|
16
17
|
}) {
|
|
17
|
-
|
|
18
|
+
const keyIndicatorsCards = Array.isArray(data?.keyIndicatorsData)
|
|
19
|
+
? data.keyIndicatorsData
|
|
20
|
+
: [];
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
<div className="daf-analysis admin-dashboard">
|
|
21
|
-
<Header title={t(`${adminTranslationIdentifier}::dashboard`)} />
|
|
22
|
-
<div className="content">
|
|
23
|
-
<div className="view-content">
|
|
24
|
-
<div className="daf-analysis-layout">
|
|
25
|
-
<div className="sections-cont w-pt">
|
|
26
|
-
<section>
|
|
27
|
-
{actionWidgetConfig.map((widgetConfig) => {
|
|
28
|
-
return (
|
|
29
|
-
<ActionWidget
|
|
30
|
-
key={widgetConfig.title}
|
|
31
|
-
{...widgetConfig}
|
|
32
|
-
onClick={() => goTo(widgetConfig.goToPath)}
|
|
33
|
-
title={t(`admin::${widgetConfig.title}`)}
|
|
34
|
-
/>
|
|
35
|
-
);
|
|
36
|
-
})}
|
|
37
|
-
</section>
|
|
22
|
+
console.log("AdminDashboard:data", data);
|
|
38
23
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
24
|
+
return (
|
|
25
|
+
<div className="daf-analysis admin-dashboard">
|
|
26
|
+
<Header title={t(`${adminTranslationIdentifier}::dashboard`)} />
|
|
27
|
+
<div className="content">
|
|
28
|
+
<div className="view-content">
|
|
29
|
+
<div className="daf-analysis-layout">
|
|
30
|
+
<div className="sections-cont w-pt">
|
|
31
|
+
<section>
|
|
32
|
+
{actionWidgetConfig.map((widgetConfig) => (
|
|
33
|
+
<ActionWidget
|
|
34
|
+
key={widgetConfig.title}
|
|
35
|
+
{...widgetConfig}
|
|
36
|
+
onClick={() => goTo(widgetConfig.goToPath)}
|
|
37
|
+
title={t(`${widgetConfig.title}`)}
|
|
38
|
+
/>
|
|
39
|
+
))}
|
|
40
|
+
</section>
|
|
47
41
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
42
|
+
<section>
|
|
43
|
+
<KeyIndicatorsWidget
|
|
44
|
+
data={keyIndicatorsCards}
|
|
45
|
+
loading={loading}
|
|
46
|
+
goTo={goTo}
|
|
47
|
+
t={t}
|
|
48
|
+
/>
|
|
49
|
+
</section>
|
|
50
|
+
|
|
51
|
+
<section>
|
|
52
|
+
<UserStatistics
|
|
53
|
+
data={{ ...data }}
|
|
54
|
+
userGrowthData={userGrowthData}
|
|
55
|
+
loading={loading}
|
|
56
|
+
t={t}
|
|
57
|
+
loadingUserGrowth={loadingUserGrowth}
|
|
58
|
+
fetchUserGrowth={fetchUserGrowth}
|
|
59
|
+
translationKeys={adminTranslationIdentifier}
|
|
60
|
+
/>
|
|
61
|
+
</section>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
64
68
|
}
|
|
@@ -1,77 +1,62 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
2
|
import AdminDashboard from "../AdminDashboard/index.jsx";
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Admin Dashboard Screen Wrapper
|
|
6
|
-
* This is a ready-to-use route component that can be configured per application
|
|
7
|
-
*
|
|
8
|
-
* @param {Object} config - Application configuration
|
|
9
|
-
* @param {string} config.appName - Application name for translations (e.g., "wazi", "tazama")
|
|
10
|
-
* @param {Function} config.goTo - Navigation function (useNavigate)
|
|
11
|
-
* @param {Function} config.t - Translation function (useTranslation)
|
|
12
|
-
* @param {Function} config.getRedirectLink - Function to get redirect links
|
|
13
|
-
* @param {Function} config.getActionWidgetsConfig - Function that returns action widgets config
|
|
14
|
-
* @param {Function} config.getKeyIndicatorsConfig - Function that returns key indicators config
|
|
15
|
-
* @param {Function} config.useWidgetFetch - Hook to fetch dashboard data
|
|
16
|
-
*/
|
|
17
4
|
export default function AdminDashboardScreen({ config }) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
5
|
+
const {
|
|
6
|
+
appName = "app",
|
|
7
|
+
goTo,
|
|
8
|
+
t,
|
|
9
|
+
getRedirectLink,
|
|
10
|
+
getActionWidgetsConfig,
|
|
11
|
+
getKeyIndicatorsConfig,
|
|
12
|
+
useWidgetFetch,
|
|
13
|
+
} = config;
|
|
27
14
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
15
|
+
const {
|
|
16
|
+
data,
|
|
17
|
+
loading,
|
|
18
|
+
userGrowthData,
|
|
19
|
+
fetchUserGrowth,
|
|
20
|
+
userGrowthDataLoading,
|
|
21
|
+
} = useWidgetFetch();
|
|
35
22
|
|
|
36
|
-
|
|
37
|
-
() => getActionWidgetsConfig({ getRedirectLink }),
|
|
38
|
-
[getRedirectLink]
|
|
39
|
-
);
|
|
23
|
+
console.log({userGrowthData});
|
|
40
24
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
keyIndicatorsData: data?.keyInformation,
|
|
46
|
-
}),
|
|
47
|
-
[data?.keyInformation, getRedirectLink]
|
|
48
|
-
);
|
|
25
|
+
const actionsWidgetsConfig = useMemo(
|
|
26
|
+
() => getActionWidgetsConfig({ getRedirectLink }),
|
|
27
|
+
[getRedirectLink, getActionWidgetsConfig]
|
|
28
|
+
);
|
|
49
29
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
30
|
+
const keyIndicatorsConfig = useMemo(
|
|
31
|
+
() =>
|
|
32
|
+
getKeyIndicatorsConfig({
|
|
33
|
+
getRedirectLink,
|
|
34
|
+
keyIndicators: data?.keyIndicators ?? data?.keyInformation,
|
|
35
|
+
}),
|
|
36
|
+
[data?.keyIndicators, data?.keyInformation, getRedirectLink, getKeyIndicatorsConfig]
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const safeUserActivity = Array.isArray(data?.data?.userActivity) ? data.data.userActivity : [];
|
|
40
|
+
const safeTopContributors = Array.isArray(data?.topContributors) ? data.topContributors : [];
|
|
41
|
+
const safeUserGrowth = Array.isArray(data?.userGrowthData) ? data.userGrowthData : [];
|
|
58
42
|
|
|
59
|
-
return (
|
|
60
|
-
<AdminDashboard
|
|
61
|
-
t={t}
|
|
62
|
-
loading={loading}
|
|
63
|
-
goTo={goTo}
|
|
64
|
-
actionWidgetConfig={actionsWidgetsConfig}
|
|
65
|
-
loadingUserGrowth={userGrowthDataLoading}
|
|
66
|
-
fetchUserGrowth={fetchUserGrowth}
|
|
67
|
-
data={{
|
|
68
|
-
keyIndicatorsData: keyIndicatorsConfig,
|
|
69
|
-
userActivityData: data?.userActivity,
|
|
70
|
-
topContributorsData: data?.topContributors || TOTAL_DUMMY,
|
|
71
|
-
userGrowthData: userGrowthData,
|
|
72
|
-
}}
|
|
73
|
-
adminTranslationIdentifier={appName}
|
|
74
|
-
/>
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
43
|
|
|
44
|
+
return (
|
|
45
|
+
<AdminDashboard
|
|
46
|
+
t={t}
|
|
47
|
+
goTo={goTo}
|
|
48
|
+
loading={loading}
|
|
49
|
+
actionWidgetConfig={actionsWidgetsConfig}
|
|
50
|
+
loadingUserGrowth={userGrowthDataLoading}
|
|
51
|
+
fetchUserGrowth={fetchUserGrowth}
|
|
52
|
+
adminTranslationIdentifier={appName}
|
|
53
|
+
data={{
|
|
54
|
+
keyIndicatorsData: keyIndicatorsConfig,
|
|
55
|
+
userActivityData: safeUserActivity,
|
|
56
|
+
topContributorsData: safeTopContributors,
|
|
57
|
+
userGrowthData: safeUserGrowth,
|
|
58
|
+
data: data,
|
|
59
|
+
}}
|
|
60
|
+
/>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React, { useCallback } from "react";
|
|
2
|
+
import { message } from "antd";
|
|
3
|
+
import LocationTable from "../AdminTables/LocationTable/index.jsx";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Admin Location Screen Wrapper
|
|
7
|
+
* This is a ready-to-use route component that can be configured per application
|
|
8
|
+
*
|
|
9
|
+
* @param {Object} config - Application configuration
|
|
10
|
+
* @param {string} config.appName - Application name
|
|
11
|
+
* @param {string} config.module - Module identifier (APP constant)
|
|
12
|
+
* @param {Function} config.goTo - Navigation function
|
|
13
|
+
* @param {Function} config.t - Translation function
|
|
14
|
+
* @param {Object} config.location - Router location object
|
|
15
|
+
* @param {boolean} config.isMobile - Is mobile viewport
|
|
16
|
+
* @param {Function} config.getRedirectLink - Function to get redirect links
|
|
17
|
+
* @param {Object} config.AdminService - Admin service with methods
|
|
18
|
+
* @param {Object} config.options - Options object with categories, countries, etc.
|
|
19
|
+
* @param {Function} config.handleError - Error handling function
|
|
20
|
+
* @param {number} config.defaultPageSize - Default pagination page size
|
|
21
|
+
* @param {string} config.view - View identifier
|
|
22
|
+
* @param {string} config.headerTitle - Header title for the table
|
|
23
|
+
* @param {Array} config.breadcrumbs - Breadcrumbs configuration
|
|
24
|
+
* @param {any} config.refetchTrigger - Trigger to refetch data
|
|
25
|
+
* @param {Function} config.getData - Optional custom getData function
|
|
26
|
+
*/
|
|
27
|
+
export default function AdminLocationScreen({ config }) {
|
|
28
|
+
const {
|
|
29
|
+
appName = "app",
|
|
30
|
+
module,
|
|
31
|
+
goTo,
|
|
32
|
+
t,
|
|
33
|
+
location,
|
|
34
|
+
isMobile,
|
|
35
|
+
getRedirectLink,
|
|
36
|
+
AdminService,
|
|
37
|
+
options,
|
|
38
|
+
handleError,
|
|
39
|
+
defaultPageSize = 20,
|
|
40
|
+
view,
|
|
41
|
+
headerTitle = "location",
|
|
42
|
+
breadcrumbs,
|
|
43
|
+
refetchTrigger,
|
|
44
|
+
getData
|
|
45
|
+
} = config;
|
|
46
|
+
|
|
47
|
+
const handleMergeLocations = useCallback(
|
|
48
|
+
async (mergeData) => {
|
|
49
|
+
try {
|
|
50
|
+
if (AdminService.mergeLocations) {
|
|
51
|
+
await AdminService.mergeLocations(mergeData);
|
|
52
|
+
message.success(t("Locations merged successfully"));
|
|
53
|
+
} else {
|
|
54
|
+
console.warn("AdminService.mergeLocations is not implemented");
|
|
55
|
+
message.success(t("Locations merged successfully"));
|
|
56
|
+
}
|
|
57
|
+
} catch (err) {
|
|
58
|
+
handleError?.(err);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
[AdminService, t, handleError]
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Use custom getData if provided, otherwise use default AdminService.getLocations
|
|
65
|
+
const getLocations = useCallback((params) => {
|
|
66
|
+
if (getData) {
|
|
67
|
+
return getData(params);
|
|
68
|
+
}
|
|
69
|
+
return AdminService.getLocations(params);
|
|
70
|
+
}, [getData, AdminService]);
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<LocationTable
|
|
74
|
+
t={t}
|
|
75
|
+
goTo={goTo}
|
|
76
|
+
getRedirectLink={getRedirectLink}
|
|
77
|
+
location={location}
|
|
78
|
+
module={module}
|
|
79
|
+
headerTitle={headerTitle}
|
|
80
|
+
getData={getLocations}
|
|
81
|
+
isMobile={isMobile}
|
|
82
|
+
defaultPageSize={defaultPageSize}
|
|
83
|
+
view={view}
|
|
84
|
+
breadcrumbs={breadcrumbs}
|
|
85
|
+
mergeSubjectsFunction={handleMergeLocations}
|
|
86
|
+
refetchTrigger={refetchTrigger}
|
|
87
|
+
config={{
|
|
88
|
+
options: {
|
|
89
|
+
category: options?.category,
|
|
90
|
+
countries: options?.countries,
|
|
91
|
+
},
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|