Removed dependency on redux-actions for all reducers already migrated to typescript

This commit is contained in:
Alejandro Celaya
2020-08-25 19:41:48 +02:00
parent d8f3952920
commit f04aece7df
15 changed files with 99 additions and 74 deletions

View File

@@ -1,8 +1,8 @@
import { Action, handleActions } from 'redux-actions';
import PropTypes from 'prop-types';
import { Dispatch } from 'redux';
import { Action, Dispatch } from 'redux';
import { ShlinkApiClientBuilder, ShlinkMercureInfo } from '../../utils/services/types';
import { GetState } from '../../container/types';
import { buildReducer } from '../../utils/helpers/redux';
/* eslint-disable padding-line-between-statements */
export const GET_MERCURE_INFO_START = 'shlink/mercure/GET_MERCURE_INFO_START';
@@ -25,15 +25,17 @@ export interface MercureInfo {
error: boolean;
}
export type GetMercureInfoAction = Action<string> & ShlinkMercureInfo;
const initialState: MercureInfo = {
loading: true,
error: false,
};
export default handleActions<MercureInfo, ShlinkMercureInfo>({
export default buildReducer<MercureInfo, GetMercureInfoAction>({
[GET_MERCURE_INFO_START]: (state) => ({ ...state, loading: true, error: false }),
[GET_MERCURE_INFO_ERROR]: (state) => ({ ...state, loading: false, error: true }),
[GET_MERCURE_INFO]: (_, { payload }) => ({ ...payload, loading: false, error: false }),
[GET_MERCURE_INFO]: (_, { token, mercureHubUrl }) => ({ token, mercureHubUrl, loading: false, error: false }),
}, initialState);
export const loadMercureInfo = (buildShlinkApiClient: ShlinkApiClientBuilder) =>
@@ -50,9 +52,9 @@ export const loadMercureInfo = (buildShlinkApiClient: ShlinkApiClientBuilder) =>
}
try {
const payload = await mercureInfo();
const result = await mercureInfo();
dispatch<Action<ShlinkMercureInfo>>({ type: GET_MERCURE_INFO, payload });
dispatch<Action<ShlinkMercureInfo>>({ type: GET_MERCURE_INFO, ...result });
} catch (e) {
dispatch({ type: GET_MERCURE_INFO_ERROR });
}

View File

@@ -1,11 +1,11 @@
import { createAction, handleActions } from 'redux-actions';
import { identity, memoizeWith, pipe } from 'ramda';
import { Action, Dispatch } from 'redux';
import { resetShortUrlParams } from '../../short-urls/reducers/shortUrlsListParams';
import { versionToPrintable, versionToSemVer as toSemVer } from '../../utils/helpers/version';
import { NonReachableServer, NotFoundServer, ReachableServer, SelectedServer } from '../data';
import { SelectedServer } from '../data';
import { GetState } from '../../container/types';
import { ShlinkApiClientBuilder, ShlinkHealth } from '../../utils/services/types';
import { buildActionCreator, buildReducer } from '../../utils/helpers/redux';
/* eslint-disable padding-line-between-statements */
export const SELECT_SERVER = 'shlink/selectedServer/SELECT_SERVER';
@@ -16,7 +16,10 @@ export const MAX_FALLBACK_VERSION = '999.999.999';
export const LATEST_VERSION_CONSTRAINT = 'latest';
/* eslint-enable padding-line-between-statements */
const initialState: SelectedServer = null;
export interface SelectServerAction extends Action<string> {
selectedServer: SelectedServer;
}
const versionToSemVer = pipe(
(version: string) => version === LATEST_VERSION_CONSTRAINT ? MAX_FALLBACK_VERSION : version,
toSemVer(MIN_FALLBACK_VERSION),
@@ -30,7 +33,14 @@ const getServerVersion = memoizeWith(
})),
);
export const resetSelectedServer = createAction(RESET_SELECTED_SERVER);
const initialState: SelectedServer = null;
export default buildReducer<SelectedServer, SelectServerAction>({
[RESET_SELECTED_SERVER]: () => initialState,
[SELECT_SERVER]: (_, { selectedServer }) => selectedServer,
}, initialState);
export const resetSelectedServer = buildActionCreator(RESET_SELECTED_SERVER);
export const selectServer = (
buildShlinkApiClient: ShlinkApiClientBuilder,
@@ -48,7 +58,7 @@ export const selectServer = (
const selectedServer = servers[serverId];
if (!selectedServer) {
dispatch<Action & { selectedServer: NotFoundServer }>({
dispatch<SelectServerAction>({
type: SELECT_SERVER,
selectedServer: { serverNotFound: true },
});
@@ -60,7 +70,7 @@ export const selectServer = (
const { health } = buildShlinkApiClient(selectedServer);
const { version, printableVersion } = await getServerVersion(serverId, health);
dispatch<Action & { selectedServer: ReachableServer }>({
dispatch<SelectServerAction>({
type: SELECT_SERVER,
selectedServer: {
...selectedServer,
@@ -70,14 +80,9 @@ export const selectServer = (
});
dispatch(loadMercureInfo());
} catch (e) {
dispatch<Action & { selectedServer: NonReachableServer }>({
dispatch<SelectServerAction>({
type: SELECT_SERVER,
selectedServer: { ...selectedServer, serverNotReachable: true },
});
}
};
export default handleActions<SelectedServer, any>({
[RESET_SELECTED_SERVER]: () => initialState,
[SELECT_SERVER]: (_, { selectedServer }: any) => selectedServer,
}, initialState);

View File

@@ -1,7 +1,8 @@
import { handleActions } from 'redux-actions';
import { pipe, assoc, map, reduce, dissoc } from 'ramda';
import { v4 as uuid } from 'uuid';
import { Action } from 'redux';
import { ServerData, ServerWithId } from '../data';
import { buildReducer } from '../../utils/helpers/redux';
/* eslint-disable padding-line-between-statements */
export const EDIT_SERVER = 'shlink/servers/EDIT_SERVER';
@@ -11,6 +12,10 @@ export const CREATE_SERVERS = 'shlink/servers/CREATE_SERVERS';
export type ServersMap = Record<string, ServerWithId>;
export interface CreateServersAction extends Action<string> {
newServers: ServersMap;
}
const initialState: ServersMap = {};
const serverWithId = (server: ServerWithId | ServerData): ServerWithId => {
@@ -21,8 +26,8 @@ const serverWithId = (server: ServerWithId | ServerData): ServerWithId => {
return assoc('id', uuid(), server);
};
export default handleActions<ServersMap, any>({
[CREATE_SERVERS]: (state, { newServers }: any) => ({ ...state, ...newServers }),
export default buildReducer<ServersMap, CreateServersAction>({
[CREATE_SERVERS]: (state, { newServers }) => ({ ...state, ...newServers }),
[DELETE_SERVER]: (state, { serverId }: any) => dissoc(serverId, state),
[EDIT_SERVER]: (state, { serverId, serverData }: any) => !state[serverId]
? state

View File

@@ -1,5 +1,5 @@
import { handleActions } from 'redux-actions';
import { Action } from 'redux';
import { buildReducer } from '../../utils/helpers/redux';
export const SET_REAL_TIME_UPDATES = 'shlink/realTimeUpdates/SET_REAL_TIME_UPDATES';
@@ -17,11 +17,13 @@ const initialState: Settings = {
},
};
export default handleActions<Settings, any>({
[SET_REAL_TIME_UPDATES]: (state, { realTimeUpdates }: any) => ({ ...state, realTimeUpdates }),
type SettingsAction = Action & Settings;
export default buildReducer<Settings, SettingsAction>({
[SET_REAL_TIME_UPDATES]: (state, { realTimeUpdates }) => ({ ...state, realTimeUpdates }),
}, initialState);
export const setRealTimeUpdates = (enabled: boolean): Action & Settings => ({
export const setRealTimeUpdates = (enabled: boolean): SettingsAction => ({
type: SET_REAL_TIME_UPDATES,
realTimeUpdates: { enabled },
});

View File

@@ -1,9 +1,9 @@
import PropTypes from 'prop-types';
import { createAction, handleActions } from 'redux-actions';
import { Action, Dispatch } from 'redux';
import { ShlinkApiClientBuilder } from '../../utils/services/types';
import { GetState } from '../../container/types';
import { ShortUrl, ShortUrlData } from '../data';
import { buildReducer, buildActionCreator } from '../../utils/helpers/redux';
/* eslint-disable padding-line-between-statements */
export const CREATE_SHORT_URL_START = 'shlink/createShortUrl/CREATE_SHORT_URL_START';
@@ -27,16 +27,20 @@ export interface ShortUrlCreation {
error: boolean;
}
export interface CreateShortUrlAction extends Action<string> {
result: ShortUrl;
}
const initialState: ShortUrlCreation = {
result: null,
saving: false,
error: false,
};
export default handleActions<ShortUrlCreation, any>({
export default buildReducer<ShortUrlCreation, CreateShortUrlAction>({
[CREATE_SHORT_URL_START]: (state) => ({ ...state, saving: true, error: false }),
[CREATE_SHORT_URL_ERROR]: (state) => ({ ...state, saving: false, error: true }),
[CREATE_SHORT_URL]: (_, { result }: any) => ({ result, saving: false, error: false }),
[CREATE_SHORT_URL]: (_, { result }) => ({ result, saving: false, error: false }),
[RESET_CREATE_SHORT_URL]: () => initialState,
}, initialState);
@@ -50,7 +54,7 @@ export const createShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) =>
try {
const result = await createShortUrl(data);
dispatch<Action & { result: ShortUrl }>({ type: CREATE_SHORT_URL, result });
dispatch<CreateShortUrlAction>({ type: CREATE_SHORT_URL, result });
} catch (e) {
dispatch({ type: CREATE_SHORT_URL_ERROR });
@@ -58,4 +62,4 @@ export const createShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) =>
}
};
export const resetCreateShortUrl = createAction(RESET_CREATE_SHORT_URL);
export const resetCreateShortUrl = buildActionCreator(RESET_CREATE_SHORT_URL);

View File

@@ -1,9 +1,9 @@
import { createAction, handleActions, Action } from 'redux-actions';
import PropTypes from 'prop-types';
import { Dispatch } from 'redux';
import { Dispatch, Action } from 'redux';
import { ShortUrlMeta } from '../data';
import { ShlinkApiClientBuilder } from '../../utils/services/types';
import { GetState } from '../../container/types';
import { buildActionCreator, buildReducer } from '../../utils/helpers/redux';
/* eslint-disable padding-line-between-statements */
export const EDIT_SHORT_URL_META_START = 'shlink/shortUrlMeta/EDIT_SHORT_URL_META_START';
@@ -34,7 +34,7 @@ export interface ShortUrlMetaEdition {
error: boolean;
}
interface ShortUrlMetaEditedAction {
interface ShortUrlMetaEditedAction extends Action<string> {
shortCode: string;
domain?: string | null;
meta: ShortUrlMeta;
@@ -47,10 +47,10 @@ const initialState: ShortUrlMetaEdition = {
error: false,
};
export default handleActions<ShortUrlMetaEdition, ShortUrlMetaEditedAction>({
export default buildReducer<ShortUrlMetaEdition, ShortUrlMetaEditedAction>({
[EDIT_SHORT_URL_META_START]: (state) => ({ ...state, saving: true, error: false }),
[EDIT_SHORT_URL_META_ERROR]: (state) => ({ ...state, saving: false, error: true }),
[SHORT_URL_META_EDITED]: (_, { payload }) => ({ ...payload, saving: false, error: false }),
[SHORT_URL_META_EDITED]: (_, { shortCode, meta }) => ({ shortCode, meta, saving: false, error: false }),
[RESET_EDIT_SHORT_URL_META]: () => initialState,
}, initialState);
@@ -64,10 +64,7 @@ export const editShortUrlMeta = (buildShlinkApiClient: ShlinkApiClientBuilder) =
try {
await updateShortUrlMeta(shortCode, domain, meta);
dispatch<Action<ShortUrlMetaEditedAction>>({
type: SHORT_URL_META_EDITED,
payload: { shortCode, meta, domain },
});
dispatch<ShortUrlMetaEditedAction>({ shortCode, meta, domain, type: SHORT_URL_META_EDITED });
} catch (e) {
dispatch({ type: EDIT_SHORT_URL_META_ERROR });
@@ -75,4 +72,4 @@ export const editShortUrlMeta = (buildShlinkApiClient: ShlinkApiClientBuilder) =
}
};
export const resetShortUrlMeta = createAction(RESET_EDIT_SHORT_URL_META);
export const resetShortUrlMeta = buildActionCreator(RESET_EDIT_SHORT_URL_META);

View File

@@ -49,13 +49,7 @@ export default handleActions({
state,
),
[SHORT_URL_TAGS_EDITED]: setPropFromActionOnMatchingShortUrl('tags'),
[SHORT_URL_META_EDITED]: (state, { payload: { shortCode, domain, meta } }) => assocPath(
[ 'shortUrls', 'data' ],
state.shortUrls.data.map(
(shortUrl) => shortUrlMatches(shortUrl, shortCode, domain) ? assoc('meta', meta, shortUrl) : shortUrl,
),
state,
),
[SHORT_URL_META_EDITED]: setPropFromActionOnMatchingShortUrl('meta'),
[SHORT_URL_EDITED]: setPropFromActionOnMatchingShortUrl('longUrl'),
[CREATE_VISIT]: (state, { shortUrl: { shortCode, domain, visitsCount } }) => assocPath(
[ 'shortUrls', 'data' ],

View File

@@ -0,0 +1,17 @@
import { Action } from 'redux';
type ActionDispatcher<State, AT> = (currentState: State, action: AT) => State;
type ActionDispatcherMap<State, AT> = Record<string, ActionDispatcher<State, AT>>;
export const buildReducer = <State, AT extends Action>(map: ActionDispatcherMap<State, AT>, initialState: State) => (
state: State | undefined,
action: AT,
): State => {
const { type } = action;
const actionDispatcher = map[type];
const currentState = state ?? initialState;
return actionDispatcher ? actionDispatcher(currentState, action) : currentState;
};
export const buildActionCreator = <T extends string>(type: T) => (): Action<T> => ({ type });