Skip to content

Commit

Permalink
Merge pull request #1725 from RodriSanchez1/feature/syncCommunicator
Browse files Browse the repository at this point in the history
Feature/sync communicator
  • Loading branch information
tomivm authored Jul 3, 2024
2 parents ebb62a9 + 023bc5d commit 42c1242
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 36 deletions.
5 changes: 4 additions & 1 deletion src/components/Account/Login/Login.actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,10 @@ export function login({ email, password, activatedData }, type = 'local') {
);

if (loginData.communicators && loginData.communicators.length) {
currentCommunicator = loginData.communicators[0];
const lastRemoteSavedCommunicatorIndex =
loginData.communicators.length - 1;
currentCommunicator =
loginData.communicators[lastRemoteSavedCommunicatorIndex]; //use the latest communicator
}

const localBoardsIds = [];
Expand Down
115 changes: 104 additions & 11 deletions src/components/Communicator/Communicator.actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@ import {
UPDATE_API_COMMUNICATOR_STARTED,
GET_API_MY_COMMUNICATORS_SUCCESS,
GET_API_MY_COMMUNICATORS_FAILURE,
GET_API_MY_COMMUNICATORS_STARTED
GET_API_MY_COMMUNICATORS_STARTED,
SYNC_COMMUNICATORS
} from './Communicator.constants';
import { defaultCommunicatorID } from './Communicator.reducer';
import API from '../../api';
import shortid from 'shortid';
import moment from 'moment';
import { switchBoard } from '../Board/Board.actions';
import history from './../../history';

