datastake-daf 0.6.767 → 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 +1007 -730
- package/dist/layouts/index.js +495 -459
- package/dist/pages/index.js +7914 -6836
- 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/Map/ChainIcon/Markers/StakeholderMarker.js +5 -2
- package/src/@daf/core/components/Dashboard/Map/ChainIcon/index.js +67 -27
- package/src/@daf/core/components/Dashboard/Map/hook.js +26 -32
- 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/Screens/BaseScreen/index.jsx +1 -1
- package/src/@daf/core/components/Screens/TableScreen/TablePageWithTabs/index.jsx +1 -1
- package/src/@daf/core/components/Sidenav/Menu.jsx +4 -4
- package/src/@daf/core/components/UI/MissingTagButton/index.jsx +36 -0
- package/src/@daf/pages/Dashboards/SupplyChain/components/SupplyChainMap/index.js +0 -2
- package/src/@daf/pages/Documents/config.js +0 -10
- package/src/@daf/pages/Documents/index.jsx +51 -108
- package/src/@daf/pages/Events/Activities/config.js +1 -11
- package/src/@daf/pages/Events/Activities/index.jsx +47 -105
- package/src/@daf/pages/Events/Incidents/config.js +1 -11
- package/src/@daf/pages/Events/Incidents/index.jsx +47 -105
- package/src/@daf/pages/Events/config.js +18 -34
- package/src/@daf/pages/Events/index.jsx +49 -111
- package/src/@daf/pages/Locations/MineSite/config.js +0 -10
- package/src/@daf/pages/Locations/MineSite/index.jsx +47 -105
- package/src/@daf/pages/Locations/config.js +4 -16
- package/src/@daf/pages/Locations/index.jsx +53 -110
- package/src/@daf/pages/Stakeholders/Operators/config.js +0 -10
- package/src/@daf/pages/Stakeholders/Operators/index.jsx +47 -105
- package/src/@daf/pages/Stakeholders/Workers/config.js +0 -10
- package/src/@daf/pages/Stakeholders/Workers/index.jsx +47 -105
- package/src/@daf/pages/Stakeholders/config.js +3 -15
- package/src/@daf/pages/Stakeholders/index.jsx +53 -109
- 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/@daf/pages/TablePage/config.js +78 -0
- package/src/@daf/{core/components/Screens/TableScreen/TableWithTabsAndCreate → pages/TablePage}/create.jsx +6 -5
- package/src/@daf/pages/TablePage/hook.js +123 -0
- package/src/@daf/pages/TablePage/index.jsx +142 -0
- package/src/index.js +2 -0
- package/src/@daf/core/components/Screens/TableScreen/TableWithTabsAndCreate/index.jsx +0 -115
- package/src/@daf/pages/Documents/create.jsx +0 -105
- package/src/@daf/pages/Events/Activities/create.jsx +0 -104
- package/src/@daf/pages/Events/Incidents/create.jsx +0 -104
- package/src/@daf/pages/Events/create.jsx +0 -104
- package/src/@daf/pages/Locations/MineSite/create.jsx +0 -104
- package/src/@daf/pages/Locations/create.jsx +0 -104
- package/src/@daf/pages/Stakeholders/Operators/create.jsx +0 -104
- package/src/@daf/pages/Stakeholders/Workers/create.jsx +0 -104
- package/src/@daf/pages/Stakeholders/create.jsx +0 -105
package/package.json
CHANGED
|
@@ -104,6 +104,8 @@ export default function ColumnChart({
|
|
|
104
104
|
width,
|
|
105
105
|
legendConfig = {},
|
|
106
106
|
isPdf = false,
|
|
107
|
+
yAxis: customYAxis,
|
|
108
|
+
xAxis: customXAxis,
|
|
107
109
|
...rest
|
|
108
110
|
}) {
|
|
109
111
|
const containerRef = React.useRef(null);
|
|
@@ -146,6 +148,7 @@ export default function ColumnChart({
|
|
|
146
148
|
label: {
|
|
147
149
|
formatter: formattedXAxis,
|
|
148
150
|
},
|
|
151
|
+
...(customXAxis || {}),
|
|
149
152
|
},
|
|
150
153
|
yAxis: {
|
|
151
154
|
...(isPercentage
|
|
@@ -163,7 +166,12 @@ export default function ColumnChart({
|
|
|
163
166
|
(s) => `${s},`
|
|
164
167
|
) + " %"
|
|
165
168
|
: formattedYAxis,
|
|
169
|
+
...(customYAxis?.label || {}),
|
|
166
170
|
},
|
|
171
|
+
// Merge customYAxis properties (excluding label which is already merged above)
|
|
172
|
+
...(customYAxis ? Object.fromEntries(
|
|
173
|
+
Object.entries(customYAxis).filter(([key]) => key !== 'label')
|
|
174
|
+
) : {}),
|
|
167
175
|
},
|
|
168
176
|
legend: false,
|
|
169
177
|
...(showBackground && isPercentage && {
|
|
@@ -196,6 +204,8 @@ export default function ColumnChart({
|
|
|
196
204
|
color,
|
|
197
205
|
token.colorPrimary9,
|
|
198
206
|
groupField,
|
|
207
|
+
customYAxis,
|
|
208
|
+
customXAxis,
|
|
199
209
|
]);
|
|
200
210
|
|
|
201
211
|
React.useEffect(() => {
|
|
@@ -88,6 +88,8 @@ export default function LineChart({
|
|
|
88
88
|
isPdf = false,
|
|
89
89
|
legendConfig = {},
|
|
90
90
|
width,
|
|
91
|
+
yAxis: customYAxis,
|
|
92
|
+
xAxis: customXAxis,
|
|
91
93
|
...rest
|
|
92
94
|
}) {
|
|
93
95
|
const containerRef = React.useRef(null);
|
|
@@ -129,7 +131,12 @@ export default function LineChart({
|
|
|
129
131
|
style: {
|
|
130
132
|
fontSize: !autoHideXLabel ? 10 : undefined,
|
|
131
133
|
},
|
|
134
|
+
...(customXAxis?.label || {}),
|
|
132
135
|
},
|
|
136
|
+
// Merge customXAxis properties (excluding label which is already merged above)
|
|
137
|
+
...(customXAxis ? Object.fromEntries(
|
|
138
|
+
Object.entries(customXAxis).filter(([key]) => key !== 'label')
|
|
139
|
+
) : {}),
|
|
133
140
|
},
|
|
134
141
|
yAxis: {
|
|
135
142
|
...(isPercentage
|
|
@@ -143,7 +150,12 @@ export default function LineChart({
|
|
|
143
150
|
formatter: isPercentage
|
|
144
151
|
? (v) => `${v}`.replace(/\d{1,3}(?=(\d{3})+$)/g, (s) => `${s},`) + " %"
|
|
145
152
|
: formattedYAxis,
|
|
153
|
+
...(customYAxis?.label || {}),
|
|
146
154
|
},
|
|
155
|
+
// Merge customYAxis properties (excluding label which is already merged above)
|
|
156
|
+
...(customYAxis ? Object.fromEntries(
|
|
157
|
+
Object.entries(customYAxis).filter(([key]) => key !== 'label')
|
|
158
|
+
) : {}),
|
|
147
159
|
},
|
|
148
160
|
smooth: isSmooth,
|
|
149
161
|
meta: {
|
|
@@ -183,6 +195,8 @@ export default function LineChart({
|
|
|
183
195
|
tooltipConfig,
|
|
184
196
|
isPdf,
|
|
185
197
|
t,
|
|
198
|
+
customYAxis,
|
|
199
|
+
customXAxis,
|
|
186
200
|
]);
|
|
187
201
|
|
|
188
202
|
React.useEffect(() => {
|
|
@@ -90,7 +90,7 @@ export default function StakeholderIcon({
|
|
|
90
90
|
useEffect(() => {
|
|
91
91
|
linkNodesData.map((node) => {
|
|
92
92
|
const isConnectingToStakeholder = node.isStakeholder;
|
|
93
|
-
const id = `${data.datastakeId}-${node.stakeholderId}`;
|
|
93
|
+
const id = `${data.datastakeId}-${node.stakeholderId || node.datastakeId}`;
|
|
94
94
|
const targetsParentId = node.parentId;
|
|
95
95
|
const targetMarkerIndex = node.stakeholdersIndex;
|
|
96
96
|
const isSibling = targetsParentId === parentId;
|
|
@@ -234,7 +234,10 @@ export default function StakeholderIcon({
|
|
|
234
234
|
onClickLink(data);
|
|
235
235
|
},
|
|
236
236
|
})}
|
|
237
|
-
getPopupContainer={() =>
|
|
237
|
+
getPopupContainer={(triggerNode) => {
|
|
238
|
+
const mapElement = document.getElementById("map");
|
|
239
|
+
return mapElement || triggerNode.parentElement || document.body;
|
|
240
|
+
}}
|
|
238
241
|
>
|
|
239
242
|
<StakeholderMarker
|
|
240
243
|
className={`${data.type} ${
|
|
@@ -32,7 +32,8 @@ export default function LocationIcon({
|
|
|
32
32
|
activeMarker,
|
|
33
33
|
setActiveMarker,
|
|
34
34
|
}) {
|
|
35
|
-
const
|
|
35
|
+
const rootsMapRef = useRef(new Map());
|
|
36
|
+
const markersRef = useRef([])
|
|
36
37
|
const isSelected = selectedMarkersId.includes(data.datastakeId);
|
|
37
38
|
const Marker = useMemo(() => {
|
|
38
39
|
if (isMineSite(data.type)) {
|
|
@@ -75,7 +76,22 @@ export default function LocationIcon({
|
|
|
75
76
|
}, [data.stakeholders, zoom]);
|
|
76
77
|
|
|
77
78
|
useEffect(() => {
|
|
78
|
-
|
|
79
|
+
const currentRoots = rootsMapRef.current;
|
|
80
|
+
const currentMarkers = markersRef.current;
|
|
81
|
+
|
|
82
|
+
currentMarkers.forEach(marker => {
|
|
83
|
+
if (mapRef.hasLayer(marker)) {
|
|
84
|
+
mapRef.removeLayer(marker);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
currentRoots.forEach(root => {
|
|
88
|
+
root.unmount();
|
|
89
|
+
});
|
|
90
|
+
currentRoots.clear();
|
|
91
|
+
markersRef.current = [];
|
|
92
|
+
|
|
93
|
+
// Create new markers
|
|
94
|
+
stakeholdersOfLocation.forEach((stakeholder, index) => {
|
|
79
95
|
const markerId = `${stakeholder.datastakeId}`;
|
|
80
96
|
const { x, y, radius, center } = getStakeholderPosition({
|
|
81
97
|
zoom,
|
|
@@ -94,6 +110,7 @@ export default function LocationIcon({
|
|
|
94
110
|
const pathLocLatLng = mapRef.layerPointToLatLng(pathLocPoint);
|
|
95
111
|
const isForceOpen = activeMarker?.datastakeId === data.datastakeId;
|
|
96
112
|
const iconSize = isSmallMarker(zoom) || isExtraSmallMarker(zoom) ? [11, 11] : [25, 25];
|
|
113
|
+
|
|
97
114
|
const marker = L.marker(stakeholderLatLng, {
|
|
98
115
|
icon: L.divIcon({
|
|
99
116
|
html: `<div id="${markerId}"></div>`,
|
|
@@ -102,31 +119,38 @@ export default function LocationIcon({
|
|
|
102
119
|
}),
|
|
103
120
|
}).addTo(mapRef);
|
|
104
121
|
|
|
105
|
-
|
|
106
|
-
root.current = createRoot(div);
|
|
122
|
+
markersRef.current.push(marker);
|
|
107
123
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
124
|
+
setTimeout(() => {
|
|
125
|
+
const div = document.getElementById(markerId);
|
|
126
|
+
if (div && !rootsMapRef.current.has(markerId)) {
|
|
127
|
+
const root = createRoot(div);
|
|
128
|
+
rootsMapRef.current.set(markerId, root);
|
|
129
|
+
|
|
130
|
+
root.render(
|
|
131
|
+
<StakeholderIcon
|
|
132
|
+
data={stakeholder}
|
|
133
|
+
zoom={zoom}
|
|
134
|
+
allData={allData}
|
|
135
|
+
link={link}
|
|
136
|
+
parentId={data.datastakeId}
|
|
137
|
+
renderTooltip={renderTooltip}
|
|
138
|
+
onClickLink={onClickLink}
|
|
139
|
+
selectedMarkersId={selectedMarkersId}
|
|
140
|
+
handleSelectMarker={handleSelectMarker}
|
|
141
|
+
mapRef={mapRef}
|
|
142
|
+
radius={radius}
|
|
143
|
+
index={index}
|
|
144
|
+
x={x}
|
|
145
|
+
y={y}
|
|
146
|
+
openPopupIdRef={openPopupIdRef}
|
|
147
|
+
polylinesRef={polylinesRef}
|
|
148
|
+
isForceOpen={isForceOpen}
|
|
149
|
+
activeMarker={activeMarker}
|
|
150
|
+
/>,
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
}, 0);
|
|
130
154
|
|
|
131
155
|
setMapMarkers((prev) => {
|
|
132
156
|
const array = [
|
|
@@ -162,6 +186,19 @@ export default function LocationIcon({
|
|
|
162
186
|
listOfPolylines: polylinesRef.current,
|
|
163
187
|
});
|
|
164
188
|
});
|
|
189
|
+
|
|
190
|
+
return () => {
|
|
191
|
+
markersRef.current.forEach(marker => {
|
|
192
|
+
if (mapRef.hasLayer(marker)) {
|
|
193
|
+
mapRef.removeLayer(marker);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
rootsMapRef.current.forEach(root => {
|
|
197
|
+
root.unmount();
|
|
198
|
+
});
|
|
199
|
+
rootsMapRef.current.clear();
|
|
200
|
+
markersRef.current = [];
|
|
201
|
+
};
|
|
165
202
|
}, [stakeholdersOfLocation, selectedMarkersId, activeMarker]);
|
|
166
203
|
|
|
167
204
|
linkedNodesData.map((node) => {
|
|
@@ -213,7 +250,10 @@ export default function LocationIcon({
|
|
|
213
250
|
// (!openPopupIdRef.current || openPopupIdRef.current === data.datastakeId) &&
|
|
214
251
|
// isHovering
|
|
215
252
|
// }
|
|
216
|
-
getPopupContainer={() =>
|
|
253
|
+
getPopupContainer={(triggerNode) => {
|
|
254
|
+
const mapElement = document.getElementById("map");
|
|
255
|
+
return mapElement || triggerNode.parentElement || document.body;
|
|
256
|
+
}}
|
|
217
257
|
>
|
|
218
258
|
<div style={{ position: "relative", display: "inline-block" }}>
|
|
219
259
|
{(isSelected || selectedMarkersId.length === 0) && (
|
|
@@ -82,43 +82,37 @@ export const useMap = ({
|
|
|
82
82
|
const highlightTable = {};
|
|
83
83
|
|
|
84
84
|
for (const [node] of graph) {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (current !== node && isLocation(currentType)) continue;
|
|
95
|
-
|
|
96
|
-
visited.add(current);
|
|
97
|
-
|
|
98
|
-
for (const neighbor of graph.get(current)) {
|
|
99
|
-
if (!visited.has(neighbor)) queue.push(neighbor);
|
|
100
|
-
}
|
|
85
|
+
const highlighted = new Set();
|
|
86
|
+
|
|
87
|
+
highlighted.add(node);
|
|
88
|
+
|
|
89
|
+
const nodeIsStakeholder = !isLocation(nodeTypes.get(node));
|
|
90
|
+
if (nodeIsStakeholder && stakeToLoc.has(node)) {
|
|
91
|
+
const parentLoc = stakeToLoc.get(node);
|
|
92
|
+
highlighted.add(parentLoc);
|
|
101
93
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
94
|
+
|
|
95
|
+
for (const neighbor of graph.get(node) || []) {
|
|
96
|
+
const neighborIsStakeholder = !isLocation(nodeTypes.get(neighbor));
|
|
97
|
+
|
|
98
|
+
if (neighborIsStakeholder && stakeToLoc.has(neighbor)) {
|
|
99
|
+
const neighborParent = stakeToLoc.get(neighbor);
|
|
100
|
+
|
|
101
|
+
if (
|
|
102
|
+
(isLocation(nodeTypes.get(node)) && neighborParent === node) ||
|
|
103
|
+
(nodeIsStakeholder && stakeToLoc.get(node) === neighborParent)
|
|
104
|
+
) {
|
|
105
|
+
highlighted.add(neighbor);
|
|
106
|
+
} else {
|
|
107
|
+
highlighted.add(neighbor);
|
|
108
|
+
highlighted.add(neighborParent);
|
|
114
109
|
}
|
|
110
|
+
} else {
|
|
111
|
+
highlighted.add(neighbor);
|
|
115
112
|
}
|
|
116
113
|
}
|
|
117
|
-
for (const loc of extraLocs) {
|
|
118
|
-
visited.add(loc);
|
|
119
|
-
}
|
|
120
114
|
|
|
121
|
-
highlightTable[node] = [...
|
|
115
|
+
highlightTable[node] = [...highlighted];
|
|
122
116
|
}
|
|
123
117
|
|
|
124
118
|
return highlightTable;
|
|
@@ -48,6 +48,7 @@ export default function ActivityIndicatorsWidget({
|
|
|
48
48
|
}, [config, filterMode]);
|
|
49
49
|
|
|
50
50
|
const component = (
|
|
51
|
+
<section>
|
|
51
52
|
<Widget
|
|
52
53
|
loading={loading}
|
|
53
54
|
className={formatClassname(["flex-1 with-border-header h-w-btn-header no-p-body", widgetClassName])}
|
|
@@ -81,6 +82,7 @@ export default function ActivityIndicatorsWidget({
|
|
|
81
82
|
))}
|
|
82
83
|
</Style>
|
|
83
84
|
</Widget>
|
|
85
|
+
</section>
|
|
84
86
|
);
|
|
85
87
|
|
|
86
88
|
if (noMinWidth) {
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import ThemeLayout from "../../../ThemeLayout";
|
|
2
|
+
import StatCard from "./index";
|
|
3
|
+
import Widget from "../index.jsx";
|
|
4
|
+
import DashboardLayout from "../../DashboardLayout/index.jsx";
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: "Dashboard/Widgets/StatCard",
|
|
8
|
+
component: StatCard,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
decorators: [
|
|
11
|
+
(Story) => (
|
|
12
|
+
<ThemeLayout>
|
|
13
|
+
<Story />
|
|
14
|
+
</ThemeLayout>
|
|
15
|
+
),
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const Primary = {
|
|
20
|
+
name: "StatCard - With All Props",
|
|
21
|
+
args: {
|
|
22
|
+
title: "Activity Participants",
|
|
23
|
+
value: "325",
|
|
24
|
+
icon: "Users",
|
|
25
|
+
change: {
|
|
26
|
+
value: 20,
|
|
27
|
+
direction: "up",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const WithPositiveChange = {
|
|
33
|
+
name: "With Positive Change",
|
|
34
|
+
args: {
|
|
35
|
+
title: "Activity Participants",
|
|
36
|
+
value: "325",
|
|
37
|
+
icon: "Users",
|
|
38
|
+
change: {
|
|
39
|
+
value: 20,
|
|
40
|
+
direction: "up",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const WithNegativeChange = {
|
|
46
|
+
name: "With Negative Change",
|
|
47
|
+
args: {
|
|
48
|
+
title: "Total Revenue",
|
|
49
|
+
value: "$12,450",
|
|
50
|
+
icon: "Package",
|
|
51
|
+
change: {
|
|
52
|
+
value: 15,
|
|
53
|
+
direction: "down",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const WithoutChange = {
|
|
59
|
+
name: "Without Change Indicator",
|
|
60
|
+
args: {
|
|
61
|
+
title: "Total Projects",
|
|
62
|
+
value: "48",
|
|
63
|
+
icon: "Lock",
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const WithoutIcon = {
|
|
68
|
+
name: "Without Icon",
|
|
69
|
+
args: {
|
|
70
|
+
title: "Active Users",
|
|
71
|
+
value: "1,234",
|
|
72
|
+
change: {
|
|
73
|
+
value: 12,
|
|
74
|
+
direction: "up",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const CustomChangeColors = {
|
|
80
|
+
name: "Custom Change Colors",
|
|
81
|
+
args: {
|
|
82
|
+
title: "Custom Metric",
|
|
83
|
+
value: "999",
|
|
84
|
+
icon: "Package",
|
|
85
|
+
change: {
|
|
86
|
+
value: 5,
|
|
87
|
+
direction: "up",
|
|
88
|
+
color: "#E0F2FE",
|
|
89
|
+
borderColor: "#7DD3FC",
|
|
90
|
+
textColor: "#0369A1",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const MultipleCards = {
|
|
96
|
+
name: "Multiple Stat Cards",
|
|
97
|
+
render: () => (
|
|
98
|
+
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))", gap: "16px" }}>
|
|
99
|
+
<StatCard
|
|
100
|
+
title="Activity Participants"
|
|
101
|
+
value="325"
|
|
102
|
+
icon="Users"
|
|
103
|
+
change={{
|
|
104
|
+
value: 20,
|
|
105
|
+
direction: "up",
|
|
106
|
+
}}
|
|
107
|
+
/>
|
|
108
|
+
<StatCard
|
|
109
|
+
title="Total Revenue"
|
|
110
|
+
value="$12,450"
|
|
111
|
+
icon="Package"
|
|
112
|
+
change={{
|
|
113
|
+
value: 15,
|
|
114
|
+
direction: "down",
|
|
115
|
+
}}
|
|
116
|
+
/>
|
|
117
|
+
<StatCard
|
|
118
|
+
title="Total Projects"
|
|
119
|
+
value="48"
|
|
120
|
+
icon="Lock"
|
|
121
|
+
/>
|
|
122
|
+
<StatCard
|
|
123
|
+
title="Active Users"
|
|
124
|
+
value="1,234"
|
|
125
|
+
icon="User"
|
|
126
|
+
change={{
|
|
127
|
+
value: 8,
|
|
128
|
+
direction: "up",
|
|
129
|
+
}}
|
|
130
|
+
/>
|
|
131
|
+
</div>
|
|
132
|
+
),
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export const InWidget = {
|
|
136
|
+
name: "Inside Widget",
|
|
137
|
+
render: () => (
|
|
138
|
+
<Widget title="Key Statistics" className="with-border-header">
|
|
139
|
+
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))", gap: "16px" }}>
|
|
140
|
+
<StatCard
|
|
141
|
+
title="Activity Participants"
|
|
142
|
+
value="325"
|
|
143
|
+
icon="Users"
|
|
144
|
+
change={{
|
|
145
|
+
value: 20,
|
|
146
|
+
direction: "up",
|
|
147
|
+
}}
|
|
148
|
+
/>
|
|
149
|
+
<StatCard
|
|
150
|
+
title="Total Revenue"
|
|
151
|
+
value="$12,450"
|
|
152
|
+
icon="Package"
|
|
153
|
+
change={{
|
|
154
|
+
value: 15,
|
|
155
|
+
direction: "down",
|
|
156
|
+
}}
|
|
157
|
+
/>
|
|
158
|
+
<StatCard
|
|
159
|
+
title="Total Projects"
|
|
160
|
+
value="48"
|
|
161
|
+
icon="Lock"
|
|
162
|
+
/>
|
|
163
|
+
</div>
|
|
164
|
+
</Widget>
|
|
165
|
+
),
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export const InDashboard = {
|
|
169
|
+
name: "In Dashboard Layout",
|
|
170
|
+
render: () => (
|
|
171
|
+
<DashboardLayout>
|
|
172
|
+
<section>
|
|
173
|
+
<Widget>
|
|
174
|
+
<div
|
|
175
|
+
style={{
|
|
176
|
+
height: "500px",
|
|
177
|
+
backgroundColor: "#f0f0f0",
|
|
178
|
+
display: "flex",
|
|
179
|
+
alignItems: "center",
|
|
180
|
+
justifyContent: "center",
|
|
181
|
+
}}
|
|
182
|
+
>
|
|
183
|
+
Placeholder
|
|
184
|
+
</div>
|
|
185
|
+
</Widget>
|
|
186
|
+
<Widget title="Statistics Overview" className="with-border-header">
|
|
187
|
+
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))", gap: "16px" }}>
|
|
188
|
+
<StatCard
|
|
189
|
+
title="Activity Participants"
|
|
190
|
+
value="325"
|
|
191
|
+
icon="Users"
|
|
192
|
+
change={{
|
|
193
|
+
value: 20,
|
|
194
|
+
direction: "up",
|
|
195
|
+
}}
|
|
196
|
+
/>
|
|
197
|
+
<StatCard
|
|
198
|
+
title="Total Revenue"
|
|
199
|
+
value="$12,450"
|
|
200
|
+
icon="Package"
|
|
201
|
+
change={{
|
|
202
|
+
value: 15,
|
|
203
|
+
direction: "down",
|
|
204
|
+
}}
|
|
205
|
+
/>
|
|
206
|
+
<StatCard
|
|
207
|
+
title="Total Projects"
|
|
208
|
+
value="48"
|
|
209
|
+
icon="Lock"
|
|
210
|
+
/>
|
|
211
|
+
<StatCard
|
|
212
|
+
title="Active Users"
|
|
213
|
+
value="1,234"
|
|
214
|
+
icon="User"
|
|
215
|
+
change={{
|
|
216
|
+
value: 8,
|
|
217
|
+
direction: "up",
|
|
218
|
+
}}
|
|
219
|
+
/>
|
|
220
|
+
</div>
|
|
221
|
+
</Widget>
|
|
222
|
+
</section>
|
|
223
|
+
</DashboardLayout>
|
|
224
|
+
),
|
|
225
|
+
};
|
|
226
|
+
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Tooltip } from 'antd';
|
|
3
|
+
import CustomIcon from '../../../Icon/CustomIcon.jsx';
|
|
4
|
+
import Style from './style.js';
|
|
5
|
+
|
|
6
|
+
const StatCard = ({
|
|
7
|
+
title,
|
|
8
|
+
value,
|
|
9
|
+
icon,
|
|
10
|
+
iconTooltip,
|
|
11
|
+
change = null, // Object with { value, direction?, color?, borderColor?, textColor? }
|
|
12
|
+
}) => {
|
|
13
|
+
// Default colors for positive change (green)
|
|
14
|
+
const getChangeColors = () => {
|
|
15
|
+
if (!change) return {};
|
|
16
|
+
|
|
17
|
+
const isPositive = change.direction !== 'down';
|
|
18
|
+
const defaultPositive = {
|
|
19
|
+
backgroundColor: '#ECFDF3',
|
|
20
|
+
borderColor: '#A7F3D0',
|
|
21
|
+
textColor: '#52C41A',
|
|
22
|
+
};
|
|
23
|
+
const defaultNegative = {
|
|
24
|
+
backgroundColor: '#FEF3F2',
|
|
25
|
+
borderColor: '#FECACA',
|
|
26
|
+
textColor: '#D92D20',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const defaults = isPositive ? defaultPositive : defaultNegative;
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
changeColor: change.color || defaults.backgroundColor,
|
|
33
|
+
changeBorderColor: change.borderColor || defaults.borderColor,
|
|
34
|
+
changeTextColor: change.textColor || defaults.textColor,
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const changeColors = getChangeColors();
|
|
39
|
+
const isPositive = change?.direction !== 'down';
|
|
40
|
+
|
|
41
|
+
// Check if change value is 0 (handle both number and string formats like "0", "0%", "0.0%")
|
|
42
|
+
const isChangeZero = () => {
|
|
43
|
+
if (!change || !change.value) return true;
|
|
44
|
+
const valueStr = String(change.value).replace(/[%,]/g, '').trim();
|
|
45
|
+
const numValue = parseFloat(valueStr);
|
|
46
|
+
return isNaN(numValue) || numValue === 0;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const shouldShowChange = change && !isChangeZero();
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<Style {...changeColors}>
|
|
53
|
+
<div className="stat-card-header">
|
|
54
|
+
<h3 className="stat-card-title">{title}</h3>
|
|
55
|
+
{icon && (
|
|
56
|
+
<div className="stat-card-icon">
|
|
57
|
+
<CustomIcon name={icon} width={24} height={24} />
|
|
58
|
+
</div>
|
|
59
|
+
)}
|
|
60
|
+
</div>
|
|
61
|
+
<div className="stat-card-content">
|
|
62
|
+
<h2 className="stat-card-value">{value}</h2>
|
|
63
|
+
{shouldShowChange && (
|
|
64
|
+
<Tooltip
|
|
65
|
+
title={
|
|
66
|
+
change.tooltipText ||
|
|
67
|
+
(isPositive
|
|
68
|
+
? `Increased by ${change.value}`
|
|
69
|
+
: `Decreased by ${change.value}`)
|
|
70
|
+
}
|
|
71
|
+
>
|
|
72
|
+
<div className="stat-card-change">
|
|
73
|
+
<div className="change-icon">
|
|
74
|
+
{isPositive ? (
|
|
75
|
+
<>
|
|
76
|
+
<CustomIcon
|
|
77
|
+
name="Up"
|
|
78
|
+
width={10}
|
|
79
|
+
height={10}
|
|
80
|
+
color={changeColors.changeTextColor}
|
|
81
|
+
/>
|
|
82
|
+
</>
|
|
83
|
+
) : (
|
|
84
|
+
<>
|
|
85
|
+
<CustomIcon
|
|
86
|
+
name="Down"
|
|
87
|
+
width={10}
|
|
88
|
+
height={10}
|
|
89
|
+
color={changeColors.changeTextColor}
|
|
90
|
+
/>
|
|
91
|
+
</>
|
|
92
|
+
)}
|
|
93
|
+
</div>
|
|
94
|
+
<span className="change-value">{change.value}</span>
|
|
95
|
+
</div>
|
|
96
|
+
</Tooltip>
|
|
97
|
+
)}
|
|
98
|
+
</div>
|
|
99
|
+
</Style>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default StatCard;
|