diff --git a/src/channels/actions/NoContentActionsUpdate.js b/src/channels/actions/NoContentActionsUpdate.js index 63ef068864db8066767db4942c736a8d82c2a379..a4462ed1c909e0606b30c2d9d343f8a8503bb3f2 100644 --- a/src/channels/actions/NoContentActionsUpdate.js +++ b/src/channels/actions/NoContentActionsUpdate.js @@ -1,5 +1,8 @@ -// Triggered after subscribing to a channel, to update the state +// Triggered after any 204 no Content response (usually Deletes), to update the state export const SUBSCRIBE_TO_CHANNEL_UPDATE_SUCCESS = 'SUBSCRIBE_TO_CHANNEL_UPDATE_SUCCESS'; +export const DELETE_CHANNEL_UPDATE_SUCCESS = 'DELETE_CHANNEL_UPDATE_SUCCESS'; +export const UPDATE_REMOVE_USER_FROM_CHANNEL = 'UPDATE_REMOVE_USER_FROM_CHANNEL'; +export const UPDATE_REMOVE_GROUP_FROM_CHANNEL = 'UPDATE_REMOVE_GROUP_FROM_CHANNEL'; export const updateSubscribeToChannel = (channelId, newValue) => { return { @@ -10,3 +13,24 @@ export const updateSubscribeToChannel = (channelId, newValue) => { type: SUBSCRIBE_TO_CHANNEL_UPDATE_SUCCESS, }; }; + +export const updateDeletedChannel = channelId => { + return { + channelId, + type: DELETE_CHANNEL_UPDATE_SUCCESS, + }; +}; + +export const updateRemoveUser = userId => { + return { + userId, + type: UPDATE_REMOVE_USER_FROM_CHANNEL, + }; +}; + +export const updateRemoveGroup = groupId => { + return { + groupId, + type: UPDATE_REMOVE_GROUP_FROM_CHANNEL, + }; +}; diff --git a/src/channels/components/AddGroupToChannelComponent/AddGroupToChannelComponent.js b/src/channels/components/AddGroupToChannelComponent/AddGroupToChannelComponent.js index e770ce9d86a2a75039e88527c9d17ca2fd175de1..ac026067c03d810dc40b711a66507bddf58a2d1f 100644 --- a/src/channels/components/AddGroupToChannelComponent/AddGroupToChannelComponent.js +++ b/src/channels/components/AddGroupToChannelComponent/AddGroupToChannelComponent.js @@ -33,10 +33,20 @@ const AddGroupToChannelComponent = ({ response?.payload?.response?.message || 'An error occurred while adding the group', 'error' ); - } else { + return; + } + const updateFetchResponse = await getChannelGroups(channelId, getChannelGroupsQuery); + if (updateFetchResponse.error) { handleClose(); - showSnackbar('The group has been added successfully', 'success'); + showSnackbar( + 'Group added with success, but an error ocurred while fetching the updated group member list.' + + 'Please refresh the page.', + 'error' + ); + return; } + handleClose(); + showSnackbar('The group has been added successfully', 'success'); } return ( @@ -80,6 +90,7 @@ const AddGroupToChannelComponent = ({ const mapStateToProps = state => { return { getChannelGroupsQuery: state.channels.channel.getChannelGroupsQuery, + totalNumberOfGroups: state.channels.channel.totalNumberOfGroups, loading: state.channels.channel.loadingAddGroup, }; }; diff --git a/src/channels/components/AddUserToChannelComponent/AddUserToChannelComponent.js b/src/channels/components/AddUserToChannelComponent/AddUserToChannelComponent.js index d7137442519a3e29e0e83b854484da0355a87714..c833b721255e4e73268e27d3ee5b3198e165e784 100644 --- a/src/channels/components/AddUserToChannelComponent/AddUserToChannelComponent.js +++ b/src/channels/components/AddUserToChannelComponent/AddUserToChannelComponent.js @@ -6,8 +6,16 @@ import {useParams} from 'react-router-dom'; import * as AddUserToChannelActionCreators from 'channels/actions/AddUserToChannel'; import * as showSnackBarActionCreators from 'common/actions/Snackbar'; +import * as getChannelMembersActionCreators from 'channels/actions/GetChannelMembers'; -const AddGroupToChannelComponent = ({addUserToChannel, showSnackbar, loading}) => { +const AddGroupToChannelComponent = ({ + addUserToChannel, + showSnackbar, + loading, + getChannelMembers, + totalNumberOfMembers, + getChannelMembersQuery, +}) => { const [username, updateUsername] = useState(null); const [modalOpen, setModelOpen] = useState(false); @@ -26,10 +34,20 @@ const AddGroupToChannelComponent = ({addUserToChannel, showSnackbar, loading}) = response?.payload?.response?.message || 'An error occurred while adding the user', 'error' ); - } else { + return; + } + const updateFetchResponse = await getChannelMembers(channelId, getChannelMembersQuery); + if (updateFetchResponse.error) { handleClose(); - showSnackbar('The user has been added successfully', 'success'); + showSnackbar( + 'Member added with success, but an error ocurred while fetching the updated member list.' + + 'Please refresh the page.', + 'error' + ); + return; } + handleClose(); + showSnackbar('The user has been added successfully', 'success'); } return ( @@ -73,6 +91,7 @@ const AddGroupToChannelComponent = ({addUserToChannel, showSnackbar, loading}) = const mapStateToProps = state => { return { getChannelMembersQuery: state.channels.channel.getChannelMembersQuery, + totalNumberOfMembers: state.channels.channel.totalNumberOfMembers, loading: state.channels.channel.loadingAddUser, }; }; @@ -81,6 +100,7 @@ const mapDispatchToProps = dispatch => { return { ...bindActionCreators(AddUserToChannelActionCreators, dispatch), ...bindActionCreators(showSnackBarActionCreators, dispatch), + ...bindActionCreators(getChannelMembersActionCreators, dispatch), }; }; diff --git a/src/channels/components/AdvancedSettingsChannelComponent/AdvancedSettingsChannelComponent.js b/src/channels/components/AdvancedSettingsChannelComponent/AdvancedSettingsChannelComponent.js index e2fb36876b503fc99933b8164ee96a7eac36b397..be3445f52e2c2c65933a53623247d65d0f90b754 100644 --- a/src/channels/components/AdvancedSettingsChannelComponent/AdvancedSettingsChannelComponent.js +++ b/src/channels/components/AdvancedSettingsChannelComponent/AdvancedSettingsChannelComponent.js @@ -12,6 +12,7 @@ import * as generateAPIKeyActionCreators from 'channels/actions/GenerateAPIKey'; import * as getTagsActionCreators from 'channels/actions/GetTags'; import * as createTagActionCreators from 'channels/actions/CreateTag'; import * as setChannelTagsActionCreators from 'channels/actions/SetChannelTags'; +import * as noContentActionCreators from 'channels/actions/NoContentActionsUpdate'; import UpdateChannelAdminGroupComponent from 'channels/components/UpdateChannelAdminGroupComponent/UpdateChannelAdminGroupComponent'; import APIHelp from 'help/components/APIHelp'; @@ -22,6 +23,7 @@ const AdvancedSettingsChannelComponent = ({ tags, showSnackbar, deleteChannel, + updateDeletedChannel, history, loading, loadingDelete, @@ -88,6 +90,7 @@ const AdvancedSettingsChannelComponent = ({ 'error' ); } else { + updateDeletedChannel(channelId); showSnackbar('The channel has been deleted successfully', 'success'); history.push('/'); } @@ -224,7 +227,7 @@ const AdvancedSettingsChannelComponent = ({ onClick={copyApiKeyToClipboard} icon="copy" content="Copy to Clipboad" - ></Button> + /> </Grid.Column> </Grid.Row> <Grid.Row> @@ -350,6 +353,7 @@ const mapDispatchToProps = dispatch => { ...bindActionCreators(showSnackBarActionCreators, dispatch), ...bindActionCreators(updateChannelActionCreators, dispatch), ...bindActionCreators(deleteChannelActionCreators, dispatch), + ...bindActionCreators(noContentActionCreators, dispatch), ...bindActionCreators(generateAPIKeyActionCreators, dispatch), ...bindActionCreators(getTagsActionCreators, dispatch), ...bindActionCreators(createTagActionCreators, dispatch), diff --git a/src/channels/components/ChannelMembers/ChannelGroupsComponent.js b/src/channels/components/ChannelMembers/ChannelGroupsComponent.js index 9316a926d63333c89b7236d04fa165810f129eba..1b2d11703c15950946e697f2bd376ea8e16fbf4c 100644 --- a/src/channels/components/ChannelMembers/ChannelGroupsComponent.js +++ b/src/channels/components/ChannelMembers/ChannelGroupsComponent.js @@ -18,6 +18,7 @@ import * as showSnackBarActionCreator from 'common/actions/Snackbar'; import * as removeGroupFromChannelActionCreators from 'channels/actions/RemoveGroupFromChannel'; import * as getChannelGroupsActionCreators from 'channels/actions/GetChannelGroups'; import AddGroupToChannelComponent from 'channels/components/AddGroupToChannelComponent/AddGroupToChannelComponent'; +import * as noContentActionCreators from 'channels/actions/NoContentActionsUpdate'; import './ChannelMembers.scss'; @@ -37,6 +38,7 @@ const ChannelGroupsComponent = ({ groups, getChannelGroups, removeGroupFromChannel, + updateRemoveGroup, setGetChannelGroupsQuery, getChannelGroupsQuery, totalNumberOfGroups, @@ -59,10 +61,21 @@ const ChannelGroupsComponent = ({ `An error occurred while removing the group ${deleteName} from the channel`, 'error' ); - } else { + return; + } + updateRemoveGroup(deleteId); + const updateFetchResponse = await getChannelGroups(channelId, getChannelGroupsQuery); + if (updateFetchResponse.error) { setDeleteId(null); - showSnackbar(`Group ${deleteName} removed successfully`, 'success'); + showSnackbar( + 'Group deleted with success, but an error ocurred while fetching the updated group member list.' + + 'Please refresh the page.', + 'error' + ); + return; } + setDeleteId(null); + showSnackbar(`Group ${deleteName || ''} removed successfully`, 'success'); } useEffect(() => { @@ -123,7 +136,7 @@ const ChannelGroupsComponent = ({ setDeleteName(group.groupIdentifier); setChannelGroupDeletionModalVisible(true); }} - ></Button> + /> } content={`Remove ${group.groupIdentifier}`} /> @@ -195,6 +208,7 @@ const mapDispatchToProps = dispatch => { return { ...bindActionCreators(getChannelGroupsActionCreators, dispatch), ...bindActionCreators(removeGroupFromChannelActionCreators, dispatch), + ...bindActionCreators(noContentActionCreators, dispatch), ...bindActionCreators(showSnackBarActionCreator, dispatch), }; }; diff --git a/src/channels/components/ChannelMembers/ChannelUsersComponent.js b/src/channels/components/ChannelMembers/ChannelUsersComponent.js index 29ae571fedd789984f735115e3b14dcc74b356cd..eb99e24e2fd3bf5ca071573e710710a54a09d457 100644 --- a/src/channels/components/ChannelMembers/ChannelUsersComponent.js +++ b/src/channels/components/ChannelMembers/ChannelUsersComponent.js @@ -18,6 +18,7 @@ import * as showSnackBarActionCreator from 'common/actions/Snackbar'; import * as getChannelMembersActionCreators from 'channels/actions/GetChannelMembers'; import AddUserToChannelComponent from 'channels/components/AddUserToChannelComponent/AddUserToChannelComponent'; import * as removeUserFromChannelActionCreators from 'channels/actions/RemoveUserFromChannel'; +import * as noContentActionCreators from 'channels/actions/NoContentActionsUpdate'; import './ChannelMembers.scss'; @@ -38,6 +39,7 @@ const ChannelUsersComponent = ({ members, getChannelMembers, removeUserFromChannel, + updateRemoveUser, setGetChannelMembersQuery, getChannelMembersQuery, totalNumberOfMembers, @@ -60,10 +62,20 @@ const ChannelUsersComponent = ({ `An error occurred while removing the user ${deleteName} from the channel`, 'error' ); - } else { + return; + } + const updateFetchResponse = await getChannelMembers(channelId, getChannelMembersQuery); + if (updateFetchResponse.error) { setDeleteId(null); - showSnackbar(`User ${deleteName} removed successfully`, 'success'); + showSnackbar( + 'Member deleted with success, but an error ocurred while fetching the updated member list.' + + 'Please refresh the page.', + 'error' + ); + return; } + setDeleteId(null); + showSnackbar(`User ${deleteName || ''} removed successfully`, 'success'); } useEffect(() => { @@ -136,7 +148,7 @@ const ChannelUsersComponent = ({ setDeleteName(member.username); setChannelUserDeletionModalVisible(true); }} - ></Button> + /> } content={`Remove ${member.username}`} /> @@ -208,6 +220,7 @@ const mapDispatchToProps = dispatch => { return { ...bindActionCreators(getChannelMembersActionCreators, dispatch), ...bindActionCreators(removeUserFromChannelActionCreators, dispatch), + ...bindActionCreators(noContentActionCreators, dispatch), ...bindActionCreators(showSnackBarActionCreator, dispatch), }; }; diff --git a/src/channels/reducers/Channel.js b/src/channels/reducers/Channel.js index dce87e585ae568547cddf20ce1251ef113662b56..3ef9697a8ecef0d869d56bdd53319eed134544ac 100644 --- a/src/channels/reducers/Channel.js +++ b/src/channels/reducers/Channel.js @@ -66,6 +66,10 @@ import { SET_CHANNEL_TAGS_FAILURE, SET_CHANNEL_TAGS_SUCCESS, } from 'channels/actions/SetChannelTags'; +import { + UPDATE_REMOVE_USER_FROM_CHANNEL, + UPDATE_REMOVE_GROUP_FROM_CHANNEL, +} from 'channels/actions/NoContentActionsUpdate'; const INITIAL_STATE = { channel: {}, @@ -263,7 +267,7 @@ function processGetChannelMembersFailure(state, error) { return { ...state, channel: {}, - members: null, + members: [], error, loadingMembers: false, }; @@ -291,8 +295,7 @@ function processGetChannelGroupsSuccess(state, {groups, totalNumberOfGroups}) { function processGetChannelGroupsFailure(state, error) { return { ...state, - groups: {}, - members: null, + groups: [], error, loadingGroups: false, }; @@ -307,8 +310,8 @@ function processRemoveUserFromChannel(state) { }; } -function processRemoveUserFromChannelSuccess(state, memberId) { - const updatedMemberList = state.members.filter(m => m.id !== memberId); +function processUpdateRemoveUserFromChannel(state, userId) { + const updatedMemberList = state.members.filter(m => m.id !== userId); return { ...state, loadingRemoveUser: false, @@ -333,7 +336,7 @@ function processRemoveGroupFromChannel(state) { }; } -function processRemoveGroupFromChannelSuccess(state, groupId) { +function processUpdateRemoveGroupFromChannel(state, groupId) { const updatedGroups = state.groups.filter(g => g.id !== groupId); return { ...state, @@ -524,7 +527,9 @@ export default function (state = INITIAL_STATE, action) { case REMOVE_USER_FROM_CHANNEL: return processRemoveUserFromChannel(state); case REMOVE_USER_FROM_CHANNEL_SUCCESS: - return processRemoveUserFromChannelSuccess(state, action.payload); + return state; + case UPDATE_REMOVE_USER_FROM_CHANNEL: + return processUpdateRemoveUserFromChannel(state, action.userId); case REMOVE_USER_FROM_CHANNEL_FAILURE: error = action.payload || {message: action.payload.message}; return processRemoveUserFromChannelFailure(state, error); @@ -532,7 +537,9 @@ export default function (state = INITIAL_STATE, action) { case REMOVE_GROUP_FROM_CHANNEL: return processRemoveGroupFromChannel(state); case REMOVE_GROUP_FROM_CHANNEL_SUCCESS: - return processRemoveGroupFromChannelSuccess(state, action.payload); + return state; + case UPDATE_REMOVE_GROUP_FROM_CHANNEL: + return processUpdateRemoveGroupFromChannel(state, action.groupId); case REMOVE_GROUP_FROM_CHANNEL_FAILURE: error = action.payload || {message: action.payload.message}; return processRemoveGroupFromChannelFailure(state, error); diff --git a/src/channels/reducers/ChannelsList.js b/src/channels/reducers/ChannelsList.js index 36ea75ff8f8e9c62797d6415a7f9db7849882382..fd18c8528130f0916d2358805362ac878de714df 100644 --- a/src/channels/reducers/ChannelsList.js +++ b/src/channels/reducers/ChannelsList.js @@ -10,7 +10,10 @@ import { SUBSCRIBE_TO_CHANNEL_FAILURE, SUBSCRIBE_TO_CHANNEL_SUCCESS, } from 'channels/actions/SubscribeToChannel'; -import {SUBSCRIBE_TO_CHANNEL_UPDATE_SUCCESS} from 'channels/actions/NoContentActionsUpdate'; +import { + SUBSCRIBE_TO_CHANNEL_UPDATE_SUCCESS, + DELETE_CHANNEL_UPDATE_SUCCESS, +} from 'channels/actions/NoContentActionsUpdate'; import { UNSUBSCRIBE_FROM_CHANNEL, UNSUBSCRIBE_FROM_CHANNEL_FAILURE, @@ -168,10 +171,10 @@ function processDeleteChannel(state) { }; } -function processDeleteChannelSuccess(state, deletedChannel) { +function processUpdateDeleteChannel(state, channelId) { return { ...state, - channels: state.channels.filter(c => c.id !== deletedChannel.id), + channels: state.channels.filter(c => c.id !== channelId), loadingDelete: false, }; } @@ -278,7 +281,9 @@ export default function (state = INITIAL_STATE, action) { case DELETE_CHANNEL: return processDeleteChannel(state); case DELETE_CHANNEL_SUCCESS: - return processDeleteChannelSuccess(state, action.payload); + return state; + case DELETE_CHANNEL_UPDATE_SUCCESS: + return processUpdateDeleteChannel(state, action.channelId); case DELETE_CHANNEL_FAILURE: error = action.payload || {message: action.payload.message}; return processDeleteChannelFailure(state, error); diff --git a/src/devices/actions/NoContentActionsUpdate.js b/src/devices/actions/NoContentActionsUpdate.js new file mode 100644 index 0000000000000000000000000000000000000000..b2b80ee30db71f95e6449c942989a3ee62bbd07e --- /dev/null +++ b/src/devices/actions/NoContentActionsUpdate.js @@ -0,0 +1,9 @@ +// Triggered after any 204 no Content response (usually Deletes), to update the state +export const UPDATE_REMOVE_DEVICE = 'UPDATE_REMOVE_DEVICE'; + +export const updateRemoveDevice = deviceId => { + return { + deviceId, + type: UPDATE_REMOVE_DEVICE, + }; +}; diff --git a/src/devices/components/DevicesList.jsx b/src/devices/components/DevicesList.jsx index 6786d8ef7c3b964d964f57b073455ff74dcaead3..f214dac2e9822308ac441c4162ecac9957184bc3 100644 --- a/src/devices/components/DevicesList.jsx +++ b/src/devices/components/DevicesList.jsx @@ -9,6 +9,7 @@ import * as deviceActions from 'devices/actions/devices'; import AddDevice from 'devices/components/AddDevice'; import DeviceTypeIcon from 'utils/device-type-icon'; import DeviceHelp from 'help/components/DeviceHelp'; +import {updateRemoveDevice as updateRemoveDeviceActionCreator} from 'devices/actions/NoContentActionsUpdate'; const baseColumns = [ {id: 'name', label: 'Name'}, @@ -23,6 +24,7 @@ function DevicesList({ deleteDeviceById, tryBrowserPushNotification, updateDeviceById, + updateRemoveDevice, showSnackbar, loadingDelete, loadingUpdate, @@ -44,6 +46,7 @@ function DevicesList({ setDeleteId(null); showSnackbar('An error occurred while deleting the device', 'error'); } else { + updateRemoveDevice(device.id); setDeleteId(null); showSnackbar('Device removed successfully', 'success'); } @@ -221,6 +224,7 @@ DevicesList.propTypes = { deleteDeviceById: PropTypes.func.isRequired, tryBrowserPushNotification: PropTypes.func.isRequired, updateDeviceById: PropTypes.func.isRequired, + updateRemoveDevice: PropTypes.func.isRequired, showSnackbar: PropTypes.func.isRequired, loadingDelete: PropTypes.bool, loadingUpdate: PropTypes.bool, @@ -247,6 +251,7 @@ const mapDispatchToProps = dispatch => tryBrowserPushNotification: deviceActions.tryBrowserPushNotification, updateDeviceById: deviceActions.updateDeviceById, showSnackbar: snackBarActions.showSnackbar, + updateRemoveDevice: updateRemoveDeviceActionCreator, }, dispatch ); diff --git a/src/devices/reducers/devices.js b/src/devices/reducers/devices.js index 6c73e34cfc7e776c0d35c8bb4414a2acc1bf68b3..5e62635f73d34b54a6b621c894ebdc731ae48b7f 100644 --- a/src/devices/reducers/devices.js +++ b/src/devices/reducers/devices.js @@ -14,6 +14,7 @@ import { UPDATE_DEVICE, UPDATE_DEVICE_FAILURE, } from 'devices/actions/devices'; +import {UPDATE_REMOVE_DEVICE} from 'devices/actions/NoContentActionsUpdate'; const INITIAL_STATE = { userDevices: [], @@ -25,6 +26,18 @@ const INITIAL_STATE = { loadingCreate: false, }; +function processDeleteDeviceSuccess(state) { + return state; +} + +function processUpdateDeleteDevice(state, deviceId) { + return { + ...state, + loadingDelete: false, + userDevices: state.userDevices.filter(p => p.id !== deviceId), + }; +} + export default function (state = INITIAL_STATE, action) { switch (action.type) { case GET_DEVICES: @@ -53,11 +66,9 @@ export default function (state = INITIAL_STATE, action) { case DELETE_DEVICE: return {...state, loadingDelete: true, error: null, pageError: null}; case DELETE_DEVICE_SUCCESS: - return { - ...state, - loadingDelete: false, - userDevices: state.userDevices.filter(p => p.id !== action.payload), - }; + return processDeleteDeviceSuccess(state, action.payload); + case UPDATE_REMOVE_DEVICE: + return processUpdateDeleteDevice(state, action.deviceId); case DELETE_DEVICE_FAILURE: return { ...state,