datastake-daf 0.6.811 → 0.6.813

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 (57) hide show
  1. package/dist/components/index.js +1509 -379
  2. package/dist/hooks/index.js +11 -4
  3. package/dist/pages/index.js +138 -16
  4. package/dist/services/index.js +56 -6
  5. package/dist/utils/index.js +28 -5
  6. package/package.json +1 -1
  7. package/src/@daf/core/components/AuthForm/index.jsx +12 -3
  8. package/src/@daf/core/components/Dashboard/Widget/FaunaWidget/index.jsx +1 -2
  9. package/src/@daf/core/components/Screens/Admin/AdminDashboard/components/UserStatistics/TopContributors/index.jsx +0 -1
  10. package/src/@daf/core/components/Screens/Admin/AdminDashboard/components/UserStatistics/UserGrowth/hook.js +0 -1
  11. package/src/@daf/core/components/Screens/Admin/AdminDashboard/components/UserStatistics/UserGrowth/index.jsx +1 -3
  12. package/src/@daf/core/components/Screens/Admin/AdminModals/CombineLocation/index.jsx +51 -51
  13. package/src/@daf/core/components/Screens/Admin/AdminModals/CombineSubjects/index.jsx +6 -1
  14. package/src/@daf/core/components/Screens/Admin/AdminModals/NewAccount/index.jsx +56 -31
  15. package/src/@daf/core/components/Screens/Admin/AdminModals/NewUser/index.jsx +36 -10
  16. package/src/@daf/core/components/Screens/Admin/AdminModals/TransferRights/index.jsx +1 -1
  17. package/src/@daf/core/components/Screens/Admin/AdminScreens/Accounts.jsx +37 -10
  18. package/src/@daf/core/components/Screens/Admin/AdminScreens/Dashboard.jsx +2 -2
  19. package/src/@daf/core/components/Screens/Admin/AdminScreens/Documents.jsx +81 -0
  20. package/src/@daf/core/components/Screens/Admin/AdminScreens/Events.jsx +77 -0
  21. package/src/@daf/core/components/Screens/Admin/AdminScreens/index.js +2 -0
  22. package/src/@daf/core/components/Screens/Admin/AdminTables/AccountTable/helper.js +22 -30
  23. package/src/@daf/core/components/Screens/Admin/AdminTables/AccountTable/index.jsx +25 -13
  24. package/src/@daf/core/components/Screens/Admin/AdminTables/DocumentsTable/column.js +127 -0
  25. package/src/@daf/core/components/Screens/Admin/AdminTables/DocumentsTable/helper.js +43 -0
  26. package/src/@daf/core/components/Screens/Admin/AdminTables/DocumentsTable/index.jsx +201 -0
  27. package/src/@daf/core/components/Screens/Admin/AdminTables/EventsTable/column.js +146 -0
  28. package/src/@daf/core/components/Screens/Admin/AdminTables/EventsTable/helper.js +58 -0
  29. package/src/@daf/core/components/Screens/Admin/AdminTables/EventsTable/index.jsx +176 -0
  30. package/src/@daf/core/components/Screens/Admin/AdminTables/LocationTable/index.jsx +17 -2
  31. package/src/@daf/core/components/Screens/Admin/AdminTables/SubjectsTable/index.jsx +27 -13
  32. package/src/@daf/core/components/Screens/Admin/AdminTables/UserTable/index.jsx +0 -1
  33. package/src/@daf/core/components/Screens/Admin/AdminTables/components/index.jsx +4 -2
  34. package/src/@daf/core/components/Screens/Admin/AdminTables/hook.js +3 -0
  35. package/src/@daf/core/components/Screens/Admin/AdminViews/components/Edit/index.jsx +12 -9
  36. package/src/@daf/core/components/Screens/Admin/AdminViews/components/Users/index.jsx +16 -4
  37. package/src/@daf/core/components/Screens/Admin/AdminViews/components/View/helpers.js +9 -17
  38. package/src/@daf/core/components/Screens/Admin/AdminViews/index.jsx +9 -8
  39. package/src/@daf/core/components/Screens/Admin/AppInvitation/index.jsx +124 -99
  40. package/src/@daf/core/components/Screens/Admin/adminRoutes.js +48 -1
  41. package/src/@daf/hooks/useAdminDashboard.js +7 -4
  42. package/src/@daf/pages/Summary/Activities/Monitoring/components/BiodiversityAndHabitat/index.jsx +2 -2
  43. package/src/@daf/pages/Summary/Activities/Monitoring/helper.js +24 -0
  44. package/src/@daf/pages/View/hooks/useViewActions.js +13 -0
  45. package/src/@daf/pages/View/hooks/useViewPermissions.js +16 -0
  46. package/src/@daf/pages/View/index.jsx +29 -4
  47. package/src/@daf/services/AdminService.js +47 -5
  48. package/src/@daf/services/DashboardService.js +3 -3
  49. package/src/@daf/utils/filters.js +13 -15
  50. package/src/constants/locales/en/translation.js +13 -0
  51. package/src/helpers/copyToClipboard.js +60 -0
  52. package/build/favicon.ico +0 -0
  53. package/build/logo192.png +0 -0
  54. package/build/logo512.png +0 -0
  55. package/build/manifest.json +0 -25
  56. package/build/robots.txt +0 -3
  57. package/dist/style/datastake/mapbox-gl.css +0 -330
