datastake-daf 0.6.782 → 0.6.783

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,95 @@
1
+ import { renderType } from './config.js';
2
+ import { renderDateFormatted } from '../../../../../helpers/Forms.js';
3
+ import CustomIcon from '../../../../core/components/Icon/CustomIcon.jsx';
4
+
5
+ export const getColumns = ({ t, redirect = () => "", mod, mode = "app", options }) => [
6
+ {
7
+ title: "ID",
8
+ dataIndex: "datastakeId",
9
+ key: "datastakeId",
10
+ },
11
+ {
12
+ title: t("Type"),
13
+ dataIndex: "type",
14
+ key: "type",
15
+ render: (type, all) => renderType({ item: all, t, type }),
16
+ },
17
+ {
18
+ title: t("Name"),
19
+ dataIndex: "name",
20
+ key: "name",
21
+ render: (name, all) => {
22
+ if (all.empty) {
23
+ return <div className="daf-default-cell" />;
24
+ }
25
+
26
+ if (all?.form === "products") {
27
+ const { minerals } = options;
28
+ const mineral = minerals.find(
29
+ (mineral) => mineral.value === all?.typeOfProduct,
30
+ )?.label;
31
+ return mineral || "--";
32
+ }
33
+
34
+ return name || "--";
35
+ },
36
+ },
37
+ {
38
+ title: t("Last Update"),
39
+ dataIndex: "updatedAt",
40
+ key: "updateAt",
41
+ render: (updatedAt, all) => {
42
+ if (all.empty) {
43
+ return <div className="daf-default-cell" />;
44
+ }
45
+
46
+ return (
47
+ <div className="daf-default-cell">
48
+ {renderDateFormatted(updatedAt, "DD MMM YYYY")}
49
+ </div>
50
+ );
51
+ },
52
+ },
53
+ {
54
+ title: "",
55
+ dataIndex: "actions",
56
+ width: 50,
57
+ key: "actions",
58
+ render: (_, all) => {
59
+ if (all.empty) {
60
+ return <div className="daf-default-cell" />;
61
+ }
62
+
63
+ return mode === "proxy" ? (
64
+ <a
65
+ onClick={() =>
66
+ redirect({
67
+ id: all.datastakeId,
68
+ type: all.type,
69
+ mod,
70
+ mode,
71
+ item: all,
72
+ })
73
+ }
74
+ href="#"
75
+ >
76
+ <CustomIcon name="LinkNewTab" width={14} height={14} color="#6C737F" />
77
+ </a>
78
+ ) : (
79
+ <a
80
+ href={redirect({
81
+ id: all.datastakeId,
82
+ type: all.type,
83
+ mod,
84
+ mode,
85
+ item: all,
86
+ })}
87
+ target="_blank"
88
+ rel="noreferrer"
89
+ >
90
+ <CustomIcon name="LinkNewTab" width={14} height={14} color="#6C737F" />
91
+ </a>
92
+ );
93
+ },
94
+ },
95
+ ];
@@ -0,0 +1,75 @@
1
+ import React from "react";
2
+ import { capitalizeAll } from '../../../../../helpers/StringHelper.js';
3
+
4
+
5
+ export const decapitalize = string =>
6
+ string && string.charAt(0).toLowerCase() + string.slice(1);
7
+
8
+ const formatRedirectString = (stringItem) => {
9
+ let string;
10
+ if (stringItem.includes("nashiriki")) {
11
+ string = decapitalize(stringItem?.replaceAll("nashiriki", ""));
12
+ } else {
13
+ string = stringItem;
14
+ }
15
+ return string;
16
+ };
17
+
18
+ export const getLanguage = (lng = "") => {
19
+ if (lng.includes("en")) {
20
+ return "en";
21
+ }
22
+
23
+ if (lng.includes("fr")) {
24
+ return "fr";
25
+ }
26
+ };
27
+
28
+ export const redirect = ({ id, item }) => {
29
+ const viewMode = "view";
30
+ let type = "testimonials";
31
+
32
+ if (item.category === "mineSite") {
33
+ type = "scl";
34
+ }
35
+
36
+ if (item.stakeholderType === "operator") {
37
+ type = "operators";
38
+ }
39
+
40
+ if (item.stakeholderType === "worker") {
41
+ type = "workers";
42
+ }
43
+
44
+ if (item.form) {
45
+ type = `${formatRedirectString(item.form)}s`;
46
+ }
47
+
48
+ let url = `/${viewMode}/${type}/${id}`;
49
+
50
+ return `/app${url}`;
51
+ };
52
+
53
+ export const renderType = ({ item = {}, t = (s) => s }) => {
54
+ if (item.empty) {
55
+ return <div className="daf-default-cell" />;
56
+ }
57
+
58
+ if (item.category === "mineSite") {
59
+ return t("Mine Site");
60
+ }
61
+
62
+ if (item.stakeholderType === "operator") {
63
+ return t("Operator");
64
+ }
65
+
66
+ if (item.stakeholderType === "worker") {
67
+ return t("Worker");
68
+ }
69
+
70
+ if (item.form) {
71
+ return t(capitalizeAll(item.form));
72
+ }
73
+
74
+ return "--";
75
+ };
@@ -0,0 +1,119 @@
1
+ import React, { useEffect, useMemo } from 'react';
2
+ import { useFilters } from '../../../../hooks/useFilters.js';
3
+ import { getColumns } from './columns.js';
4
+ import { redirect } from './config.js';
5
+ import LinkedSubjectsService from '../../../../services/LinkedSubjects.js';
6
+ import { formatClassname } from '../../../../../helpers/ClassesHelper.js';
7
+ import Table from '../../../../core/components/Table/index.jsx';
8
+ import Pagination from '../../../../core/components/Table/Pagination/index.jsx';
9
+
10
+ const emptyObject = {};
11
+
12
+ const LinkingTemplate = ({
13
+ conf,
14
+ namespace
15
+ }) => {
16
+ const view = useMemo(() => conf?.location?.pathname?.split(`/app/${conf.mod}/`)[1], [conf]);
17
+
18
+ const {
19
+ pagination,
20
+ onTableChange,
21
+ totalPages,
22
+ canGoNext,
23
+ canGoPrev,
24
+ setPagination,
25
+ goPrev,
26
+ goNext,
27
+ } = useFilters({
28
+ module: conf.mod,
29
+ view,
30
+ selectFiltersConfig: emptyObject,
31
+ filtersConfig: emptyObject,
32
+ });
33
+
34
+ const columns = useMemo(() => getColumns({
35
+ t: conf.t,
36
+ redirect,
37
+ mod: conf.mod,
38
+ language: conf.user?.language,
39
+ mode: conf.mode,
40
+ options: conf.options,
41
+ }), [conf]);
42
+
43
+ const id = conf.allData.id;
44
+
45
+ const dataSource = conf?.linkingTemplateContextData?.[id];
46
+
47
+ const changeData = async () => {
48
+ try {
49
+ const _data = await LinkedSubjectsService.getLinkedSubjects({ namespace, id, mod: conf.mod });
50
+ const data = (_data?.data || []).map((d, i) => ({ ...d, key: `${d.id}-${i}` }));
51
+ conf?.addData(id, data);
52
+ setPagination((prev) => ({
53
+ ...prev,
54
+ current: 1,
55
+ total: data.length ? data.length : 1,
56
+ }));
57
+ } catch (err) {
58
+ console.log(err);
59
+ }
60
+ };
61
+
62
+ const _dataSource = useMemo(() => {
63
+ const startIndex = pagination.pageSize * (pagination.current - 1);
64
+ const endIndex = Math.min(startIndex + pagination.pageSize, dataSource?.length || 0);
65
+ return [...(dataSource || [])].slice(startIndex, endIndex);
66
+ }, [pagination, dataSource]);
67
+
68
+ useEffect(() => {
69
+ if (!dataSource) {
70
+ changeData();
71
+ } else {
72
+ setPagination((prev) => ({
73
+ ...prev,
74
+ current: 1,
75
+ total: dataSource.length ? dataSource.length : 1,
76
+ }));
77
+ }
78
+ }, []);
79
+
80
+
81
+ return ( <div className={formatClassname(["content", "documents-layout"])} style={{}}>
82
+ <div className="view-header" style={{ flexDirection: "column", paddingTop: 0 }}>
83
+ <div className="daf-table-wrapper pagination-no-padding">
84
+ <Table
85
+ className="mt-0 p-0"
86
+ columns={columns}
87
+ hideOnLoading={false}
88
+ data={_dataSource}
89
+ doEmptyRows
90
+ loading={!dataSource}
91
+ rowKey="key"
92
+ pagination={pagination}
93
+ size="small"
94
+ />
95
+
96
+ <Pagination
97
+ t={conf?.t}
98
+ isMobile={conf?.isMobile}
99
+ page={pagination.current}
100
+ totalPages={totalPages}
101
+ goPrev={goPrev}
102
+ goNext={goNext}
103
+ canGoNext={canGoNext}
104
+ canGoPrev={canGoPrev}
105
+ totalItems={pagination.total}
106
+ doTotalItems
107
+ onChangePagination={(val) => {
108
+ onTableChange({ ...pagination, current: 1, pageSize: val });
109
+ }}
110
+ perPage={pagination.pageSize}
111
+ arrowIcons
112
+ />
113
+ </div>
114
+ </div>
115
+ </div>
116
+ )
117
+ };
118
+
119
+ export default LinkingTemplate;
@@ -0,0 +1,19 @@
1
+ /* eslint-disable react/prop-types */
2
+ import React from 'react';
3
+ import LinkingTemplate from './components/LinkingTemplate/index.jsx';
4
+
5
+ export function Template({
6
+ conf,
7
+ namespace,
8
+ }) {
9
+ switch (namespace) {
10
+ case 'locations':
11
+ case 'documents':
12
+ case 'stakeholders':
13
+ case 'events':
14
+ return <LinkingTemplate conf={conf} namespace={namespace} />
15
+ default:
16
+ return null;
17
+
18
+ }
19
+ }
@@ -0,0 +1,73 @@
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
+ }
@@ -0,0 +1,86 @@
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
+ }
@@ -0,0 +1,40 @@
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
+ };
@@ -0,0 +1,83 @@
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
+ };
@@ -0,0 +1,74 @@
1
+ import { useMemo, useEffect } from "react";
2
+
3
+ export const useViewPermissions = ({
4
+ data,
5
+ id,
6
+ namespaceOverrides = {
7
+ supportedNamespaces: {},
8
+ canEdit: {},
9
+ },
10
+ namespace,
11
+ user,
12
+ push,
13
+ getRedirectLink,
14
+ namespaceConfig,
15
+ APP,
16
+ viewConfig,
17
+ }) => {
18
+ const baseNamespaceKeys = Object.keys(namespaceConfig || {});
19
+
20
+ const baseSupportedNamespaces = baseNamespaceKeys?.reduce((acc, key) => {
21
+ acc[key] = () => true;
22
+ return acc;
23
+ }, {});
24
+
25
+ const isSupportedNamespaces = useMemo(
26
+ () => ({
27
+ ...baseSupportedNamespaces,
28
+ ...namespaceOverrides?.supportedNamespaces,
29
+ }),
30
+ [data, id],
31
+ );
32
+
33
+ const isSupported = typeof isSupportedNamespaces[namespace] === "function"
34
+ ? isSupportedNamespaces[namespace]() &&
35
+ viewConfig?.supportedNamespaces[APP] &&
36
+ viewConfig?.supportedNamespaces[APP]?.includes(namespace)
37
+ : viewConfig?.supportedNamespaces[APP] && viewConfig?.supportedNamespaces[APP].includes(namespace);
38
+
39
+
40
+ const isUserData = () => {
41
+ return data && data.authorId && user?.company?.id === data.authorId;
42
+ };
43
+
44
+ const canEdit = useMemo(() => {
45
+ const baseCanEditAction = baseNamespaceKeys.reduce((acc, key) => {
46
+ acc[key] = () => isUserData();
47
+ return acc;
48
+ }, {});
49
+
50
+ const canEditAction = {
51
+ ...baseCanEditAction,
52
+ ...namespaceOverrides.canEdit,
53
+ };
54
+
55
+ return canEditAction[namespace] ? canEditAction[namespace]() : false;
56
+ }, [namespace, data, user]);
57
+
58
+ useEffect(() => {
59
+ if (data) {
60
+ if (typeof isSupportedNamespaces[namespace] === "function") {
61
+ if (!isSupportedNamespaces[namespace]()) {
62
+ push(getRedirectLink(`/app`));
63
+ }
64
+ }
65
+ }
66
+ }, [data, namespace]);
67
+
68
+ return {
69
+ isSupportedNamespaces,
70
+ canEdit,
71
+ isSupported,
72
+ }
73
+
74
+ }