From c49a4a7afefcb05db171746cc015646358b9bcd6 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Sun, 30 Jun 2024 20:34:29 -0300 Subject: [PATCH 01/10] Add lastEdited prop on communicator modifications --- .../Communicator/Communicator.reducer.js | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/components/Communicator/Communicator.reducer.js b/src/components/Communicator/Communicator.reducer.js index cadca19ef..0b5eefb84 100644 --- a/src/components/Communicator/Communicator.reducer.js +++ b/src/components/Communicator/Communicator.reducer.js @@ -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 } from './Communicator.constants'; import { LOGIN_SUCCESS, LOGOUT } from '../Account/Login/Login.constants'; +import moment from 'moment'; export const defaultCommunicatorID = 'cboard_default'; const initialState = { @@ -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: @@ -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; @@ -96,6 +106,7 @@ function communicatorReducer(state = initialState, action) { if (index !== -1) { const updatedCommunicators = [...state.communicators]; updatedCommunicators[index].boards.push(action.boardId); + updatedCommunicators.lastEdited = moment().format(); return { ...state, communicators: updatedCommunicators @@ -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 @@ -135,6 +147,7 @@ function communicatorReducer(state = initialState, action) { 1, action.nextBoardId ); + updatedCommunicators[index].lastEdited = moment().format(); return { ...state, communicators: updatedCommunicators @@ -163,6 +176,7 @@ function communicatorReducer(state = initialState, action) { updatedCommunicators[ index ].defaultBoardsIncluded = defaultBoardsIncluded; + updatedCommunicators[index].lastEdited = moment().format(); return { ...state, @@ -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, @@ -201,7 +216,8 @@ function communicatorReducer(state = initialState, action) { communicator.id === action.communicatorId ? { ...communicator, id: action.communicator.id } : communicator - ) + ), + lastEdited: action.communicator.lastEdited }; case CREATE_API_COMMUNICATOR_FAILURE: return { @@ -216,7 +232,8 @@ function communicatorReducer(state = initialState, action) { case UPDATE_API_COMMUNICATOR_SUCCESS: return { ...state, - isFetching: false + isFetching: false, + lastEdited: action.communicator.lastEdited }; case UPDATE_API_COMMUNICATOR_FAILURE: return { From 4048b6b24ce30234153fc5fdda76d1cfd48f6334 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Sun, 30 Jun 2024 20:35:35 -0300 Subject: [PATCH 02/10] Refactor GET_API_MY_COMMUNICATORS_SUCCESS reducer --- .../Communicator/Communicator.reducer.js | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/components/Communicator/Communicator.reducer.js b/src/components/Communicator/Communicator.reducer.js index 0b5eefb84..83b18d3a1 100644 --- a/src/components/Communicator/Communicator.reducer.js +++ b/src/components/Communicator/Communicator.reducer.js @@ -246,25 +246,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 { From 4d30a8aed5443d919ddc57b3a03461779e306697 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Sun, 30 Jun 2024 20:37:18 -0300 Subject: [PATCH 03/10] Add sync communicactor action and reducer --- .../Communicator/Communicator.actions.js | 70 ++++++++++++++++++- .../Communicator/Communicator.constants.js | 1 + .../Communicator/Communicator.reducer.js | 9 ++- 3 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/components/Communicator/Communicator.actions.js b/src/components/Communicator/Communicator.actions.js index 221d30c6d..6748486e0 100644 --- a/src/components/Communicator/Communicator.actions.js +++ b/src/components/Communicator/Communicator.actions.js @@ -17,11 +17,13 @@ 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'; export function importCommunicator(communicator) { return { @@ -230,12 +232,15 @@ export function verifyAndUpsertCommunicator( */ export function getApiMyCommunicators() { - return dispatch => { + return async dispatch => { dispatch(getApiMyCommunicatorsStarted()); return API.getCommunicators() .then(res => { dispatch(getApiMyCommunicatorsSuccess(res)); - return res; + + return dispatch(syncCommunicators(res.data)).catch(e => { + console.error(e); + }); }) .catch(err => { dispatch(getApiMyCommunicatorsFailure(err.message)); @@ -291,3 +296,62 @@ 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)) { + console.log('comm local is after remote', local); + return local; + } + if (moment(local.lastEdited).isBefore(remote.lastEdited)) { + console.log('Comm local is before remote', remote); + return remote; + } + if (moment(local.lastEdited).isSame(remote.lastEdited)) { + console.log('Comm sync isSame', local); + return remote; + } + } + console.log('no entro'); + return remote; + }; + + return async (dispatch, getState) => { + const localCommunicators = getState().communicator.communicators; + + 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]) + ); + localCommunicators[localIndex] = res; + } catch (e) { + console.error(e); + } + } else { + localCommunicators[localIndex] = reconciled; + } + } else { + // If the communicator does not exist locally, add it + localCommunicators.push(remote); + } + } + dispatch({ + type: SYNC_COMMUNICATORS, + communicators: localCommunicators + }); + }; +} diff --git a/src/components/Communicator/Communicator.constants.js b/src/components/Communicator/Communicator.constants.js index 3caa635b6..6b681e9a2 100644 --- a/src/components/Communicator/Communicator.constants.js +++ b/src/components/Communicator/Communicator.constants.js @@ -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'; diff --git a/src/components/Communicator/Communicator.reducer.js b/src/components/Communicator/Communicator.reducer.js index 83b18d3a1..8f6158cde 100644 --- a/src/components/Communicator/Communicator.reducer.js +++ b/src/components/Communicator/Communicator.reducer.js @@ -20,7 +20,7 @@ import { 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'; @@ -260,6 +260,13 @@ function communicatorReducer(state = initialState, action) { ...state, isFetching: true }; + case SYNC_COMMUNICATORS: + return { + ...state, + communicators: action.communicators, + activeCommunicatorId: + action.communicators[action.communicators.length - 1].id + }; default: return state; } From 0bebfd82113922eb3a3387b08922be558453f580 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Mon, 1 Jul 2024 21:45:07 -0300 Subject: [PATCH 04/10] Fix lastEdit update --- .../Communicator/Communicator.reducer.js | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/Communicator/Communicator.reducer.js b/src/components/Communicator/Communicator.reducer.js index 8f6158cde..e36f4575e 100644 --- a/src/components/Communicator/Communicator.reducer.js +++ b/src/components/Communicator/Communicator.reducer.js @@ -106,7 +106,7 @@ function communicatorReducer(state = initialState, action) { if (index !== -1) { const updatedCommunicators = [...state.communicators]; updatedCommunicators[index].boards.push(action.boardId); - updatedCommunicators.lastEdited = moment().format(); + updatedCommunicators[index].lastEdited = moment().format(); return { ...state, communicators: updatedCommunicators @@ -214,10 +214,13 @@ 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 - ), - lastEdited: action.communicator.lastEdited + ) }; case CREATE_API_COMMUNICATOR_FAILURE: return { @@ -233,7 +236,14 @@ function communicatorReducer(state = initialState, action) { return { ...state, isFetching: false, - lastEdited: action.communicator.lastEdited + communicators: state.communicators.map(communicator => + communicator.id === action.communicator.id + ? { + ...communicator, + lastEdited: action.communicator.lastEdited + } + : communicator + ) }; case UPDATE_API_COMMUNICATOR_FAILURE: return { From 00e2c15a8066ceaea7e8fd04dc5c4e5ebb2909d1 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Mon, 1 Jul 2024 21:46:47 -0300 Subject: [PATCH 05/10] Set last saved communicator and change board if it is necessary --- .../Communicator/Communicator.actions.js | 40 +++++++++++++++---- .../Communicator/Communicator.reducer.js | 3 +- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/components/Communicator/Communicator.actions.js b/src/components/Communicator/Communicator.actions.js index 6748486e0..de4f4c4ab 100644 --- a/src/components/Communicator/Communicator.actions.js +++ b/src/components/Communicator/Communicator.actions.js @@ -24,6 +24,8 @@ 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 { @@ -301,24 +303,26 @@ export function syncCommunicators(remoteCommunicators) { const reconcileCommunicators = (local, remote) => { if (local.lastEdited && remote.lastEdited) { if (moment(local.lastEdited).isAfter(remote.lastEdited)) { - console.log('comm local is after remote', local); return local; } if (moment(local.lastEdited).isBefore(remote.lastEdited)) { - console.log('Comm local is before remote', remote); return remote; } if (moment(local.lastEdited).isSame(remote.lastEdited)) { - console.log('Comm sync isSame', local); return remote; } } - console.log('no entro'); 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( @@ -337,21 +341,41 @@ export function syncCommunicators(remoteCommunicators) { const res = await dispatch( updateApiCommunicator(localCommunicators[localIndex]) ); - localCommunicators[localIndex] = res; + updatedCommunicators[localIndex] = res; } catch (e) { console.error(e); } } else { - localCommunicators[localIndex] = reconciled; + updatedCommunicators[localIndex] = reconciled; } } else { // If the communicator does not exist locally, add it - localCommunicators.push(remote); + 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 && + updatedCommunicators.findIndex( + communicator => communicator.id === lastRemoteSavedCommunicatorId + ) !== -1; + dispatch({ type: SYNC_COMMUNICATORS, - communicators: localCommunicators + communicators: updatedCommunicators, + activeCommunicatorId: needToChangeActiveCommunicator + ? remoteCommunicators[0].id + : activeCommunicatorId }); + + if (needToChangeActiveCommunicator) { + const newActiveCommunicator = getActiveCommunicator(getState); + const rootBoard = newActiveCommunicator.rootBoard; + dispatch(switchBoard(rootBoard)); + history.replace(rootBoard); + } }; } diff --git a/src/components/Communicator/Communicator.reducer.js b/src/components/Communicator/Communicator.reducer.js index e36f4575e..5b19818b2 100644 --- a/src/components/Communicator/Communicator.reducer.js +++ b/src/components/Communicator/Communicator.reducer.js @@ -274,8 +274,7 @@ function communicatorReducer(state = initialState, action) { return { ...state, communicators: action.communicators, - activeCommunicatorId: - action.communicators[action.communicators.length - 1].id + activeCommunicatorId: action.activeCommunicatorId }; default: return state; From a17f59852dc5eafebd5a726206266ef7a15c1431 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Mon, 1 Jul 2024 21:49:14 -0300 Subject: [PATCH 06/10] Fix currentCommunicator on login action --- src/components/Account/Login/Login.actions.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Account/Login/Login.actions.js b/src/components/Account/Login/Login.actions.js index cf96125bf..1c19a48bf 100644 --- a/src/components/Account/Login/Login.actions.js +++ b/src/components/Account/Login/Login.actions.js @@ -147,7 +147,8 @@ export function login({ email, password, activatedData }, type = 'local') { ); if (loginData.communicators && loginData.communicators.length) { - currentCommunicator = loginData.communicators[0]; + currentCommunicator = + loginData.communicators[loginData.communicators.length - 1]; //use the latest communicator } const localBoardsIds = []; From 0241e1d2ac305d17c7d1ce500c034e4aad494e52 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Wed, 3 Jul 2024 11:23:21 -0300 Subject: [PATCH 07/10] Add lastRemoteSavedCommunicatorIndex constant to avoid magic number --- src/components/Account/Login/Login.actions.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/Account/Login/Login.actions.js b/src/components/Account/Login/Login.actions.js index 1c19a48bf..31022cc73 100644 --- a/src/components/Account/Login/Login.actions.js +++ b/src/components/Account/Login/Login.actions.js @@ -147,8 +147,10 @@ export function login({ email, password, activatedData }, type = 'local') { ); if (loginData.communicators && loginData.communicators.length) { + const lastRemoteSavedCommunicatorIndex = + loginData.communicators.length - 1; currentCommunicator = - loginData.communicators[loginData.communicators.length - 1]; //use the latest communicator + loginData.communicators[lastRemoteSavedCommunicatorIndex]; //use the latest communicator } const localBoardsIds = []; From 3ee64a8d69458edca56b255ecf2fc1a9cd9ccb1d Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Wed, 3 Jul 2024 11:25:55 -0300 Subject: [PATCH 08/10] Comprobe if lastRemoteSavedCommunicatorId is not null and use it on sync communicator action --- src/components/Communicator/Communicator.actions.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Communicator/Communicator.actions.js b/src/components/Communicator/Communicator.actions.js index de4f4c4ab..625dd26e9 100644 --- a/src/components/Communicator/Communicator.actions.js +++ b/src/components/Communicator/Communicator.actions.js @@ -359,6 +359,7 @@ export function syncCommunicators(remoteCommunicators) { const needToChangeActiveCommunicator = activeCommunicatorId !== lastRemoteSavedCommunicatorId && updatedCommunicators.length && + lastRemoteSavedCommunicatorId && updatedCommunicators.findIndex( communicator => communicator.id === lastRemoteSavedCommunicatorId ) !== -1; @@ -367,7 +368,7 @@ export function syncCommunicators(remoteCommunicators) { type: SYNC_COMMUNICATORS, communicators: updatedCommunicators, activeCommunicatorId: needToChangeActiveCommunicator - ? remoteCommunicators[0].id + ? lastRemoteSavedCommunicatorId : activeCommunicatorId }); From 0bf1006db1605c874ebfb43ac4143613b118a3f1 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Wed, 3 Jul 2024 12:31:46 -0300 Subject: [PATCH 09/10] Add lastEdited prop to initialState Communcator reducer test --- .../Communicator/__tests__/Communicator.reducer.test.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/Communicator/__tests__/Communicator.reducer.test.js b/src/components/Communicator/__tests__/Communicator.reducer.test.js index 1b6703f41..1cee3ea57 100644 --- a/src/components/Communicator/__tests__/Communicator.reducer.test.js +++ b/src/components/Communicator/__tests__/Communicator.reducer.test.js @@ -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', () => { @@ -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 = { @@ -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) From 023bc5d318760efb700b97fa3024a497ee36dc56 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Wed, 3 Jul 2024 14:13:09 -0300 Subject: [PATCH 10/10] Refactor getApiCommunicator to use try catch block --- .../Communicator/Communicator.actions.js | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/components/Communicator/Communicator.actions.js b/src/components/Communicator/Communicator.actions.js index 625dd26e9..54f5d1b3f 100644 --- a/src/components/Communicator/Communicator.actions.js +++ b/src/components/Communicator/Communicator.actions.js @@ -236,18 +236,22 @@ export function verifyAndUpsertCommunicator( export function getApiMyCommunicators() { return async dispatch => { dispatch(getApiMyCommunicatorsStarted()); - return API.getCommunicators() - .then(res => { - dispatch(getApiMyCommunicatorsSuccess(res)); - - return dispatch(syncCommunicators(res.data)).catch(e => { + 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); - }); - }) - .catch(err => { - dispatch(getApiMyCommunicatorsFailure(err.message)); - throw new Error(err.message); - }); + } + } + + return res; + } catch (err) { + dispatch(getApiMyCommunicatorsFailure(err.message)); + throw new Error(err.message); + } }; }