Skip to content

Commit

Permalink
Merge pull request #113 from ReCodEx/more_group_admins
Browse files Browse the repository at this point in the history
Group can have more admins
  • Loading branch information
SemaiCZE committed Oct 23, 2017
2 parents 170fcab + b138afc commit 73bb8d1
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 45 deletions.
7 changes: 4 additions & 3 deletions src/components/Groups/GroupDetail/GroupDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const GroupDetail = ({
parentGroupId,
isPublic = false,
childGroups,
adminId,
primaryAdminsIds,
...group
},
groups,
Expand Down Expand Up @@ -131,7 +131,7 @@ const GroupDetail = ({
groupId={id}
users={supervisors}
isAdmin={isAdmin}
mainAdminId={adminId}
primaryAdminsIds={primaryAdminsIds}
isLoaded={supervisors.length === group.supervisors.length}
/>
</Box>
Expand All @@ -151,7 +151,8 @@ GroupDetail.propTypes = {
}),
threshold: PropTypes.number,
isPublic: PropTypes.bool,
supervisors: PropTypes.array.isRequired
supervisors: PropTypes.array.isRequired,
primaryAdminsIds: PropTypes.array.isRequired
}),
groups: PropTypes.object.isRequired,
publicGroups: ImmutablePropTypes.map.isRequired,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import Button from '../../widgets/FlatButton';
import Icon from 'react-fontawesome';

const RemoveGroupAdminButton = ({ onClick, ...props }) =>
<Button {...props} onClick={onClick} bsStyle="danger" className="btn-flat">
<Icon name="user-secret" />{' '}
<FormattedMessage
id="app.groups.removeGroupAdminButton"
defaultMessage="Remove group admin"
/>
</Button>;

RemoveGroupAdminButton.propTypes = {
onClick: PropTypes.func.isRequired
};

export default RemoveGroupAdminButton;
1 change: 1 addition & 0 deletions src/components/Groups/RemoveGroupAdminButton/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default from './RemoveGroupAdminButton';
6 changes: 3 additions & 3 deletions src/components/Users/SupervisorsList/SupervisorsList.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const SupervisorsList = ({
users,
isLoaded = true,
isAdmin,
mainAdminId
primaryAdminsIds
}) =>
<Table hover>
<tbody>
Expand All @@ -21,7 +21,7 @@ const SupervisorsList = ({
{...user}
groupId={groupId}
isAdmin={isAdmin}
mainAdminId={mainAdminId}
primaryAdminsIds={primaryAdminsIds}
/>
)}

Expand All @@ -45,7 +45,7 @@ SupervisorsList.propTypes = {
groupId: PropTypes.string.isRequired,
isLoaded: PropTypes.bool,
isAdmin: PropTypes.bool,
mainAdminId: PropTypes.string
primaryAdminsIds: PropTypes.array.isRequired
};

export default SupervisorsList;
34 changes: 24 additions & 10 deletions src/components/Users/SupervisorsListItem/SupervisorsListItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import MakeRemoveSupervisorButtonContainer from '../../../containers/MakeRemoveSupervisorButtonContainer';
import MakeGroupAdminButton from '../../Groups/MakeGroupAdminButton';
import { makeAdmin } from '../../../redux/modules/groups';
import RemoveGroupAdminButton from '../../Groups/RemoveGroupAdminButton';
import { addAdmin, removeAdmin } from '../../../redux/modules/groups';
import { adminsOfGroup } from '../../../redux/selectors/groups';
import UsersNameContainer from '../../../containers/UsersNameContainer';

