@truedat/auth 8.14.3 → 8.14.4

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 (66) hide show
  1. package/package.json +4 -4
  2. package/src/messages/en.js +6 -5
  3. package/src/messages/es.js +8 -7
  4. package/src/styles/UserCard.less +582 -0
  5. package/src/styles/UserModals.less +826 -0
  6. package/src/styles/Users.less +280 -0
  7. package/src/users/components/AdminUserRoutes.js +7 -20
  8. package/src/users/components/EditUser.js +7 -34
  9. package/src/users/components/EditUserModal.js +150 -0
  10. package/src/users/components/NewUser.js +128 -17
  11. package/src/users/components/Password.js +11 -189
  12. package/src/users/components/UserAcls.js +56 -6
  13. package/src/users/components/UserActions.js +99 -34
  14. package/src/users/components/UserCard.js +168 -22
  15. package/src/users/components/UserCards.js +273 -35
  16. package/src/users/components/UserFormFields.js +206 -0
  17. package/src/users/components/UserGroupAclRow.js +8 -2
  18. package/src/users/components/UserGroupAcls.js +2 -2
  19. package/src/users/components/UserGroupLink.js +21 -0
  20. package/src/users/components/UserInfoModal.js +268 -0
  21. package/src/users/components/UserPasswordField.js +66 -0
  22. package/src/users/components/UserPasswordModal.js +210 -0
  23. package/src/users/components/UserRoutes.js +4 -13
  24. package/src/users/components/UserTabs.js +5 -2
  25. package/src/users/components/UserTypeSelector.js +109 -0
  26. package/src/users/components/UsersAndGroups.js +39 -5
  27. package/src/users/components/UsersTable.js +234 -0
  28. package/src/users/components/__tests__/EditUser.spec.js +84 -10
  29. package/src/users/components/__tests__/NewUser.spec.js +34 -4
  30. package/src/users/components/__tests__/Password.spec.js +53 -146
  31. package/src/users/components/__tests__/UserAcls.spec.js +23 -2
  32. package/src/users/components/__tests__/UserCard.spec.js +111 -5
  33. package/src/users/components/__tests__/UserCards.spec.js +194 -0
  34. package/src/users/components/__tests__/UserGroupAclRow.spec.js +19 -1
  35. package/src/users/components/__tests__/UserModals.spec.js +507 -0
  36. package/src/users/components/__tests__/UserRoutes.spec.js +8 -3
  37. package/src/users/components/__tests__/UserTypeSelector.spec.js +32 -0
  38. package/src/users/components/__tests__/UsersAndGroups.spec.js +17 -0
  39. package/src/users/components/__tests__/__snapshots__/UserCard.spec.js.snap +64 -37
  40. package/src/users/components/__tests__/__snapshots__/UserCards.spec.js.snap +424 -75
  41. package/src/users/components/__tests__/__snapshots__/UserGroupAclRow.spec.js.snap +7 -3
  42. package/src/users/components/__tests__/__snapshots__/UserRoutes.spec.js.snap +4 -13
  43. package/src/users/hooks/useSortedGroups.js +13 -0
  44. package/src/users/hooks/useUserModalOperation.js +55 -0
  45. package/src/users/reducers/__tests__/userRedirect.spec.js +14 -3
  46. package/src/users/reducers/index.js +1 -0
  47. package/src/users/reducers/userModalOperation.js +29 -0
  48. package/src/users/reducers/userRedirect.js +5 -4
  49. package/src/users/sagas/__tests__/updateUser.spec.js +19 -1
  50. package/src/users/sagas/createUser.js +12 -5
  51. package/src/users/sagas/deleteUser.js +12 -5
  52. package/src/users/sagas/updateUser.js +19 -8
  53. package/src/users/selectors/__tests__/filterUsers.spec.js +11 -0
  54. package/src/users/selectors/__tests__/getUserAcls.spec.js +1 -0
  55. package/src/users/selectors/__tests__/getUserGroupAcls.spec.js +2 -0
  56. package/src/users/selectors/filterUsers.js +9 -1
  57. package/src/users/selectors/getUserGroupAcls.js +1 -0
  58. package/src/users/components/User.js +0 -68
  59. package/src/users/components/UserPassword.js +0 -24
  60. package/src/users/components/__tests__/User.spec.js +0 -20
  61. package/src/users/components/__tests__/UserPassword.spec.js +0 -24
  62. package/src/users/components/__tests__/__snapshots__/EditUser.spec.js.snap +0 -281
  63. package/src/users/components/__tests__/__snapshots__/NewUser.spec.js.snap +0 -321
  64. package/src/users/components/__tests__/__snapshots__/Password.spec.js.snap +0 -128
  65. package/src/users/components/__tests__/__snapshots__/User.spec.js.snap +0 -129
  66. package/src/users/components/__tests__/__snapshots__/UserPassword.spec.js.snap +0 -124