@@ -1,30 +1,30 @@
1
1
  import React, { useState, useEffect } from "react";
2
- import { Checkbox, Form, Input, message } from 'antd';
2
+ import { Checkbox, message } from 'antd';
3
3
  import DafButton from '../../../Button/index.jsx';
4
4
  import Loading from "../../../Loading/index.jsx";
5
+ import AuthForm from "../../../AuthForm/index.jsx";
5
6
 
7
+
8
+
9
+ const theme = window.theme;
6
10
  export default function AppInvitation({
7
- // Redux State
8
11
  errors,
9
12
  user,
10
13
  invitationSuccess,
11
- // Actions
12
14
  confirmInvitation,
13
15
  getUserFromInvitation,
14
- // Configuration
16
+ theme,
15
17
  Layout,
16
18
  redirectPath = "/",
17
19
  loginPath = "/login",
18
20
  appRedirectPath = "/app",
19
21
  params: propParams = {},
22
+ goTo,
23
+ isMobile = false,
24
+ t,
20
25
  }) {
21
- const { t } = useTranslation();
22
- const routeParams = useParams();
23
- const { app, companyCode, userCode } = { ...routeParams, ...propParams };
24
- const [passwords] = Form.useForm();
26
+ const { app, companyCode, userCode } = propParams;
25
27
  const [checking, setChecking] = useState(true);
26
- const goTo = useNavigate();
27
- const [termsAgreed, setTermsAgreed] = useState(false);
28
28
  const [passwordReseted, setPasswordReseted] = useState(false);
29
29
 
30
30
  useEffect(() => {
@@ -46,36 +46,125 @@ export default function AppInvitation({
46
46
  localStorage.setItem('token', data.token);
47
47
  }
48
48
  message.success(t('Invitation accepted'));
49
- // Fix: ensure we don't rely on a variable from useParams that might not exist
50
- // Just use the configured redirectPath
51
- goTo(redirectPath);
49
+ if (goTo && typeof goTo === 'function') {
50
+ goTo(redirectPath);
51
+ } else {
52
+ window.location.href = redirectPath;
53
+ }
52
54
  },
53
55
  { companyCode, userCode }
54
56
  );
55
57
  }
56
58
  }, [invitationSuccess, user, confirmInvitation, goTo, redirectPath, companyCode, userCode, t]);
57
59
 