Expand All @@ -13,19 +14,30 @@ const SupervisorsListItem = ({
fullName,
avatarUrl,
groupId,
makeAdmin,
mainAdminId
addAdmin,
removeAdmin,
primaryAdminsIds
}) =>
<tr>
<td>
<UsersNameContainer userId={id} />
</td>
{isAdmin &&
<td>
<MakeRemoveSupervisorButtonContainer userId={id} groupId={groupId} />
{id !== mainAdminId &&
<MakeGroupAdminButton
onClick={() => makeAdmin(groupId, id)}
{primaryAdminsIds.indexOf(id) < 0 &&
<div>
<MakeRemoveSupervisorButtonContainer
userId={id}
groupId={groupId}
/>
<MakeGroupAdminButton
onClick={() => addAdmin(groupId, id)}
bsSize="xs"
/>
</div>}
{primaryAdminsIds.indexOf(id) >= 0 &&
<RemoveGroupAdminButton
onClick={() => removeAdmin(groupId, id)}
bsSize="xs"
/>}
</td>}
Expand All @@ -37,16 +49,18 @@ SupervisorsListItem.propTypes = {
groupId: PropTypes.string.isRequired,
fullName: PropTypes.string.isRequired,
avatarUrl: PropTypes.string.isRequired,
makeAdmin: PropTypes.func.isRequired,
mainAdminId: PropTypes.string.isRequired
addAdmin: PropTypes.func.isRequired,
removeAdmin: PropTypes.func.isRequired,
primaryAdminsIds: PropTypes.array.isRequired
};

const mapStateToProps = (state, { groupId }) => ({
groupAdmins: adminsOfGroup(groupId)(state)
});

const mapDispatchToProps = {
makeAdmin
addAdmin,
removeAdmin
};

export default connect(mapStateToProps, mapDispatchToProps)(
Expand Down
99 changes: 70 additions & 29 deletions src/redux/modules/groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,14 @@ export const additionalActionTypes = {
REMOVE_SUPERVISOR_PENDING: 'recodex/groups/REMOVE_SUPERVISOR_PENDING',
REMOVE_SUPERVISOR_FULFILLED: 'recodex/groups/REMOVE_SUPERVISOR_FULFILLED',
REMOVE_SUPERVISOR_REJECTED: 'recodex/groups/REMOVE_SUPERVISOR_REJECTED',
MAKE_ADMIN: 'recodex/groups/MAKE_ADMIN',
MAKE_ADMIN_PENDING: 'recodex/groups/MAKE_ADMIN_PENDING',
MAKE_ADMIN_FULFILLED: 'recodex/groups/MAKE_ADMIN_FULFILLED',
MAKE_ADMIN_REJECTED: 'recodex/groups/MAKE_ADMIN_REJECTED'
ADD_ADMIN: 'recodex/groups/ADD_ADMIN',
ADD_ADMIN_PENDING: 'recodex/groups/ADD_ADMIN_PENDING',
ADD_ADMIN_FULFILLED: 'recodex/groups/ADD_ADMIN_FULFILLED',
ADD_ADMIN_REJECTED: 'recodex/groups/ADD_ADMIN_REJECTED',
REMOVE_ADMIN: 'recodex/groups/REMOVE_ADMIN',
REMOVE_ADMIN_PENDING: 'recodex/groups/REMOVE_ADMIN_PENDING',
REMOVE_ADMIN_FULFILLED: 'recodex/groups/REMOVE_ADMIN_FULFILLED',
REMOVE_ADMIN_REJECTED: 'recodex/groups/REMOVE_ADMIN_REJECTED'
};

export const loadGroup = actions.pushResource;
Expand All @@ -52,9 +56,10 @@ export const validateAddGroup = (name, instanceId, parentGroupId = null) =>
type: 'VALIDATE_ADD_GROUP_DATA',
endpoint: '/groups/validate-add-group-data',
method: 'POST',
body: parentGroupId === null
? { name, instanceId }
: { name, instanceId, parentGroupId }
body:
parentGroupId === null
? { name, instanceId }
: { name, instanceId, parentGroupId }
});

export const fetchSubgroups = groupId =>
Expand Down Expand Up @@ -132,10 +137,10 @@ export const removeSupervisor = (groupId, userId) => dispatch =>
})
).catch(() => dispatch(addNotification('Cannot remove supervisor.', false))); // @todo: Make translatable