@@ -0,0 +1,280 @@
1
+ .users-role-accordion.ui.styled.accordion {
2
+ clear: both;
3
+ border: 0;
4
+ border-radius: 0;
5
+ box-shadow: none;
6
+ margin-top: 0.8rem;
7
+ background: transparent;
8
+ }
9
+
10
+ .users-role-accordion.ui.styled.accordion .title.users-role-title {
11
+ margin-bottom: 0.28rem;
12
+ border: 0;
13
+ border-bottom: 1px solid #d1d5db;
14
+ border-radius: 0;
15
+ background: transparent;
16
+ padding: 0.2rem 0.52rem 0.2rem 0.7rem;
17
+ box-shadow: none;
18
+ }
19
+
20
+ .users-role-toggle {
21
+ display: block;
22
+ width: 100%;
23
+ margin: 0;
24
+ padding: 0;
25
+ border: 0;
26
+ background: transparent;
27
+ color: inherit;
28
+ font: inherit;
29
+ text-align: left;
30
+ cursor: pointer;
31
+
32
+ &:focus-visible {
33
+ outline: 2px solid #1d4ed8;
34
+ outline-offset: 2px;
35
+ border-radius: 2px;
36
+ }
37
+ }
38
+
39
+ .users-role-title-content {
40
+ display: flex;
41
+ align-items: center;
42
+ justify-content: flex-start;
43
+ gap: 0.3rem;
44
+ }
45
+
46
+ .users-role-title-header.ui.header {
47
+ margin: 0;
48
+ display: flex;
49
+ align-items: center;
50
+ color: #0f172a;
51
+ min-height: 0.92rem;
52
+ }
53
+
54
+ .users-role-title-header.ui.header .content {
55
+ display: inline-flex;
56
+ align-items: center;
57
+ min-height: 0.9rem;
58
+ font-size: 1.34rem;
59
+ font-weight: 800;
60
+ letter-spacing: 0.01em;
61
+ line-height: 1;
62
+ }
63
+
64
+ .users-role-accordion.ui.styled.accordion
65
+ .users-role-title-header.ui.header
66
+ .content {
67
+ padding: 1rem 0 !important;
68
+ }
69
+
70
+ .users-role-count.ui.circular.label {
71
+ min-width: 1.34rem;
72
+ height: 1.34rem;
73
+ display: inline-flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ margin: 0;
77
+ font-size: 0.68rem;
78
+ font-weight: 800;
79
+ background: #0f172a;
80
+ color: #ffffff;
81
+ }
82
+
83
+ .users-role-chevron.icon {
84
+ margin: 0;
85
+ color: #334155;
86
+ font-size: 1.15rem;
87
+ line-height: 1;
88
+ }
89
+
90
+ .users-role-accordion.ui.styled.accordion .content.users-role-content {
91
+ margin: 0 0 0.55rem;
92
+ padding: 0 0.14rem 0.12rem;
93
+ border: 0;
94
+ background: transparent;
95
+ }
96
+
97
+ .users-role-card-group.ui.cards {
98
+ display: grid;
99
+ grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
100
+ gap: 1.75em 1rem;
101
+ margin: 0;
102
+ padding-block: 0.875em;
103
+
104
+ &::before,
105
+ &::after {
106
+ display: none;
107
+ }
108
+
109
+ > .ui.card.td-card-base.td-card--user {
110
+ width: 100%;
111
+ max-width: none;
112
+ min-width: 0;
113
+ margin: 0;
114
+ }
115
+ }
116
+
117
+ @media (min-width: 1600px) {
118
+ .users-role-card-group.ui.cards {
119
+ grid-template-columns: repeat(5, minmax(0, 1fr));
120
+ }
121
+ }
122
+
123
+ .users-role-title.users-role-title--admin {
124
+ border-bottom-color: #93c5fd;
125
+ }
126
+
127
+ .users-role-title.users-role-title--user {
128
+ border-bottom-color: #86efac;
129
+ }
130
+
131
+ .users-role-title.users-role-title--agent {
132
+ border-bottom-color: #c4b5fd;
133
+ }
134
+
135
+ .users-role-title.users-role-title--service {
136
+ border-bottom-color: #fdba74;
137
+ }
138
+
139
+ @media (max-width: 767px) {
140
+ .users-role-accordion.ui.styled.accordion .title.users-role-title {
141
+ padding: 0.18rem 0.42rem;
142
+ }
143
+
144
+ .users-role-title-header.ui.header .content {
145
+ font-size: 1.16rem;
146
+ }
147
+ }
148
+
149
+ .users-toolbar {
150
+ display: flex;
151
+ flex-wrap: wrap;
152
+ align-items: center;
153
+ gap: 0.75rem;
154
+ margin-bottom: 0.75rem;
155
+
156
+ > .ui.input {
157
+ flex: 1 1 12rem;
158
+ min-width: 0;
159
+
160
+ > input {
161
+ min-width: 0;
162
+ width: 0;
163
+ flex: 1 1 0;
164
+ }
165
+ }
166
+
167
+ > .ui.button,
168
+ .users-toolbar-actions .ui.button {
169
+ margin: 0;
170
+ }
171
+ }
172
+
173
+ .users-filters {
174
+ display: flex;
175
+ flex-wrap: wrap;
176
+ align-items: center;
177
+ gap: 0.75rem;
178
+ margin-bottom: 0.75rem;
179
+ }
180
+
181
+ .users-toolbar-actions,
182
+ .users-view-buttons {
183
+ display: flex;
184
+ align-items: center;
185
+ gap: 0.75rem;
186
+ }
187
+
188
+ .users-toolbar-actions {
189
+ margin-left: auto;
190
+ flex-wrap: wrap;
191
+ }
192
+
193
+ .users-results {
194
+ display: flex;
195
+ justify-content: flex-end;
196
+ margin-bottom: 0.75rem;
197
+
198
+ > .ui.label {
199
+ margin: 0;
200
+ font-weight: 400;
201
+ }
202
+ }
203
+
204
+ .users-table-scroll {
205
+ max-width: 100%;
206
+ overflow-x: auto;
207
+ }
208
+
209
+ .ui.table.users-table {
210
+ min-width: 850px;
211
+ box-shadow: none;
212
+
213
+ td {
214
+ overflow-wrap: anywhere;
215
+ max-width: 22rem;
216
+ }
217
+ .users-table-actions {
218
+ white-space: nowrap;
219
+ .ui.button {
220
+ margin: 0 0 0 0.5rem;
221
+ }
222
+ }
223
+ .users-table-type .icon {
224
+ margin: 0;
225
+ }
226
+ .users-sort-hidden {
227
+ visibility: hidden;
228
+ }
229
+ .users-table-name {
230
+ font-weight: 700;
231
+ }
232
+ .users-table-username {
233
+ display: block;
234
+ color: #6b7280;
235
+ font-size: 0.875rem;
236
+ }
237
+ }
238
+
239
+ .users-table-sort {
240
+ display: inline-flex;
241
+ align-items: center;
242
+ gap: 0.35rem;
243
+ padding: 0;
244
+ border: 0;
245
+ background: transparent;
246
+ color: inherit;
247
+ font: inherit;
248
+ cursor: pointer;
249
+ }
250
+
251
+ .users-table-scroll:focus-visible,
252
+ .users-table-sort:focus-visible,
253
+ .users-table a:focus-visible,
254
+ .users-table button:focus-visible {
255
+ outline: 2px solid currentColor;
256
+ outline-offset: 2px;
257
+ }
258
+
259
+ .users-toolbar .ui.input input::placeholder {
260
+ color: #6b7280;
261
+ font-weight: 400;
262
+ opacity: 1;
263
+ }
264
+
265
+ @media (max-width: 767px) {
266
+ .users-filters {
267
+ position: relative;
268
+
269
+ > .ui.dropdown {
270
+ position: static;
271
+
272
+ > .menu {
273
+ left: 0;
274
+ right: auto;
275
+ min-width: min(16rem, 100%);
276
+ max-width: 100%;
277
+ }
278
+ }
279
+ }
280
+ }
@@ -1,42 +1,29 @@
1
- import React from "react";
2
1
  import { Route, Routes } from "react-router";
