mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2025-01-09 09:47:28 +03:00
Migrated first reducer to typescript, adding also type for the shared app state
This commit is contained in:
parent
e193a692e8
commit
87e64e5899
8 changed files with 117 additions and 59 deletions
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -3441,6 +3441,12 @@
|
|||
"popper.js": "^1.14.1"
|
||||
}
|
||||
},
|
||||
"@types/redux-actions": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/redux-actions/-/redux-actions-2.6.1.tgz",
|
||||
"integrity": "sha512-zKgK+ATp3sswXs6sOYo1tk8xdXTy4CTaeeYrVQlClCjeOpag5vzPo0ASWiiBJ7vsiQRAdb3VkuFLnDoBimF67g==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/stack-utils": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
"@types/react-redux": "^7.1.9",
|
||||
"@types/react-router-dom": "^5.1.5",
|
||||
"@types/reactstrap": "^8.5.1",
|
||||
"@types/redux-actions": "^2.6.1",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"adm-zip": "^0.4.13",
|
||||
"autoprefixer": "^9.6.3",
|
||||
|
|
|
@ -1 +1,25 @@
|
|||
import { MercureInfo } from '../mercure/reducers/mercureInfo';
|
||||
|
||||
export type ConnectDecorator = (props: string[], actions?: string[]) => any;
|
||||
|
||||
export interface ShlinkState {
|
||||
servers: any;
|
||||
selectedServer: any;
|
||||
shortUrlsList: any;
|
||||
shortUrlsListParams: any;
|
||||
shortUrlCreationResult: any;
|
||||
shortUrlDeletion: any;
|
||||
shortUrlTags: any;
|
||||
shortUrlMeta: any;
|
||||
shortUrlEdition: any;
|
||||
shortUrlVisits: any;
|
||||
tagVisits: any;
|
||||
shortUrlDetail: any;
|
||||
tagsList: any;
|
||||
tagDelete: any;
|
||||
tagEdit: any;
|
||||
mercureInfo: MercureInfo;
|
||||
settings: any;
|
||||
}
|
||||
|
||||
export type GetState = () => ShlinkState;
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
import { handleActions } from 'redux-actions';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/* eslint-disable padding-line-between-statements */
|
||||
export const GET_MERCURE_INFO_START = 'shlink/mercure/GET_MERCURE_INFO_START';
|
||||
export const GET_MERCURE_INFO_ERROR = 'shlink/mercure/GET_MERCURE_INFO_ERROR';
|
||||
export const GET_MERCURE_INFO = 'shlink/mercure/GET_MERCURE_INFO';
|
||||
/* eslint-enable padding-line-between-statements */
|
||||
|
||||
export const MercureInfoType = PropTypes.shape({
|
||||
token: PropTypes.string,
|
||||
mercureHubUrl: PropTypes.string,
|
||||
loading: PropTypes.bool,
|
||||
error: PropTypes.bool,
|
||||
});
|
||||
|
||||
const initialState = {
|
||||
token: undefined,
|
||||
mercureHubUrl: undefined,
|
||||
loading: true,
|
||||
error: false,
|
||||
};
|
||||
|
||||
export default handleActions({
|
||||
[GET_MERCURE_INFO_START]: (state) => ({ ...state, loading: true, error: false }),
|
||||
[GET_MERCURE_INFO_ERROR]: (state) => ({ ...state, loading: false, error: true }),
|
||||
[GET_MERCURE_INFO]: (state, { token, mercureHubUrl }) => ({ token, mercureHubUrl, loading: false, error: false }),
|
||||
}, initialState);
|
||||
|
||||
export const loadMercureInfo = (buildShlinkApiClient) => () => async (dispatch, getState) => {
|
||||
dispatch({ type: GET_MERCURE_INFO_START });
|
||||
|
||||
const { settings } = getState();
|
||||
const { mercureInfo } = buildShlinkApiClient(getState);
|
||||
|
||||
if (!settings.realTimeUpdates.enabled) {
|
||||
dispatch({ type: GET_MERCURE_INFO_ERROR });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await mercureInfo();
|
||||
|
||||
dispatch({ type: GET_MERCURE_INFO, ...result });
|
||||
} catch (e) {
|
||||
dispatch({ type: GET_MERCURE_INFO_ERROR });
|
||||
}
|
||||
};
|
59
src/mercure/reducers/mercureInfo.ts
Normal file
59
src/mercure/reducers/mercureInfo.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { handleActions } from 'redux-actions';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Dispatch } from 'redux';
|
||||
import { ShlinkApiClientBuilder, ShlinkMercureInfo } from '../../utils/services/types';
|
||||
import { GetState } from '../../container/types';
|
||||
|
||||
/* eslint-disable padding-line-between-statements */
|
||||
export const GET_MERCURE_INFO_START = 'shlink/mercure/GET_MERCURE_INFO_START';
|
||||
export const GET_MERCURE_INFO_ERROR = 'shlink/mercure/GET_MERCURE_INFO_ERROR';
|
||||
export const GET_MERCURE_INFO = 'shlink/mercure/GET_MERCURE_INFO';
|
||||
/* eslint-enable padding-line-between-statements */
|
||||
|
||||
/** @deprecated Use MercureInfo interface */
|
||||
export const MercureInfoType = PropTypes.shape({
|
||||
token: PropTypes.string,
|
||||
mercureHubUrl: PropTypes.string,
|
||||
loading: PropTypes.bool,
|
||||
error: PropTypes.bool,
|
||||
});
|
||||
|
||||
export interface MercureInfo {
|
||||
token?: string;
|
||||
mercureHubUrl?: string;
|
||||
loading: boolean;
|
||||
error: boolean;
|
||||
}
|
||||
|
||||
const initialState: MercureInfo = {
|
||||
loading: true,
|
||||
error: false,
|
||||
};
|
||||
|
||||
export default handleActions<MercureInfo, ShlinkMercureInfo>({
|
||||
[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 }),
|
||||
}, initialState);
|
||||
|
||||
export const loadMercureInfo = (buildShlinkApiClient: ShlinkApiClientBuilder) =>
|
||||
() => async (dispatch: Dispatch, getState: GetState) => {
|
||||
dispatch({ type: GET_MERCURE_INFO_START });
|
||||
|
||||
const { settings } = getState();
|
||||
const { mercureInfo } = buildShlinkApiClient(getState);
|
||||
|
||||
if (!settings.realTimeUpdates.enabled) {
|
||||
dispatch({ type: GET_MERCURE_INFO_ERROR });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const payload = await mercureInfo();
|
||||
|
||||
dispatch({ type: GET_MERCURE_INFO, payload });
|
||||
} catch (e) {
|
||||
dispatch({ type: GET_MERCURE_INFO_ERROR });
|
||||
}
|
||||
};
|
|
@ -16,8 +16,9 @@ import tagDeleteReducer from '../tags/reducers/tagDelete';
|
|||
import tagEditReducer from '../tags/reducers/tagEdit';
|
||||
import mercureInfoReducer from '../mercure/reducers/mercureInfo';
|
||||
import settingsReducer from '../settings/reducers/settings';
|
||||
import { ShlinkState } from '../container/types';
|
||||
|
||||
export default combineReducers({
|
||||
export default combineReducers<ShlinkState>({
|
||||
servers: serversReducer,
|
||||
selectedServer: selectedServerReducer,
|
||||
shortUrlsList: shortUrlsListReducer,
|
||||
|
|
11
src/utils/services/types.ts
Normal file
11
src/utils/services/types.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { RegularServer } from '../../servers/data';
|
||||
import { GetState } from '../../container/types';
|
||||
import ShlinkApiClient from './ShlinkApiClient';
|
||||
|
||||
// FIXME Move to ShlinkApiClientBuilder
|
||||
export type ShlinkApiClientBuilder = (getStateOrSelectedServer: RegularServer | GetState) => ShlinkApiClient;
|
||||
|
||||
export interface ShlinkMercureInfo {
|
||||
token: string;
|
||||
mercureHubUrl: string;
|
||||
}
|
|
@ -1,9 +1,14 @@
|
|||
import { Mock } from 'ts-mockery';
|
||||
import { Action } from 'redux-actions';
|
||||
import reducer, {
|
||||
GET_MERCURE_INFO_START,
|
||||
GET_MERCURE_INFO_ERROR,
|
||||
GET_MERCURE_INFO,
|
||||
loadMercureInfo,
|
||||
} from '../../../src/mercure/reducers/mercureInfo.js';
|
||||
} from '../../../src/mercure/reducers/mercureInfo';
|
||||
import { ShlinkMercureInfo } from '../../../src/utils/services/types';
|
||||
import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient';
|
||||
import { GetState } from '../../../src/container/types';
|
||||
|
||||
describe('mercureInfoReducer', () => {
|
||||
const mercureInfo = {
|
||||
|
@ -13,21 +18,21 @@ describe('mercureInfoReducer', () => {
|
|||
|
||||
describe('reducer', () => {
|
||||
it('returns loading on GET_MERCURE_INFO_START', () => {
|
||||
expect(reducer({}, { type: GET_MERCURE_INFO_START })).toEqual({
|
||||
expect(reducer(undefined, { type: GET_MERCURE_INFO_START } as Action<ShlinkMercureInfo>)).toEqual({
|
||||
loading: true,
|
||||
error: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('returns error on GET_MERCURE_INFO_ERROR', () => {
|
||||
expect(reducer({}, { type: GET_MERCURE_INFO_ERROR })).toEqual({
|
||||
expect(reducer(undefined, { type: GET_MERCURE_INFO_ERROR } as Action<ShlinkMercureInfo>)).toEqual({
|
||||
loading: false,
|
||||
error: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('returns mercure info on GET_MERCURE_INFO', () => {
|
||||
expect(reducer({}, { type: GET_MERCURE_INFO, ...mercureInfo })).toEqual({
|
||||
expect(reducer(undefined, { type: GET_MERCURE_INFO, payload: mercureInfo })).toEqual({
|
||||
...mercureInfo,
|
||||
loading: false,
|
||||
error: false,
|
||||
|
@ -36,15 +41,15 @@ describe('mercureInfoReducer', () => {
|
|||
});
|
||||
|
||||
describe('loadMercureInfo', () => {
|
||||
const createApiClientMock = (result) => ({
|
||||
mercureInfo: jest.fn(() => result),
|
||||
const createApiClientMock = (result: Promise<ShlinkMercureInfo>) => Mock.of<ShlinkApiClient>({
|
||||
mercureInfo: jest.fn().mockReturnValue(result),
|
||||
});
|
||||
const dispatch = jest.fn();
|
||||
const createGetStateMock = (enabled) => jest.fn(() => ({
|
||||
const createGetStateMock = (enabled: boolean): GetState => jest.fn().mockReturnValue({
|
||||
settings: {
|
||||
realTimeUpdates: { enabled },
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
afterEach(jest.resetAllMocks);
|
||||
|
||||
|
@ -69,7 +74,7 @@ describe('mercureInfoReducer', () => {
|
|||
expect(apiClientMock.mercureInfo).toHaveBeenCalledTimes(1);
|
||||
expect(dispatch).toHaveBeenCalledTimes(2);
|
||||
expect(dispatch).toHaveBeenNthCalledWith(1, { type: GET_MERCURE_INFO_START });
|
||||
expect(dispatch).toHaveBeenNthCalledWith(2, { type: GET_MERCURE_INFO, ...mercureInfo });
|
||||
expect(dispatch).toHaveBeenNthCalledWith(2, { type: GET_MERCURE_INFO, payload: mercureInfo });
|
||||
});
|
||||
|
||||
it('throws error on failure', async () => {
|
Loading…
Reference in a new issue