58
- const displayError = (name) => {
59
- return errors && errors[name] && errors[name].length > 0 && {
60
- help: errors[name][0],
61
- validateStatus: 'error',
62
- };
63
- };
60
+
61
+ useEffect(() => {
62
+
63
+ const isInInvitationFlow = checking ||
64
+ (invitationSuccess && user && user.inviteToken) ||
65
+ (invitationSuccess && user && !user.inviteToken);
66
+
67
+ if (!isInInvitationFlow) {
68
+ if (user) {
69
+ if (goTo && typeof goTo === 'function') {
70
+ goTo(appRedirectPath);
71
+ } else {
72
+ window.location.href = appRedirectPath;
73
+ }
74
+ } else {
75
+ if (goTo && typeof goTo === 'function') {
76
+ goTo(redirectPath);
77
+ } else {
78
+ window.location.href = redirectPath;
79
+ }
80
+ }
81
+ }
82
+ }, [user, goTo, appRedirectPath, redirectPath, checking, invitationSuccess]);
64
83
 
65
84
  const subTitle = !passwordReseted ? 'Set up your password and agree with out terms and conditions.' :
66
85
  isMobile ? 'Your account has been successfully set up. To log in use a desktop device.'
67
86
  : 'Your account has been successfully set up. Please click the button below to log in.';
68
87
  const title = passwordReseted ? 'Thank You!' : undefined;
69
88
 
89
+ const fields = [
90
+ {
91
+ name: 'email',
92
+ label: t("Email"),
93
+ type: 'input',
94
+ disabled: true,
95
+ },
96
+ {
97
+ name: 'password',
98
+ label: t("Password"),
99
+ type: 'password',
100
+ required: true,
101
+ rules: [{
102
+ required: true,
103
+ message: t("errors::password should not be empty")
104
+ }],
105
+ placeholder: t("Password"),
106
+ },
107
+ {
108
+ name: 'confirmPassword',
109
+ label: t("Confirm Password"),
110
+ type: 'password',
111
+ required: true,
112
+ dependencies: ['password'],
113
+ rules: [
114
+ {
115
+ required: true,
116
+ message: t("errors::password should not be empty"),
117
+ },
118
+ ({ getFieldValue }) => ({
119
+ validator(rule, value) {
120
+ if (!value || getFieldValue('password') === value) {
121
+ return Promise.resolve();
122
+ }
123
+ return Promise.reject(t('errors::passwordNotMatch'));
124
+ },
125
+ }),
126
+ ],
127
+ placeholder: t("Confirm Password"),
128
+ },
129
+ {
130
+ name: 'mailUpdates',
131
+ type: 'custom',
132
+ valuePropName: 'checked',
133
+ component: <Checkbox>{t("Sign up to receive updates")}</Checkbox>,
134
+ },
135
+ {
136
+ name: 'agreeTerms',
137
+ type: 'custom',
138
+ valuePropName: 'checked',
139
+ rules: [{
140
+ validator: (_, value) => value ? Promise.resolve() : Promise.reject(new Error(t('You must agree to the terms and conditions')))
141
+ }],
142
+ component: (
143
+ <Checkbox>
144
+ <p className="mb-0">
145
+ {t('Agree to the Terms of Use of this application and the Privacy Policy')}
146
+ </p>
147
+ </Checkbox>
148
+ ),
149
+ }
150
+ ];
151
+
152
+ const handleSubmit = (values) => {
153
+ const { password, mailUpdates } = values;
154
+ confirmInvitation(
155
+ { password, mailUpdates },
156
+ () => { },
157
+ { companyCode, userCode }
158
+ );
159
+ setPasswordReseted(true);
160
+ };
161
+
70
162
  if (checking && !invitationSuccess) {
71
163
  return <Loading />;
72
164
  }
73
165
 
74
- // If auto-confirming (inviteToken present), we might want to show loading or nothing until redirect
75
166
  if (invitationSuccess && user && user.inviteToken) {
76
- // The useEffect will handle the redirect/confirm.
77
- // We can show loading here too or just return null.
78
- // Original code: checks invitationSuccess && !user.inviteToken for form, else redirect.
167
+
79
168
  return <Loading />;
80
169
  }
81
170
 