3
2
  import { Divider, Segment } from "semantic-ui-react";
4
- import Unauthorized from "@truedat/core/components/Unauthorized";
5
3
  import { useActiveRoute, useAuthorized } from "@truedat/core/hooks";
6
- import { ProtectedRoute, Loader } from "@truedat/core/router";
4
+ import { ProtectedRoute } from "@truedat/core/router";
7
5
  import {
8
6
  GROUP,
9
7
  GROUP_CREATE,
10
8
  GROUP_EDIT,
11
9
  GROUPS,
12
- USER,
13
- USER_EDIT,
14
10
  USERS,
15
- USERS_NEW,
16
- USER_EDIT_PASSWORD,
17
11
  } from "@truedat/core/routes";
18
12
  import Group from "../../groups/components/Group";
19
13
  import GroupUsers from "../../groups/components/GroupUsers";
20
14
  import NewGroup from "../../groups/components/NewGroup";
21
15
  import EditGroup from "../../groups/components/EditGroup";
22
- import EditUser from "./EditUser";
23
16
  import GroupUserCrumbs from "./GroupUserCrumbs";
24
- import NewUser from "./NewUser";
25
- import User from "./User";
26
- import UserLoader from "./UserLoader";
27
17
  import UsersAndGroups from "./UsersAndGroups";
