Migrated servers reducer to RTK

This commit is contained in:
Alejandro Celaya 2022-11-05 10:08:24 +01:00
parent 6f67f7bbf0
commit 10d4419387
4 changed files with 86 additions and 92 deletions

View file

@ -1,6 +1,6 @@
import { IContainer } from 'bottlejs'; import { IContainer } from 'bottlejs';
import { combineReducers } from 'redux'; import { combineReducers } from 'redux';
import serversReducer from '../servers/reducers/servers'; import { serversReducer } from '../servers/reducers/servers';
import selectedServerReducer from '../servers/reducers/selectedServer'; import selectedServerReducer from '../servers/reducers/selectedServer';
import shortUrlsListReducer from '../short-urls/reducers/shortUrlsList'; import shortUrlsListReducer from '../short-urls/reducers/shortUrlsList';
import shortUrlCreationReducer from '../short-urls/reducers/shortUrlCreation'; import shortUrlCreationReducer from '../short-urls/reducers/shortUrlCreation';

View file

@ -1,24 +1,17 @@
import { PayloadAction } from '@reduxjs/toolkit'; import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { assoc, dissoc, fromPairs, map, pipe, reduce, toPairs } from 'ramda'; import { assoc, dissoc, fromPairs, map, pipe, reduce, toPairs } from 'ramda';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { ServerData, ServersMap, ServerWithId } from '../data'; import { ServerData, ServersMap, ServerWithId } from '../data';
import { buildReducer } from '../../utils/helpers/redux';
export const EDIT_SERVER = 'shlink/servers/EDIT_SERVER'; interface EditServer {
export const DELETE_SERVER = 'shlink/servers/DELETE_SERVER';
export const CREATE_SERVERS = 'shlink/servers/CREATE_SERVERS';
export const SET_AUTO_CONNECT = 'shlink/servers/SET_AUTO_CONNECT';
export type CreateServersAction = PayloadAction<ServersMap>;
type DeleteServerAction = PayloadAction<{
serverId: string; serverId: string;
}>; serverData: Partial<ServerData>;
}
type SetAutoConnectAction = PayloadAction<{ interface SetAutoConnect {
serverId: string; serverId: string;
autoConnect: boolean; autoConnect: boolean;
}>; }
const initialState: ServersMap = {}; const initialState: ServersMap = {};
@ -30,53 +23,57 @@ const serverWithId = (server: ServerWithId | ServerData): ServerWithId => {
return assoc('id', uuid(), server); return assoc('id', uuid(), server);
}; };
export default buildReducer<ServersMap, CreateServersAction & DeleteServerAction & SetAutoConnectAction>({
[CREATE_SERVERS]: (state, { payload: newServers }) => ({ ...state, ...newServers }),
[DELETE_SERVER]: (state, { payload }) => dissoc(payload.serverId, state),
[EDIT_SERVER]: (state, { payload }: any) => {
const { serverId, serverData } = payload;
return (
!state[serverId] ? state : assoc(serverId, { ...state[serverId], ...serverData }, state)
);
},
[SET_AUTO_CONNECT]: (state, { payload }) => {
const { serverId, autoConnect } = payload;
if (!state[serverId]) {
return state;
}
if (!autoConnect) {
return assoc(serverId, { ...state[serverId], autoConnect }, state);
}
return fromPairs(
toPairs(state).map(([evaluatedServerId, server]) => [
evaluatedServerId,
{ ...server, autoConnect: evaluatedServerId === serverId },
]),
);
},
}, initialState);
const serversListToMap = reduce<ServerWithId, ServersMap>((acc, server) => assoc(server.id, server, acc), {}); const serversListToMap = reduce<ServerWithId, ServersMap>((acc, server) => assoc(server.id, server, acc), {});
export const createServers = pipe( export const { actions, reducer } = createSlice({
map(serverWithId), name: 'serversReducer',
serversListToMap, initialState,
(newServers: ServersMap) => ({ type: CREATE_SERVERS, payload: newServers }), reducers: {
); editServer: {
prepare: (serverId: string, serverData: Partial<ServerData>) => ({
payload: { serverId, serverData },
}),
reducer: (state, { payload }: PayloadAction<EditServer>) => {
const { serverId, serverData } = payload;
return (
!state[serverId] ? state : assoc(serverId, { ...state[serverId], ...serverData }, state)
);
},
},
deleteServer: (state, { payload }) => dissoc(payload.id, state),
setAutoConnect: {
prepare: ({ id: serverId }: ServerWithId, autoConnect: boolean) => ({
payload: { serverId, autoConnect },
}),
reducer: (state, { payload }: PayloadAction<SetAutoConnect>) => {
const { serverId, autoConnect } = payload;
if (!state[serverId]) {
return state;
}
export const editServer = (serverId: string, serverData: Partial<ServerData>) => ({ if (!autoConnect) {
type: EDIT_SERVER, return assoc(serverId, { ...state[serverId], autoConnect }, state);
payload: { serverId, serverData }, }
return fromPairs(
toPairs(state).map(([evaluatedServerId, server]) => [
evaluatedServerId,
{ ...server, autoConnect: evaluatedServerId === serverId },
]),
);
},
},
createServers: {
prepare: pipe(
map(serverWithId),
serversListToMap,
(payload: ServersMap) => ({ payload }),
),
reducer: (state, { payload: newServers }: PayloadAction<ServersMap>) => ({ ...state, ...newServers }),
},
},
}); });
export const deleteServer = ({ id }: ServerWithId): DeleteServerAction => ({ export const { editServer, deleteServer, setAutoConnect, createServers } = actions;
type: DELETE_SERVER,
payload: { serverId: id },
});
export const setAutoConnect = ({ id }: ServerWithId, autoConnect: boolean): SetAutoConnectAction => ({ export const serversReducer = reducer;
type: SET_AUTO_CONNECT,
payload: { serverId: id, autoConnect },
});

