Skip to content
This repository has been archived by the owner on Jun 19, 2023. It is now read-only.

WP 458 move platform reducer to 'store' package #346

Merged
merged 7 commits into from
Aug 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
- **Moved + renamed** `src/middleware/platform:getEpicMiddleware` has moved to
`require('src/api-state').getApiMiddleware`

- **Moved + renamed** `src/reducers/platform` has moved to `src/store/reducer`.
`makeRootReducer` is now the default export of the module.

## [5.1]

- **Change** (could be considered breaking, but it's specifically for a
Expand Down
2 changes: 1 addition & 1 deletion docs/Rendering.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The browser entry script would typically have the following structure:

```jsx
import { resolveAppProps } from 'meetup-web-platform/lib/renderers/browser-render';
import makeRootReducer from 'meetup-web-platform/lib/reducers/platform';
import makeRootReducer from 'meetup-web-platform/lib/store/reducer';

const appReducers = require('./reducers'); // map of reducer keys to reducer functions
const reducer = makeRootReducer(appReducers); // create the root reducer function
Expand Down
39 changes: 0 additions & 39 deletions flow-typed/platform.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,42 +108,3 @@ declare type CookieOpts = {
isSecure?: boolean,
encoding?: string,
};

declare type Match = {
params: Params,
isExact: boolean,
path: string,
url: string,
};

declare type MatchedRoute = { route: PlatformRoute, match: Match };
declare type MatchPathOptions = {
path: string,
exact?: boolean,
strict?: boolean,
};

declare module 'react-router-dom/matchPath' {
declare function matchPath(
pathname: string,
options: MatchPathOptions
): null | Match;
declare module.exports: typeof matchPath;
}

declare type LocationShape = {
pathname?: string,
search?: string,
hash?: string,
state?: any,
};

declare class RouterRedirect extends React$Component {
props: {
to: string | LocationShape,
push?: boolean,
},
}
declare module 'react-router-dom/Redirect' {
declare export default typeof RouterRedirect
}
42 changes: 42 additions & 0 deletions flow-typed/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
declare type RouterTo = string | LocationShape | URL;

declare type Match = {
params: Params,
isExact: boolean,
path: string,
url: string,
};

declare type MatchedRoute = { route: PlatformRoute, match: Match };
declare type MatchPathOptions = {
path: string,
exact?: boolean,
strict?: boolean,
};

declare module 'react-router-dom/matchPath' {
declare function matchPath(
pathname: string,
options: MatchPathOptions
): null | Match;
declare module.exports: typeof matchPath;
}

declare type LocationShape = {
pathname?: string,
search?: string,
hash?: string,
state?: any,
};

declare class RouterRedirect extends React$Component {
props: {
to: string | LocationShape,
push?: boolean,
},
}
declare module 'react-router-dom/Redirect' {
declare export default typeof RouterRedirect
}

declare type LocationAction = { type: string, payload: LocationShape };
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
actions as clickActionCreators,
reducer as clickTracking,
DEFAULT_CLICK_TRACK,
} from '../plugins/tracking/util/clickState';
} from './clickState';

describe('clickTracking reducer', () => {
it('appends a click action to state.clicks', () => {
Expand Down
1 change: 0 additions & 1 deletion src/router/Redirect.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import withSideEffect from 'react-side-effect';
import RouterRedirect from 'react-router-dom/Redirect';
import Route from 'react-router-dom/Route';
import { testForExternal } from './util';
import type { RouterTo } from './util/types';

type RedirectProps = {
to: RouterTo,
Expand Down
1 change: 1 addition & 0 deletions src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export {
SERVER_RENDER,
locationChange,
} from './routeActionCreators';
export { default as routing } from './reducer';
18 changes: 18 additions & 0 deletions src/router/reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// @flow
import { LOCATION_CHANGE, SERVER_RENDER } from './routeActionCreators';
/*
* Store routing state to allow middleware to record more accurate
* tracking info
*/
export default function routing(
state: { location?: LocationShape, referrer?: LocationShape | {} } = {},
action: LocationAction
) {
if (action.type === LOCATION_CHANGE || action.type === SERVER_RENDER) {
return {
referrer: state.location || {},
location: action.payload,
};
}
return state;
}
3 changes: 2 additions & 1 deletion src/router/routeActionCreators.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// @flow
export const LOCATION_CHANGE = '@@router/LOCATION_CHANGE';
export const SERVER_RENDER = '@@router/INITIAL_RENDER';

export function locationChange(location) {
export function locationChange(location: LocationShape): LocationAction {
return {
type: LOCATION_CHANGE,
payload: location,
Expand Down
1 change: 0 additions & 1 deletion src/router/util/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// @flow
import type { RouterTo } from './types';
export * from './resolve';
export { decodeParams, getMatchedQueries } from './query';

Expand Down
2 changes: 0 additions & 2 deletions src/router/util/types.js

This file was deleted.

18 changes: 2 additions & 16 deletions src/reducers/platform.js → src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { combineReducers } from 'redux';
import { api, app, API_RESP_COMPLETE } from '../api-state'; // mwp-api-state
import { LOCATION_CHANGE, SERVER_RENDER } from '../router'; // mwp-router
import { routing } from '../router'; // mwp-router
import { reducer as clickTracking } from '../plugins/tracking/util/clickState'; // mwp-tracking/util/clickState

export function config(state = {}, action) {
Expand All @@ -28,21 +28,7 @@ export function preRenderChecklist([apiDataLoaded] = [false], action) {
return [apiDataLoaded || action.type === API_RESP_COMPLETE];
}

/*
* Store routing state to allow middleware to record more accurate
* tracking info
*/
export function routing(state = {}, action) {
if (action.type === LOCATION_CHANGE || action.type === SERVER_RENDER) {
return {
referrer: state.location || {},
location: action.payload,
};
}
return state;
}

const platformReducers = {
export const platformReducers = {
api,
app,
clickTracking,
Expand Down
40 changes: 40 additions & 0 deletions src/store/reducer.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as redux from 'redux';
import makeRootReducer, { platformReducers } from './reducer';
/**
* A function that builds a reducer combining platform-standard reducers and
* app-specific reducers
export default function makeRootReducer(appReducers = {}) {
Object.keys(appReducers).forEach(reducer => {
if (reducer in platformReducers) {
throw new Error(`'${reducer}' is a reserved platform reducer name`);
}
});
return combineReducers({
...platformReducers,
...appReducers,
});
}
*/
redux.combineReducers = jest.fn();

describe('makeRootReducer', () => {
it('calls combineReducers with platform reducers + supplied reducers', () => {
redux.combineReducers.mockClear();
const foo = () => {};
const appReducers = { foo };
makeRootReducer(appReducers);
expect(redux.combineReducers).toHaveBeenCalled();
const calledWith = redux.combineReducers.mock.calls[0][0];
expect(calledWith).toMatchObject(platformReducers); // all platform reducers
expect(calledWith).toMatchObject(appReducers); // additional app reducer
});

it('throws error when attempting to overwrite a platform reducer', () => {
const invalidReducerKey = Object.keys(platformReducers)[0];
expect(() =>
makeRootReducer({
[invalidReducerKey]: platformReducers[invalidReducerKey],
})
).toThrow();
});
});
2 changes: 1 addition & 1 deletion tests/mockApp.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import Helmet from 'react-helmet';
import makeRootReducer from '../src/reducers/platform';
import makeRootReducer from '../src/store/reducer';
import { Redirect } from '../src/router';

export const clientFilename = 'client.whatever.js';
Expand Down