@truedat/auth 8.14.0 → 8.14.2
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.
- package/package.json +4 -4
- package/src/groups/components/EditGroup.js +64 -20
- package/src/groups/components/Group.js +39 -41
- package/src/groups/components/GroupCard.js +51 -54
- package/src/groups/components/GroupCards.js +60 -25
- package/src/groups/components/GroupDeleteModal.js +98 -0
- package/src/groups/components/GroupDropdown.js +92 -0
- package/src/groups/components/GroupForm.js +165 -84
- package/src/groups/components/GroupFormModal.js +137 -0
- package/src/groups/components/GroupInfoModal.js +114 -0
- package/src/groups/components/GroupMemberPicker.js +364 -0
- package/src/groups/components/GroupRouteModal.js +46 -0
- package/src/groups/components/GroupUsers.js +31 -14
- package/src/groups/components/GroupUsersTable.js +136 -83
- package/src/groups/components/NewGroup.js +38 -10
- package/src/groups/components/__tests__/EditGroup.spec.js +105 -0
- package/src/groups/components/__tests__/Group.spec.js +29 -47
- package/src/groups/components/__tests__/GroupCard.spec.js +8 -20
- package/src/groups/components/__tests__/GroupDropdown.spec.js +27 -0
- package/src/groups/components/__tests__/GroupForm.spec.js +32 -5
- package/src/groups/components/__tests__/GroupMemberPicker.spec.js +378 -0
- package/src/groups/components/__tests__/GroupModals.spec.js +210 -0
- package/src/groups/components/__tests__/GroupUsers.spec.js +17 -2
- package/src/groups/components/__tests__/GroupUsersTable.spec.js +34 -2
- package/src/groups/components/__tests__/__snapshots__/Group.spec.js.snap +1 -0
- package/src/groups/components/__tests__/__snapshots__/GroupCard.spec.js.snap +32 -30
- package/src/groups/components/__tests__/__snapshots__/GroupCards.spec.js.snap +90 -77
- package/src/groups/components/__tests__/__snapshots__/GroupUsers.spec.js.snap +75 -11
- package/src/groups/components/__tests__/__snapshots__/GroupUsersTable.spec.js.snap +70 -13
- package/src/groups/components/index.js +0 -4
- package/src/groups/hooks/__tests__/useGroupOperation.spec.js +167 -0
- package/src/groups/hooks/__tests__/useGroups.spec.js +90 -0
- package/src/groups/hooks/useGroupOperation.js +83 -0
- package/src/groups/hooks/useGroups.js +64 -0
- package/src/groups/reducers/index.js +0 -4
- package/src/groups/routines.js +0 -7
- package/src/groups/sagas/index.js +2 -24
- package/src/hooks/useRoles.js +6 -3
- package/src/styles/Groups.less +1009 -0
- package/src/users/components/AdminUserRoutes.js +1 -14
- package/src/users/components/GroupUserCrumbs.js +7 -12
- package/src/users/components/UserRoutes.js +12 -35
- package/src/users/components/UsersAndGroups.js +3 -6
- package/src/users/components/__tests__/GroupUserCrumbs.spec.js +26 -30
- package/src/users/components/__tests__/UserRoutes.spec.js +4 -6
- package/src/users/components/__tests__/UsersAndGroups.spec.js +5 -7
- package/src/users/components/__tests__/__snapshots__/UserRoutes.spec.js.snap +9 -55
- package/src/groups/components/GroupLoader.js +0 -27
- package/src/groups/components/GroupsLoader.js +0 -30
- package/src/groups/components/__tests__/GroupLoader.spec.js +0 -71
- package/src/groups/components/__tests__/__snapshots__/GroupLoader.spec.js.snap +0 -11
- package/src/groups/reducers/__tests__/groupRedirect.spec.js +0 -51
- package/src/groups/reducers/__tests__/groupUsers.spec.js +0 -60
- package/src/groups/reducers/group.js +0 -56
- package/src/groups/reducers/groupRedirect.js +0 -20
- package/src/groups/reducers/groupUsers.js +0 -16
- package/src/groups/reducers/groups.js +0 -29
- package/src/groups/sagas/__tests__/deleteGroup.spec.js +0 -93
- package/src/groups/sagas/__tests__/deleteGroupUser.spec.js +0 -80
- package/src/groups/sagas/createGroup.js +0 -27
- package/src/groups/sagas/deleteGroup.js +0 -31
- package/src/groups/sagas/deleteGroupUser.js +0 -35
- package/src/groups/sagas/fetchGroup.js +0 -30
- package/src/groups/sagas/fetchGroups.js +0 -26
- package/src/groups/sagas/updateGroup.js +0 -28
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
|
+
import { useId, useMemo } from "react";
|
|
2
3
|
import PropTypes from "prop-types";
|
|
3
4
|
import { useForm, Controller } from "react-hook-form";
|
|
4
5
|
import { useIntl } from "react-intl";
|
|
5
|
-
import { connect } from "react-redux";
|
|
6
6
|
import { Button, Form, Header } from "semantic-ui-react";
|
|
7
7
|
import HistoryBackButton from "@truedat/core/components/HistoryBackButton";
|
|
8
8
|
import { accentInsensitivePathOrder } from "@truedat/core/services/sort";
|
|
9
|
+
import GroupMemberPicker from "./GroupMemberPicker";
|
|
9
10
|
|
|
10
11
|
const toOption = ({ id, full_name, user_name }) => ({
|
|
11
12
|
key: id,
|
|
@@ -26,8 +27,12 @@ export const GroupForm = ({
|
|
|
26
27
|
isSubmitting,
|
|
27
28
|
users,
|
|
28
29
|
onSubmit,
|
|
30
|
+
onCancel,
|
|
31
|
+
onDelete,
|
|
32
|
+
memberFilters = false,
|
|
29
33
|
}) => {
|
|
30
34
|
const { formatMessage } = useIntl();
|
|
35
|
+
const nameFieldId = useId();
|
|
31
36
|
const { handleSubmit, control, formState } = useForm({
|
|
32
37
|
mode: "all",
|
|
33
38
|
defaultValues: {
|
|
@@ -38,96 +43,174 @@ export const GroupForm = ({
|
|
|
38
43
|
},
|
|
39
44
|
});
|
|
40
45
|
const { errors, isDirty, isValid } = formState;
|
|
46
|
+
const DescriptionField = memberFilters ? Form.Input : Form.TextArea;
|
|
47
|
+
const options = useMemo(() => userOptions(users || []), [users]);
|
|
41
48
|
return (
|
|
42
|
-
<Form
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
49
|
+
<Form
|
|
50
|
+
className="group-form"
|
|
51
|
+
onSubmit={handleSubmit((data) => !isSubmitting && onSubmit(data))}
|
|
52
|
+
>
|
|
53
|
+
<fieldset disabled={isSubmitting} className="group-form-fields">
|
|
54
|
+
<Controller
|
|
55
|
+
control={control}
|
|
56
|
+
name="name"
|
|
57
|
+
rules={{
|
|
58
|
+
required: formatMessage(
|
|
59
|
+
{ id: "form.validation.required" },
|
|
60
|
+
{ prop: formatMessage({ id: "group.props.name" }) },
|
|
61
|
+
),
|
|
62
|
+
}}
|
|
63
|
+
render={({ field: { onBlur, onChange, value } }) => (
|
|
64
|
+
<Form.Input
|
|
65
|
+
id={nameFieldId}
|
|
66
|
+
className={
|
|
67
|
+
memberFilters
|
|
68
|
+
? `group-name-field${value ? " group-name-field--filled" : ""}`
|
|
69
|
+
: undefined
|
|
70
|
+
}
|
|
71
|
+
autoComplete="off"
|
|
72
|
+
error={_.path(["name", "message"])(errors)}
|
|
73
|
+
label={formatMessage(
|
|
74
|
+
memberFilters
|
|
75
|
+
? {
|
|
76
|
+
id: "group.form.name.label",
|
|
77
|
+
defaultMessage: "Nombre del grupo",
|
|
78
|
+
}
|
|
79
|
+
: { id: "group.props.name" },
|
|
80
|
+
)}
|
|
81
|
+
onBlur={onBlur}
|
|
82
|
+
onChange={(_e, { value }) => onChange(value)}
|
|
83
|
+
placeholder={formatMessage({
|
|
84
|
+
id: "group.form.name.placeholder",
|
|
85
|
+
})}
|
|
86
|
+
value={value || ""}
|
|
87
|
+
required
|
|
88
|
+
/>
|
|
89
|
+
)}
|
|
90
|
+
/>
|
|
91
|
+
<Controller
|
|
92
|
+
control={control}
|
|
93
|
+
name="alias"
|
|
94
|
+
render={({ field: { onBlur, onChange, value } }) => (
|
|
95
|
+
<Form.Input
|
|
96
|
+
autoComplete="off"
|
|
97
|
+
label={formatMessage({ id: "group.props.alias" })}
|
|
98
|
+
onBlur={onBlur}
|
|
99
|
+
onChange={(_e, { value }) => onChange(value)}
|
|
100
|
+
placeholder={formatMessage({
|
|
101
|
+
id: "group.form.alias.placeholder",
|
|
102
|
+
})}
|
|
103
|
+
value={value || ""}
|
|
104
|
+
/>
|
|
105
|
+
)}
|
|
106
|
+
/>
|
|
107
|
+
<Controller
|
|
108
|
+
control={control}
|
|
109
|
+
name="description"
|
|
110
|
+
rules={
|
|
111
|
+
memberFilters
|
|
112
|
+
? {
|
|
113
|
+
maxLength: {
|
|
114
|
+
value: 55,
|
|
115
|
+
message: formatMessage({
|
|
116
|
+
id: "group.description.maxLength",
|
|
117
|
+
defaultMessage:
|
|
118
|
+
"La descripción no puede superar los 55 caracteres.",
|
|
119
|
+
}),
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
: undefined
|
|
123
|
+
}
|
|
124
|
+
render={({ field: { onBlur, onChange, value } }) => (
|
|
125
|
+
<DescriptionField
|
|
126
|
+
className="group-form-description"
|
|
127
|
+
{...(memberFilters ? { maxLength: 55 } : { rows: 2 })}
|
|
128
|
+
error={errors.description?.message}
|
|
129
|
+
label={formatMessage({
|
|
130
|
+
id: memberFilters
|
|
131
|
+
? "group.description.short"
|
|
132
|
+
: "group.props.description",
|
|
133
|
+
defaultMessage: memberFilters
|
|
134
|
+
? "Descripción breve"
|
|
135
|
+
: "Descripción",
|
|
136
|
+
})}
|
|
137
|
+
onBlur={onBlur}
|
|
138
|
+
onChange={(_e, { value }) => onChange(value)}
|
|
139
|
+
placeholder={formatMessage({
|
|
140
|
+
id: "group.form.description.placeholder",
|
|
141
|
+
defaultMessage: "Descripción del grupo",
|
|
142
|
+
})}
|
|
143
|
+
value={value || ""}
|
|
144
|
+
/>
|
|
145
|
+
)}
|
|
146
|
+
/>
|
|
147
|
+
<Controller
|
|
148
|
+
control={control}
|
|
149
|
+
name="user_ids"
|
|
150
|
+
render={({ field: { onBlur, onChange, value } }) =>
|
|
151
|
+
memberFilters ? (
|
|
152
|
+
<GroupMemberPicker
|
|
153
|
+
showFilters={false}
|
|
154
|
+
users={users || []}
|
|
155
|
+
options={options}
|
|
156
|
+
value={value || []}
|
|
157
|
+
onChange={onChange}
|
|
158
|
+
onBlur={onBlur}
|
|
159
|
+
disabled={isSubmitting}
|
|
160
|
+
/>
|
|
161
|
+
) : (
|
|
162
|
+
<Form.Dropdown
|
|
163
|
+
disabled={isSubmitting}
|
|
164
|
+
name="user_ids"
|
|
165
|
+
label={formatMessage({ id: "group.props.users" })}
|
|
166
|
+
search
|
|
167
|
+
selection
|
|
168
|
+
clearable
|
|
169
|
+
multiple
|
|
170
|
+
options={options}
|
|
171
|
+
onBlur={onBlur}
|
|
172
|
+
onChange={(_e, { value }) => onChange(value)}
|
|
173
|
+
placeholder={formatMessage({
|
|
174
|
+
id: "group.form.users.placeholder",
|
|
175
|
+
})}
|
|
176
|
+
value={value || []}
|
|
177
|
+
/>
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
/>
|
|
181
|
+
</fieldset>
|
|
182
|
+
<div className="actions">
|
|
183
|
+
{onDelete && (
|
|
184
|
+
<Button
|
|
185
|
+
type="button"
|
|
186
|
+
className="group-delete-action"
|
|
187
|
+
icon="trash alternate outline"
|
|
188
|
+
content={formatMessage({ id: "actions.delete" })}
|
|
189
|
+
disabled={isSubmitting}
|
|
190
|
+
onClick={onDelete}
|
|
80
191
|
/>
|
|
81
192
|
)}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
label={formatMessage({ id: "group.props.alias" })}
|
|
90
|
-
onBlur={onBlur}
|
|
91
|
-
onChange={(_e, { value }) => onChange(value)}
|
|
92
|
-
placeholder={formatMessage({
|
|
93
|
-
id: "group.form.alias.placeholder",
|
|
94
|
-
})}
|
|
95
|
-
value={value || ""}
|
|
193
|
+
{onCancel ? (
|
|
194
|
+
<Button
|
|
195
|
+
type="button"
|
|
196
|
+
secondary
|
|
197
|
+
disabled={isSubmitting}
|
|
198
|
+
onClick={onCancel}
|
|
199
|
+
content={formatMessage({ id: "actions.cancel" })}
|
|
96
200
|
/>
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
name="user_ids"
|
|
102
|
-
render={({ field: { onBlur, onChange, value } }) => (
|
|
103
|
-
<Form.Dropdown
|
|
104
|
-
name="user_ids"
|
|
105
|
-
label={formatMessage({ id: "group.props.users" })}
|
|
106
|
-
search
|
|
107
|
-
selection
|
|
108
|
-
clearable
|
|
109
|
-
multiple
|
|
110
|
-
options={userOptions(users)}
|
|
111
|
-
onBlur={onBlur}
|
|
112
|
-
onChange={(_e, { value }) => onChange(value)}
|
|
113
|
-
placeholder={formatMessage({ id: "group.form.users.placeholder" })}
|
|
114
|
-
value={value || []}
|
|
201
|
+
) : (
|
|
202
|
+
<HistoryBackButton
|
|
203
|
+
content={formatMessage({ id: "actions.cancel" })}
|
|
204
|
+
disabled={isSubmitting}
|
|
115
205
|
/>
|
|
116
206
|
)}
|
|
117
|
-
/>
|
|
118
|
-
<div className="actions">
|
|
119
207
|
<Button
|
|
120
|
-
floated="right"
|
|
121
208
|
type="submit"
|
|
122
209
|
primary
|
|
123
210
|
loading={isSubmitting}
|
|
124
211
|
disabled={isSubmitting || !isDirty || !isValid}
|
|
125
212
|
content={formatMessage({ id: "actions.save" })}
|
|
126
213
|
/>
|
|
127
|
-
<HistoryBackButton
|
|
128
|
-
content={formatMessage({ id: "actions.cancel" })}
|
|
129
|
-
disabled={isSubmitting}
|
|
130
|
-
/>
|
|
131
214
|
</div>
|
|
132
215
|
</Form>
|
|
133
216
|
);
|
|
@@ -135,15 +218,13 @@ export const GroupForm = ({
|
|
|
135
218
|
|
|
136
219
|
GroupForm.propTypes = {
|
|
137
220
|
users: PropTypes.array,
|
|
221
|
+
memberFilters: PropTypes.bool,
|
|
138
222
|
group: PropTypes.object,
|
|
139
223
|
groupUsers: PropTypes.array,
|
|
140
224
|
onSubmit: PropTypes.func,
|
|
141
225
|
isSubmitting: PropTypes.bool,
|
|
226
|
+
onCancel: PropTypes.func,
|
|
227
|
+
onDelete: PropTypes.func,
|
|
142
228
|
};
|
|
143
229
|
|
|
144
|
-
|
|
145
|
-
isSubmitting,
|
|
146
|
-
users,
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
export default connect(mapStateToProps)(GroupForm);
|
|
230
|
+
export default GroupForm;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { useIntl } from "react-intl";
|
|
4
|
+
import { useParams } from "react-router";
|
|
5
|
+
import { TrueModal } from "@truedat/core/components/TrueModal";
|
|
6
|
+
import { useGroup, useGroupUsers } from "../hooks/useGroups";
|
|
7
|
+
import { useGroupOperation } from "../hooks/useGroupOperation";
|
|
8
|
+
import GroupForm from "./GroupForm";
|
|
9
|
+
import GroupDeleteModal from "./GroupDeleteModal";
|
|
10
|
+
|
|
11
|
+
const GroupFormModal = ({ editing = false, onClose }) => {
|
|
12
|
+
const [deleting, setDeleting] = useState(null);
|
|
13
|
+
const { formatMessage } = useIntl();
|
|
14
|
+
const { id } = useParams();
|
|
15
|
+
const {
|
|
16
|
+
group,
|
|
17
|
+
members: groupUsers,
|
|
18
|
+
hasData: hasGroup,
|
|
19
|
+
loading,
|
|
20
|
+
error,
|
|
21
|
+
retry,
|
|
22
|
+
} = useGroup(editing ? id : null);
|
|
23
|
+
const {
|
|
24
|
+
users,
|
|
25
|
+
hasData: hasUsers,
|
|
26
|
+
loading: usersLoading,
|
|
27
|
+
error: usersError,
|
|
28
|
+
retry: retryUsers,
|
|
29
|
+
} = useGroupUsers();
|
|
30
|
+
const { submit, pending, failed } = useGroupOperation(
|
|
31
|
+
editing ? "update" : "create",
|
|
32
|
+
id,
|
|
33
|
+
onClose,
|
|
34
|
+
);
|
|
35
|
+
const ready =
|
|
36
|
+
hasUsers &&
|
|
37
|
+
(!editing || (hasGroup && Boolean(group?.id) && String(group.id) === id));
|
|
38
|
+
return (
|
|
39
|
+
<>
|
|
40
|
+
<TrueModal
|
|
41
|
+
open
|
|
42
|
+
size="small"
|
|
43
|
+
className={`group-modal group-modal--form${editing ? " group-modal--edit" : " group-modal--new"}`}
|
|
44
|
+
title={
|
|
45
|
+
editing
|
|
46
|
+
? formatMessage(
|
|
47
|
+
{
|
|
48
|
+
id: "group.edit.title",
|
|
49
|
+
defaultMessage: "Editar grupo {name}",
|
|
50
|
+
},
|
|
51
|
+
{ name: group?.name || "" },
|
|
52
|
+
)
|
|
53
|
+
: formatMessage({ id: "groups.actions.create" })
|
|
54
|
+
}
|
|
55
|
+
icon="users"
|
|
56
|
+
onClose={() => !pending && !deleting && onClose()}
|
|
57
|
+
closeDisabled={pending || deleting}
|
|
58
|
+
closeOnEscape={!pending && !deleting}
|
|
59
|
+
closeOnDimmerClick={!pending && !deleting}
|
|
60
|
+
banner={
|
|
61
|
+
failed
|
|
62
|
+
? formatMessage({
|
|
63
|
+
id: "group.operation.error",
|
|
64
|
+
defaultMessage:
|
|
65
|
+
"No se ha podido completar la operación. Inténtalo de nuevo.",
|
|
66
|
+
})
|
|
67
|
+
: null
|
|
68
|
+
}
|
|
69
|
+
bannerType="danger"
|
|
70
|
+
>
|
|
71
|
+
{ready ? (
|
|
72
|
+
<GroupForm
|
|
73
|
+
key={editing ? group.id : "new"}
|
|
74
|
+
memberFilters
|
|
75
|
+
group={editing ? group : {}}
|
|
76
|
+
groupUsers={editing ? groupUsers : []}
|
|
77
|
+
users={users}
|
|
78
|
+
isSubmitting={pending || deleting}
|
|
79
|
+
onDelete={editing ? () => setDeleting(group) : undefined}
|
|
80
|
+
onCancel={onClose}
|
|
81
|
+
onSubmit={(values) =>
|
|
82
|
+
submit(editing ? { ...values, id: group.id } : values)
|
|
83
|
+
}
|
|
84
|
+
/>
|
|
85
|
+
) : (
|
|
86
|
+
<p role="status">
|
|
87
|
+
{formatMessage({
|
|
88
|
+
id:
|
|
89
|
+
loading || usersLoading ? "group.loading" : "group.unavailable",
|
|
90
|
+
defaultMessage:
|
|
91
|
+
loading || usersLoading
|
|
92
|
+
? "Cargando grupo…"
|
|
93
|
+
: "El grupo no está disponible.",
|
|
94
|
+
})}
|
|
95
|
+
</p>
|
|
96
|
+
)}
|
|
97
|
+
{usersError && (
|
|
98
|
+
<div role="alert">
|
|
99
|
+
{formatMessage({
|
|
100
|
+
id: "group.members.error",
|
|
101
|
+
defaultMessage: "No se han podido cargar los usuarios.",
|
|
102
|
+
})}
|
|
103
|
+
<button type="button" onClick={() => retryUsers().catch(() => {})}>
|
|
104
|
+
{formatMessage({
|
|
105
|
+
id: "group.members.retry",
|
|
106
|
+
defaultMessage: "Reintentar",
|
|
107
|
+
})}
|
|
108
|
+
</button>
|
|
109
|
+
</div>
|
|
110
|
+
)}
|
|
111
|
+
{error && (
|
|
112
|
+
<div role="alert">
|
|
113
|
+
{formatMessage({ id: "group.unavailable" })}
|
|
114
|
+
<button type="button" onClick={() => retry().catch(() => {})}>
|
|
115
|
+
{formatMessage({
|
|
116
|
+
id: "group.members.retry",
|
|
117
|
+
defaultMessage: "Reintentar",
|
|
118
|
+
})}
|
|
119
|
+
</button>
|
|
120
|
+
</div>
|
|
121
|
+
)}
|
|
122
|
+
</TrueModal>
|
|
123
|
+
{deleting && (
|
|
124
|
+
<GroupDeleteModal
|
|
125
|
+
group={deleting}
|
|
126
|
+
onClose={() => setDeleting(false)}
|
|
127
|
+
onDeleted={onClose}
|
|
128
|
+
/>
|
|
129
|
+
)}
|
|
130
|
+
</>
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
GroupFormModal.propTypes = {
|
|
134
|
+
editing: PropTypes.bool,
|
|
135
|
+
onClose: PropTypes.func.isRequired,
|
|
136
|
+
};
|
|
137
|
+
export default GroupFormModal;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { Link, useParams } from "react-router";
|
|
4
|
+
import { useIntl } from "react-intl";
|
|
5
|
+
import { TrueModal } from "@truedat/core/components/TrueModal";
|
|
6
|
+
import { linkTo } from "@truedat/core/routes";
|
|
7
|
+
import { Button, Icon } from "semantic-ui-react";
|
|
8
|
+
import { useGroup, useGroupUsers } from "../hooks/useGroups";
|
|
9
|
+
import GroupUsersTable from "./GroupUsersTable";
|
|
10
|
+
|
|
11
|
+
const GroupInfoModal = ({ onClose }) => {
|
|
12
|
+
const { id } = useParams();
|
|
13
|
+
const { group, members: groupUsers, loading, error, retry } = useGroup(id);
|
|
14
|
+
const { users } = useGroupUsers();
|
|
15
|
+
const [filter, setFilter] = useState("");
|
|
16
|
+
const empty = Array.isArray(groupUsers) && groupUsers.length === 0;
|
|
17
|
+
const { formatMessage } = useIntl();
|
|
18
|
+
const ready = Boolean(group?.id) && String(group.id) === id;
|
|
19
|
+
return (
|
|
20
|
+
<TrueModal
|
|
21
|
+
open
|
|
22
|
+
centered={false}
|
|
23
|
+
dimmer={{ className: "group-info-dimmer" }}
|
|
24
|
+
size="large"
|
|
25
|
+
className="group-modal group-modal--info"
|
|
26
|
+
icon="users"
|
|
27
|
+
title={
|
|
28
|
+
ready
|
|
29
|
+
? group.name
|
|
30
|
+
: formatMessage({
|
|
31
|
+
id: "group.loading",
|
|
32
|
+
defaultMessage: "Cargando grupo…",
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
subtitle={ready ? group.description || "" : ""}
|
|
36
|
+
onClose={onClose}
|
|
37
|
+
actions={[
|
|
38
|
+
{
|
|
39
|
+
key: "close",
|
|
40
|
+
secondary: true,
|
|
41
|
+
content: formatMessage({ id: "actions.close" }),
|
|
42
|
+
onClick: onClose,
|
|
43
|
+
},
|
|
44
|
+
...(ready && !empty
|
|
45
|
+
? [
|
|
46
|
+
{
|
|
47
|
+
key: "edit",
|
|
48
|
+
as: Link,
|
|
49
|
+
to: linkTo.GROUP_EDIT(group),
|
|
50
|
+
primary: true,
|
|
51
|
+
content: formatMessage({ id: "actions.edit" }),
|
|
52
|
+
},
|
|
53
|
+
]
|
|
54
|
+
: []),
|
|
55
|
+
]}
|
|
56
|
+
>
|
|
57
|
+
{error ? (
|
|
58
|
+
<div role="alert">
|
|
59
|
+
{formatMessage({ id: "group.unavailable" })}
|
|
60
|
+
<Button type="button" onClick={() => retry().catch(() => {})}>
|
|
61
|
+
{formatMessage({
|
|
62
|
+
id: "group.members.retry",
|
|
63
|
+
defaultMessage: "Reintentar",
|
|
64
|
+
})}
|
|
65
|
+
</Button>
|
|
66
|
+
</div>
|
|
67
|
+
) : !ready ? (
|
|
68
|
+
<p role="status">
|
|
69
|
+
{formatMessage({
|
|
70
|
+
id: loading ? "group.loading" : "group.unavailable",
|
|
71
|
+
defaultMessage: loading
|
|
72
|
+
? "Cargando grupo…"
|
|
73
|
+
: "El grupo no está disponible.",
|
|
74
|
+
})}
|
|
75
|
+
</p>
|
|
76
|
+
) : empty ? (
|
|
77
|
+
<div className="group-members-empty">
|
|
78
|
+
<Icon name="users" aria-hidden="true" />
|
|
79
|
+
<h3>
|
|
80
|
+
{formatMessage({
|
|
81
|
+
id: "group.members.empty.title",
|
|
82
|
+
defaultMessage: "Este grupo no tiene miembros",
|
|
83
|
+
})}
|
|
84
|
+
</h3>
|
|
85
|
+
<p>
|
|
86
|
+
{formatMessage({
|
|
87
|
+
id: "group.members.empty.description",
|
|
88
|
+
defaultMessage: "Edita el grupo para añadir miembros.",
|
|
89
|
+
})}
|
|
90
|
+
</p>
|
|
91
|
+
<Button
|
|
92
|
+
as={Link}
|
|
93
|
+
to={linkTo.GROUP_EDIT(group)}
|
|
94
|
+
primary
|
|
95
|
+
content={formatMessage({ id: "actions.edit" })}
|
|
96
|
+
/>
|
|
97
|
+
</div>
|
|
98
|
+
) : (
|
|
99
|
+
<div className="group-members">
|
|
100
|
+
<GroupUsersTable
|
|
101
|
+
group={group}
|
|
102
|
+
groupUsers={groupUsers}
|
|
103
|
+
users={users}
|
|
104
|
+
readOnly
|
|
105
|
+
filter={filter}
|
|
106
|
+
onFilterChange={setFilter}
|
|
107
|
+
/>
|
|
108
|
+
</div>
|
|
109
|
+
)}
|
|
110
|
+
</TrueModal>
|
|
111
|
+
);
|
|
112
|
+
};
|
|
113
|
+
GroupInfoModal.propTypes = { onClose: PropTypes.func.isRequired };
|
|
114
|
+
export default GroupInfoModal;
|