datastake-daf 0.6.797 → 0.6.798

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.
@@ -0,0 +1,356 @@
1
+ import React, { useMemo, useState, useCallback, useEffect } from 'react'
2
+ import { Form, message } from 'antd';
3
+ import { useViewUrlParams } from '../View/hooks/useViewUrlParams';
4
+ import { usePrepareForm } from './hooks/usePrepareForm';
5
+ import { useViewPermissions } from '../View/hooks/useViewPermissions';
6
+ import { useCallToGetData } from '../View/hooks/useCallToGetData';
7
+ import { MessageTypes } from '../../../helpers/messages.js';
8
+ import { editErrorHandler } from "../../core/components/EditForm/helper.js"
9
+ import { transformPayload } from "../../../helpers/Forms.js"
10
+ import Loading from "../../../@daf/core/components/Loading/index.jsx"
11
+ import NotFound from "../../core/components/Screens/NotFound/index.jsx"
12
+ import Header from "../../core/components/Header/index.jsx"
13
+ import MissingTagButton from "../../core/components/UI/MissingTagButton/index.jsx"
14
+ import { Sections as EditFormSections} from "../../core/components/EditForm/sections.jsx"
15
+ import { EditForm } from "../../core/components/EditForm/form.jsx"
16
+
17
+
18
+ const Edit = ({
19
+ goTo = () => {},
20
+ allData = {},
21
+ query,
22
+ push,
23
+ searchParams,
24
+ setSearchParams,
25
+ setNotificationMode,
26
+ changeNotificationState,
27
+ addCheck,
28
+ removeCheck,
29
+ ajaxForms,
30
+ changeAjaxForms,
31
+ ajaxOptions,
32
+ changeAjaxOptions,
33
+ params,
34
+ clear,
35
+ getRedirectLink,
36
+ pathname,
37
+ search,
38
+ viewConfig,
39
+ APP,
40
+ namespaceConfiguration,
41
+ user,
42
+ t,
43
+ actionMap,
44
+ submitCall,
45
+ notificationMode,
46
+ breadcrumbs,
47
+ generatePath,
48
+ getAppHeader,
49
+ getApiBaseUrl,
50
+ namespaceOverrides,
51
+ getSubjectsDetails,
52
+
53
+ excludedKeys = [],
54
+ disabledInputs = [],
55
+ checkDuplicates = true,
56
+
57
+ }) => {
58
+ const [MainForm] = Form.useForm();
59
+ const [isChanged, setIsChanged] = useState(false);
60
+ const [highlightMandatory, setHighlightMandatory] = useState(false);
61
+ const [hasMissing, setHasMissing] = useState(false);
62
+ const [selectedForm, setSelectedForm] = useState({});
63
+ const [errors, setErrors] = useState({});
64
+ const changeErrors = useCallback((key, val) => {
65
+ setErrors((p) => ({ ...p, [key]: val }));
66
+ }, []);
67
+ const {
68
+ namespace,
69
+ id,
70
+ group,
71
+ subsection,
72
+ match,
73
+ subgroup,
74
+ formId,
75
+ getViewLink,
76
+ changedPath,
77
+ setChangedPath,
78
+ } = useViewUrlParams({
79
+ params,
80
+ push,
81
+ pathname,
82
+ search,
83
+ searchParams,
84
+ setSearchParams,
85
+ getRedirectLink,
86
+ })
87
+
88
+ const isSupported = viewConfig?.supportedNamespaces?.[APP] && viewConfig?.supportedNamespaces?.[APP]?.includes(namespace);
89
+ const getNamespaceConfig = (namespace) => namespaceConfiguration?.[namespace] || {};
90
+ const namespaceConfig = useMemo(() => getNamespaceConfig(namespace), [namespace]);
91
+
92
+ const {
93
+ form,
94
+ data,
95
+ linkingForms,
96
+ loading,
97
+ editValues,
98
+ inputsMeta,
99
+ setLoading,
100
+ changeLinking,
101
+ changeInputMeta,
102
+ onValuesChange,
103
+ } = usePrepareForm({
104
+ isSupported,
105
+ namespaceConfig,
106
+ APP,
107
+ allData,
108
+ id,
109
+ MainForm,
110
+ namespace,
111
+ setIsChanged,
112
+ changedPath,
113
+ setChangedPath,
114
+ })
115
+
116
+ useEffect(() => {
117
+ if(namespace && id && namespaceConfig && typeof getSubjectsDetails === 'function') {
118
+ getSubjectsDetails({
119
+ namespace,
120
+ id,
121
+ namespaceConfig,
122
+ })
123
+ }
124
+ }, [namespace, id, namespaceConfig])
125
+
126
+
127
+ const { canEdit } = useViewPermissions({
128
+ data,
129
+ id,
130
+ namespace,
131
+ user,
132
+ push,
133
+ getRedirectLink,
134
+ namespaceConfig: namespaceConfiguration,
135
+ APP,
136
+ viewConfig: viewConfig,
137
+ namespaceOverrides,
138
+ });
139
+
140
+ const action = useMemo(() => actionMap?.[namespaceConfig?.action], [namespaceConfig?.action, actionMap]);
141
+
142
+ const namespaceGet = {
143
+ [namespace]: () => {
144
+ return action?.({
145
+ namespace: namespaceConfig?.namespace,
146
+ module: APP,
147
+ view: namespaceConfig?.view,
148
+ ...(namespaceConfig?.scope && { scope: namespaceConfig.scope }),
149
+ datastakeId: id ? id : 'user',
150
+ })
151
+ }
152
+ }
153
+
154
+ useCallToGetData({
155
+ namespaceConfig,
156
+ namespace,
157
+ allData,
158
+ id,
159
+ isSupported,
160
+ namespaceGet,
161
+ source: null,
162
+ version: null,
163
+ user,
164
+ setLoading,
165
+ APP,
166
+ })
167
+
168
+ const callback = (type, m) => {
169
+ localStorage.removeItem(`${id}-loading`);
170
+ localStorage.setItem(`${id}-updated`, true);
171
+ if (type === MessageTypes.SUCCESS) {
172
+ message.success(m);
173
+ setIsChanged(false);
174
+ } else {
175
+ message.error(m);
176
+ }
177
+ localStorage.removeItem(`${id}-updated`);
178
+ setLoading(false);
179
+ };
180
+
181
+ const onSubmitData = () => {
182
+ clear();
183
+
184
+ // Validate custom errors
185
+ const _errors = Object.keys(errors)
186
+ .filter((k) => !!errors[k])
187
+ .map((k) => ({ name: [k] }));
188
+
189
+ if (_errors.length) {
190
+ editErrorHandler({ errorFields: _errors, t });
191
+ return;
192
+ }
193
+
194
+ // Validate and submit form
195
+ MainForm.validateFields()
196
+ .then(() => {
197
+ // Build base payload
198
+ const { _id, ..._payloadData } = {
199
+ ...editValues,
200
+ form: subsection || group,
201
+ module: APP,
202
+ view: namespaceConfig?.view,
203
+ namespace,
204
+ };
205
+
206
+ // Transform payload (process files, clean arrays)
207
+ const finalPayload = transformPayload(_payloadData);
208
+
209
+ // Setup UI state
210
+ setIsChanged(false);
211
+ setNotificationMode(notificationMode.EMPTY);
212
+ setLoading(true);
213
+ localStorage.setItem(`${id}-loading`, true);
214
+
215
+ // Submit
216
+ submitCall[namespace](
217
+ !editValues?.id
218
+ ? finalPayload
219
+ : Object.assign(finalPayload, { id: data.id }),
220
+ callback,
221
+ );
222
+ })
223
+ .catch((e) => {
224
+ console.log(e);
225
+ editErrorHandler({ errorFields: e.errorFields, t });
226
+ });
227
+ };
228
+
229
+ useEffect(
230
+ () => () => {
231
+ clear();
232
+ },
233
+ [],
234
+ );
235
+
236
+ const pageActions = [
237
+ {
238
+ tooltip: t("Save"),
239
+ onClick: () => onSubmitData(true),
240
+ disabled: !isChanged,
241
+ type: "primary",
242
+ icon: "Save",
243
+ },
244
+ {
245
+ icon: "Close",
246
+ tooltip: t("Back"),
247
+ onClick: () => {
248
+ changeNotificationState({ onYes: () => goTo(getViewLink()) });
249
+ },
250
+ },
251
+ ];
252
+
253
+ useEffect(() => {
254
+ if (isChanged) {
255
+ addCheck(() => {
256
+ goTo(`/app/view/${namespace}/${id}/${group}`);
257
+ });
258
+ } else {
259
+ removeCheck();
260
+ }
261
+ }, [isChanged, addCheck, removeCheck]);
262
+
263
+ if (!data.id && namespace !== 'kyc') {
264
+ return <Loading />;
265
+ }
266
+
267
+ if(!isSupported && !canEdit) {
268
+ return <NotFound t={t} />
269
+ }
270
+
271
+ return (
272
+ <div className="daf-edit-form">
273
+ <React.Fragment>
274
+ <Header
275
+ breadcrumbs={breadcrumbs}
276
+ title={(namespace === 'kyc' ? "KYC" : data?.name) || ""}
277
+ actionButtons={pageActions}
278
+ renderExtraComponents={
279
+ () => {
280
+ return <MissingTagButton hasMissing={hasMissing} highlightMandatory={highlightMandatory} setHighlightMandatory={setHighlightMandatory} t={t} />
281
+ }
282
+ }
283
+ />
284
+ <div className="view-content">
285
+ <EditFormSections
286
+ t={t}
287
+ data={editValues}
288
+ MainForm={MainForm}
289
+ getRedirectLink={getRedirectLink}
290
+ highlightMandatory={highlightMandatory}
291
+ search={search}
292
+ setHasMissing={setHasMissing}
293
+ mod={APP}
294
+ formConf={form}
295
+ values={data}
296
+ errors={errors}
297
+ onChangeForm={(sForm) => {
298
+ setSelectedForm(sForm);
299
+ }}
300
+ match={match}
301
+ group={group}
302
+ subsection={subsection}
303
+ subgroup={subgroup}
304
+ formid={formId}
305
+ user={user}
306
+ {...{
307
+ goTo,
308
+ pathname,
309
+ generatePath,
310
+ }}
311
+ />
312
+ <div className="form-edit">
313
+ {loading ? (
314
+ <div style={{ minHeight: 10000 }}>
315
+ <Loading background="white" />
316
+ </div>
317
+ ) : (
318
+ <EditForm
319
+ errors={errors}
320
+ changeErrors={changeErrors}
321
+ highlightMandatory={highlightMandatory}
322
+ MainForm={MainForm}
323
+ onValuesChange={onValuesChange}
324
+ disabledInputs={disabledInputs}
325
+ checkDuplicates={checkDuplicates}
326
+ inputsMeta={inputsMeta}
327
+ changeInputMeta={changeInputMeta}
328
+ changeLinking={changeLinking}
329
+ excludedKeys={excludedKeys}
330
+ hasSections={[]}
331
+ linkingForms={linkingForms}
332
+ form={selectedForm}
333
+ data={data}
334
+ {...{
335
+ t,
336
+ user,
337
+ ajaxForms,
338
+ ajaxOptions,
339
+ getAppHeader,
340
+ getApiBaseUrl,
341
+ changeAjaxOptions,
342
+ app: APP,
343
+ query,
344
+ goTo,
345
+ changeAjaxForms,
346
+ }}
347
+ />
348
+ )}
349
+ </div>
350
+ </div>
351
+ </React.Fragment>
352
+ </div>
353
+ )
354
+ }
355
+
356
+ export default Edit
@@ -7,15 +7,19 @@ export const useViewUrlParams = ({
7
7
  search,
8
8
  searchParams,
9
9
  setSearchParams,
10
+ getRedirectLink,
10
11
  }) => {
11
12
  const [namespace, setNamespace] = useState(params?.namespace);
12
13
  const [id, setId] = useState(params?.id);
13
14
  const [group, setGroup] = useState(params?.group);
14
15
  const [subsection, setSubSection] = useState(params?.subsection);
16
+ const [formId, setFormId] = useState(params?.formid);
17
+ const [subgroup, setSubGroup] = useState(params?.subgroup);
15
18
  const sourceUrl = searchParams.get("source");
16
19
  const versionUrl = searchParams.get("version");
17
20
  const [source, setSource] = useState(sourceUrl || null);
18
21
  const [version, setVersion] = useState(versionUrl || null);
22
+ const [changedPath, setChangedPath] = useState([]);
19
23
 
20
24
  useEffect(() => {
21
25
  if ((id && params.id !== id) || (namespace && namespace !== params.namespace)) {
@@ -29,6 +33,8 @@ export const useViewUrlParams = ({
29
33
  }
30
34
  setNamespace(params.namespace);
31
35
  setId(params.id);
36
+ setSubGroup(params.subgroup);
37
+ setFormId(params.formid);
32
38
  }, [params]);
33
39
 
34
40
  useEffect(() => {
@@ -64,7 +70,18 @@ export const useViewUrlParams = ({
64
70
  push(`${previous}/edit/${extra}`);
65
71
  }
66
72
  }, [pathname, search, push]);
67
-
73
+
74
+ const getViewLink = useCallback(() => {
75
+ switch (namespace) {
76
+ default:
77
+ }
78
+ return getRedirectLink(
79
+ `/app/view/${namespace}/${id}/${group}${subsection ? `/${subsection}` : ""}${
80
+ subgroup ? `/${subgroup}` : ""
81
+ }${search ? `/${search}` : ""}`,
82
+ );
83
+ }, [namespace, id, group, subsection, subgroup, search, getRedirectLink, pathname, search]);
84
+
68
85
  const match = useMemo(
69
86
  () => ({
70
87
  params,
@@ -89,5 +106,10 @@ export const useViewUrlParams = ({
89
106
  getEditLink,
90
107
  match,
91
108
  search,
109
+ formId,
110
+ subgroup,
111
+ getViewLink,
112
+ changedPath,
113
+ setChangedPath,
92
114
  };
93
115
  }
@@ -77,6 +77,7 @@ const View = ({
77
77
  search,
78
78
  searchParams,
79
79
  setSearchParams,
80
+ getRedirectLink,
80
81
  });
81
82
 
82
83
  const namespaceConfig = useMemo(() => getNamespaceConfig(namespace), [namespace]);
@@ -0,0 +1 @@
1
+ export const isArrayOfObjects = (arr) => Array.isArray(arr) && arr.map((i) => typeof i === "object").every((i) => i);
@@ -829,3 +829,63 @@ export const getValueOnSelectFromDefaultKeys = (val, options, uniqueDefaultKeys)
829
829
  }
830
830
  return null;
831
831
  }
832
+
833
+ // REQUIRED FOR EDIT FORM SUBMIT(SAVE)
834
+ export const extractFiles = (fileList = []) => {
835
+ const processedFiles = fileList
836
+ .map(file => file.response || file)
837
+ .filter(file => file?.status === "done");
838
+
839
+ // Remove duplicates
840
+ return Array.isArray(processedFiles)
841
+ ? [...new Set(processedFiles)]
842
+ : processedFiles;
843
+ };
844
+
845
+ export const hasFileList = (value) => {
846
+ return value &&
847
+ typeof value === "object" &&
848
+ value !== null &&
849
+ "fileList" in value;
850
+ };
851
+
852
+ export const hasContent = (obj) => {
853
+ if (typeof obj !== "object" || obj === null) return true;
854
+ return Object.keys(obj).some(key => propHasValue(obj[key]));
855
+ };
856
+
857
+ export const transformPayload = (payload) => {
858
+ if (!payload || typeof payload !== "object") return payload;
859
+
860
+ const transformed = { ...payload };
861
+
862
+ Object.keys(transformed).forEach(key => {
863
+ const value = transformed[key];
864
+
865
+ // Skip null or non-object values
866
+ if (!value || typeof value !== "object" || !propHasValue(value)) return;
867
+
868
+ // Handle arrays - filter out empty objects
869
+ if (Array.isArray(value)) {
870
+ transformed[key] = value.filter(hasContent);
871
+ return;
872
+ }
873
+
874
+ // Handle objects with fileLists
875
+ if (hasFileList(value)) {
876
+ transformed[key] = extractFiles(value.fileList);
877
+ return;
878
+ }
879
+
880
+ // Handle nested objects that might have fileLists
881
+ Object.keys(value).forEach(nestedKey => {
882
+ const nestedValue = value[nestedKey];
883
+
884
+ if (hasFileList(nestedValue)) {
885
+ transformed[key][nestedKey] = extractFiles(nestedValue.fileList);
886
+ }
887
+ });
888
+ });
889
+
890
+ return transformed;
891
+ };
package/src/pages.js CHANGED
@@ -16,4 +16,7 @@ export { default as MineSummary } from './@daf/pages/Summary/Minesite/index.jsx'
16
16
  export { default as MonitoringActivitySummary } from './@daf/pages/Summary/Activities/Monitoring/index.jsx';
17
17
 
18
18
  // View
19
- export { default as View } from './@daf/pages/View/index.jsx';
19
+ export { default as View } from './@daf/pages/View/index.jsx';
20
+
21
+ // Edit
22
+ export { default as Edit } from './@daf/pages/Edit/index.jsx';
package/src/utils.js CHANGED
@@ -12,7 +12,7 @@ export { propHasValue } from './helpers/deepFind'
12
12
  export { isEmptyOrSpaces, capitalizeAll, capitalize, camelCaseToTitle, snakeCaseToTitleCase, titleToCamelCase, findOptions, getOptionAsObject, nowToIso, renderTemplateString, renderTemplateStringInObject, truncateString, splitStringInMultipleLines, safeJsonParse, cleanJSON, formatToKebabCase } from './helpers/StringHelper.js'
13
13
  export { getNkey, groupSubsections, getImageUploadViewValue } from './@daf/core/components/ViewForm/helper'
14
14
  export { renderRows } from './@daf/core/components/Table/helper'
15
- export { filterOptions, filterString, hasNotChanged, filterSelectOptions, mapSubGroupsInSubmit, mapSubGroupsInGet, filterCreateData, changeInputMeta, renderDateFormatted, sortForm } from './helpers/Forms'
15
+ export { filterOptions, filterString, hasNotChanged, filterSelectOptions, mapSubGroupsInSubmit, mapSubGroupsInGet, filterCreateData, changeInputMeta, renderDateFormatted, sortForm, extractFiles, hasFileList, hasContent, transformPayload } from './helpers/Forms'
16
16
  export { mapFormGroup, showHideInput, editErrorHandler } from './@daf/core/components/EditForm/helper'
17
17
 
18
18
  export { defaultFilterKeys, getDefaultActiveFilters, filterParams } from './@daf/utils/filters';
@@ -62,4 +62,6 @@ export {
62
62
 
63
63
  export { renderBreadCrumbs, buildBreadCrumbs as buildBreadCrumbsHelper } from './helpers/breadCrumbs.js'
64
64
 
65
- export { copyToClipboard } from './helpers/copyToClipboard.js'
65
+ export { copyToClipboard } from './helpers/copyToClipboard.js'
66
+
67
+ export { isArrayOfObjects } from './@daf/utils/arrays.js'