export const makeAdmin = (groupId, userId) => dispatch =>
export const addAdmin = (groupId, userId) => dispatch =>
dispatch(
createApiAction({
type: additionalActionTypes.MAKE_ADMIN,
type: additionalActionTypes.ADD_ADMIN,
endpoint: `/groups/${groupId}/admin`,
method: 'POST',
meta: { groupId, userId },
Expand All @@ -147,6 +152,23 @@ export const makeAdmin = (groupId, userId) => dispatch =>
)
); // @todo: Make translatable

export const removeAdmin = (groupId, userId) => dispatch =>
dispatch(
createApiAction({
type: additionalActionTypes.REMOVE_ADMIN,
endpoint: `/groups/${groupId}/admin/${userId}`,
method: 'DELETE',
meta: { groupId, userId }
})
).catch(() =>
dispatch(
addNotification(
'Cannot remove this person from admins of the group.',
false
)
)
); // @todo: Make translatable

/**
* Reducer
*/
Expand Down Expand Up @@ -250,41 +272,60 @@ const reducer = handleActions(
supervisors => supervisors.filter(id => id !== userId)
),

[additionalActionTypes.MAKE_ADMIN_PENDING]: (
[additionalActionTypes.ADD_ADMIN_PENDING]: (
state,
{ payload: { userId }, meta: { groupId } }
{ payload, meta: { groupId, userId } }
) =>
state.updateIn(['resources', groupId, 'data'], group =>
group
.set('oldAdminId', group.get('adminId'))
.update('admins', admins =>
admins.filter(id => id !== userId).push(userId)
)
.set('adminId', userId)
state.updateIn(
['resources', groupId, 'data', 'primaryAdminsIds'],
admins => admins.filter(id => id !== userId).concat([userId])
),

[additionalActionTypes.ADD_ADMIN_FAILED]: (
state,
{ payload, meta: { groupId, userId } }
) =>
state.updateIn(
['resources', groupId, 'data', 'primaryAdminsIds'],
admins => admins.filter(id => id !== userId)
),

[additionalActionTypes.MAKE_ADMIN_FAILED]: (
[additionalActionTypes.ADD_ADMIN_FULFILLED]: (
state,
{ payload: { userId }, meta: { groupId } }
{ payload: { primaryAdminsIds, admins }, meta: { groupId } }
) =>
state.updateIn(['resources', groupId, 'data'], group =>
group
.update('admins', admins =>
admins.filter(id => id !== group.get('adminId')).push(userId)
)
.set('adminId', group.get('oldAdminId'))
.remove('oldAdminId')
.set('admins', List(admins))
.set('primaryAdminsIds', primaryAdminsIds)
),

[additionalActionTypes.REMOVE_ADMIN_PENDING]: (
state,
{ payload, meta: { groupId, userId } }
) =>
state.updateIn(
['resources', groupId, 'data', 'primaryAdminsIds'],
admins => admins.filter(id => id !== userId)
),

[additionalActionTypes.REMOVE_ADMIN_FAILED]: (
state,
{ payload, meta: { groupId, userId } }
) =>
state.updateIn(
['resources', groupId, 'data', 'primaryAdminsIds'],
admins => admins.filter(id => id !== userId).concat([userId])
),

[additionalActionTypes.MAKE_ADMIN_FULFILLED]: (
[additionalActionTypes.REMOVE_ADMIN_FULFILLED]: (
state,
{ payload: { adminId, admins }, meta: { groupId } }
{ payload: { primaryAdminsIds, admins }, meta: { groupId } }
) =>
state.updateIn(['resources', groupId, 'data'], group =>
group
.remove('oldAdminId')
.set('admins', List(admins))
.set('adminId', adminId)
.set('primaryAdminsIds', primaryAdminsIds)
),

[additionalActionTypes.LOAD_USERS_GROUPS_FULFILLED]: (
Expand Down

0 comments on commit 73bb8d1

Please sign in to comment.