datastake-daf 0.6.780 → 0.6.781

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.
@@ -6,171 +6,176 @@ import CustomIcon from '../../../../../../../../src/@daf/core/components/Icon/Cu
6
6
  import { renderDateFormatted } from '../../../../../../../../src/helpers/Forms';
7
7
 
8
8
  const PlantingLocations = ({
9
- id,
10
- getSummaryDetail,
11
- loading = false,
12
- t = (s) => s
9
+ id,
10
+ getSummaryDetail,
11
+ loading = false,
12
+ t = (s) => s
13
13
  }) => {
14
- const defaultConfig = useMemo(
15
- () => ({
16
- basepath: "planting-cycle",
17
- url: `/summary/${id}/locations`,
18
- stop: !id,
19
- }),
20
- [id],
21
- );
22
-
23
- const customGetData = useMemo(() => {
24
- if (getSummaryDetail && id) {
25
- return ({ url, params = {} }) => {
26
- const match = url.match(/\/summary\/[^/]+\/(.+)/);
27
- if (match) {
28
- const [, type] = match;
29
- return getSummaryDetail(id, type, params);
30
- }
31
- throw new Error(`Invalid URL format: ${url}`);
32
- };
33
- }
34
- return undefined;
35
- }, [getSummaryDetail, id]);
36
-
37
- const { loading: plantingLocationsLoading, data: plantingLocationsData } = useWidgetFetch({
38
- config: defaultConfig,
39
- getData: customGetData
40
- });
41
-
42
-
43
- const mappedData = useMemo(() => {
44
- if (!plantingLocationsData || !plantingLocationsData.events) {
45
- return [];
46
- }
47
-
48
- const { locations = [], events } = plantingLocationsData;
49
-
50
- // Filter events that have valid GPS coordinates
51
- const eventsWithGPS = events.filter(event =>
52
- event.locationCheckArrival &&
53
- event.locationCheckArrival.latitude &&
54
- event.locationCheckArrival.longitude
55
- );
56
-
57
- return eventsWithGPS.map((event, index) => {
58
- const locationCheckArrival = event.locationCheckArrival;
59
-
60
- const matchingLocation = locations.find(location =>
61
- locationCheckArrival.name === location.name ||
62
- locationCheckArrival._id === location.id ||
63
- location.id === locationCheckArrival._id
64
- ) || locations[0];
65
-
66
-
67
- const area = matchingLocation?.perimeter ? matchingLocation.perimeter.map(coord =>
68
- Array.isArray(coord) && coord.length >= 2
69
- ? [coord[1], coord[0]]
70
- : coord
71
- ) : [];
72
-
73
-
74
- const gps = {
75
- latitude: locationCheckArrival.latitude,
76
- longitude: locationCheckArrival.longitude
77
- };
78
-
79
-
80
- const color = "#15FFFFB2"
81
-
82
- const locationName = matchingLocation?.name || locationCheckArrival.name || 'Planting Location';
83
-
84
- return {
85
- _id: locationCheckArrival._id || event._id || {},
86
- area: area,
87
- color: color,
88
- datastakeId: `LOC-${String(index + 1).padStart(9, '0')}`,
89
- gps: gps,
90
- id: matchingLocation?.id || locationCheckArrival._id || `event-${index}`,
91
- name: event.name || t("Activity Start"),
92
- date: event.date,
93
- sources: 1,
94
- subTitle: event.date ? renderDateFormatted(event.date, "DD MMM YY") : locationName,
95
- plotName: locationName,
96
- territoryTitle: locationName,
97
- type: 'Planting Location'
98
- };
99
- });
100
- }, [plantingLocationsData, t]);
101
-
102
- return (
103
- <section>
104
- <Widget
105
- title={t("Planting Locations")}
106
- className="no-px h-w-btn-header no-pt-body no-p-body no-pb-body"
107
- style={{ height: '100%', display: 'flex', flexDirection: 'column' }}
108
- >
109
- <MineSiteMap
110
- data={mappedData}
111
- link
112
- style={{ height: '100%', width: '100%' }}
113
- maxZoom={18}
114
- isSatellite={true}
115
- onClickLink={() => { }}
116
- onFilterChange={() => { }}
117
- primaryLink
118
- renderTooltipForLocation={(data) => {
119
- const coordinates = data.gps?.latitude && data.gps?.longitude
120
- ? convertDMS(data.gps.latitude, data.gps.longitude)
121
- : null;
122
-
123
- if (!coordinates) {
124
- return [];
125
- }
126
-
127
- const iconColor = "#016C6E"; // Activity Start color
128
-
129
- return [
130
- {
131
- label: t("Coordinates"),
132
- value: (
133
- <div style={{ display: 'flex', alignItems: 'center', gap: '6px', flexWrap: 'nowrap' }}>
134
- {/* Latitude icon (vertical) */}
135
- <div style={{ display: 'flex', alignItems: 'center' }}>
136
- <CustomIcon
137
- name="SpacingHeight"
138
- width={14}
139
- height={14}
140
- color={iconColor}
141
- />
142
- <span style={{ fontWeight: 600, marginLeft: '4px' }}>{coordinates[0]}</span>
143
- </div>
144
- {/* Longitude icon (horizontal) */}
145
- <div style={{ display: 'flex', alignItems: 'center' }}>
146
- <CustomIcon
147
- name="SpacingWidth"
148
- width={14}
149
- height={14}
150
- color={iconColor}
151
- />
152
- <span style={{ fontWeight: 600, marginLeft: '4px' }}>{coordinates[1]}</span>
153
- </div>
154
- </div>
155
- ),
156
- },
157
- ];
158
- }}
159
- renderTooltipForTerritory={(data) => {
160
- return [
161
- {
162
- label: t("Plot Name"),
163
- value: data.plotName || data.name || "--",
164
- },
165
- ];
166
- }}
167
- renderTooltipTags={() => { }}
168
- type="location-territory"
169
- />
170
- </Widget>
171
- </section>
172
- );
14
+ const defaultConfig = useMemo(
15
+ () => ({
16
+ basepath: "planting-cycle",
17
+ url: `/summary/${id}/locations`,
18
+ stop: !id,
19
+ }),
20
+ [id],
21
+ );
22
+
23
+ const customGetData = useMemo(() => {
24
+ if (getSummaryDetail && id) {
25
+ return ({ url, params = {} }) => {
26
+ const match = url.match(/\/summary\/[^/]+\/(.+)/);
27
+ if (match) {
28
+ const [, type] = match;
29
+ return getSummaryDetail(id, type, params);
30
+ }
31
+ throw new Error(`Invalid URL format: ${url}`);
32
+ };
33
+ }
34
+ return undefined;
35
+ }, [getSummaryDetail, id]);
36
+
37
+ const { loading: plantingLocationsLoading, data: plantingLocationsData } = useWidgetFetch({
38
+ config: defaultConfig,
39
+ getData: customGetData
40
+ });
41
+
42
+
43
+ const mappedData = useMemo(() => {
44
+ if (!plantingLocationsData || !plantingLocationsData.events) {
45
+ return [];
46
+ }
47
+
48
+ const { locations = [], events } = plantingLocationsData;
49
+
50
+ // Filter events that have valid GPS coordinates
51
+ const eventsWithGPS = events.filter(event =>
52
+ event.locationCheckArrival &&
53
+ event.locationCheckArrival.latitude &&
54
+ event.locationCheckArrival.longitude
55
+ );
56
+
57
+ return eventsWithGPS.map((event, index) => {
58
+ const locationCheckArrival = event.locationCheckArrival;
59
+
60
+ const matchingLocation = locations.find(location =>
61
+ locationCheckArrival.name === location.name ||
62
+ locationCheckArrival._id === location.id ||
63
+ location.id === locationCheckArrival._id
64
+ ) || locations[0];
65
+
66
+
67
+ const area = matchingLocation?.perimeter ? matchingLocation.perimeter.map(coord =>
68
+ Array.isArray(coord) && coord.length >= 2
69
+ ? [coord[1], coord[0]]
70
+ : coord
71
+ ) : null;
72
+
73
+ // Only include area if it has at least 3 valid coordinates
74
+ const validArea = area && Array.isArray(area) && area.length >= 3 ? area : null;
75
+
76
+
77
+ const gps = {
78
+ latitude: locationCheckArrival.latitude,
79
+ longitude: locationCheckArrival.longitude
80
+ };
81
+
82
+
83
+ const color = "#15FFFFB2"
84
+
85
+ const locationName = matchingLocation?.name || locationCheckArrival.name || 'Planting Location';
86
+
87
+ return {
88
+ _id: locationCheckArrival._id || event._id || {},
89
+ area: validArea,
90
+ color: color,
91
+ datastakeId: `LOC-${String(index + 1).padStart(9, '0')}`,
92
+ gps: gps,
93
+ id: matchingLocation?.id || locationCheckArrival._id || `event-${index}`,
94
+ name: event.name || t("Activity Start"),
95
+ date: event.date,
96
+ sources: 1,
97
+ subTitle: event.date ? renderDateFormatted(event.date, "DD MMM YY") : locationName,
98
+ plotName: locationName,
99
+ territoryTitle: locationName,
100
+ type: 'Planting Location'
101
+ };
102
+ });
103
+ }, [plantingLocationsData, t]);
104
+
105
+ return (
106
+ <section>
107
+ <Widget
108
+ title={t("Planting Locations")}
109
+ className="no-px h-w-btn-header no-pt-body no-p-body no-pb-body"
110
+ style={{ height: '100%', display: 'flex', flexDirection: 'column' }}
111
+ >
112
+ <MineSiteMap
113
+ data={mappedData}
114
+ link
115
+ style={{ height: '100%', width: '100%' }}
116
+ maxZoom={18}
117
+ isSatellite={true}
118
+ onClickLink={() => { }}
119
+ onFilterChange={() => { }}
120
+ primaryLink
121
+ renderTooltipForLocation={(data) => {
122
+ const coordinates = data.gps?.latitude && data.gps?.longitude
123
+ ? convertDMS(data.gps.latitude, data.gps.longitude)
124
+ : null;
125
+
126
+ if (!coordinates) {
127
+ return [];
128
+ }
129
+
130
+ const iconColor = "#016C6E"; // Activity Start color
131
+
132
+ return [
133
+ {
134
+ label: t("Coordinates"),
135
+ value: (
136
+ <div style={{ display: 'flex', alignItems: 'center', gap: '6px', flexWrap: 'nowrap' }}>
137
+ {/* Latitude icon (vertical) */}
138
+ <div style={{ display: 'flex', alignItems: 'center' }}>
139
+ <CustomIcon
140
+ name="SpacingHeight"
141
+ width={14}
142
+ height={14}
143
+ color={iconColor}
144
+ />
145
+ <span style={{ fontWeight: 600, marginLeft: '4px' }}>{coordinates[0]}</span>
146
+ </div>
147
+ {/* Longitude icon (horizontal) */}
148
+ <div style={{ display: 'flex', alignItems: 'center' }}>
149
+ <CustomIcon
150
+ name="SpacingWidth"
151
+ width={14}
152
+ height={14}
153
+ color={iconColor}
154
+ />
155
+ <span style={{ fontWeight: 600, marginLeft: '4px' }}>{coordinates[1]}</span>
156
+ </div>
157
+ </div>
158
+ ),
159
+ },
160
+ ];
161
+ }}
162
+ renderTooltipForTerritory={(data) => {
163
+ return [
164
+ {
165
+ label: t("Plot Name"),
166
+ value: data.plotName || data.name || "--",
167
+ },
168
+ ];
169
+ }}
170
+ renderTooltipTags={() => { }}
171
+ type="location-territory"
172
+ />
173
+ </Widget>
174
+ </section>
175
+ );
173
176
  };
