[UI] Loader reducer

This commit is contained in:
Oleg Shuralev 2020-01-06 13:44:34 +03:00
parent 3bfa1a7d1e
commit a70a688b64
No known key found for this signature in database
GPG key ID: 0459DF80E1A2FD1B
10 changed files with 65 additions and 36 deletions

View file

@ -1,7 +1,7 @@
enum ActionType { enum ActionType {
CLUSTERS__FETCH_REQUEST = 'CLUSTERS__FETCH_REQUEST', GET_CLUSTERS__REQUEST = 'GET_CLUSTERS__REQUEST',
CLUSTERS__FETCH_SUCCESS = 'CLUSTERS__FETCH_SUCCESS', GET_CLUSTERS__SUCCESS = 'GET_CLUSTERS__SUCCESS',
CLUSTERS__FETCH_FAILURE = 'CLUSTERS__FETCH_FAILURE', GET_CLUSTERS__FAILURE = 'GET_CLUSTERS__FAILURE',
} }
export default ActionType; export default ActionType;

View file

@ -3,7 +3,7 @@ import ActionType from './actionType';
import { Cluster } from 'types'; import { Cluster } from 'types';
export const fetchClusterListAction = createAsyncAction( export const fetchClusterListAction = createAsyncAction(
ActionType.CLUSTERS__FETCH_REQUEST, ActionType.GET_CLUSTERS__REQUEST,
ActionType.CLUSTERS__FETCH_SUCCESS, ActionType.GET_CLUSTERS__SUCCESS,
ActionType.CLUSTERS__FETCH_FAILURE, ActionType.GET_CLUSTERS__FAILURE,
)<undefined, Cluster[], undefined>(); )<undefined, Cluster[], undefined>();

View file

@ -1,30 +1,12 @@
import { ClustersState, FetchStatus, Action } from 'types'; import { ClustersState, Action } from 'types';
import actionType from 'redux/reducers/actionType'; import actionType from 'redux/reducers/actionType';
export const initialState: ClustersState = { export const initialState: ClustersState = [];
fetchStatus: FetchStatus.notFetched,
items: [],
};
const reducer = (state = initialState, action: Action): ClustersState => { const reducer = (state = initialState, action: Action): ClustersState => {
switch (action.type) { switch (action.type) {
case actionType.CLUSTERS__FETCH_REQUEST: case actionType.GET_CLUSTERS__SUCCESS:
return { return action.payload;
...state,
fetchStatus: FetchStatus.fetching,
};
case actionType.CLUSTERS__FETCH_SUCCESS:
return {
...state,
fetchStatus: FetchStatus.fetched,
items: action.payload,
};
case actionType.CLUSTERS__FETCH_FAILURE:
return {
...state,
fetchStatus: FetchStatus.errorFetching,
};
default: default:
return state; return state;
} }

View file

@ -1,8 +1,11 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { ClustersState, RootState, FetchStatus } from 'types'; import { ClustersState, RootState, FetchStatus } from 'types';
import { createFetchingSelector } from 'redux/reducers/loader/selectors';
const clustersState = ({ clusters }: RootState): ClustersState => clusters; const clustersState = ({ clusters }: RootState): ClustersState => clusters;
export const getIsClusterListFetched = createSelector(clustersState, ({ fetchStatus }) => fetchStatus === FetchStatus.fetched); const getClusterListFetchingStatus = createFetchingSelector('GET_CLUSTERS');
export const getClusterList = createSelector(clustersState, ({ items }) => items); export const getIsClusterListFetched = createSelector(getClusterListFetchingStatus, (status) => status === FetchStatus.fetched);
export const getClusterList = createSelector(clustersState, (items) => items);

View file

@ -1,9 +1,11 @@
import { combineReducers } from 'redux'; import { combineReducers } from 'redux';
import topics from './topics/reducer'; import topics from './topics/reducer';
import clusters from './clusters/reducer'; import clusters from './clusters/reducer';
import loader from './loader/reducer';
import { RootState } from 'types'; import { RootState } from 'types';
export default combineReducers<RootState>({ export default combineReducers<RootState>({
topics, topics,
clusters, clusters,
loader,
}); });

View file

@ -0,0 +1,35 @@
import { FetchStatus, Action, LoaderState } from 'types';
export const initialState: LoaderState = {};
const reducer = (state = initialState, action: Action): LoaderState => {
const { type } = action;
const matches = /(.*)__(REQUEST|SUCCESS|FAILURE)/.exec(type);
// not a *__REQUEST / *__SUCCESS / *__FAILURE actions, so we ignore them
if (!matches) return state;
const [, requestName, requestState] = matches;
switch (requestState) {
case 'REQUEST':
return {
...state,
[requestName]: FetchStatus.fetching,
};
case 'SUCCESS':
return {
...state,
[requestName]: FetchStatus.fetched,
};
case 'FAILURE':
return {
...state,
[requestName]: FetchStatus.errorFetching,
};
default:
return state;
}
};
export default reducer;

View file

@ -0,0 +1,4 @@
import { RootState, FetchStatus } from 'types';
export const createFetchingSelector = (action: string) =>
(state: RootState) => (state.loader[action] || FetchStatus.notFetched);

View file

@ -1,5 +1,3 @@
import { FetchStatus } from "types";
export enum ClusterStatus { export enum ClusterStatus {
Online = 'online', Online = 'online',
Offline = 'offline', Offline = 'offline',
@ -17,7 +15,4 @@ export interface Cluster {
topicCount: number; topicCount: number;
} }
export interface ClustersState { export type ClustersState = Cluster[];
fetchStatus: FetchStatus;
items: Cluster[];
}

View file

@ -5,9 +5,11 @@ import { ThunkAction } from 'redux-thunk';
import { TopicsState } from './topic'; import { TopicsState } from './topic';
import { AnyAction } from 'redux'; import { AnyAction } from 'redux';
import { ClustersState } from './cluster'; import { ClustersState } from './cluster';
import { LoaderState } from './loader';
export * from './topic'; export * from './topic';
export * from './cluster'; export * from './cluster';
export * from './loader';
export enum FetchStatus { export enum FetchStatus {
notFetched = 'notFetched', notFetched = 'notFetched',
@ -19,6 +21,7 @@ export enum FetchStatus {
export interface RootState { export interface RootState {
topics: TopicsState; topics: TopicsState;
clusters: ClustersState; clusters: ClustersState;
loader: LoaderState;
} }
export type Action = ActionType<typeof topicsActions | typeof clustersActions>; export type Action = ActionType<typeof topicsActions | typeof clustersActions>;

View file

@ -0,0 +1,5 @@
import { FetchStatus } from "types";
export interface LoaderState {
[key: string]: FetchStatus;
}