Skip to content

Commit 132b339

Browse files
committed
Setup redux structure
* setup redux utils, devtools, folder structure * data model is normalized via ids and jsons * promise middleware to handle api requests * ready to test with react redux hooks * schema to create associations between data sets * reselect to organize complex selectors
1 parent 822a794 commit 132b339

File tree

20 files changed

+281
-74
lines changed

20 files changed

+281
-74
lines changed

package-lock.json

Lines changed: 102 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"formik": "^1.5.4",
1818
"i": "^0.3.6",
1919
"lodash": "^4.17.11",
20+
"normalizr": "^3.4.1",
2021
"prop-types": "^15.7.2",
2122
"react": "^16.8.2",
2223
"react-avatar": "^3.5.0",
@@ -26,13 +27,18 @@
2627
"react-icons-kit": "^1.2.1",
2728
"react-messenger-customer-chat": "^0.7.2",
2829
"react-modal": "^3.8.1",
29-
"react-redux": "^6.0.0",
30+
"react-redux": "^7.1.0",
3031
"react-router-dom": "^4.3.1",
3132
"react-scripts": "^2.1.5",
3233
"react-select": "^2.4.3",
3334
"react-share": "^2.4.0",
3435
"react-sortable-hoc": "^1.8.3",
3536
"reactstrap": "^6.5.0",
37+
"redux": "^4.0.4",
38+
"redux-actions": "^2.6.5",
39+
"redux-devtools-extension": "^2.13.8",
40+
"redux-promise-middleware": "^6.1.1",
41+
"reselect": "^4.0.0",
3642
"styled-components": "^4.3.2",
3743
"styled-theming": "^2.2.0",
3844
"uuid": "^3.3.2",

src/components/app/actions/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './project';
2+
export * from './tag';

src/components/app/actions/project.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { normalize } from 'normalizr';
2+
import { createAction } from 'redux-actions';
3+
import { schema } from '../../../utils';
4+
import { db, Project } from '../../../firebase';
5+
6+
export const createProject = createAction('CREATE_PROJECT', async (values) => {
7+
const response = await Project.create(values);
8+
return response;
9+
});
10+
11+
export const getProjects = createAction('GET_PROJECTS', async () => {
12+
const response = await db.getAll('projects');
13+
return normalize(response, [ schema.project ]);
14+
});

src/components/app/actions/tag.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { normalize } from 'normalizr';
2+
import { createAction } from 'redux-actions';
3+
4+
import { schema } from '../../../utils';
5+
import { db } from '../../../firebase';
6+
7+
export const getTags = createAction('GET_TAGS', async () => {
8+
const response = await db.getAll('tags');
9+
return normalize(response, [ schema.tag ]);
10+
});

src/components/app/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1+
import * as actions from './actions';
2+
3+
export { actions };
4+
export { default as getRootReducer } from './reducers';
15
export { default } from './App';

src/components/app/reducers/index.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { combineReducers } from 'redux';
2+
3+
import projects from './project';
4+
import tags from './tag';
5+
6+
export default () => {
7+
const data = combineReducers({
8+
projects,
9+
tags,
10+
});
11+
12+
const appReducer = combineReducers({
13+
data,
14+
});
15+
16+
const rootReducer = (state, action) => appReducer(state, action);
17+
return rootReducer;
18+
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { handleActions } from 'redux-actions';
2+
3+
import { createProject, getProjects } from '../actions';
4+
5+
const reducer = handleActions(
6+
{
7+
[createProject]: {
8+
FULFILLED: (state, { payload }) => {
9+
const id = payload.result;
10+
const values = payload.entities.projects[id];
11+
return {
12+
...state,
13+
[id]: { ...state[id], ...values },
14+
};
15+
},
16+
},
17+
[getProjects]: {
18+
FULFILLED: (state, { payload }) => ({
19+
...state,
20+
...payload.entities.projects,
21+
}),
22+
},
23+
},
24+
{},
25+
);
26+
27+
export default reducer;

src/components/app/reducers/tag.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { handleActions } from 'redux-actions';
2+
3+
import { getTags } from '../actions';
4+
5+
const reducer = handleActions(
6+
{
7+
[getTags]: {
8+
FULFILLED: (state, { payload }) => ({
9+
...state,
10+
...payload.entities.tags,
11+
}),
12+
},
13+
},
14+
{},
15+
);
16+
17+
export default reducer;

src/components/app/selectors.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { orderBy, isNil } from 'lodash';
2+
import { createSelector } from 'reselect';
3+
4+
const getTags = state => state.data.tags;
5+
6+
const getProjects = state => orderBy(state.data.projects, [ 'title' ], [ 'asc' ]);
7+
8+
export default createSelector(
9+
[ getTags, getProjects ],
10+
(tags, projects) =>
11+
projects.map(project =>
12+
(!isNil(project.tags)
13+
? { ...project, tags: project.tags.map(id => tags[id]) }
14+
: { ...project, tags: [] })),
15+
);

src/components/explore-projects/ExploreProjects.jsx

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import React, { useState, useEffect } from 'react';
1+
import React, { useState } from 'react';
22
import styled from 'styled-components';
33

4-
import { db } from '../../firebase';
5-
64
import Filter from '../shared/filter';
75
import ProjectList from './components/project-list';
6+
import useProjects from '../../hooks/use-projects';
87

98
const Header = styled.h2`
109
margin-bottom: 20px;
@@ -14,16 +13,7 @@ const filterTypes = [ 'project-category', 'release-status', 'organization' ];
1413

1514
const ExploreProjects = () => {
1615
const [ appliedTags, setAppliedTags ] = useState([]);
17-
const [ projects, setProjects ] = useState([]);
18-
19-
useEffect(() => {
20-
const init = async () => {
21-
const _projects = await db.getAll('projects');
22-
setProjects(_projects);
23-
};
24-
25-
init();
26-
}, []);
16+
const projects = useProjects();
2717

2818
const handleFilter = (tag) => {
2919
const index = appliedTags.findIndex(_tag => _tag === tag.id);

0 commit comments

Comments
 (0)