174
177
 
175
178
  export default PlantingLocations;
176
179
 
180
+
181
+
@@ -61,6 +61,4 @@ export const removeKeysFromObject = (obj = {}, keys = []) => {
61
61
  }
62
62
  }
63
63
  return result;
64
- }
65
-
66
- export const hasKeyInObject = (obj, key) => Object.keys(obj || {}).includes(key);
64
+ }
package/src/pages.js CHANGED
@@ -19,7 +19,4 @@ export { default as TablePage } from './@daf/pages/TablePage/index.jsx';
19
19
  export { default as OperatorSummary } from './@daf/pages/Summary/Operator/index.jsx';
20
20
  export { default as RestorationActivitySummary } from './@daf/pages/Summary/Activities/Restoration/index.jsx';
21
21
  export { default as PlantingCycleSummary } from './@daf/pages/Summary/Activities/PlantingCycle/index.jsx';
22
- export { default as MineSummary } from './@daf/pages/Summary/Minesite/index.jsx';
23
-
24
- // View
25
- export { default as View } from './@daf/pages/View/index.jsx';
22
+ export { default as MineSummary } from './@daf/pages/Summary/Minesite/index.jsx';
package/src/utils.js CHANGED
@@ -27,7 +27,7 @@ export { default as locales } from './constants/locales/index.js';
27
27
 
