datastake-daf 0.6.350 → 0.6.352

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.
@@ -7416,6 +7416,7 @@ const en = {
7416
7416
  FB00006: "Account successfully activated",
7417
7417
  FB00007: "Make sure that this has been properly communicated, as the account admin holds critical user management privileges.",
7418
7418
  admin: {
7419
+ "merge-subjects": "Merge Subjects",
7419
7420
  "events": "Events",
7420
7421
  "documents": "Documents",
7421
7422
  "stakeholders": "Stakeholders",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datastake-daf",
3
- "version": "0.6.350",
3
+ "version": "0.6.352",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^5.2.5",
6
6
  "@antv/g2": "^5.1.1",
@@ -1,6 +1,6 @@
1
1
  import { findOptions } from "../../../../../../../helpers/StringHelper.js";
2
2
  import { Tooltip } from "antd";
3
- import { getNameByLevel } from "../../AdminTables/LocationTable/helper.js";
3
+ import { getNameByLevel } from "../../AdminTables/SubjectsTable/helper.js";
4
4
 
5
5
  export const getColumns = ({ t, selectOptions, module, entity }) => {
6
6
  return [
@@ -5,7 +5,7 @@ import { findOptions } from "../../../../../../../helpers/StringHelper.js";
5
5
  import DAFTable from "../../../../Table/index.jsx";
6
6
  import { useMemo, useState } from "react";
7
7
  import { getColumns } from "./helper.js";
8
- import { getNameByLevel } from "../../AdminTables/LocationTable/helper.js";
8
+ import { getNameByLevel } from "../../AdminTables/SubjectsTable/helper.js";
9
9
 
10
10
  const { useToken } = theme;
11
11
 
@@ -0,0 +1,79 @@
1
+ import { findOptions } from "../../../../../../../helpers/StringHelper.js";
2
+ import { Tooltip } from "antd";
3
+ import { getNameByLevel } from "../../AdminTables/SubjectsTable/helper.js";
4
+
5
+ export const getColumns = ({ t, selectOptions, module, entity }) => {
6
+ return [
7
+ {
8
+ title: t("admin::organisation_id"),
9
+ dataIndex: "datastakeId",
10
+ key: "datastakeId",
11
+ show: true,
12
+ render: (value, all) => {
13
+ return <Tooltip title={value}>{value}</Tooltip>;
14
+ },
15
+ },
16
+ {
17
+ title: t("Name"),
18
+ dataIndex: "name",
19
+ key: "name",
20
+ show: true,
21
+ render: (value, all) => {
22
+ return <Tooltip title={value}>{value}</Tooltip>;
23
+ },
24
+ },
25
+ {
26
+ title: t("Category"),
27
+ dataIndex: "category",
28
+ key: "category",
29
+ show: true,
30
+ render: (value, all) => {
31
+ const label = findOptions(value, selectOptions?.category);
32
+ return <Tooltip title={label}>{label}</Tooltip>;
33
+ },
34
+ },
35
+ {
36
+ title: t("Country"),
37
+ dataIndex: "country",
38
+ key: "country",
39
+ show: true,
40
+ render: (value, all) => {
41
+ const label = findOptions(value, selectOptions?.country);
42
+ return <Tooltip title={label}>{label}</Tooltip>;
43
+ },
44
+ },
45
+ {
46
+ title: t("Province"),
47
+ dataIndex: "administrativeLevel1",
48
+ key: "administrativeLevel1",
49
+ ellipsis: true,
50
+ show: entity.includes("locations"),
51
+ render: (value, all) => {
52
+ let label;
53
+ if(all?.administrativeLevel1 && value === all?.administrativeLevel1) {
54
+ label = all?.linking?.SCL?.[value]?.name
55
+ } else {
56
+ label = getNameByLevel(all?.linking?.SCL, "level_1")?.name
57
+ }
58
+
59
+ return <Tooltip title={label || '-'}>{label || '-'}</Tooltip>;
60
+ },
61
+ },
62
+ {
63
+ title: t("Territory"),
64
+ dataIndex: "administrativeLevel2",
65
+ key: "administrativeLevel2",
66
+ show: entity.includes("locations"),
67
+ render: (value, all) => {
68
+ let label;
69
+ if(all?.administrativeLevel2 && value === all?.administrativeLevel2) {
70
+ label = all?.linking?.SCL?.[value]?.name
71
+ } else {
72
+ label = getNameByLevel(all?.linking?.SCL, "level_2")?.name
73
+ }
74
+
75
+ return <Tooltip title={label || '-'}>{label || '-'}</Tooltip>;
76
+ },
77
+ },
78
+ ].filter((c) => c?.show);
79
+ };
@@ -0,0 +1,21 @@
1
+ export const mapToSelectOptions = (items, valueKey, selectOptions, optionKey, customMapper = null) => {
2
+ return items
3
+ .map((item) => {
4
+ if (customMapper) {
5
+ return customMapper(item);
6
+ }
7
+
8
+ const value = item?.[valueKey] || "-";
9
+ const optionsList = selectOptions?.[optionKey] || [];
10
+ const foundOption = optionsList.find((option) => option.value === value);
11
+
12
+ return {
13
+ label: foundOption?.label || value,
14
+ value: value,
15
+ };
16
+ })
17
+ .filter(
18
+ (option, index, self) =>
19
+ index === self.findIndex((o) => o.value === option.value),
20
+ );
21
+ };
@@ -0,0 +1,172 @@
1
+ import Modal from "../../../../Modal/index.jsx";
2
+ import { Form, Input, Select, theme } from "antd";
3
+ import { Container } from "../CombineModalStyle.js";
4
+ import { findOptions } from "../../../../../../../helpers/StringHelper.js";
5
+ import DAFTable from "../../../../Table/index.jsx";
6
+ import { useMemo, useState } from "react";
7
+ import { mapToSelectOptions } from "./helper.js";
8
+ import { getColumns } from "./columns.js";
9
+ import { getNameByLevel } from "../../AdminTables/SubjectsTable/helper.js";
10
+
11
+ const { useToken } = theme;
12
+
13
+ export default function CombineSubjectsModal({
14
+ isOpen,
15
+ t,
16
+ onClose,
17
+ onSuccess,
18
+ selectedSubjects,
19
+ selectOptions,
20
+ module,
21
+ entity,
22
+ }) {
23
+ const { token } = useToken();
24
+ const [MainForm] = Form.useForm();
25
+ const [isDisabled, setIsDisabled] = useState(true);
26
+
27
+ const columns = useMemo(() => {
28
+ return getColumns({
29
+ t,
30
+ selectOptions,
31
+ module,
32
+ selectedSubjects,
33
+ entity,
34
+ });
35
+ }, [selectedSubjects, t, selectOptions, module, entity]);
36
+
37
+ const onSubmit = () => {
38
+ MainForm.validateFields().then((data) => {
39
+ const ids = selectedSubjects.map((subject) => subject._id);
40
+ onSuccess({
41
+ ids,
42
+ data,
43
+ });
44
+ });
45
+ };
46
+
47
+ return (
48
+ <Modal
49
+ open={isOpen}
50
+ title={t("admin::merge")}
51
+ onClose={onClose}
52
+ onSuccess={onSubmit}
53
+ withModalFormWrapper={false}
54
+ width={1100}
55
+ disabled={isDisabled}
56
+ destroyOnClose={true}
57
+ onValuesChange={() => {
58
+ setIsDisabled(() => {
59
+ const values = MainForm.getFieldsValue();
60
+
61
+ const requiredFields =
62
+ entity === "location"
63
+ ? ["id", "name", "category", "country", "administrativeLevel1", "administrativeLevel2"]
64
+ : ["id", "name", "category", "country"];
65
+
66
+ return requiredFields.some((field) => values[field] === undefined);
67
+ });
68
+ }}
69
+ >
70
+ <Container>
71
+ <div className="daf-table-wrapper no-pagination">
72
+ <span
73
+ className="merge-modal-section-text"
74
+ style={{
75
+ color: token.baseGray90,
76
+ }}
77
+ >
78
+ {t("admin::current_subjects")}
79
+ </span>
80
+ <DAFTable
81
+ columns={columns}
82
+ data={selectedSubjects}
83
+ pagination={false}
84
+ loading={false}
85
+ rowKey="userId"
86
+ />
87
+ </div>
88
+
89
+ <span
90
+ className="merge-modal-section-text"
91
+ style={{
92
+ color: token.baseGray90,
93
+ marginTop: 14,
94
+ }}
95
+ >
96
+ {t("admin::merged_output")}
97
+ </span>
98
+
99
+ <Form
100
+ form={MainForm}
101
+ clearOnDestroy={true}
102
+ className="select-container"
103
+ onValuesChange={() => {
104
+ setIsDisabled((prev) => {
105
+ const values = MainForm.getFieldsValue();
106
+ return Object.keys(values).some((key) => values[key] === undefined);
107
+ });
108
+ }}
109
+ style={{
110
+ borderColor: token.baseGray50,
111
+ }}
112
+ >
113
+ <Form.Item className="flex-1" name="id">
114
+ <Select
115
+ options={mapToSelectOptions(selectedSubjects, "datastakeId", selectOptions, null)}
116
+ placeholder={t("ID")}
117
+ ></Select>
118
+ </Form.Item>
119
+
120
+ <Form.Item className="flex-1" name="name">
121
+ <Input placeholder={t("Name")}></Input>
122
+ </Form.Item>
123
+
124
+ <Form.Item className="flex-1" name="category">
125
+ <Select
126
+ options={mapToSelectOptions(selectedSubjects, "category", selectOptions, "category")}
127
+ placeholder={t("Category")}
128
+ ></Select>
129
+ </Form.Item>
130
+
131
+ <Form.Item className="flex-1" name="country">
132
+ <Select
133
+ options={mapToSelectOptions(selectedSubjects, "country", selectOptions, "country")}
134
+ placeholder={t("admin::country")}
135
+ ></Select>
136
+ </Form.Item>
137
+
138
+ {entity.includes("locations") && (
139
+ <>
140
+ <Form.Item className="flex-1" name="administrativeLevel1">
141
+ <Select
142
+ placeholder={t("Province")}
143
+ options={mapToSelectOptions(selectedSubjects, null, selectOptions, null, (subject) => {
144
+ const _data = getNameByLevel(subject?.linking?.SCL, "level_1");
145
+ return {
146
+ label: _data?.name || "-",
147
+ value: _data?.id || "-",
148
+ };
149
+ })}
150
+ />
151
+ </Form.Item>
152
+
153
+ <Form.Item className="flex-1" name="administrativeLevel2">
154
+ <Select
155
+ placeholder={t("Territory")}
156
+ options={mapToSelectOptions(selectedSubjects, null, selectOptions, null, (subject) => {
157
+ const _data = getNameByLevel(subject?.linking?.SCL, "level_2");
158
+ return {
159
+ label: _data?.name || "-",
160
+ value: _data?.id || "-",
161
+ };
162
+ })}
163
+ />
164
+ </Form.Item>
165
+ </>
166
+ )}
167
+ </Form>
168
+ </Container>
169
+ <div style={{ height: 57 }} />
170
+ </Modal>
171
+ );
172
+ }
@@ -10,8 +10,8 @@ import {
10
10
  filtersConfig,
11
11
  defaultUrlParams,
12
12
  checkboxConfig,
13
- getColumns,
14
- } from "./helper.js";
13
+ } from "../SubjectsTable/helper.js";
14
+ import { getColumns } from "../SubjectsTable/columns.js";
15
15
  import CombineLocationModal from "../../AdminModals/CombineLocation/index.jsx";
16
16
  const { useToken } = theme;
17
17
 
@@ -1,9 +1,9 @@
1
- import LocationTable from ".";
1
+ import SubjectsTable from "./index.jsx";
2
2
  import ThemeLayout from "../../../../ThemeLayout";
3
3
 
4
4
  export default {
5
- title: "Screen/Admin/LocationTable",
6
- component: LocationTable,
5
+ title: "Screen/Admin/SubjectsTable",
6
+ component: SubjectsTable,
7
7
  tags: ["autodocs"],
8
8
  decorators: [
9
9
  (Story) => (
@@ -17,7 +17,7 @@ export default {
17
17
  };
18
18
 
19
19
  export const Primary = {
20
- name: "Location Table",
20
+ name: "Subjects Table",
21
21
  args: {
22
22
  goTo: (goToPath) => console.log("Go to", goToPath),
23
23
  t: (text) => text,
@@ -1,72 +1,7 @@
1
1
  import { Checkbox, Tooltip, Avatar } from "antd";
2
2
  import CustomIcon from "../../../../Icon/CustomIcon.jsx";
3
3
  import { findOptions } from "../../../../../../../helpers/StringHelper.js";
4
-
5
- export const view = "locations";
6
-
7
- export const getTabs = ({ t }) => {
8
- return [
9
- {
10
- key: "active",
11
- label: t("Active"),
12
- },
13
- {
14
- key: "pending",
15
- label: t("Pending"),
16
- },
17
- {
18
- key: 'suspended',
19
- label: t("Suspended"),
20
- }
21
- ];
22
- };
23
-
24
- export const selectFiltersConfig = {
25
- category: {
26
- type: "select",
27
- label: "Category",
28
- placeholder: (t) => t("Category"),
29
- style: { flex: 1 },
30
- labelStyle: { flex: 1 },
31
- getLabel: (option) => option.label,
32
- getValue: (option) => option.value,
33
- },
34
- country: {
35
- type: "select",
36
- label: "Country",
37
- placeholder: (t) => t("Country"),
38
- style: { flex: 1 },
39
- labelStyle: { flex: 1 },
40
- getLabel: (option) => option.label,
41
- getValue: (option) => option.value,
42
- },
43
- sources: {
44
- type: "select",
45
- label: "Sources",
46
- placeholder: (t) => t("Sources"),
47
- style: { flex: 1 },
48
- labelStyle: { flex: 1 },
49
- getLabel: (option) => option.label,
50
- getValue: (option) => option.value,
51
- },
52
- };
53
-
54
- export const filtersConfig = {
55
- name: "",
56
- datastakeId: "",
57
- };
58
-
59
- export const defaultUrlParams = { activeTab: "active" };
60
-
61
- export const checkboxConfig = {
62
- name: "Name",
63
- datastakeId: "ID",
64
- };
65
-
66
- export const getNameByLevel = (data, level) => {
67
- const entry = Object.values(data || {}).find(item => item.level === level);
68
- return entry;
69
- }
4
+ import { getNameByLevel } from "./helper.js";
70
5
 
71
6
  export const getColumns = ({
72
7
  t,
@@ -74,8 +9,8 @@ export const getColumns = ({
74
9
  show = "show",
75
10
  getRedirectLink = () => {},
76
11
  token,
77
- selectedLocations,
78
- setSelectedLocations,
12
+ selectedSubjects,
13
+ setSelectedSubjects,
79
14
  selectOptions,
80
15
  entity,
81
16
  }) => {
@@ -93,7 +28,7 @@ export const getColumns = ({
93
28
  return (
94
29
  <Checkbox
95
30
  onChange={() =>
96
- setSelectedLocations((prev) => {
31
+ setSelectedSubjects((prev) => {
97
32
  const isSelected = prev.some((p) => p.id === all.id);
98
33
  if (isSelected) {
99
34
  return prev.filter((p) => p.id !== all.id);
@@ -101,10 +36,10 @@ export const getColumns = ({
101
36
  return [...prev, all];
102
37
  })
103
38
  }
104
- checked={selectedLocations.some((p) => p.id === all.id)}
39
+ checked={selectedSubjects.some((p) => p.id === all.id)}
105
40
  disabled={
106
- selectedLocations?.length >= 3 &&
107
- !selectedLocations.some((p) => p.id === all.id)
41
+ selectedSubjects?.length >= 3 &&
42
+ !selectedSubjects.some((p) => p.id === all.id)
108
43
  }
109
44
  />
110
45
  );
@@ -286,4 +221,4 @@ export const getColumns = ({
286
221
  ];
287
222
 
288
223
  return cols.filter((c) => c[show]);
289
- };
224
+ };
@@ -0,0 +1,65 @@
1
+ export const getTabs = ({ t }) => {
2
+ return [
3
+ {
4
+ key: "active",
5
+ label: t("Active"),
6
+ },
7
+ {
8
+ key: "pending",
9
+ label: t("Pending"),
10
+ },
11
+ {
12
+ key: 'suspended',
13
+ label: t("Suspended"),
14
+ }
15
+ ];
16
+ };
17
+
18
+ export const selectFiltersConfig = {
19
+ category: {
20
+ type: "select",
21
+ label: "Category",
22
+ placeholder: (t) => t("Category"),
23
+ style: { flex: 1 },
24
+ labelStyle: { flex: 1 },
25
+ getLabel: (option) => option.label,
26
+ getValue: (option) => option.value,
27
+ },
28
+ country: {
29
+ type: "select",
30
+ label: "Country",
31
+ placeholder: (t) => t("Country"),
32
+ style: { flex: 1 },
33
+ labelStyle: { flex: 1 },
34
+ getLabel: (option) => option.label,
35
+ getValue: (option) => option.value,
36
+ },
37
+ sources: {
38
+ type: "select",
39
+ label: "Sources",
40
+ placeholder: (t) => t("Sources"),
41
+ style: { flex: 1 },
42
+ labelStyle: { flex: 1 },
43
+ getLabel: (option) => option.label,
44
+ getValue: (option) => option.value,
45
+ },
46
+ };
47
+
48
+ export const filtersConfig = {
49
+ name: "",
50
+ datastakeId: "",
51
+ };
52
+
53
+ export const defaultUrlParams = { activeTab: "active" };
54
+
55
+ export const checkboxConfig = {
56
+ name: "Name",
57
+ datastakeId: "ID",
58
+ };
59
+
60
+ export const getNameByLevel = (data, level) => {
61
+ const entry = Object.values(data || {}).find(item => item.level === level);
62
+ return entry;
63
+ }
64
+
65
+
@@ -0,0 +1,181 @@
1
+ import { useState, useMemo } from "react";
2
+ import { useAdminTable } from "../hook";
3
+ import AdminTable from "../components/index.jsx";
4
+ import DAFTable from "../../../../Table/index.jsx";
5
+ import { theme, Tag } from "antd";
6
+ import CustomIcon from "../../../../Icon/CustomIcon.jsx";
7
+ import {
8
+ getTabs,
9
+ selectFiltersConfig,
10
+ filtersConfig,
11
+ defaultUrlParams,
12
+ checkboxConfig,
13
+ } from "./helper.js";
14
+ import { getColumns } from "./columns.js";
15
+ import CombineSubjectsModal from "../../AdminModals/CombineSubjects/index.jsx";
16
+
17
+ const { useToken } = theme;
18
+
19
+ export default function SubjectsTable({
20
+ t = (text) => text,
21
+ isMobile,
22
+ goTo,
23
+ getRedirectLink,
24
+ location,
25
+ getData,
26
+ module,
27
+ config,
28
+ defaultPageSize = 20,
29
+ view,
30
+ headerTitle,
31
+ breadcrumbs,
32
+ mergeSubjectsFunction,
33
+ refetchTrigger,
34
+ }) {
35
+ const [showFilters, setShowFilters] = useState(false);
36
+ const [hasError, setHasError] = useState(false);
37
+ const [selectedSubjects, setSelectedSubjects] = useState([]);
38
+ const { token } = useToken();
39
+ const [isCombineModalOpen, setIsModalOpen] = useState(false);
40
+
41
+ const {
42
+ filter,
43
+ activeTab,
44
+ canClearSearch,
45
+ totalPending,
46
+ data,
47
+ loading,
48
+ initFetchDone,
49
+ fetchData,
50
+ fetchPendingAccounts,
51
+ setLoading,
52
+ } = useAdminTable({
53
+ goTo,
54
+ location,
55
+ selectFiltersConfig,
56
+ view,
57
+ defaultUrlParams,
58
+ module,
59
+ defaultPageSize,
60
+ filtersConfig,
61
+ getRedirectLink,
62
+ getData,
63
+ refetchTrigger,
64
+ });
65
+
66
+ const selectOptions = useMemo(() => {
67
+ return {
68
+ category: config.options?.category,
69
+ country: config.options?.countries,
70
+ sources: [], //TODO: add sources logic and make sure you only show unique sources only once
71
+ };
72
+ }, [config.options]);
73
+
74
+ const columns = useMemo(() => {
75
+ return getColumns({
76
+ t,
77
+ goTo,
78
+ token,
79
+ module,
80
+ selectedSubjects,
81
+ setSelectedSubjects,
82
+ getRedirectLink,
83
+ selectOptions,
84
+ entity: headerTitle
85
+ });
86
+ }, [t, goTo, module, token, selectedSubjects, getRedirectLink, selectOptions, headerTitle]);
87
+
88
+ return (
89
+ <>
90
+ <AdminTable
91
+ filters={filter}
92
+ t={t}
93
+ headerTitle={headerTitle}
94
+ actionButton={[
95
+ {
96
+ icon: "Merge",
97
+ onClick: () => setIsModalOpen(true),
98
+ tooltip: t("admin::merge-subjects"),
99
+ disabled: selectedSubjects.length < 2,
100
+ },
101
+ ]}
102
+ tabs={getTabs({ t })}
103
+ isMobile={isMobile}
104
+ activeTab={activeTab}
105
+ showFilters={showFilters}
106
+ setShowFilters={setShowFilters}
107
+ hasError={hasError}
108
+ setHasError={setHasError}
109
+ canClearSearch={canClearSearch}
110
+ selectOptions={selectOptions}
111
+ checkboxConfig={checkboxConfig}
112
+ defaultTableFilters={{}}
113
+ breadcrumbs={breadcrumbs}
114
+ >
115
+ {selectedSubjects.length > 0 && (
116
+ <div
117
+ className="flex flex-row ml-6 mt-5"
118
+ style={{
119
+ flexWrap: "wrap",
120
+ gap: "8px",
121
+ }}
122
+ >
123
+ {selectedSubjects.map((account) => (
124
+ <Tag
125
+ key={account.userId}
126
+ className="flex flex-row gap-2 items-center"
127
+ onClick={() =>
128
+ setSelectedSubjects((prev) =>
129
+ prev.filter((a) => a.datastakeId !== account.datastakeId),
130
+ )
131
+ }
132
+ style={{
133
+ cursor: "pointer",
134
+ }}
135
+ >
136
+ <span>{account.datastakeId}</span>
137
+ <CustomIcon name="Close" size={10} />
138
+ </Tag>
139
+ ))}
140
+ </div>
141
+ )}
142
+ <DAFTable
143
+ columns={columns}
144
+ data={data}
145
+ loading={loading}
146
+ hideOnLoading={false}
147
+ pagination={filter.pagination}
148
+ rowKey="id"
149
+ selectOptions={selectOptions}
150
+ doEmptyRows
151
+ setShowFilters={setShowFilters}
152
+ filtersConfig={selectFiltersConfig}
153
+ onFilterChange={filter.onFiltersChange}
154
+ showFilters={showFilters}
155
+ defaultFilters={filter.defaultFilters}
156
+ onChange={filter.onTableChange}
157
+ />
158
+ </AdminTable>
159
+
160
+ <CombineSubjectsModal
161
+ isOpen={isCombineModalOpen}
162
+ t={t}
163
+ onClose={() => {
164
+ setIsModalOpen(false);
165
+ }}
166
+ onSuccess={(data) => {
167
+ setIsModalOpen(false);
168
+ setLoading(true);
169
+ if (typeof mergeSubjectsFunction === 'function') {
170
+ mergeSubjectsFunction(data);
171
+ setSelectedSubjects([])
172
+ }
173
+ }}
174
+ selectedSubjects={selectedSubjects}
175
+ selectOptions={selectOptions || {}}
176
+ module={module}
177
+ entity={headerTitle}
178
+ />
179
+ </>
180
+ );
181
+ }