Skip to content

Commit

Permalink
Merge pull request #2857 from marmelab/typescript-reducers
Browse files Browse the repository at this point in the history
[RFR] Migrate reducers to TypeScript
  • Loading branch information
fzaninotto authored Feb 11, 2019
2 parents d0a60e5 + 3b79b99 commit f00663b
Show file tree
Hide file tree
Showing 32 changed files with 785 additions and 519 deletions.
16 changes: 12 additions & 4 deletions packages/ra-core/src/actions/listActions.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
export const CRUD_CHANGE_LIST_PARAMS = 'RA/CRUD_CHANGE_LIST_PARAMS';

interface Params {
sort: string;
order: string;
page: number;
perPage: number;
filter: any;
}

export interface ChangeListParamsAction {
readonly type: typeof CRUD_CHANGE_LIST_PARAMS;
readonly payload: any;
readonly payload: Params;
readonly meta: { resource: string };
}
export const changeListParams = (
resource: string,
params: any
params: Params
): ChangeListParamsAction => ({
type: CRUD_CHANGE_LIST_PARAMS,
payload: params,
Expand All @@ -16,15 +24,15 @@ export const changeListParams = (

export const SET_LIST_SELECTED_IDS = 'RA/SET_LIST_SELECTED_IDS';

export interface SetListLelectedIdsAction {
export interface SetListSelectedIdsAction {
readonly type: typeof SET_LIST_SELECTED_IDS;
readonly payload: [];
readonly meta: { resource: string };
}
export const setListSelectedIds = (
resource: string,
ids: []
): SetListLelectedIdsAction => ({
): SetListSelectedIdsAction => ({
type: SET_LIST_SELECTED_IDS,
payload: ids,
meta: { resource },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { Reducer } from 'redux';
import { USER_LOGIN_SUCCESS, USER_LOGOUT } from '../../actions';

const initialState = { isLoggedIn: false };

export default (previousState = initialState, action) => {
interface State {
isLoggedIn: boolean;
}

const authReducer: Reducer<State> = (previousState = initialState, action) => {
switch (action.type) {
case USER_LOGIN_SUCCESS:
return { ...previousState, isLoggedIn: true };
Expand All @@ -14,3 +19,5 @@ export default (previousState = initialState, action) => {
};

export const isLoggedIn = state => state.isLoggedIn;

export default authReducer;
File renamed without changes.
32 changes: 0 additions & 32 deletions packages/ra-core/src/reducer/admin/loading.spec.js

This file was deleted.

32 changes: 32 additions & 0 deletions packages/ra-core/src/reducer/admin/loading.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import expect from 'expect';
import {
FETCH_START,
FETCH_END,
FETCH_ERROR,
FETCH_CANCEL,
} from '../../actions/fetchActions';

import {
USER_LOGIN_LOADING,
USER_LOGIN_SUCCESS,
USER_LOGIN_FAILURE,
} from '../../actions/authActions';

import reducer from './loading';

describe('loading reducer', () => {
it('should return 0 by default', () => {
expect(reducer(undefined, { type: 'ANY' })).toEqual(0);
});
it('should increase with fetch or auth actions', () => {
expect(reducer(0, { type: FETCH_START })).toEqual(1);
expect(reducer(0, { type: USER_LOGIN_LOADING })).toEqual(1);
});
it('should decrease with fetch or auth actions success or failure', () => {
expect(reducer(1, { type: FETCH_END })).toEqual(0);
expect(reducer(1, { type: FETCH_ERROR })).toEqual(0);
expect(reducer(1, { type: FETCH_CANCEL })).toEqual(0);
expect(reducer(1, { type: USER_LOGIN_SUCCESS })).toEqual(0);
expect(reducer(1, { type: USER_LOGIN_FAILURE })).toEqual(0);
});
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Reducer } from 'redux';
import {
FETCH_START,
FETCH_END,
Expand All @@ -11,7 +12,9 @@ import {
USER_LOGIN_FAILURE,
} from '../../actions/authActions';

export default (previousState = 0, { type }) => {
type State = number;

const loadingReducer: Reducer<State> = (previousState = 0, { type }) => {
switch (type) {
case FETCH_START:
case USER_LOGIN_LOADING:
Expand All @@ -26,3 +29,5 @@ export default (previousState = 0, { type }) => {
return previousState;
}
};

export default loadingReducer;
23 changes: 0 additions & 23 deletions packages/ra-core/src/reducer/admin/record.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import assert from 'assert';
import expect from 'expect';
import { INITIALIZE_FORM, RESET_FORM } from '../../actions/formActions';
import reducer from './record';

describe('record reducer', () => {
it('should return an empty record by default', () => {
assert.deepEqual({}, reducer(undefined, {}));
expect(reducer(undefined, { type: 'OTHER_ACTION' })).toEqual({});
});

it('should return an empty record upon RESET_FORM', () => {
assert.deepEqual({}, reducer({ foo: 'bar' }, { type: RESET_FORM }));
expect(reducer({ foo: 'bar' }, { type: RESET_FORM })).toEqual({});
});

it('should return the current record with new fields upon INITIALIZE_FORM', () => {
assert.deepEqual(
{ foo: 'bar', bar: 'foo', deep: { very: { deep: 'gotme' } } },
expect(
reducer(
{ foo: 'bar' },
{
type: INITIALIZE_FORM,
payload: { bar: 'foo', 'deep.very.deep': 'gotme' },
}
)
);
).toEqual({
foo: 'bar',
bar: 'foo',
deep: { very: { deep: 'gotme' } },
});
});
});
42 changes: 42 additions & 0 deletions packages/ra-core/src/reducer/admin/record.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Reducer } from 'redux';
import {
INITIALIZE_FORM,
InitializeFormAction,
RESET_FORM,
ResetFormAction,
} from '../../actions/formActions';
import set from 'lodash/set';

const initialState = {};

interface State {
[key: string]: any;
}

type ActionTypes =
| InitializeFormAction
| ResetFormAction
| { type: 'OTHER_ACTION' };

const recordReducer: Reducer<State> = (
previousState = initialState,
action: ActionTypes
) => {
if (action.type === RESET_FORM) {
return initialState;
}

if (action.type === INITIALIZE_FORM) {
return Object.keys(action.payload).reduce(
(acc, key) => {
// Ensure we correctly set default values for path with dot notation
set(acc, key, action.payload[key]);
return acc;
},
{ ...previousState }
);
}
return previousState;
};

export default recordReducer;
Original file line number Diff line number Diff line change
@@ -1,33 +1,51 @@
import { CRUD_GET_MANY_REFERENCE_SUCCESS } from '../../../actions/dataActions';
import { Reducer } from 'redux';
import {
CRUD_GET_MANY_REFERENCE_SUCCESS,
CrudGetManyReferenceSuccessAction,
} from '../../../actions/dataActions';
import { Identifier, ReduxState } from '../../../types';

const initialState = {};

export default (previousState = initialState, { type, payload, meta }) => {
switch (type) {
interface State {
[relatedTo: string]: { ids: Identifier[]; total: number };
}

type ActionTypes =
| CrudGetManyReferenceSuccessAction
| { type: 'OTHER_ACTION'; payload: any; meta?: any };

const oneToManyReducer: Reducer<State> = (
previousState = initialState,
action: ActionTypes
) => {
switch (action.type) {
case CRUD_GET_MANY_REFERENCE_SUCCESS:
return {
...previousState,
[meta.relatedTo]: {
ids: payload.data.map(record => record.id),
total: payload.total,
[action.meta.relatedTo]: {
ids: action.payload.data.map(record => record.id),
total: action.payload.total,
},
};
default:
return previousState;
}
};

export const getIds = (state, relatedTo) =>
export const getIds = (state: ReduxState, relatedTo) =>
state.admin.references.oneToMany[relatedTo] &&
state.admin.references.oneToMany[relatedTo].ids;

export const getTotal = (state, relatedTo) =>
export const getTotal = (state: ReduxState, relatedTo) =>
state.admin.references.oneToMany[relatedTo] &&
state.admin.references.oneToMany[relatedTo].total;

export const getReferences = (state, reference, relatedTo) => {
export const getReferences = (state: ReduxState, reference, relatedTo) => {
const ids = getIds(state, relatedTo);
if (typeof ids === 'undefined') return undefined;
if (typeof ids === 'undefined') {
return undefined;
}

if (!state.admin.resources[reference]) {
// eslint-disable-next-line no-console
Expand Down Expand Up @@ -57,8 +75,10 @@ export const getReferences = (state, reference, relatedTo) => {
}, {});
};

export const getReferencesByIds = (state, reference, ids) => {
if (ids.length === 0) return {};
export const getReferencesByIds = (state: ReduxState, reference, ids) => {
if (ids.length === 0) {
return {};
}

if (!state.admin.resources[reference]) {
// eslint-disable-next-line no-console
Expand Down Expand Up @@ -100,3 +120,5 @@ export const nameRelatedTo = (reference, id, resource, target, filter = {}) => {
.map(key => `${key}=${JSON.stringify(filter[key])}`)
.join('&')}`;
};

export default oneToManyReducer;
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
import { Reducer } from 'redux';
import {
CRUD_GET_MATCHING_SUCCESS,
CrudGetMatchingSuccessAction,
CRUD_GET_MATCHING_FAILURE,
CrudGetMatchingFailureAction,
} from '../../../actions/dataActions';
import { Identifier } from '../../../types';

const initialState = {};

export default (previousState = initialState, { type, payload, meta }) => {
switch (type) {
interface State {
[relatedTo: string]: { error?: string | object } | Identifier[];
}

type ActionTypes =
| CrudGetMatchingSuccessAction
| CrudGetMatchingFailureAction
| { type: 'OTHER_ACTION' };

const possibleValuesreducer: Reducer<State> = (
previousState = initialState,
action: ActionTypes
) => {
switch (action.type) {
case CRUD_GET_MATCHING_SUCCESS:
return {
...previousState,
[meta.relatedTo]: payload.data.map(record => record.id),
[action.meta.relatedTo]: action.payload.data.map(
record => record.id
),
};
case CRUD_GET_MATCHING_FAILURE:
return {
...previousState,
[meta.relatedTo]: { error: payload.error },
[action.meta.relatedTo]: { error: action.error },
};
default:
return previousState;
Expand All @@ -40,10 +58,12 @@ export const getPossibleReferences = (
possibleValues = Array.from(possibleValues);
selectedIds.forEach(
id =>
possibleValues.some(value => value == id) ||
possibleValues.some(value => value === id) ||
possibleValues.unshift(id)
);
return possibleValues
.map(id => referenceState.data[id])
.filter(r => typeof r !== 'undefined');
};

export default possibleValuesreducer;
Loading

0 comments on commit f00663b

Please sign in to comment.