@@ -88,6 +177,7 @@ export default function AppInvitation({
88
177
  <DafButton
89
178
  type="primary"
90
179
  className="normal-br"
180
+ style={theme || window.theme ? { backgroundColor: (theme || window.theme).colorPrimary, borderColor: (theme || window.theme).colorPrimary } : {}}
91
181
  onClick={() => {
92
182
  window.location.href = loginPath;
93
183
  }}
@@ -97,86 +187,21 @@ export default function AppInvitation({
97
187
  )}
98
188
  </div>
99
189
  ) : (
100
- <>
101
- <Form name="password" layout="vertical" form={passwords} >
102
- <Form.Item
103
- required
104
- name="password"
105
- {...displayError('password')}
106
- label={t("Password")}
107
- rules={[{
108
- required: true,
109
- message: t("errors::password should not be empty")
110
- }]}>
111
- <Input.Password size="large" placeholder={t("Password")} />
112
- </Form.Item>
113
- <Form.Item
114
- required
115
- name="confirmPassword"
116
- {...displayError('confirmPassword')}
117
- label={t("Confirm Password")}
118
- dependencies={['password']}
119
- rules={[
120
- {
121
- required: true,
122
- message: t("errors::password should not be empty"),
123
- },
124
- ({ getFieldValue }) => ({
125
- validator(rule, value) {
126
- if (!value || getFieldValue('password') === value) {
127
- return Promise.resolve();
128
- }
129
- return Promise.reject(t('errors::passwordNotMatch'));
130
- },
131
- }),
132
- ]}>
133
- <Input.Password size="large" placeholder={t("Confirm Password")} />
134
- </Form.Item>
135
- <Form.Item
136
- name="mailUpdates" valuePropName="checked" noStyle>
137
- <Checkbox>{t("Sign up to receive updates")}</Checkbox>
138
- </Form.Item>
139
- <Form.Item
140
- name="agreeTerms" valuePropName="checked" noStyle>
141
- <Checkbox
142
- checked={termsAgreed}
143
- onChange={(e) => setTermsAgreed(e.target.checked)}
144
- >
145
- <p className="mb-0">
146
- {t('Agree to the Terms of Use of this application and the Privacy Policy')}
147
- </p>
148
- </Checkbox>
149
- </Form.Item>
150
- </Form>
151
- <div className="buttons">
152
- <DafButton
153
- className="normal-br"
154
- type="primary"
155
- block
156
- size="large"
157
- disabled={!termsAgreed}
158
- onClick={() => {
159
- passwords.validateFields().then(data => {
160
- const { password, mailUpdates } = data;
161
- confirmInvitation(
162
- { password, mailUpdates },
163
- () => { },
164
- { companyCode, userCode }
165
- );
166
- setPasswordReseted(true);
167
- });
168
- }}
169
- >
170
- {t("Confirm")}
171
- </DafButton>
172
- </div>
173
- </>
190
+ <AuthForm
191
+ fields={fields}
192
+ onSubmit={handleSubmit}
193
+ submitText={t("Confirm")}
194
+ initialValues={{ email: user?.email }}
195
+ errors={errors}
196
+ t={t}
197
+ executeRecaptcha={() => Promise.resolve(true)}
198
+ theme={theme || window.theme}
199
+ />
174
200
  )}
175
201
  </>
176
202
  );
177
203
 
178
204
  if (Layout) {
179
- // Assuming Layout accepts these props as per Nashiriki AuthLayout
180
205
  return <Layout app={app} step={1} subTitle={subTitle} title={title}>{Content}</Layout>;
181
206
  }
182
207
 
@@ -189,5 +214,5 @@ export default function AppInvitation({
189
214
  );
190
215
  }
191
216
 
192
- return user ? <Navigate to={appRedirectPath} /> : <Navigate to={redirectPath} />;
217
+ return null;
193
218
  }
@@ -6,7 +6,8 @@ import AdminAccountsViewScreen from "./AdminScreens/AccountsView.jsx";
6
6
  import AdminSubjectsScreen from "./AdminScreens/Subjects.jsx";
7
7
  import AdminLocationScreen from "./AdminScreens/Location.jsx";
