datastake-daf 0.6.745 → 0.6.747

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 (91) hide show
  1. package/build/favicon.ico +0 -0
  2. package/build/logo192.png +0 -0
  3. package/build/logo512.png +0 -0
  4. package/build/manifest.json +25 -0
  5. package/build/robots.txt +3 -0
  6. package/dist/components/index.js +71 -7
  7. package/dist/hooks/index.js +2 -2
  8. package/dist/pages/index.css +1 -0
  9. package/dist/pages/index.js +5924 -32
  10. package/dist/services/index.js +23 -1
  11. package/package.json +1 -1
  12. package/src/@daf/core/components/Dashboard/Widget/ImageCarousel/index.jsx +75 -54
  13. package/src/@daf/core/components/Dashboard/Widget/ImageCarousel/style.js +44 -0
  14. package/src/@daf/core/components/Screens/TableScreen/TablePageWithTabs/index.jsx +128 -0
  15. package/src/@daf/{pages/pages → core/components/TableScreen}/TablePageWithTabs/index.jsx +3 -3
  16. package/src/@daf/hooks/useSources.js +1 -1
  17. package/src/@daf/pages/Documents/index.jsx +1 -1
  18. package/src/@daf/pages/Events/Activities/index.jsx +1 -1
  19. package/src/@daf/pages/Events/Incidents/index.jsx +1 -1
  20. package/src/@daf/pages/Events/index.jsx +1 -1
  21. package/src/@daf/pages/Locations/MineSite/index.jsx +1 -1
  22. package/src/@daf/pages/Locations/index.jsx +1 -1
  23. package/src/@daf/pages/Stakeholders/Operators/index.jsx +1 -1
  24. package/src/@daf/pages/Stakeholders/Workers/index.jsx +1 -1
  25. package/src/@daf/pages/Stakeholders/index.jsx +1 -1
  26. package/src/@daf/pages/Summary/Activities/Restoration/config.js +36 -0
  27. package/src/@daf/pages/Summary/Activities/Restoration/helper.js +98 -0
  28. package/src/@daf/pages/Summary/Activities/Restoration/index.jsx +178 -0
  29. package/src/@daf/pages/Summary/Minesite/components/LocationMap/index.js +61 -0
  30. package/src/@daf/pages/Summary/Minesite/components/MineSiteDetails/config.js +77 -0
  31. package/src/@daf/pages/Summary/Minesite/components/MineSiteDetails/index.js +47 -0
  32. package/src/@daf/pages/Summary/Minesite/components/StakeholderMapping/config.js +26 -0
  33. package/src/@daf/pages/Summary/Minesite/components/StakeholderMapping/helper.js +64 -0
  34. package/src/@daf/pages/Summary/Minesite/components/StakeholderMapping/index.js +56 -0
  35. package/src/@daf/pages/Summary/Minesite/index.jsx +162 -0
  36. package/src/@daf/pages/Summary/Operator/components/Governance/config.js +26 -0
  37. package/src/@daf/pages/Summary/Operator/components/Governance/helper.js +61 -0
  38. package/src/@daf/pages/Summary/Operator/components/Governance/index.js +55 -0
  39. package/src/@daf/pages/Summary/Operator/components/KeyInformation/config.js +84 -0
  40. package/src/@daf/pages/Summary/Operator/components/KeyInformation/index.js +46 -0
  41. package/src/@daf/pages/Summary/Operator/components/TradeRelationships/config.js +40 -0
  42. package/src/@daf/pages/Summary/Operator/components/TradeRelationships/helper.js +98 -0
  43. package/src/@daf/pages/Summary/Operator/components/TradeRelationships/hook.js +160 -0
  44. package/src/@daf/pages/Summary/Operator/components/TradeRelationships/index.js +83 -0
  45. package/src/@daf/pages/Summary/Operator/hook.js +176 -0
  46. package/src/@daf/pages/Summary/Operator/index.jsx +170 -0
  47. package/src/@daf/pages/Summary/components/InformationAvailability/components/Contributions/index.js +36 -0
  48. package/src/@daf/pages/Summary/components/InformationAvailability/components/InformationCompleteness/index.js +58 -0
  49. package/src/@daf/pages/Summary/components/InformationAvailability/index.js +42 -0
  50. package/src/@daf/pages/Summary/hook.js +188 -0
  51. package/src/@daf/services/OperatorService.js +16 -0
  52. package/src/@daf/services/SourceService.js +1 -1
  53. package/src/helpers/StringHelper.js +7 -0
  54. package/src/pages.js +6 -4
  55. package/src/@daf/pages/Events/Incidents2/columns.js +0 -176
  56. package/src/@daf/pages/Events/Incidents2/config.js +0 -170
  57. package/src/@daf/pages/Events/Incidents2/create.jsx +0 -104
  58. package/src/@daf/pages/Events/Incidents2/index.jsx +0 -156
  59. /package/src/@daf/pages/{dashboards → Dashboards}/SupplyChain/components/ChartsContainer/components/GenderDistribution/config.js +0 -0
  60. /package/src/@daf/pages/{dashboards → Dashboards}/SupplyChain/components/ChartsContainer/components/GenderDistribution/index.js +0 -0
  61. /package/src/@daf/pages/{dashboards → Dashboards}/SupplyChain/components/ChartsContainer/components/Identification/hook.js +0 -0
  62. /package/src/@daf/pages/{dashboards → Dashboards}/SupplyChain/components/ChartsContainer/components/Identification/index.js +0 -0
  63. /package/src/@daf/pages/{dashboards → Dashboards}/SupplyChain/components/ChartsContainer/components/Locations/config.js +0 -0
  64. /package/src/@daf/pages/{dashboards → Dashboards}/SupplyChain/components/ChartsContainer/components/Locations/index.js +0 -0
  65. /package/src/@daf/pages/{dashboards → Dashboards}/SupplyChain/components/ChartsContainer/index.js +0 -0
  66. /package/src/@daf/pages/{dashboards → Dashboards}/SupplyChain/components/KeyIndicators/config.js +0 -0
  67. /package/src/@daf/pages/{dashboards → Dashboards}/SupplyChain/components/KeyIndicators/index.js +0 -0
  68. /package/src/@daf/pages/{dashboards → Dashboards}/SupplyChain/components/SupplyChainMap/index.js +0 -0
  69. /package/src/@daf/pages/{dashboards → Dashboards}/SupplyChain/components/TradeRelationships/index.js +0 -0
  70. /package/src/@daf/pages/{dashboards → Dashboards}/SupplyChain/config.js +0 -0
  71. /package/src/@daf/pages/{dashboards → Dashboards}/SupplyChain/index.jsx +0 -0
  72. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/AccumulationGraph/hook.js +0 -0
  73. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/AccumulationGraph/index.jsx +0 -0
  74. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/ContributionsGraph/helper.js +0 -0
  75. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/ContributionsGraph/hook.js +0 -0
  76. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/ContributionsGraph/index.jsx +0 -0
  77. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/CustomSegment/index.jsx +0 -0
  78. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/DataChainOfCustody/index.jsx +0 -0
  79. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/DataCompilation/index.jsx +0 -0
  80. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/DataConsilidation/index.jsx +0 -0
  81. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/KeyIndicators/config.js +0 -0
  82. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/KeyIndicators/index.jsx +0 -0
  83. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/MineSites/config.js +0 -0
  84. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/MineSites/helper.js +0 -0
  85. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/MineSites/index.jsx +0 -0
  86. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/Triangulation/config.js +0 -0
  87. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/Triangulation/hook.js +0 -0
  88. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/components/Triangulation/index.jsx +0 -0
  89. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/config.js +0 -0
  90. /package/src/@daf/pages/{dashboards → Dashboards}/UserDashboard/index.jsx +0 -0
  91. /package/src/@daf/pages/{dashboards → Dashboards}/helper.js +0 -0