View file

@ -1,7 +1,7 @@
import { Mock } from 'ts-mockery'; import { Mock } from 'ts-mockery';
import { AxiosInstance } from 'axios'; import { AxiosInstance } from 'axios';
import { fetchServers } from '../../../src/servers/reducers/remoteServers'; import { fetchServers } from '../../../src/servers/reducers/remoteServers';
import { CREATE_SERVERS } from '../../../src/servers/reducers/servers'; import { createServers } from '../../../src/servers/reducers/servers';
describe('remoteServersReducer', () => { describe('remoteServersReducer', () => {
afterEach(jest.clearAllMocks); afterEach(jest.clearAllMocks);
@ -87,7 +87,7 @@ describe('remoteServersReducer', () => {
await fetchServers(axios)()(dispatch); await fetchServers(axios)()(dispatch);
expect(dispatch).toHaveBeenCalledWith({ type: CREATE_SERVERS, payload: expectedNewServers }); expect(dispatch).toHaveBeenCalledWith({ type: createServers.toString(), payload: expectedNewServers });
expect(get).toHaveBeenCalledTimes(1); expect(get).toHaveBeenCalledTimes(1);
}); });
}); });

View file

@ -1,14 +1,11 @@
import { dissoc, values } from 'ramda'; import { dissoc, values } from 'ramda';
import { Mock } from 'ts-mockery'; import { Mock } from 'ts-mockery';
import reducer, { import {
deleteServer, deleteServer,
createServers, createServers,
editServer, editServer,
setAutoConnect, setAutoConnect,
EDIT_SERVER, serversReducer,
DELETE_SERVER,
CREATE_SERVERS,
SET_AUTO_CONNECT,
} from '../../../src/servers/reducers/servers'; } from '../../../src/servers/reducers/servers';
import { RegularServer } from '../../../src/servers/data'; import { RegularServer } from '../../../src/servers/data';
@ -22,38 +19,38 @@ describe('serversReducer', () => {
describe('reducer', () => { describe('reducer', () => {
it('returns edited server when action is EDIT_SERVER', () => it('returns edited server when action is EDIT_SERVER', () =>
expect(reducer(list, { expect(serversReducer(list, {
type: EDIT_SERVER, type: editServer.toString(),
payload: { serverId: 'abc123', serverData: { foo: 'foo' } }, payload: { serverId: 'abc123', serverData: { foo: 'foo' } },
} as any)).toEqual({ })).toEqual({
abc123: { id: 'abc123', foo: 'foo' }, abc123: { id: 'abc123', foo: 'foo' },
def456: { id: 'def456' }, def456: { id: 'def456' },
})); }));
it('returns as it is when action is EDIT_SERVER and server does not exist', () => it('returns as it is when action is EDIT_SERVER and server does not exist', () =>
expect(reducer(list, { expect(serversReducer(list, {
type: EDIT_SERVER, type: editServer.toString(),
payload: { serverId: 'invalid', serverData: { foo: 'foo' } }, payload: { serverId: 'invalid', serverData: { foo: 'foo' } },
} as any)).toEqual({ })).toEqual({
abc123: { id: 'abc123' }, abc123: { id: 'abc123' },
def456: { id: 'def456' }, def456: { id: 'def456' },
})); }));
it('removes server when action is DELETE_SERVER', () => it('removes server when action is DELETE_SERVER', () =>
expect(reducer(list, { expect(serversReducer(list, {
type: DELETE_SERVER, type: deleteServer.toString(),
payload: { serverId: 'abc123' }, payload: { id: 'abc123' },
} as any)).toEqual({ })).toEqual({
def456: { id: 'def456' }, def456: { id: 'def456' },
})); }));
it('appends server when action is CREATE_SERVERS', () => it('appends server when action is CREATE_SERVERS', () =>
expect(reducer(list, { expect(serversReducer(list, {
type: CREATE_SERVERS, type: createServers.toString(),
payload: { payload: {
ghi789: { id: 'ghi789' }, ghi789: { id: 'ghi789' },
}, },
} as any)).toEqual({ })).toEqual({
abc123: { id: 'abc123' }, abc123: { id: 'abc123' },
def456: { id: 'def456' }, def456: { id: 'def456' },
ghi789: { id: 'ghi789' }, ghi789: { id: 'ghi789' },
@ -63,10 +60,10 @@ describe('serversReducer', () => {
[true], [true],
[false], [false],
])('returns state as it is when trying to set auto-connect on invalid server', (autoConnect) => ])('returns state as it is when trying to set auto-connect on invalid server', (autoConnect) =>
expect(reducer(list, { expect(serversReducer(list, {
type: SET_AUTO_CONNECT, type: setAutoConnect.toString(),
payload: { serverId: 'invalid', autoConnect }, payload: { serverId: 'invalid', autoConnect },
} as any)).toEqual({ })).toEqual({
abc123: { id: 'abc123' }, abc123: { id: 'abc123' },
def456: { id: 'def456' }, def456: { id: 'def456' },
})); }));
@ -77,10 +74,10 @@ describe('serversReducer', () => {
abc123: { ...list.abc123, autoConnect: true }, abc123: { ...list.abc123, autoConnect: true },
}; };
expect(reducer(listWithDisabledAutoConnect, { expect(serversReducer(listWithDisabledAutoConnect, {
type: SET_AUTO_CONNECT, type: setAutoConnect.toString(),
payload: { serverId: 'abc123', autoConnect: false }, payload: { serverId: 'abc123', autoConnect: false },
} as any)).toEqual({ })).toEqual({
abc123: { id: 'abc123', autoConnect: false }, abc123: { id: 'abc123', autoConnect: false },
def456: { id: 'def456' }, def456: { id: 'def456' },
}); });
@ -92,10 +89,10 @@ describe('serversReducer', () => {
abc123: { ...list.abc123, autoConnect: true }, abc123: { ...list.abc123, autoConnect: true },
}; };
expect(reducer(listWithEnabledAutoConnect, { expect(serversReducer(listWithEnabledAutoConnect, {
type: SET_AUTO_CONNECT, type: setAutoConnect.toString(),
payload: { serverId: 'def456', autoConnect: true }, payload: { serverId: 'def456', autoConnect: true },
} as any)).toEqual({ })).toEqual({
abc123: { id: 'abc123', autoConnect: false }, abc123: { id: 'abc123', autoConnect: false },
def456: { id: 'def456', autoConnect: true }, def456: { id: 'def456', autoConnect: true },
}); });
@ -109,7 +106,7 @@ describe('serversReducer', () => {
const result = editServer('123', serverData); const result = editServer('123', serverData);
expect(result).toEqual({ expect(result).toEqual({
type: EDIT_SERVER, type: editServer.toString(),
payload: { serverId: '123', serverData }, payload: { serverId: '123', serverData },
}); });
}); });
@ -121,8 +118,8 @@ describe('serversReducer', () => {
const result = deleteServer(serverToDelete); const result = deleteServer(serverToDelete);
expect(result).toEqual({ expect(result).toEqual({
type: DELETE_SERVER, type: deleteServer.toString(),
payload: { serverId: 'abc123' }, payload: { id: 'abc123' },
}); });
}); });
}); });
@ -132,7 +129,7 @@ describe('serversReducer', () => {
const newServers = values(list); const newServers = values(list);
const result = createServers(newServers); const result = createServers(newServers);
expect(result).toEqual(expect.objectContaining({ type: CREATE_SERVERS })); expect(result).toEqual(expect.objectContaining({ type: createServers.toString() }));
}); });
it('generates an id for every provided server if they do not have it', () => { it('generates an id for every provided server if they do not have it', () => {
@ -152,7 +149,7 @@ describe('serversReducer', () => {
const result = setAutoConnect(serverToEdit, autoConnect); const result = setAutoConnect(serverToEdit, autoConnect);
expect(result).toEqual({ expect(result).toEqual({
type: SET_AUTO_CONNECT, type: setAutoConnect.toString(),
payload: { serverId: 'abc123', autoConnect }, payload: { serverId: 'abc123', autoConnect },
}); });
}); });