export function importCommunicator(communicator) {
return {
Expand Down Expand Up @@ -230,17 +234,24 @@ export function verifyAndUpsertCommunicator(
*/

export function getApiMyCommunicators() {
return dispatch => {
return async dispatch => {
dispatch(getApiMyCommunicatorsStarted());
return API.getCommunicators()
.then(res => {
dispatch(getApiMyCommunicatorsSuccess(res));
return res;
})
.catch(err => {
dispatch(getApiMyCommunicatorsFailure(err.message));
throw new Error(err.message);
});
try {
const res = await API.getCommunicators();
dispatch(getApiMyCommunicatorsSuccess(res));
if (res?.data && res.data.length) {
try {
await dispatch(syncCommunicators(res.data));
} catch (e) {
console.error(e);
}
}

return res;
} catch (err) {
dispatch(getApiMyCommunicatorsFailure(err.message));
throw new Error(err.message);
}
};
}

Expand Down Expand Up @@ -291,3 +302,85 @@ export function updateDefaultBoardsIncluded(boardAlreadyIncludedData) {
defaultBoardsIncluded: boardAlreadyIncludedData
};
}

export function syncCommunicators(remoteCommunicators) {
const reconcileCommunicators = (local, remote) => {
if (local.lastEdited && remote.lastEdited) {
if (moment(local.lastEdited).isAfter(remote.lastEdited)) {
return local;
}
if (moment(local.lastEdited).isBefore(remote.lastEdited)) {
return remote;
}
if (moment(local.lastEdited).isSame(remote.lastEdited)) {
return remote;
}
}
return remote;
};
const getActiveCommunicator = getState => {
return getState().communicator.communicators.find(
c => c.id === getState().communicator.activeCommunicatorId
);
};

return async (dispatch, getState) => {
const localCommunicators = getState().communicator.communicators;
const updatedCommunicators = [...localCommunicators];

for (const remote of remoteCommunicators) {
const localIndex = localCommunicators.findIndex(
local => local.id === remote.id
);

if (localIndex !== -1) {
// If the communicator exists locally, reconcile the two
const reconciled = reconcileCommunicators(
localCommunicators[localIndex],
remote
);
if (reconciled === localCommunicators[localIndex]) {
// Local is more recent, update the server
try {
const res = await dispatch(
updateApiCommunicator(localCommunicators[localIndex])
);
updatedCommunicators[localIndex] = res;
} catch (e) {
console.error(e);
}
} else {
updatedCommunicators[localIndex] = reconciled;
}
} else {
// If the communicator does not exist locally, add it
updatedCommunicators.push(remote);
}
}

const activeCommunicatorId = getActiveCommunicator(getState).id ?? null;
const lastRemoteSavedCommunicatorId = remoteCommunicators[0].id ?? null; //The last communicator saved on the server
const needToChangeActiveCommunicator =
activeCommunicatorId !== lastRemoteSavedCommunicatorId &&
updatedCommunicators.length &&
lastRemoteSavedCommunicatorId &&
updatedCommunicators.findIndex(
communicator => communicator.id === lastRemoteSavedCommunicatorId
) !== -1;

dispatch({
type: SYNC_COMMUNICATORS,
communicators: updatedCommunicators,
activeCommunicatorId: needToChangeActiveCommunicator
? lastRemoteSavedCommunicatorId
: activeCommunicatorId
});

if (needToChangeActiveCommunicator) {
const newActiveCommunicator = getActiveCommunicator(getState);
const rootBoard = newActiveCommunicator.rootBoard;
dispatch(switchBoard(rootBoard));
history.replace(rootBoard);
}
};
}
1 change: 1 addition & 0 deletions src/components/Communicator/Communicator.constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ export const GET_API_MY_COMMUNICATORS_FAILURE =
'cboard/Communicator/GET_API_MY_COMMUNICATORS_FAILURE';
export const GET_API_MY_COMMUNICATORS_STARTED =
'cboard/Communicator/GET_API_MY_COMMUNICATORS_STARTED';
export const SYNC_COMMUNICATORS = 'Communicator/SYNC_COMMUNICATORS';
61 changes: 39 additions & 22 deletions src/components/Communicator/Communicator.reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import {
UPDATE_API_COMMUNICATOR_STARTED,
GET_API_MY_COMMUNICATORS_SUCCESS,
GET_API_MY_COMMUNICATORS_FAILURE,
GET_API_MY_COMMUNICATORS_STARTED
GET_API_MY_COMMUNICATORS_STARTED,
SYNC_COMMUNICATORS
} from './Communicator.constants';
import { LOGIN_SUCCESS, LOGOUT } from '../Account/Login/Login.constants';
import moment from 'moment';

export const defaultCommunicatorID = 'cboard_default';
const initialState = {
Expand Down Expand Up @@ -55,9 +57,13 @@ function communicatorReducer(state = initialState, action) {
};

case CREATE_COMMUNICATOR:
const newCommunicator = {
...action.payload,
lastEdited: moment().format()
};
return {
...state,
communicators: state.communicators.concat(action.payload)
communicators: state.communicators.concat(newCommunicator)
};

case EDIT_COMMUNICATOR:
Expand All @@ -67,7 +73,11 @@ function communicatorReducer(state = initialState, action) {
let newState = { ...state };

if (communicatorIndex >= 0) {
newState.communicators[communicatorIndex] = action.payload;
const updatedCommunicator = {
...action.payload,
lastEdited: moment().format()
};
newState.communicators[communicatorIndex] = updatedCommunicator;
}

return newState;
Expand Down Expand Up @@ -96,6 +106,7 @@ function communicatorReducer(state = initialState, action) {
if (index !== -1) {
const updatedCommunicators = [...state.communicators];
updatedCommunicators[index].boards.push(action.boardId);
updatedCommunicators[index].lastEdited = moment().format();
return {
...state,
communicators: updatedCommunicators
Expand All @@ -112,6 +123,7 @@ function communicatorReducer(state = initialState, action) {
const bindex = activeCommunicator.boards.indexOf(action.boardId);
if (bindex !== -1) {
dupdatedCommunicators[index].boards.splice(bindex, 1);
dupdatedCommunicators[index].lastEdited = moment().format();
return {
...state,
communicators: dupdatedCommunicators
Expand All @@ -135,6 +147,7 @@ function communicatorReducer(state = initialState, action) {
1,
action.nextBoardId
);
updatedCommunicators[index].lastEdited = moment().format();
return {
...state,
communicators: updatedCommunicators
Expand Down Expand Up @@ -163,6 +176,7 @@ function communicatorReducer(state = initialState, action) {
updatedCommunicators[
index
].defaultBoardsIncluded = defaultBoardsIncluded;
updatedCommunicators[index].lastEdited = moment().format();

return {
...state,
Expand All @@ -179,6 +193,7 @@ function communicatorReducer(state = initialState, action) {
const updatedCommunicators = [...state.communicators];
updatedCommunicators[index].defaultBoardsIncluded =
action.defaultBoardsIncluded;
updatedCommunicators[index].lastEdited = moment().format();

return {
...state,
Expand All @@ -199,7 +214,11 @@ function communicatorReducer(state = initialState, action) {
: state.activeCommunicatorId,
communicators: state.communicators.map(communicator =>
communicator.id === action.communicatorId
? { ...communicator, id: action.communicator.id }
? {
...communicator,
id: action.communicator.id,
lastEdited: action.communicator.lastEdited
}
: communicator
)
};
Expand All @@ -216,7 +235,15 @@ function communicatorReducer(state = initialState, action) {
case UPDATE_API_COMMUNICATOR_SUCCESS:
return {
...state,
isFetching: false
isFetching: false,
communicators: state.communicators.map(communicator =>
communicator.id === action.communicator.id
? {
...communicator,
lastEdited: action.communicator.lastEdited
}
: communicator
)
};
case UPDATE_API_COMMUNICATOR_FAILURE:
return {
Expand All @@ -229,25 +256,9 @@ function communicatorReducer(state = initialState, action) {
isFetching: true
};
case GET_API_MY_COMMUNICATORS_SUCCESS:
let flag = false;
const myCommunicators = [...state.communicators];
for (let i = 0; i < action.communicators.data.length; i++) {
for (let j = 0; j < myCommunicators.length; j++) {
if (myCommunicators[j].id === action.communicators.data[i].id) {
myCommunicators[j].boards = action.communicators.data[i].boards;
flag = true;
break;
}
}
if (!flag) {
myCommunicators.push(action.communicators.data[i]);
flag = false;
}
}
return {
...state,
isFetching: false,
communicators: myCommunicators
isFetching: false
};
case GET_API_MY_COMMUNICATORS_FAILURE:
return {
Expand All @@ -259,6 +270,12 @@ function communicatorReducer(state = initialState, action) {
...state,
isFetching: true
};
case SYNC_COMMUNICATORS:
return {
...state,
communicators: action.communicators,
activeCommunicatorId: action.activeCommunicatorId
};
default:
return state;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
GET_API_MY_COMMUNICATORS_STARTED
} from '../Communicator.constants';
import { LOGIN_SUCCESS, LOGOUT } from '../../Account/Login/Login.constants';
import moment from 'moment';

let mockComm, defaultCommunicatorID, initialState;
describe('reducer', () => {
Expand All @@ -32,7 +33,8 @@ describe('reducer', () => {
email: 'anything@cboard.io',
id: '123',
name: "Cboard's Communicator",
rootBoard: '1'
rootBoard: '1',
lastEdited: moment().format()
};
defaultCommunicatorID = 'cboard_default';
initialState = {
Expand Down Expand Up @@ -124,7 +126,8 @@ describe('reducer', () => {
});
it('should handle updateApiCommunicatorSuccess', () => {
const updateApiCommunicatorSuccess = {
type: UPDATE_API_COMMUNICATOR_SUCCESS
type: UPDATE_API_COMMUNICATOR_SUCCESS,
communicator: initialState
};
expect(
communicatorReducer(initialState, updateApiCommunicatorSuccess)
Expand Down

0 comments on commit 42c1242

Please sign in to comment.