@@ -1188,7 +1188,7 @@ class SourceService extends BaseService {
1188
1188
  id
1189
1189
  }) {
1190
1190
  return this.apiGet({
1191
- url: `/${type}/sources-for-subject/${id}`
1191
+ url: `/${type}/sources/${id}`
1192
1192
  });
1193
1193
  }
1194
1194
  }
@@ -1435,8 +1435,30 @@ var LinkedSubjects = createLazyService(LinkedSubjectsService);
1435
1435
 
1436
1436
  class OperatorService extends BaseService {
1437
1437
  get(params) {
1438
+ const {
1439
+ datastakeId,
1440
+ ...rest
1441
+ } = params;
1442
+ if (datastakeId) {
1443
+ return this.apiGet({
1444
+ url: `/stakeholder/${datastakeId}`,
1445
+ params: {
1446
+ ...rest
1447
+ },
1448
+ isApp: true
1449
+ });
1450
+ }
1438
1451
  return this.apiGet({
1439
1452
  url: "/stakeholder",
1453
+ params: {
1454
+ ...rest
1455
+ },
1456
+ isApp: true
1457
+ });
1458
+ }
1459
+ getOne(id, params) {
1460
+ return this.apiGet({
1461
+ url: `/stakeholder/${id}`,
1440
1462
  params,
1441
1463
  isApp: true
1442
1464
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datastake-daf",
3
- "version": "0.6.745",
3
+ "version": "0.6.747",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^5.2.5",
6
6
  "@antv/g2": "^5.1.1",
@@ -1,9 +1,9 @@
1
1
  import React, { useState, useRef } from "react";
2
2
  import CarouselWidget from "../CarouselWidget/index.jsx";
3
- import { Image, Carousel } from "antd";
3
+ import { Image, Carousel, Empty } from "antd";
4
4
  import { LeftOutlined, RightOutlined } from "@ant-design/icons";
5
5
  import CustomArrowButton from "./components/CustomArrowButton/index.js";
6
- import { StyledCarouselWrapper } from "./style.js";
6
+ import { StyledCarouselWrapper, EmptyStateContainer } from "./style.js";
7
7
  import PropTypes from "prop-types";
8
8
 
9
9
  /**
@@ -45,6 +45,8 @@ import PropTypes from "prop-types";
45
45
  * @param {string} [props.arrowIconColor="#666"] - Default color of arrow icons
46
46
  * @param {string} [props.arrowHoverIconColor="#1890ff"] - Color of arrow icons on hover
47
47
  * @param {boolean} [props.customArrows=false] - Whether to show custom navigation arrows
48
+ * @param {ReactNode} [props.emptyLogo] - Custom logo/icon for empty state (defaults to Ant Design simple empty icon)
49
+ * @param {string|ReactNode} [props.emptyText="No Image"] - Custom text for empty state
48
50
  * @param {Object} [props.rest] - Additional props passed to the underlying CarouselWidget component
49
51
  *
50
52
  * @features
@@ -74,6 +76,8 @@ function ImageCarousel({
74
76
  arrowIconColor = "#666",
75
77
  arrowHoverIconColor = "#1890ff",
76
78
  customArrows = false,
79
+ emptyLogo = Empty.PRESENTED_IMAGE_SIMPLE,
80
+ emptyText = "No Image",
77
81
  ...rest
78
82
  }) {
79
83
  const [previewVisible, setPreviewVisible] = useState(false);
@@ -92,7 +96,11 @@ function ImageCarousel({
92
96
  carouselRef.current?.next();
93
97
  };
94
98
 
95
-
99
+ // Check if images array is empty or has no valid images
100
+ const hasImages = images && images.length > 0 && images.some(image => {
101
+ const imageSrc = typeof image === "string" ? image : image?.src;
102
+ return imageSrc && imageSrc.trim().length > 0;
103
+ });
96
104
  return (
97
105
  <>
98
106
  <StyledCarouselWrapper
@@ -108,38 +116,47 @@ function ImageCarousel({
108
116
  infinite
109
117
  dots={false}
110
118
  >
111
- <Carousel ref={carouselRef} afterChange={handleCarouselChange} arrows={false} {...rest} infinite>
112
- {images.map((image, index) => {
113
- const imageSrc = typeof image === "string" ? image : image.src;
114
- const imageAlt =
115
- typeof image === "string"
116
- ? `${title} - Image ${index + 1}`
117
- : image.alt;
119
+ {hasImages ? (
120
+ <Carousel ref={carouselRef} afterChange={handleCarouselChange} arrows={false} {...rest} infinite>
121
+ {images.map((image, index) => {
122
+ const imageSrc = typeof image === "string" ? image : image.src;
123
+ const imageAlt =
124
+ typeof image === "string"
125
+ ? `${title} - Image ${index + 1}`
126
+ : image.alt;
118
127
 
119
- return (
120
- <div key={imageSrc}>
121
- <div className="image-container">
122
- <Image
123
- src={imageSrc}
124
- alt={imageAlt}
125
- fallback={fallback}
126
- loading="lazy"
127
- preview={{
128
- visible: false,
129
- }}
130
- onClick={() => {
131
- setCurrent(index);
132
- setPreviewVisible(true);
133
- }}
134
- />
135
- </div>
136
- </div>
137
- );
138
- })}
139
- </Carousel>
128
+ return (
129
+ <div key={imageSrc}>
130
+ <div className="image-container">
131
+ <Image
132
+ src={imageSrc}
133
+ alt={imageAlt}
134
+ fallback={fallback}
135
+ loading="lazy"
136
+ preview={{
137
+ visible: false,
138
+ }}
139
+ onClick={() => {
140
+ setCurrent(index);
141
+ setPreviewVisible(true);
142
+ }}
143
+ />
144
+ </div>
145
+ </div>
146
+ );
147
+ })}
148
+ </Carousel>
149
+ ) : (
150
+ <EmptyStateContainer height={height}>
151
+ <Empty
152
+ image={emptyLogo || Empty.PRESENTED_IMAGE_SIMPLE}
153
+ description={<span style={{ color: '#8C8C8C' }}>{emptyText}</span>}
154
+ />
155
+ </EmptyStateContainer>
156
+ )}
140
157
  </CarouselWidget>
141
158
 
142
- {customArrows && images && images.length > 1 && (
159
+ {customArrows && hasImages && images.length > 1 && (
143
160
  <>
144
161
  <CustomArrowButton
145
162
  icon={<LeftOutlined />}
@@ -158,29 +175,31 @@ function ImageCarousel({
158
175
  )}
159
176
  </StyledCarouselWrapper>
160
177
 
161
- <div style={{ display: "none" }}>
162
- <Image.PreviewGroup
163
- preview={{
164
- visible: previewVisible,
165
- current,
166
- onVisibleChange: (vis) => setPreviewVisible(vis),
167
- onChange: (idx) => {
168
- setCurrent(idx);
169
- carouselRef.current?.goTo(idx);
170
- },
171
- }}
172
- >
173
- {images.map((image, index) => {
174
- const imageSrc = typeof image === "string" ? image : image.src;
175
- const imageAlt =
176
- typeof image === "string"
177
- ? `${title} - Image ${index + 1}`
178
- : image.alt;
178
+ {hasImages && (
179
+ <div style={{ display: "none" }}>
180
+ <Image.PreviewGroup
181
+ preview={{
182
+ visible: previewVisible,
183
+ current,
184
+ onVisibleChange: (vis) => setPreviewVisible(vis),
185
+ onChange: (idx) => {
186
+ setCurrent(idx);
187
+ carouselRef.current?.goTo(idx);
188
+ },
189
+ }}
190
+ >
191
+ {images.map((image, index) => {
192
+ const imageSrc = typeof image === "string" ? image : image.src;
193
+ const imageAlt =
194
+ typeof image === "string"
195
+ ? `${title} - Image ${index + 1}`
196
+ : image.alt;
179
197
 
180
- return <Image key={imageSrc} src={imageSrc} alt={imageAlt} />;
181
- })}
182
- </Image.PreviewGroup>
183
- </div>
198
+ return <Image key={imageSrc} src={imageSrc} alt={imageAlt} />;
199
+ })}
200
+ </Image.PreviewGroup>
201
+ </div>
202
+ )}
184
203
  </>
185
204
  );
186
205
  }
@@ -195,6 +214,8 @@ ImageCarousel.propTypes = {
195
214
  arrowIconColor: PropTypes.string,
196
215
  arrowHoverIconColor: PropTypes.string,
197
216
  customArrows: PropTypes.bool,
217
+ emptyLogo: PropTypes.node,
218
+ emptyText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
198
219
  };
199
220
 
200
221
  export default ImageCarousel;
@@ -42,4 +42,48 @@ export const StyledCarouselWrapper = styled.div`
42
42
  margin-bottom: -3px !important;
43
43
  }
44
44
 
45
+ `;
46
+
47
+ export const EmptyStateContainer = styled.div`
48
+ width: 100%;
49
+ height: ${props => props.height || 400}px;
50
+ display: flex;
51
+ align-items: center;
52
+ justify-content: center;
53
+ background-color: #ffffff;
54
+ border-radius: 6px;
55
+ position: relative;
56
+
57
+ .ant-empty {
58
+ margin: 0;
59
+ display: flex;
60
+ flex-direction: column;
61
+ align-items: center;
62
+ justify-content: center;
63
+ height: 100%;
64
+ width: 100%;
65
+ }
66
+
67
+ .ant-empty-image {
68
+ margin-bottom: 16px;
69
+ display: flex;
70
+ align-items: center;
71
+ justify-content: center;
72
+ }
73
+
74
+ .ant-empty-description {
75
+ text-align: center;
76
+ }
77
+
78
+ &::after {
79
+ content: '';
80
+ position: absolute;
81
+ bottom: 8px;
82
+ left: 50%;
83
+ transform: translateX(-50%);
84
+ width: 40px;
85
+ height: 2px;
86
+ background-color: #722ed1;
87
+ border-radius: 1px;
88
+ }
45
89
  `;
@@ -0,0 +1,128 @@
1
+ import React, { useState, useEffect, useRef } from 'react'
2
+ import { Tabs, Drawer } from 'antd'
3
+ import Header from '../../../Header/index.jsx'
4
+ import BaseScreen from '../../BaseScreen/index.jsx'
5
+ import { CREATE_DRAWER_WIDTH } from '../../../../../../helpers/Forms.js'
6
+ import DrawerHeader from '../../../Header/DrawerHeader/index.jsx'
7
+
8
+ const TablePageWithTabs = ({
9
+ t= () => {},
10
+ title,
11
+ breadCrumbs,
12
+ location,
13
+ loading = false,
14
+ goTo = () => {},
15
+ defaultActiveTab = "own",
16
+ checkboxConfig = {},
17
+ columns = [],
18
+ data = {},
19
+ APP,
20
+ getApiBaseUrl = () => {},
21
+ selectOptions = {},
22
+ selectFiltersConfig = {},
23
+ getRedirectLink = () => {},
24
+ filtersConfig = {},
25
+ isMobile,
26
+ view,
27
+ getActiveTab = () => {},
28
+ onDownload = () => {},
29
+ downloadDisabled = false,
30
+ drawerTitle = "",
31
+ onCreateModalClose = () => {},
32
+ children
33
+ }) => {
34
+ const params = new URLSearchParams(location?.search);
35
+ const [activeTab, setActiveTab] = useState(params.get("tab") || defaultActiveTab);
36
+ const [openCreateModal, setOpenCreateModal] = useState(params.has("create"));
37
+
38
+ const getActiveTabRef = useRef(getActiveTab);
39
+ useEffect(() => {
40
+ getActiveTabRef.current = getActiveTab;
41
+ }, [getActiveTab]);
42
+
43
+ useEffect(() => {
44
+ getActiveTabRef.current(activeTab);
45
+ }, [activeTab]);
46
+
47
+ return (
48
+ <div className="semibold form-input-output daf-create-view">
49
+ <Header
50
+ title={t(title)}
51
+ breadcrumbs={breadCrumbs}
52
+ actionButtons={[
53
+ {
54
+ type: "primary",
55
+ onClick: () => setOpenCreateModal(true),
56
+ tooltip: t("New"),
57
+ icon: "Add",
58
+ },
59
+ ]}
60
+ onDownload={onDownload}
61
+ downloadDisabled={downloadDisabled}
62
+ />
63
+ <Tabs
64
+ items={[
65
+ { label: t("All Data"), key: "all" },
66
+ { label: t("Own Data"), key: "own" },
67
+ { label: t("Partners"), key: "shared" },
68
+ ]}
69
+ defaultActiveKey={activeTab}
70
+ activeKey={activeTab}
71
+ onChange={(val) => {
72
+ if (loading) {
73
+ return;
74
+ }
75
+
76
+ setActiveTab(val);
77
+
78
+ const newParams = new URLSearchParams(location?.search);
79
+ newParams.set("tab", val);
80
+ goTo(`${location.pathname}?${newParams.toString()}`);
81
+ }}
82
+ className="view-page-tabs mt-3"
83
+ />
84
+ <BaseScreen
85
+ t={t}
86
+ checkboxConfig={checkboxConfig}
87
+ defaultTableFilters={{}}
88
+ columns={columns}
89
+ data={data}
90
+ loading={loading}
91
+ location={location}
92
+ goTo={goTo}
93
+ APP={APP}
94
+ getApiBaseUrl={getApiBaseUrl}
95
+ selectOptions={selectOptions}
96
+ selectFilters={selectFiltersConfig}
97
+ view={view}
98
+ getRedirectLink={getRedirectLink}
99
+ defaultUrlParams={{}}
100
+ module={APP}
101
+ filtersConfig={filtersConfig}
102
+ isMobile={isMobile}
103
+ />
104
+ {openCreateModal && (
105
+ <Drawer
106
+ destroyOnHidden
107
+ title={
108
+ <DrawerHeader
109
+ title={t(drawerTitle)}
110
+ />
111
+ }
112
+ open={openCreateModal}
113
+ onClose={() => setOpenCreateModal(false)}
114
+ width={CREATE_DRAWER_WIDTH}
115
+ bodyStyle={{ padding: 0 }}
116
+ >
117
+ {typeof children === 'function'
118
+ ? children({ onDrawerClose: () => setOpenCreateModal(false) })
119
+ : children
120
+ }
121
+ </Drawer>
122
+ )}
123
+
124
+ </div>
125
+ )
126
+ }
127
+
128
+ export default TablePageWithTabs
@@ -1,9 +1,9 @@
1
1
  import React, { useState, useEffect, useRef } from 'react'
2
2
  import { Tabs, Drawer } from 'antd'
3
- import Header from '../../../core/components/Header/index.jsx'
4
- import BaseScreen from '../../../core/components/Screens/BaseScreen/index.jsx'
3
+ import Header from '../../../Header/index.jsx'
4
+ import BaseScreen from '../../BaseScreen/index.jsx'
5
5
  import { CREATE_DRAWER_WIDTH } from '../../../../helpers/Forms.js'
6
- import DrawerHeader from '../../../core/components/Header/DrawerHeader/index.jsx'
6
+ import DrawerHeader from '../../../Header/DrawerHeader/index.jsx'
7
7
 
8
8
  const TablePageWithTabs = ({
9
9
  t= () => {},
@@ -82,7 +82,7 @@ export default function useSource({ user = {}, t = () => {}, getData = () => {},
82
82
 
83
83
  export const useSources = ({type, id, user, t = () => {}}) => {
84
84
  function getData(params) {
85
- if(id) {
85
+ if(id !== undefined && id !== null) {
86
86
  return SourceService.getSources({type, id});
87
87
  } else {
88
88
  return SourceService.get(null, params);
@@ -1,5 +1,5 @@
1
1
  import React, { useMemo, useState, useEffect, useCallback } from 'react'
2
- import TablePageWithTabs from '../pages/TablePageWithTabs/index.jsx'
2
+ import TablePageWithTabs from '../../core/components/Screens/TableScreen/TablePageWithTabs/index.jsx'
3
3
  import { getColumns } from './columns.js';
4
4
  import { checkboxConfig, getFiltersConfig, filtersConfig, getFilterOptions } from './config.js';
5
5
  import { useGetQueryParams } from '../../hooks/useGetQueryParams.js';
@@ -1,5 +1,5 @@
1
1
  import React, { useMemo, useState, useEffect, useCallback } from 'react'
2
- import TablePageWithTabs from '../../pages/TablePageWithTabs/index.jsx'
2
+ import TablePageWithTabs from '../../../core/components/Screens/TableScreen/TablePageWithTabs/index.jsx'
3
3
  import { getColumns } from './columns.js';
4
4
  import { checkboxConfig, getFiltersConfig, filtersConfig, getFilterOptions } from './config.js';
5
5
  import { useGetQueryParams } from '../../../hooks/useGetQueryParams.js';
@@ -1,5 +1,5 @@
1
1
  import React, { useMemo, useState, useEffect, useCallback } from 'react'
2
- import TablePageWithTabs from '../../pages/TablePageWithTabs/index.jsx'
2
+ import TablePageWithTabs from '../../../core/components/Screens/TableScreen/TablePageWithTabs/index.jsx'
3
3
  import { getColumns } from './columns.js';
4
4
  import { checkboxConfig, getFiltersConfig, filtersConfig, getFilterOptions } from './config.js';
5
5
  import { useGetQueryParams } from '../../../hooks/useGetQueryParams.js';
@@ -1,5 +1,5 @@
1
1
  import React, { useMemo, useState, useEffect, useCallback } from 'react'
2
- import TablePageWithTabs from '../pages/TablePageWithTabs/index.jsx'
2
+ import TablePageWithTabs from '../../core/components/Screens/TableScreen/TablePageWithTabs/index.jsx'
3
3
  import { getColumns } from './columns.js';
4
4
  import { checkboxConfig, getFiltersConfig, filtersConfig, getFilterOptions } from './config.js';
5
5
  import { useGetQueryParams } from '../../hooks/useGetQueryParams.js';
@@ -1,5 +1,5 @@
1
1
  import React, { useMemo, useState, useEffect, useCallback } from 'react'
2
- import TablePageWithTabs from '../../pages/TablePageWithTabs/index.jsx'
2
+ import TablePageWithTabs from '../../../core/components/Screens/TableScreen/TablePageWithTabs/index.jsx'
3
3
  import { getColumns } from './columns.js';
4
4
  import { checkboxConfig, getFiltersConfig, filtersConfig, getFilterOptions } from './config.js';
5
5
  import { useGetQueryParams } from '../../../hooks/useGetQueryParams.js';
@@ -1,5 +1,5 @@
1
1
  import React, { useMemo, useState, useEffect, useCallback } from 'react'
2
- import TablePageWithTabs from '../pages/TablePageWithTabs/index.jsx'
2
+ import TablePageWithTabs from '../../core/components/Screens/TableScreen/TablePageWithTabs/index.jsx'
3
3
  import { getColumns } from './columns.js';
4
4
  import { checkboxConfig, getFiltersConfig, filtersConfig, getFilterOptions } from './config.js';
5
5
  import { useGetQueryParams } from '../../hooks/useGetQueryParams.js';
@@ -1,5 +1,5 @@
1
1
  import React, { useMemo, useState, useEffect, useCallback } from 'react'
2
- import TablePageWithTabs from '../../pages/TablePageWithTabs/index.jsx'
2
+ import TablePageWithTabs from '../../../core/components/Screens/TableScreen/TablePageWithTabs/index.jsx'
3
3
  import { getColumns } from './columns.js';
4
4
  import { checkboxConfig, getFiltersConfig, filtersConfig, getFilterOptions } from './config.js';
5
5
  import { useGetQueryParams } from '../../../hooks/useGetQueryParams.js';
@@ -1,5 +1,5 @@
1
1
  import React, { useMemo, useState, useEffect, useCallback } from 'react'
2
- import TablePageWithTabs from '../../pages/TablePageWithTabs/index.jsx'
2
+ import TablePageWithTabs from '../../../core/components/Screens/TableScreen/TablePageWithTabs/index.jsx'
3
3
  import { getColumns } from './columns.js';
4
4
  import { checkboxConfig, getFiltersConfig, filtersConfig, getFilterOptions } from './config.js';
5
5
  import { useGetQueryParams } from '../../../hooks/useGetQueryParams.js';
@@ -1,5 +1,5 @@
1
1
  import React, { useMemo, useState, useEffect, useCallback } from 'react'
2
- import TablePageWithTabs from '../pages/TablePageWithTabs/index.jsx'
2
+ import TablePageWithTabs from '../../core/components/Screens/TableScreen/TablePageWithTabs/index.jsx'
3
3
  import { getColumns } from './columns.js';
4
4
  import { checkboxConfig, getFiltersConfig, filtersConfig, getFilterOptions } from './config.js';
5
5
  import { useGetQueryParams } from '../../hooks/useGetQueryParams.js';
@@ -0,0 +1,36 @@
1
+ import React from "react";
2
+
3
+ export const getKeyIndicatorsRowConfig = ({ t, data = {} }) => [
4
+
5
+ {
6
+ label: t('Primary Data Collection'),
7
+ render: () => {
8
+ let displayValue = '-';
9
+
10
+ if (data?.origin?.[0]?.name === 'straatos') {
11
+ displayValue = data?.author?.name || '-';
12
+ } else if (data?.formCompleterType === 'localRelay') {
13
+ displayValue = 'Relay (Allcot Senegal)';
14
+ } else if (data?.formCompleterType === 'technicalPartner') {
15
+ displayValue = data?.technicalPartner?.name || '-';
16
+ } else {
17
+ displayValue = data?.author?.name || '-';
18
+ }
19
+
20
+ return <div className="flex">{displayValue}</div>;
21
+ }
22
+ },
23
+ {
24
+ label: t('Implementation Partner'),
25
+ render: () => <div>{data?.technicalPartner?.name || '-'}</div>
26
+ },
27
+ {
28
+ label: t('Activity Participants'),
29
+ render: () => <div>{'0'}</div>
30
+ },
31
+ {
32
+ label: t('Hectares Planted'),
33
+ render: () => <div>{data?.hectaresPlanted || '0 ha'}</div>
34
+ },
35
+
36
+ ];
@@ -0,0 +1,98 @@
1
+ // ============================================================================
2
+ // REGION: Photo/Image Extraction
3
+ // ============================================================================
4
+
5
+ /**
6
+ * Extract images from a photo document
7
+ * Handles both documents with pictures arrays and direct image objects
8
+ */
9
+ export const extractFromPhotoDoc = (photoDoc, label, docIndex) => {
10
+ const photos = photoDoc?.pictures?.filter(p => p?.url) || (photoDoc?.url ? [photoDoc] : []);
11
+
12
+ return photos.map((photo, photoIndex) => ({
13
+ src: normalizeUrl(photo.url),
14
+ alt: photo.name || photo.alt || `${label} - Image ${docIndex + 1}-${photoIndex + 1}`
15
+ }));
16
+ };
17
+
18
+ /**
19
+ * Normalize URL by removing trailing colon if present
20
+ */
21
+ const normalizeUrl = (url) => url?.endsWith(':') ? url.slice(0, -1) : url;
22
+
23
+ // ============================================================================
24
+ // REGION: Gender Distribution
25
+ // ============================================================================
26
+
27
+ // Gender distribution colors for pie chart
28
+ const GENDER_COLORS = ['#016C6E', '#00AEB1']; // Male (dark teal), Female (light teal)
29
+
30
+ /**
31
+ * Get gender distribution data from activityData
32
+ * Maps genderDistributionMale and genderDistributionFemale to a structured object
33
+ */
34
+ export const getGenderDistributionData = (activityData) => {
35
+ return {
36
+ Male: activityData?.genderDistributionMale || 0,
37
+ Female: activityData?.genderDistributionFemale || 0,
38
+ };
39
+ };
40
+
41
+ /**
42
+ * Check if gender distribution is empty
43
+ * Returns true if all values are 0 or falsy
44
+ */
45
+ export const isGenderDistributionEmpty = (genderDistributionData) => {
46
+ return Object.values(genderDistributionData).every(val => !val || val === 0);
47
+ };
48
+
49
+ /**
50
+ * Calculate pie chart data from gender distribution
51
+ * Computes percentages and assigns colors based on gender distribution values
52
+ */
53
+ export const calculateGenderPieData = (genderDistributionData) => {
54
+ const total = Object.values(genderDistributionData).reduce((all, val) => all + (val || 0), 0);
55
+
56
+ return Object.keys(genderDistributionData).map((key, index) => {
57
+ const color = GENDER_COLORS[index % GENDER_COLORS.length];
58
+
59
+ return {
60
+ value: genderDistributionData[key] || 0,
61
+ percent: total > 0 ? (genderDistributionData[key] || 0) / total : 0,
62
+ color: color,
63
+ label: key,
64
+ key: key,
65
+ };
66
+ });
67
+ };
68
+
69
+ /**
70
+ * Get tooltip children for gender distribution pie chart
71
+ * Generates tooltip content showing gender label and value
72
+ */
73
+ export const getGenderTooltipChildren = (item, isEmpty, genderDistributionData, t, renderTooltipJsx) => {
74
+ if (isEmpty) {
75
+ if (!Object.keys(genderDistributionData).length) {
76
+ return null;
77
+ }
78
+
79
+ return renderTooltipJsx({
80
+ title: t("Gender"),
81
+ items: Object.keys(genderDistributionData).map((k) => ({
82
+ label: k,
83
+ value: 0,
84
+ })),
85
+ });
86
+ }
87
+
88
+ return renderTooltipJsx({
89
+ title: t("Gender"),
90
+ items: [
91
+ {
92
+ color: item.color,
93
+ label: t(item.label),
94
+ value: `${item.value || 0}`,
95
+ },
96
+ ],
97
+ });
98
+ };