28
18
  import UsersLoader from "./UsersLoader";
29
- import UserPassword from "./UserPassword";
30
19
 
31
20
  const UserRoutes = () => (
32
21
  <Routes>
33
22
  <Route index element={<UsersAndGroups />} />
34
- <Route path="new" element={<NewUser />} />
35
- <Route path=":id" element={<Loader loaders={<UserLoader />} />}>
36
- <Route index element={<User />} />
37
- <Route path="edit" element={<EditUser />} />
38
- <Route path="password" element={<UserPassword />} />
39
- </Route>
23
+ <Route path={"new"} element={<UsersAndGroups />} />
24
+ <Route path={":id"} element={<UsersAndGroups />} />
25
+ <Route path={":id/edit"} element={<UsersAndGroups />} />
26
+ <Route path={":id/password"} element={<UsersAndGroups />} />
40
27
  </Routes>
41
28
  );
42
29
 
@@ -71,13 +58,13 @@ const GroupRoutes = () => (
71
58
 
72
59
  export const AdminUserRoutes = () => {
73
60
  const authorized = useAuthorized();
74
- const usersActive = useActiveRoute(USERS);
61
+ const usersActive = useActiveRoute(`${USERS}/*`);
75
62
  return (
76
63
  <>
77
64
  {authorized && usersActive && <UsersLoader />}
78
65
  <Routes>
79
66
  <Route
80
- path={USERS}
67
+ path={`${USERS}/*`}
81
68
  element={
82
69
  <ProtectedRoute>
83
70
  <UserRoutes />
@@ -1,37 +1,10 @@
1
- import _ from "lodash/fp";
2
- import PropTypes from "prop-types";
3
- import { Header, Container, Segment } from "semantic-ui-react";
4
- import { connect } from "react-redux";
5
- import { useIntl } from "react-intl";
6
- import { updateUser } from "../routines";
7
- import UserBreadcrumbs from "./UserBreadcrumbs";
8
- import UserForm from "./UserForm";
1
+ import { useNavigate } from "react-router";
2
+ import { USERS } from "@truedat/core/routes";
3
+ import EditUserModal from "./EditUserModal";
9
4
 
10
- const EditUser = ({ updateUser, user }) => {
11
- const { formatMessage } = useIntl();
12
- return _.isEmpty(user) ? null : (
13
- <>
14
- <UserBreadcrumbs name={formatMessage({ id: "users.actions.edit" })} />
15
- <Container text as={Segment}>
16
- <Header
17
- as="h2"
18
- icon="user"
19
- content={formatMessage({ id: "users.actions.edit" })}
20
- />
21
- <UserForm
22
- onSubmit={(props) => updateUser({ ...props, id: user?.id })}
23
- user={user}
24
- />
25
- </Container>
26
- </>
27
- );
5
+ const EditUser = () => {
6
+ const navigate = useNavigate();
7
+ return <EditUserModal onClose={() => navigate(USERS)} />;
28
8
  };
29
9
 
30
- EditUser.propTypes = {
31
- user: PropTypes.object,
32
- updateUser: PropTypes.func,
33
- };
34
-
35
- const mapStateToProps = ({ user }) => ({ user });
36
-
37
- export default connect(mapStateToProps, { updateUser })(EditUser);
10
+ export default EditUser;
@@ -0,0 +1,150 @@
1
+ import { useEffect, useState } from "react";
2
+ import PropTypes from "prop-types";
3
+ import { connect } from "react-redux";
4
+ import { Form } from "semantic-ui-react";
5
+ import { useIntl } from "react-intl";
6
+ import { useForm } from "react-hook-form";
7
+ import TrueModal from "@truedat/core/components/TrueModal";
8
+ import { updateUser } from "../routines";
9
+ import useUserModalOperation from "../hooks/useUserModalOperation";
10
+ import useSortedGroups from "../hooks/useSortedGroups";
11
+ import UserFormFields from "./UserFormFields";
12
+ import { DeleteUserModal } from "./UserActions";
13
+
14
+ const getDefaultValues = (user = {}) => ({
15
+ full_name: user.full_name || "",
16
+ email: user.email || "",
17
+ user_name: user.user_name || "",
18
+ external_id: user.external_id || "",
19
+ role: user.role || "user",
20
+ groups: user.groups || [],
21
+ });
22
+
23
+ export const EditUserModal = ({ user, groups, onClose }) => {
24
+ const { formatMessage } = useIntl();
25
+ const [deleteModalOpen, setDeleteModalOpen] = useState(false);
26
+ const {
27
+ submit,
28
+ isSubmitting,
29
+ onClose: closeModal,
30
+ error,
31
+ } = useUserModalOperation(updateUser, onClose);
32
+
33
+ const {
34
+ handleSubmit,
35
+ control,
36
+ reset,
37
+ formState: { errors, isDirty, isValid },
38
+ } = useForm({
39
+ mode: "all",
40
+ defaultValues: getDefaultValues(user),
41
+ });
42
+
43
+ useEffect(() => {
44
+ if (user?.id) {
45
+ reset(getDefaultValues(user));
46
+ }
47
+ }, [
48
+ reset,
49
+ user?.id,
50
+ user?.full_name,
51
+ user?.email,
52
+ user?.user_name,
53
+ user?.external_id,
54
+ user?.role,
55
+ user?.groups,
56
+ ]);
57
+
58
+ if (!user?.id) return null;
59
+
60
+ if (deleteModalOpen) {
61
+ return (
62
+ <DeleteUserModal
63
+ id={user.id}
64
+ name={user.full_name || user.user_name}
65
+ onClose={() => setDeleteModalOpen(false)}
66
+ onDeleted={onClose}
67
+ />
68
+ );
69
+ }
70
+
71
+ const onSubmitForm = (data) => {
72
+ submit({ ...data, id: user.id });
73
+ };
74
+
75
+ return (
76
+ <TrueModal
77
+ open
78
+ title={formatMessage({ id: "users.actions.edit" })}
79
+ icon="user"
80
+ subtitle={user.full_name || user.user_name}
81
+ actions={[
82
+ {
83
+ key: "delete",
84
+ content: formatMessage({
85
+ id: "user.actions.delete.confirmation.header",
86
+ defaultMessage: "Eliminar usuario",
87
+ }),
88
+ icon: "trash alternate",
89
+ basic: true,
90
+ negative: true,
91
+ className: "um-delete-user",
92
+ onClick: () => setDeleteModalOpen(true),
93
+ disabled: isSubmitting,
94
+ },
95
+ {
96
+ key: "cancel",
97
+ content: formatMessage({ id: "actions.cancel" }),
98
+ secondary: true,
99
+ onClick: closeModal,
100
+ disabled: isSubmitting,
101
+ },
102
+ {
103
+ key: "save",
104
+ content: formatMessage({ id: "user.edit.submit" }),
105
+ primary: true,
106
+ type: "submit",
107
+ form: "edit-user-form",
108
+ disabled: !isDirty || !isValid || isSubmitting,
109
+ loading: isSubmitting,
110
+ },
111
+ ]}
112
+ onClose={closeModal}
113
+ aria-busy={isSubmitting}
114
+ closeOnEscape={!isSubmitting}
115
+ closeOnDimmerClick={!isSubmitting}
116
+ banner={error ? <span role="alert">{error}</span> : null}
117
+ bannerType="danger"
118
+ size="small"
119
+ className="user-modal user-modal--edit"
120
+ >
121
+ <Form
122
+ id="edit-user-form"
123
+ noValidate
124
+ onSubmit={handleSubmit(onSubmitForm)}
125
+ >
126
+ <UserFormFields
127
+ control={control}
128
+ errors={errors}
129
+ isSubmitting={isSubmitting}
130
+ groups={groups}
131
+ />
132
+ </Form>
133
+ </TrueModal>
134
+ );
135
+ };
136
+
137
+ EditUserModal.propTypes = {
138
+ user: PropTypes.object,
139
+ groups: PropTypes.array,
140
+ onClose: PropTypes.func.isRequired,
141
+ };
142
+
143
+ const EditUserModalWithGroups = (props) => {
144
+ const groups = useSortedGroups();
145
+ return <EditUserModal {...props} groups={groups} />;
146
+ };
147
+
148
+ const mapStateToProps = ({ user }) => ({ user });
149
+
150
+ export default connect(mapStateToProps)(EditUserModalWithGroups);
@@ -1,30 +1,141 @@
1
+ import { useEffect } from "react";
1
2
  import PropTypes from "prop-types";
2
- import { Header, Container, Segment } from "semantic-ui-react";
3
- import { connect } from "react-redux";
3
+ import { Form } from "semantic-ui-react";
4
4
  import { useIntl } from "react-intl";
5
+ import { useForm, useWatch } from "react-hook-form";
6
+ import TrueModal from "@truedat/core/components/TrueModal";
5
7
  import { createUser } from "../routines";
6
- import UserBreadcrumbs from "./UserBreadcrumbs";
7
- import UserForm from "./UserForm";
8
+ import useUserModalOperation from "../hooks/useUserModalOperation";
9
+ import useSortedGroups from "../hooks/useSortedGroups";
10
+ import UserFormFields from "./UserFormFields";
11
+ import UserPasswordField from "./UserPasswordField";
8
12
 
9
- const NewUser = ({ createUser }) => {
13
+ const getDefaultValues = () => ({
14
+ full_name: "",
15
+ email: "",
16
+ user_name: "",
17
+ external_id: "",
18
+ role: "user",
19
+ groups: [],
20
+ password: "",
21
+ rep_password: "",
22
+ });
23
+
24
+ export const NewUser = ({ groups, onClose }) => {
10
25
  const { formatMessage } = useIntl();
26
+ const {
27
+ submit,
28
+ isSubmitting,
29
+ onClose: closeModal,
30
+ error,
31
+ } = useUserModalOperation(createUser, onClose);
32
+ const {
33
+ handleSubmit,
34
+ control,
35
+ trigger,
36
+ getValues,
37
+ formState: { errors, isValid },
38
+ } = useForm({
39
+ mode: "all",
40
+ defaultValues: getDefaultValues(),
41
+ });
42
+ const password = useWatch({ control, name: "password", defaultValue: "" });
43
+ useEffect(() => {
44
+ if (getValues("rep_password")) void trigger("rep_password");
45
+ }, [password, getValues, trigger]);
46
+
11
47
  return (
12
- <>
13
- <UserBreadcrumbs name={formatMessage({ id: "users.actions.create" })} />
14
- <Container text as={Segment}>
15
- <Header
16
- as="h2"
17
- icon="user"
18
- content={formatMessage({ id: "users.actions.create" })}
48
+ <TrueModal
49
+ open
50
+ title={formatMessage({ id: "users.actions.create" })}
51
+ icon="add user"
52
+ actions={[
53
+ {
54
+ key: "cancel",
55
+ content: formatMessage({ id: "actions.cancel" }),
56
+ secondary: true,
57
+ onClick: closeModal,
58
+ disabled: isSubmitting,
59
+ },
60
+ {
61
+ key: "save",
62
+ content: formatMessage({
63
+ id: "user.create.submit",
64
+ }),
65
+ primary: true,
66
+ type: "submit",
67
+ form: "new-user-form",
68
+ disabled: isSubmitting || !isValid,
69
+ loading: isSubmitting,
70
+ },
71
+ ]}
72
+ onClose={closeModal}
73
+ aria-busy={isSubmitting}
74
+ closeOnEscape={!isSubmitting}
75
+ closeOnDimmerClick={!isSubmitting}
76
+ banner={error ? <span role="alert">{error}</span> : null}
77
+ bannerType="danger"
78
+ size="small"
79
+ className="user-modal user-modal--create"
80
+ >
81
+ <Form id="new-user-form" noValidate onSubmit={handleSubmit(submit)}>
82
+ <UserFormFields
83
+ control={control}
84
+ errors={errors}
85
+ isSubmitting={isSubmitting}
86
+ groups={groups}
19
87
  />
20
- <UserForm onSubmit={createUser} />
21
- </Container>
22
- </>
88
+ <div className="um-section um-section--password">
89
+ <div className="um-section-header">
90
+ <div className="um-section-bar um-section-bar--password" />
91
+ <span className="um-section-label">
92
+ {formatMessage({ id: "user.password.header" })}
93
+ </span>
94
+ </div>
95
+ <div className="um-form-grid">
96
+ <UserPasswordField
97
+ control={control}
98
+ name="password"
99
+ label={formatMessage({ id: "user.form.password" })}
100
+ disabled={isSubmitting}
101
+ rules={{
102
+ required: formatMessage({ id: "user.password.required" }),
103
+ minLength: {
104
+ value: 6,
105
+ message: formatMessage(
106
+ { id: "user.password.min_length" },
107
+ { count: 6 },
108
+ ),
109
+ },
110
+ }}
111
+ />
112
+ <UserPasswordField
113
+ control={control}
114
+ name="rep_password"
115
+ label={formatMessage({ id: "user.form.password_confirmation" })}
116
+ disabled={isSubmitting}
117
+ rules={{
118
+ required: formatMessage({ id: "user.password.required" }),
119
+ validate: (value) =>
120
+ value === getValues("password") ||
121
+ formatMessage({ id: "user.password.mismatch" }),
122
+ }}
123
+ />
124
+ </div>
125
+ </div>
126
+ </Form>
127
+ </TrueModal>
23
128
  );
24
129
  };
25
130
 
26
131
  NewUser.propTypes = {
27
- createUser: PropTypes.func,
132
+ groups: PropTypes.array,
133
+ onClose: PropTypes.func.isRequired,
134
+ };
135
+
136
+ const NewUserWithGroups = (props) => {
137
+ const groups = useSortedGroups();
138
+ return <NewUser {...props} groups={groups} />;
28
139
  };
29
140
 
30
- export default connect(null, { createUser })(NewUser);
141
+ export default NewUserWithGroups;