8
8
  import AdminSubjectsViewScreen from "./AdminScreens/SubjectsView.jsx";
9
-
9
+ import AdminEventsScreen from "./AdminScreens/Events.jsx";
10
+ import AdminDocumentsScreen from "./AdminScreens/Documents.jsx";
10
11
  export function getAdminRoutes(config) {
11
12
  const {
12
13
  appName,
@@ -18,6 +19,8 @@ export function getAdminRoutes(config) {
18
19
  useAdminLocationConfig,
19
20
  useAdminSubjectsViewConfig,
20
21
  useAdminLocationViewConfig,
22
+ useAdminDocumentsConfig,
23
+ useAdminEventsConfig,
21
24
  userIsAdmin,
22
25
  } = config;
23
26
 
@@ -91,11 +94,31 @@ export function getAdminRoutes(config) {
91
94
  return <AdminSubjectsViewScreen config={{ ...stakeholderViewConfig, subject: "stakeholder", mode: "edit" }} />;
92
95
  }
93
96
 
97
+ function DocumentsWrapper() {
98
+ const documentsConfig =
99
+ typeof useAdminDocumentsConfig === "function"
100
+ ? useAdminDocumentsConfig()
101
+ : undefined;
102
+ return <AdminDocumentsScreen config={documentsConfig} />;
103
+ }
104
+
105
+ function EventsWrapper() {
106
+ const eventsConfig =
107
+ typeof useAdminEventsConfig === "function"
108
+ ? useAdminEventsConfig()
109
+ : undefined;
110
+ return <AdminEventsScreen config={eventsConfig} />;
111
+ }
112
+
94
113
  const subjectsIndexComponent =
95
114
  typeof useAdminLocationConfig === "function"
96
115
  ? <LocationWrapper />
97
116
  : typeof useAdminSubjectsConfig === "function"
98
117
  ? <SubjectsWrapper />
118
+ : typeof useAdminDocumentsConfig === "function"
119
+ ? <DocumentsWrapper />
120
+ : typeof useAdminEventsConfig === "function"
121
+ ? <EventsWrapper />
99
122
  : <div />;
100
123
 
101
124
  const routes = [
@@ -156,6 +179,30 @@ export function getAdminRoutes(config) {
156
179
  visible: (user) => userIsAdmin(user),
157
180
  component: <SubjectsWrapper />,
158
181
  },
182
+
183
+ ]
184
+
185
+ : []),
186
+ ...(typeof useAdminDocumentsConfig === "function"
187
+ ? [
188
+ {
189
+ path: "management/subjects/document",
190
+ key: `${APP_PREFIX}_ADMIN_SUBJECTS_DOCUMENTS`,
191
+ exact: true,
192
+ visible: (user) => userIsAdmin(user),
193
+ component: <DocumentsWrapper />,
194
+ },
195
+ ]
196
+ : []),
197
+ ...(typeof useAdminEventsConfig === "function"
198
+ ? [
199
+ {
200
+ path: "management/subjects/event",
201
+ key: `${APP_PREFIX}_ADMIN_SUBJECTS_EVENTS`,
202
+ exact: true,
203
+ visible: (user) => userIsAdmin(user),
204
+ component: <EventsWrapper />,
205
+ },
159
206
  ]
160
207
  : []),
161
208
  ];
@@ -46,15 +46,20 @@ export function useAdminDashboard({ dashboardService, onError }) {
46
46
  }, [dashboardService, onError]);
47
47
 
