Skip to content

Commit 07b2b77

Browse files
authored
Merge pull request #394 from Zuehlke/feat/move-to-hooks
refactor: use hooks instead of hoc
2 parents 669353c + e691e55 commit 07b2b77

32 files changed

+566
-715
lines changed

client/src/components/ActionLog/ActionLog.jsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, {useContext} from 'react';
2-
import {connect} from 'react-redux';
2+
import {useSelector} from 'react-redux';
33
import PropTypes from 'prop-types';
44

55
import {SIDEBAR_ACTIONLOG} from '../../state/actions/uiStateActions';
@@ -17,8 +17,11 @@ import {
1717
/**
1818
* The ActionLog displays a chronological list of "actions" (backend events)
1919
*/
20-
const ActionLog = ({actionLog, shown}) => {
20+
const ActionLog = () => {
2121
const {t} = useContext(L10nContext);
22+
const shown = useSelector(state => getCurrentSidebarIfAny(state) === SIDEBAR_ACTIONLOG);
23+
const actionLog = useSelector(getActionLog);
24+
2225
return (
2326
<StyledActionLog $shown={shown}>
2427
<h4>{t('log')}</h4>
@@ -42,7 +45,4 @@ ActionLog.propTypes = {
4245
actionLog: PropTypes.array
4346
};
4447

45-
export default connect((state) => ({
46-
shown: getCurrentSidebarIfAny(state) === SIDEBAR_ACTIONLOG,
47-
actionLog: getActionLog(state)
48-
}))(ActionLog);
48+
export default ActionLog;

client/src/components/Backlog/Backlog.jsx

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React, {useState, useEffect, useContext} from 'react';
2-
import {connect} from 'react-redux';
3-
import PropTypes from 'prop-types';
2+
import {useSelector, useDispatch} from 'react-redux';
43
import {useDrag} from 'react-dnd';
54
import {getEmptyImage} from 'react-dnd-html5-backend';
65

@@ -23,27 +22,30 @@ import {StyledBacklog, StyledBacklogWidthDragHandle} from './_styled';
2322
* if trash is active, only a list of "trashed" stories is displayed
2423
*
2524
*/
26-
const Backlog = ({
27-
backlogShown,
28-
backlogWidth,
29-
setBacklogWidth,
30-
trashedStoriesCount,
31-
activeStoriesCount
32-
}) => {
25+
const Backlog = () => {
3326
const {t} = useContext(L10nContext);
27+
const dispatch = useDispatch();
28+
29+
const backlogShown = useSelector(isBacklogShown);
30+
const backlogWidth = useSelector(getBacklogWidth);
31+
const trashedStoriesCount = useSelector(state => getTrashedStories(state).length);
32+
const activeStoriesCount = useSelector(state => getActiveStories(state).length);
33+
3434
const [showTrash, setShowTrash] = useState(false);
3535

36+
const handleSetBacklogWidth = (width) => dispatch(setBacklogWidth(width));
37+
3638
// There is no corresponding drop / useDrop.
3739
// We just need the dragging functionality, and set the new width of the backlog on "end(...)"
3840
const [, drag, preview] = useDrag(
3941
() => ({
4042
type: DRAG_ITEM_TYPES.backlogWidthHandle,
4143
end: (item, monitor) => {
4244
const {x} = monitor.getSourceClientOffset();
43-
setBacklogWidth(Math.max(DEFAULT_BACKLOG_WIDTH, x + 1));
45+
handleSetBacklogWidth(Math.max(DEFAULT_BACKLOG_WIDTH, x + 1));
4446
}
4547
}),
46-
[setBacklogWidth]
48+
[handleSetBacklogWidth]
4749
);
4850

4951
useEffect(() => {
@@ -75,20 +77,4 @@ const Backlog = ({
7577
);
7678
};
7779

78-
Backlog.propTypes = {
79-
backlogShown: PropTypes.bool,
80-
backlogWidth: PropTypes.number,
81-
setBacklogWidth: PropTypes.func.isRequired,
82-
trashedStoriesCount: PropTypes.number.isRequired,
83-
activeStoriesCount: PropTypes.number.isRequired
84-
};
85-
86-
export default connect(
87-
(state) => ({
88-
backlogShown: isBacklogShown(state),
89-
backlogWidth: getBacklogWidth(state),
90-
trashedStoriesCount: getTrashedStories(state).length,
91-
activeStoriesCount: getActiveStories(state).length
92-
}),
93-
{setBacklogWidth}
94-
)(Backlog);
80+
export default Backlog;

client/src/components/Backlog/BacklogActive.jsx

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React, {useCallback, useState, useEffect, useContext} from 'react';
2-
import {connect} from 'react-redux';
3-
import PropTypes from 'prop-types';
2+
import {useSelector, useDispatch} from 'react-redux';
43
import {useDrop} from 'react-dnd';
54

65
import {trashStories, setSortOrder} from '../../state/actions/commandActions';
@@ -88,8 +87,12 @@ const useStoryDnD = (sortedStories, setSortedStories, setSorting, setSortOrder)
8887
/**
8988
* List of active stories. Accepts drops of csv files for importing stories. Provides means to filter and sort active stories.
9089
*/
91-
const BacklogActive = ({activeStories, selectedStoryId, trashStories, setSortOrder}) => {
90+
const BacklogActive = () => {
9291
const {t} = useContext(L10nContext);
92+
const dispatch = useDispatch();
93+
94+
const activeStories = useSelector(getActiveStories);
95+
const selectedStoryId = useSelector(getSelectedStoryId);
9396

9497
const {highlightedStoryId, setHighlightedStoryId} = useHighlightedStory(
9598
selectedStoryId,
@@ -99,13 +102,22 @@ const BacklogActive = ({activeStories, selectedStoryId, trashStories, setSortOrd
99102
const {filterQuery, setFilterQuery, sorting, setSorting, sortedStories, setSortedStories} =
100103
useStorySortingAndFiltering(activeStories);
101104

105+
const handleSetSortOrder = useCallback(
106+
(storyIds) => dispatch(setSortOrder(storyIds)),
107+
[dispatch]
108+
);
109+
102110
const {dndFindStory, dndMoveStory, dndDragEnd, containerDropRef} = useStoryDnD(
103111
sortedStories,
104112
setSortedStories,
105113
setSorting,
106-
setSortOrder
114+
handleSetSortOrder
107115
);
108116

117+
const onTrashAll = () => {
118+
dispatch(trashStories(sortedStories.map((story) => story.id)));
119+
};
120+
109121
return (
110122
<StyledBacklogActive ref={containerDropRef}>
111123
<BacklogFileDropWrapper>
@@ -141,26 +153,6 @@ const BacklogActive = ({activeStories, selectedStoryId, trashStories, setSortOrd
141153
</BacklogFileDropWrapper>
142154
</StyledBacklogActive>
143155
);
144-
145-
/**
146-
* do only trash the currently visible stories (after filtering was applied)
147-
*/
148-
function onTrashAll() {
149-
trashStories(sortedStories.map((story) => story.id));
150-
}
151-
};
152-
153-
BacklogActive.propTypes = {
154-
activeStories: PropTypes.array,
155-
selectedStoryId: PropTypes.string,
156-
trashStories: PropTypes.func.isRequired,
157-
setSortOrder: PropTypes.func.isRequired
158156
};
159157

160-
export default connect(
161-
(state) => ({
162-
activeStories: getActiveStories(state),
163-
selectedStoryId: getSelectedStoryId(state)
164-
}),
165-
{trashStories, setSortOrder}
166-
)(BacklogActive);
158+
export default BacklogActive;

client/src/components/Backlog/BacklogFileDropWrapper.jsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, {useCallback, createContext} from 'react';
2-
import {connect} from 'react-redux';
2+
import {useDispatch} from 'react-redux';
33
import PropTypes from 'prop-types';
44
import {useDropzone} from 'react-dropzone';
55

@@ -25,12 +25,15 @@ export const OpenFileDialogContext = createContext(() => {});
2525
/**
2626
* Handles CSV and JSON file drop & importing
2727
*/
28-
const BacklogFileDropWrapper = ({importCsvFile, children}) => {
28+
const BacklogFileDropWrapper = ({children}) => {
29+
const dispatch = useDispatch();
30+
2931
const onDrop = useCallback((acceptedFiles) => {
3032
if (acceptedFiles?.length > 0) {
31-
importCsvFile(acceptedFiles[0]);
33+
dispatch(importCsvFile(acceptedFiles[0]));
3234
}
33-
}, []);
35+
}, [dispatch]);
36+
3437
const {getRootProps, isDragActive, isDragAccept, isDragReject, open} = useDropzone({
3538
onDrop,
3639
multiple: false,
@@ -52,8 +55,7 @@ const BacklogFileDropWrapper = ({importCsvFile, children}) => {
5255
};
5356

5457
BacklogFileDropWrapper.propTypes = {
55-
importCsvFile: PropTypes.func.isRequired,
5658
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node])
5759
};
5860

59-
export default connect(() => ({}), {importCsvFile})(BacklogFileDropWrapper);
61+
export default BacklogFileDropWrapper;

client/src/components/Backlog/BacklogTrash.jsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React, {useContext} from 'react';
2-
import {connect} from 'react-redux';
3-
import PropTypes from 'prop-types';
2+
import {useSelector} from 'react-redux';
43

54
import TrashedStory from './TrashedStory';
65
import {getTrashedStories} from '../../state/stories/storiesSelectors';
@@ -11,8 +10,9 @@ import {L10nContext} from '../../services/l10n';
1110
/**
1211
* List of trashed stories
1312
*/
14-
const BacklogTrash = ({trashedStories}) => {
13+
const BacklogTrash = () => {
1514
const {t} = useContext(L10nContext);
15+
const trashedStories = useSelector(getTrashedStories);
1616
const hasTrashedStories = trashedStories.length > 0;
1717

1818
return (
@@ -29,10 +29,4 @@ const BacklogTrash = ({trashedStories}) => {
2929
);
3030
};
3131

32-
BacklogTrash.propTypes = {
33-
trashedStories: PropTypes.array
34-
};
35-
36-
export default connect((state) => ({
37-
trashedStories: getTrashedStories(state)
38-
}))(BacklogTrash);
32+
export default BacklogTrash;

client/src/components/Backlog/Story.jsx

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, {useContext} from 'react';
2-
import {connect} from 'react-redux';
2+
import {useSelector, useDispatch} from 'react-redux';
33
import PropTypes from 'prop-types';
44
import {useDrag, useDrop} from 'react-dnd';
55

@@ -29,17 +29,17 @@ const Story = ({
2929
story,
3030
isHighlighted,
3131
onStoryClicked,
32-
selectedStoryId,
33-
selectStory,
34-
editStory,
35-
trashStory,
36-
isWaiting,
37-
isStoryEstimated,
3832
dndDragEnd,
3933
dndMoveStory,
4034
dndFindStory
4135
}) => {
4236
const {t, format} = useContext(L10nContext);
37+
const dispatch = useDispatch();
38+
39+
const selectedStoryId = useSelector(getSelectedStoryId);
40+
const isWaiting = useSelector(state => isThisStoryWaiting(state, story.id));
41+
const isStoryEstimated = useSelector(state => isThisStoryEstimated(state, story.id));
42+
4343
const isSelected = selectedStoryId === story.id;
4444
const hasConsensus = hasStoryConsensus(story);
4545

@@ -70,6 +70,20 @@ const Story = ({
7070
[dndFindStory, dndMoveStory]
7171
);
7272

73+
const triggerSelect = () => {
74+
dispatch(selectStory(story.id));
75+
};
76+
77+
const triggerEdit = (e) => {
78+
e.stopPropagation(); // make sure to stop bubbling up. we do not want to trigger story select
79+
dispatch(editStory(story.id));
80+
};
81+
82+
const triggerTrash = (e) => {
83+
e.stopPropagation(); // make sure to stop bubbling up. we do not want to trigger story select
84+
dispatch(trashStory(story.id));
85+
};
86+
7387
return (
7488
<StyledStory
7589
ref={(node) => drag(drop(node))}
@@ -138,42 +152,15 @@ const Story = ({
138152
}
139153
</StyledStory>
140154
);
141-
142-
function triggerSelect() {
143-
selectStory(story.id);
144-
}
145-
146-
function triggerEdit(e) {
147-
e.stopPropagation(); // make sure to stop bubbling up. we do not want to trigger story select
148-
editStory(story.id);
149-
}
150-
151-
function triggerTrash(e) {
152-
e.stopPropagation(); // make sure to stop bubbling up. we do not want to trigger story select
153-
trashStory(story.id);
154-
}
155155
};
156156

157157
Story.propTypes = {
158158
story: PropTypes.object,
159-
isWaiting: PropTypes.bool,
160159
isHighlighted: PropTypes.bool,
161-
isStoryEstimated: PropTypes.bool,
162-
selectedStoryId: PropTypes.string,
163160
onStoryClicked: PropTypes.func,
164-
selectStory: PropTypes.func,
165-
editStory: PropTypes.func,
166-
trashStory: PropTypes.func,
167161
dndDragEnd: PropTypes.func,
168162
dndMoveStory: PropTypes.func,
169163
dndFindStory: PropTypes.func
170164
};
171165

172-
export default connect(
173-
(state, props) => ({
174-
selectedStoryId: getSelectedStoryId(state),
175-
isWaiting: isThisStoryWaiting(state, props.story.id),
176-
isStoryEstimated: isThisStoryEstimated(state, props.story.id)
177-
}),
178-
{selectStory, editStory, trashStory}
179-
)(Story);
166+
export default Story;

0 commit comments

Comments
 (0)