28
28
  export { getTagColor } from "./@daf/utils/productTag.js";
29
29
 
30
- export { convertUndefinedToNull, hasKeyInObject, removeKeysFromObject } from './@daf/utils/object'
30
+ export { convertUndefinedToNull } from './@daf/utils/object'
31
31
 
32
32
  export { default as ErrorFormat, formatErrors } from './helpers/ErrorFormater'
33
33
 
@@ -1,73 +0,0 @@
1
- import { useRef, useEffect } from "react";
2
- import { hasKeyInObject } from "../../../../@daf/utils/object.js";
3
- import { getNkey } from "../../../../@daf/core/components/ViewForm/helper.js";
4
-
5
- export const useCallToGetData = ({
6
- namespaceConfig,
7
- namespace,
8
- allData,
9
- id,
10
- isSupported,
11
- namespaceGet,
12
- source,
13
- version,
14
- user,
15
- setLoading,
16
- APP,
17
- }) => {
18
- const isFirstRender = useRef(true);
19
-
20
- const callToGetData = (_doCall = false) => {
21
- const dKey = namespaceConfig.dataKey;
22
- const nKey = `${APP}-${getNkey(namespace)}`;
23
- const doCall = _doCall
24
- ? true
25
- : hasKeyInObject(allData, dKey) && hasKeyInObject(allData[dKey], nKey)
26
- ? allData[dKey][nKey]?.data?.datastakeId !== id
27
- : true;
28
- if (doCall) {
29
- if (isSupported) {
30
- namespaceGet[namespace]();
31
- }
32
- }
33
- };
34
-
35
- useEffect(() => {
36
- if (isFirstRender.current) {
37
- isFirstRender.current = false;
38
- return;
39
- }
40
- callToGetData(true);
41
- }, [source, version]);
42
-
43
- useEffect(() => {
44
- callToGetData(true);
45
- }, [id, namespace, user.language]);
46
-
47
- const onStorageUpdate = (e) => {
48
- const { key, newValue } = e;
49
- if (key === `${id}-loading` && newValue) {
50
- setLoading(newValue);
51
- }
52
- if (key === `${id}-updated` && newValue) {
53
- setLoading(true);
54
- callToGetData();
55
- }
56
- };
57
-
58
- useEffect(() => {
59
- window.addEventListener("storage", onStorageUpdate);
60
- return () => {
61
- window.removeEventListener("storage", onStorageUpdate);
62
- };
63
- }, []);
64
-
65
- useEffect(() => {
66
- setLoading(true);
67
- }, [namespace]);
68
-
69
-
70
- return {
71
- callToGetData,
72
- }
73
- }
@@ -1,86 +0,0 @@
1
- import { useState, useEffect } from "react";
2
- import { hasKeyInObject } from "../../../../@daf/utils/object.js";
3
-
4
- export const usePrepareForm = ({
5
- namespaceConfig,
6
- allData,
7
- id,
8
- namespace,
9
- t,
10
- mode,
11
- APP,
12
- viewConfig,
13
- }) => {
14
- const [form, setForm] = useState({});
15
- const [data, setData] = useState({});
16
- const [groups, setGroups] = useState({});
17
- const [linkingForms, setLinkingForms] = useState({});
18
- const [loading, setLoading] = useState(true);
19
- const [notFound, setNotFound] = useState(false);
20
-
21
- const prepareForm = (currentView) => {
22
- const dKey = namespaceConfig.dataKey;
23
- const nKey = `${APP}-${currentView}`;
24
-
25
- if (hasKeyInObject(allData, dKey) && hasKeyInObject(allData[dKey], nKey)) {
26
- const {
27
- form = {},
28
- data = {},
29
- config = {},
30
- linkingForms = {},
31
- } = JSON.parse(JSON.stringify(allData[dKey][nKey] || {}));
32
-
33
- if (data.datastakeId === id || id === "user") {
34
- if (viewConfig.linkingSubjects.includes(namespace)) {
35
- setForm({
36
- ...form,
37
- linking: {
38
- position: 100,
39
- excludeFromEdit: true,
40
- label: t("Linked Subjects"),
41
- template: "linkingSubjects",
42
- },
43
- });
44
- } else {
45
- setForm(form);
46
- }
47
- setData(data);
48
- setGroups(config.groups || {});
49
- setLinkingForms(linkingForms);
50
- setLoading(false);
51
- setNotFound(false);
52
- } else if (!data.id) {
53
- if (mode === "proxy") {
54
- window.location.reload();
55
- } else {
56
- setLoading(false);
57
- setNotFound(true);
58
- }
59
- }
60
- }
61
- };
62
-
63
- const getCertainData = allData[namespaceConfig.dataKey];
64
-
65
- useEffect(() => {
66
- if(namespace && namespaceConfig) {
67
- prepareForm(namespaceConfig.view);
68
- }
69
- }, [getCertainData, namespaceConfig]);
70
-
71
- return {
72
- form,
73
- setForm,
74
- data,
75
- setData,
76
- groups,
77
- setGroups,
78
- linkingForms,
79
- setLinkingForms,
80
- loading,
81
- setLoading,
82
- notFound,
83
- setNotFound,
84
- prepareForm,
85
- }
86
- }
@@ -1,40 +0,0 @@
1
- import { useState, useCallback } from "react";
2
-
3
- export const submitSubjectData = async (namespace, data, serviceMap) => {
4
- const service = serviceMap[namespace];
5
- if (!service) {
6
- throw new Error(`No service found for namespace: ${namespace}`);
7
- }
8
-
9
- const response = await service.submitStep(
10
- data,
11
- data.datastakeId || data.id
12
- );
13
- return response.data;
14
- };
15
-
16
- export const useSubmitSubject = ({namespace, data, serviceMap}) => {
17
- const [isDisabled, setIsDisabled] = useState(false);
18
- const [loading, setLoading] = useState(false);
19
- const [isPublished, setIsPublished] = useState(false);
20
-
21
- const submitSubject = useCallback(async () => {
22
- try {
23
- setLoading(true);
24
- const response = await submitSubjectData(namespace, data, serviceMap);
25
- setIsDisabled(response.published);
26
- setIsPublished(response.published);
27
- } catch (error) {
28
- console.error("Submit error:", error);
29
- } finally {
30
- setLoading(false);
31
- }
32
- }, [namespace, data]);
33
-
34
- return {
35
- submitSubject,
36
- isDisabled,
37
- submitLoading: loading,
38
- isPublished,
39
- };
40
- };
@@ -1,83 +0,0 @@
1
- import { useState, useEffect } from "react";
2
-
3
- export const useViewActions = ({
4
- namespace,
5
- data,
6
- isSupported,
7
- canEdit,
8
- versionUrl,
9
- sourceUrl,
10
- getEditLink,
11
- submitSubject,
12
- isDisabled,
13
- setOpenRecordsModal,
14
- goBackFromSource,
15
- push,
16
- getRedirectLink,
17
- t,
18
- viewConfig,
19
- buttonActions,
20
- }) => {
21
- const [pageActions, setPageActions] = useState([]);
22
- const [extraPageActions, setExtraPageActions] = useState([]);
23
-
24
- useEffect(() => {
25
- const actions = [];
26
- const extraActions = [];
27
-
28
- if (!isSupported) {
29
- setPageActions([]);
30
- setExtraPageActions([]);
31
- return;
32
- }
33
-
34
- if (canEdit) {
35
- if (viewConfig.namespacesWithoutActionButtons.includes(namespace)) {
36
- if (viewConfig.editOnlyButton.includes(namespace)) {
37
- if (versionUrl && sourceUrl) {
38
- actions.push(buttonActions.createBackButton(t, goBackFromSource));
39
- } else {
40
- actions.push(buttonActions.createEditButton(t, getEditLink));
41
- }
42
- }
43
- } else {
44
- if (versionUrl && sourceUrl) {
45
- actions.push(buttonActions.createBackButton(t, goBackFromSource));
46
- } else {
47
- actions.push(buttonActions.createSubmitButton(t, submitSubject, isDisabled, data));
48
- actions.push(buttonActions.createEditButton(t, getEditLink));
49
- // actions.push(createRecordsButton(t, setOpenRecordsModal));
50
- }
51
- }
52
- }
53
-
54
- if (viewConfig.summaryNamespaces.includes(namespace)) {
55
- extraActions.push(
56
- buttonActions.createSummaryButton(t, namespace, data, push, getRedirectLink)
57
- );
58
- extraActions.push(
59
- buttonActions.createRecordsButton(t, setOpenRecordsModal)
60
- );
61
- }
62
-
63
- setPageActions(actions);
64
- setExtraPageActions(extraActions);
65
- }, [
66
- namespace,
67
- data,
68
- isSupported,
69
- canEdit,
70
- versionUrl,
71
- sourceUrl,
72
- isDisabled,
73
- t,
74
- getEditLink,
75
- submitSubject,
76
- goBackFromSource,
77
- setOpenRecordsModal,
78
- push,
79
- getRedirectLink,
80
- ]);
81
-
82
- return { pageActions, extraPageActions };
83
- };