48
48
  const fetchUserGrowth = useCallback(
49
- async (params) => {
49
+ async (activeFilter) => {
50
50
  if (!dashboardService?.getUserGrowth) {
51
51
  console.warn("dashboardService.getUserGrowth not provided");
52
52
  return;
53
53
  }
54
54
 
55
+ if (activeFilter === undefined || activeFilter === null) {
56
+ console.warn("activeFilter not provided to fetchUserGrowth");
57
+ return;
58
+ }
59
+
55
60
  setUserGrowthDataLoading(true);
56
61
  try {
57
- const response = await dashboardService.getUserGrowth(params);
62
+ const response = await dashboardService.getUserGrowth(activeFilter);
58
63
  setUserGrowthData(response || []);
59
64
  } catch (err) {
60
65
  if (onError) {
@@ -68,11 +73,9 @@ export function useAdminDashboard({ dashboardService, onError }) {
68
73
  },
69
74
  [dashboardService, onError]
70
75
  );
71
-
72
76
  useEffect(() => {
73
77
  fetchDashboardData();
74
78
  }, [fetchDashboardData]);
75
-
76
79
  return {
77
80
  data,
78
81
  loading,
@@ -40,8 +40,8 @@ const BiodiversityAndHabitat = ({
40
40
  title={t("Observed Fauna")}
41
41
  faunaPresent={faunaPresent}
42
42
  columnsPerRow={5}
43
- itemWidth={120}
44
- itemHeight={120}
43
+ itemWidth={130}
44
+ itemHeight={130}
45
45
  loading={loading}
46
46
  t={t}
47
47
  />
@@ -237,6 +237,30 @@ export const getMapDataFromActivity = (activityData, t) => {
237
237
  });
238
238
  }
239
239
 
240
+ // Entry 4: Generic locationCheck marker (independent - show if it exists)
241
+ const locationCheckLat = activityData?.locationCheck?.latitude;
242
+ const locationCheckLng = activityData?.locationCheck?.longitude;
243
+ if (isValidCoordinate(locationCheckLat) && isValidCoordinate(locationCheckLng)) {
244
+ mapData.push({
245
+ _id: {},
246
+ id: `${activityData?.id || activityData?.datastakeId || 'locationcheck'}-locationcheck`,
247
+ // Include area if it exists, so marker can show on top of polygon
248
+ area: area && area.length >= 3 ? area : null,
249
+ color: baseColor,
250
+ gps: {
251
+ latitude: typeof locationCheckLat === 'number' ? locationCheckLat : parseFloat(locationCheckLat),
252
+ longitude: typeof locationCheckLng === 'number' ? locationCheckLng : parseFloat(locationCheckLng),
253
+ },
254
+ name: t("Location Check"),
255
+ plotName: locationName,
256
+ territoryTitle: t("Associated Plot"),
257
+ datastakeId: `${datastakeId}-locationcheck`,
258
+ markerColor: "#016C6E",
259
+ sources: null,
260
+ link: null,
261
+ });
262
+ }
263
+
240
264
  // Return mapData even if empty - let the map component handle empty arrays
241
265
  return mapData;
242
266
  };
@@ -17,6 +17,8 @@ export const useViewActions = ({
17
17
  t,
18
18
  viewConfig,
19
19
  buttonActions,
20
+ canDelete,
21
+ deleteSubject,
20
22
  }) => {
21
23
  const [pageActions, setPageActions] = useState([]);
22
24
  const [extraPageActions, setExtraPageActions] = useState([]);
@@ -50,6 +52,12 @@ export const useViewActions = ({
50
52
  }
51
53
  }
52
54
  }
55
+
56
+ if(canDelete) {
57
+ if(viewConfig.deleteNamespaces.includes(namespace)){
58
+ actions.push(buttonActions.createDeleteButton(t, deleteSubject))
59
+ }
60
+ }
53
61
 
54
62
  if (viewConfig.summaryNamespaces.includes(namespace)) {
55
63
  extraActions.push(
@@ -58,6 +66,11 @@ export const useViewActions = ({
58
66
  extraActions.push(
59
67
  buttonActions.createRecordsButton(t, setOpenRecordsModal)
60
68
  );
69
+ if(canDelete) {
70
+ if(viewConfig.deleteNamespaces.includes(namespace)){
71
+ extraActions.push(buttonActions.createDeleteButton(t, deleteSubject))
72
+ }
73
+ }
61
74
  }
62
75
 
63
76
  setPageActions(actions);
@@ -6,6 +6,7 @@ export const useViewPermissions = ({
6
6
  namespaceOverrides = {
7
7
  supportedNamespaces: {},
8
8
  canEdit: {},
9
+ canDelete: {},
9
10
  },
10
11
  namespace,
11
12
  user,
@@ -16,6 +17,7 @@ export const useViewPermissions = ({
16
17
  viewConfig,
17
18
  }) => {
18
19
  const baseNamespaceKeys = Object.keys(namespaceConfig || {});
20
+ console.log({namespaceConfig})
19
21
 
20
22
  const baseSupportedNamespaces = baseNamespaceKeys?.reduce((acc, key) => {
21
23
  acc[key] = () => true;
@@ -55,6 +57,19 @@ export const useViewPermissions = ({
55
57
  return canEditAction[namespace] ? canEditAction[namespace]() : false;
56
58
  }, [namespace, data, user]);
57
59
 
60
+ const canDelete = useMemo(() => {
61
+ const basecanDeleteAction = baseNamespaceKeys.reduce((acc, key) => {
62
+ acc[key] = () => isUserData();
63
+ return acc;
64
+ }, {});
65
+
66
+ const canDeleteAction = {
67
+ ...namespaceOverrides.canDelete,
68
+ };
69
+
70
+ return canDeleteAction[namespace] ? canDeleteAction[namespace]() : false;
71
+ }, [namespace, data, user, namespaceOverrides])
72
+
58
73
  useEffect(() => {
59
74
  if (data) {
60
75
  if (typeof isSupportedNamespaces[namespace] === "function") {
@@ -69,6 +84,7 @@ export const useViewPermissions = ({
69
84
  isSupportedNamespaces,
70
85
  canEdit,
71
86
  isSupported,
87
+ canDelete
72
88
  }
73
89
 
74
90
  }
@@ -1,11 +1,11 @@
1
- import React, { useMemo, useState, useEffect } from 'react'
1
+ import React, { useMemo, useState, useEffect, useCallback } from 'react'
2
2
  import { useViewUrlParams } from './hooks/useViewUrlParams.js'
3
3
  import { usePrepareForm } from './hooks/usePrepareForm.js'
4
4
  import { useViewPermissions } from './hooks/useViewPermissions.js'
5
5
  import { useSubmitSubject } from './hooks/useSubmitSubject.js'
6
6
  import { useCallToGetData } from './hooks/useCallToGetData.js'
7
7
  import { useViewActions } from './hooks/useViewActions.js'
8
-
8
+ import AdminService from '../../services/AdminService.js'
9
9
  import { groupSubsections } from '../../../@daf/core/components/ViewForm/helper.js'
10
10
  import Loading from '../../../@daf/core/components/Loading/index.jsx'
11
11
  import Header from '../../../@daf/core/components/Header/index.jsx'
@@ -14,7 +14,8 @@ import ViewFormNavigation from '../../../@daf/core/components/ViewForm/navigatio
14
14
  import ViewForm from '../../../@daf/core/components/ViewForm/content.jsx'
15
15
  import Records from '../../../@daf/core/components/ViewForm/components/Records/index.jsx'
16
16
  import { Template } from '../Template/index.jsx'
17
-
17
+ import {message} from 'antd'
18
+ import { handleError } from '../../services/ErrorService.js'
18
19
  const View = ({
19
20
  push,
20
21
  getRedirectLink,
@@ -102,7 +103,7 @@ const View = ({
102
103
  viewConfig,
103
104
  });
104
105
 
105
- const { canEdit, isSupported } = useViewPermissions({
106
+ const { canEdit, isSupported, canDelete } = useViewPermissions({
106
107
  data,
107
108
  id,
108
109
  namespace,
@@ -132,6 +133,28 @@ const View = ({
132
133
  serviceMap,
133
134
  });
134
135
 
136
+
137
+ const subjects = {
138
+ "management-location": "location",
139
+ "management-stakeholder": "stakeholder",
140
+ }
141
+
142
+
143
+ const handleDeleteSubject = useCallback(async () => {
144
+ try {
145
+ await AdminService.deleteSubject({
146
+ subject: subjects[namespace],
147
+ id: id,
148
+ })
149
+ message.success(t("Subject deleted successfully"))
150
+ goTo(getRedirectLink(`/app/management/subject/${subjects[namespace]}`))
151
+ } catch (error) {
152
+ handleError(error)
153
+ message.error(t("Failed to delete subject"))
154
+ }
155
+
156
+ }, [namespace, id, t])
157
+
135
158
  const { pageActions, extraPageActions } = useViewActions({
136
159
  namespace,
137
160
  data,
@@ -149,6 +172,8 @@ const View = ({
149
172
  t,
150
173
  viewConfig,
151
174
  buttonActions,
175
+ canDelete,
176
+ deleteSubject: handleDeleteSubject
152
177
  });
153
178
 
154
179
  useEffect(() => {
@@ -17,6 +17,8 @@ class AdminService extends BaseService {
17
17
  }
18
18
 
19
19
 
20
+
21
+
20
22
  inviteCompanyAccount({ companyId, data }) {
21
23
  return this.apiPost({
22
24
  url: `/accounts/${companyId}/invite`,
@@ -24,6 +26,21 @@ class AdminService extends BaseService {
24
26
  })
25
27
  }
26
28
 
29
+ resendInvitation({invitationToken
30
+ }){
31
+ return this.apiPost({
32
+ url: `/accounts/resendInvitation/${invitationToken}`,
33
+ })
34
+ }
35
+
36
+ copyInvitation({invitationToken
37
+ }){
38
+ return this.apiPost({
39
+ url: `/accounts/copyInvitation/${invitationToken}`,
40
+ })
41
+ }
42
+
43
+
27
44
  inviteAccount(data) {
28
45
  return this.apiPost({
29
46
  url: `/accounts/inviteAccount`,
@@ -38,7 +55,14 @@ class AdminService extends BaseService {
38
55
  })
39
56
  }
40
57
 
41
- updateAccount({ data, id }) {
58
+ updateAccount({ data, id, isPending=false }) {
59
+ if (isPending) {
60
+ return this.apiPut({
61
+ data,
62
+ url: `/accounts/invitation/${id}`,
63
+ })
64
+ }
65
+
42
66
  return this.apiPut({
43
67
  data,
44
68
  url: `/accounts/${id}`,
@@ -147,6 +171,19 @@ class AdminService extends BaseService {
147
171
  url: `/management/subject/${subject}/${id}`,
148
172
  });
149
173
  }
174
+
175
+ getItems({ item }) {
176
+ return this.apiGet({
177
+ url: `/management/items/${item}`,
178
+ });
179
+ }
180
+
181
+ getItemData({ item, id }) {
182
+ return this.apiGet({
183
+ url: `/management/item/${item}/${id}`,
184
+ });
185
+ }
186
+
150
187
 
151
188
 
152
189
  viewLocation({ id }) {
@@ -166,7 +203,7 @@ class AdminService extends BaseService {
166
203
  const type = subject === 'location' ? 'location' : 'stakeholder';
167
204
  return this.apiPut({
168
205
  url: `/management/subject/${type}/${id}`,
169
- data: filterCreateData(data),
206
+ data: data,
170
207
  });
171
208
  }
172
209
 
@@ -177,15 +214,20 @@ class AdminService extends BaseService {
177
214
  });
178
215
  }
179
216
 
180
- getUserGrowth(activeFilter) {
181
- return this.apiGet({
217
+ async getUserGrowth(activeFilter) {
218
+ const { data } = await this.apiGet({
182
219
  url: `/accounts/dashboard/user-growth`,
183
220
  isUserManager: true,
184
221
  params: { activeFilter },
185
222
  });
223
+ return data;
186
224
  }
187
225
 
188
-
226
+ removeUserFromAccount({ accountId, userId }) {
227
+ return this.apiPut({
228
+ url: `/companies/${accountId}/remove-user/${userId}`,
229
+ })
230
+ }
189
231
  }
190
232
 
191
233
  export default createLazyService(AdminService);