Skip to content

Commit 2cf5b55

Browse files
committed
Use react reducer for AggregatorSetter
1 parent 815b5a6 commit 2cf5b55

File tree

2 files changed

+101
-63
lines changed

2 files changed

+101
-63
lines changed

mithril-explorer/components/AggregatorSetter/index.js

Lines changed: 21 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,56 @@
1-
import React, { useEffect, useState } from 'react';
1+
import React, {useEffect, useReducer, useState} from 'react';
22
import { Button, Col, Form, InputGroup, OverlayTrigger, Tooltip } from "react-bootstrap";
33
import AddAggregatorModal from "./AddAggregatorModal";
4+
import { initAggregatorList, aggregatorListReducer } from "./reducer";
45

56
export default function AggregatorSetter(props) {
6-
const CUSTOM_AGGREGATORS_KEY = "CUSTOM_AGGREGATORS";
7-
const [availableAggregators, setAvailableAggregators] = useState([]);
87
const [showAddModal, toggleAddModal] = useState(false);
9-
const [canRemoveSelected, setCanRemoveSelected] = useState(false);
10-
11-
useEffect(() => {
12-
setAvailableAggregators(getAggregatorsList());
13-
}, [props.defaultAvailableAggregators]);
14-
8+
const [state, dispatch] =
9+
useReducer(
10+
aggregatorListReducer,
11+
[props.aggregator, props.defaultAvailableAggregators],
12+
initAggregatorList);
13+
1514
useEffect(() => {
16-
setCanRemoveSelected(!props.defaultAvailableAggregators.includes(props.aggregator));
17-
18-
let aggregators = getAggregatorsList();
19-
if (!aggregators.includes(props.aggregator)) {
20-
aggregators.push(props.aggregator);
21-
saveCustomAggregatorSources(aggregators);
22-
setAvailableAggregators(aggregators);
23-
}
24-
}, [props.aggregator]);
25-
26-
function getAggregatorsList() {
27-
let aggregators = [...props.defaultAvailableAggregators];
28-
29-
const storedAggregators = JSON.parse(localStorage.getItem(CUSTOM_AGGREGATORS_KEY));
30-
if (storedAggregators) {
31-
aggregators = aggregators.concat(storedAggregators);
32-
}
33-
34-
return aggregators;
35-
}
36-
37-
function handleChange(aggregator) {
15+
const aggregator = props.aggregator;
16+
dispatch({type: 'addAggregator', aggregator: aggregator});
3817
props.onAggregatorChange(aggregator);
39-
}
18+
}, [props.aggregator]);
4019

4120
function copySelected() {
4221
if (window.isSecureContext && props.aggregator) {
4322
navigator.clipboard.writeText(props.aggregator).then(() => { });
4423
}
4524
}
4625

47-
function showAddAggregatorSourceModal() {
48-
toggleAddModal(true);
49-
}
50-
51-
function hideAddAggregatorSourceModal() {
52-
toggleAddModal(false);
26+
function handleChange(aggregator) {
27+
dispatch({type: 'aggregatorSelected', aggregator: aggregator});
28+
props.onAggregatorChange(aggregator);
5329
}
5430

5531
function addAggregatorSource(aggregator) {
56-
if (availableAggregators.includes(aggregator)) {
57-
return;
58-
}
59-
60-
const aggregators = [...availableAggregators, aggregator];
61-
setAvailableAggregators(aggregators);
62-
handleChange(aggregator);
63-
saveCustomAggregatorSources(aggregators);
32+
props.onAggregatorChange(aggregator);
6433
}
6534

6635
function deleteSelectedAggregatorSource() {
67-
if (!canRemoveSelected) {
68-
return;
69-
}
70-
71-
const aggregators = availableAggregators.filter(a => a !== props.aggregator);
72-
setAvailableAggregators(aggregators);
73-
handleChange(availableAggregators.at(0));
74-
saveCustomAggregatorSources(aggregators);
75-
}
76-
77-
function saveCustomAggregatorSources(aggregators) {
78-
const customAggregators = aggregators.filter(a => !props.defaultAvailableAggregators.includes(a));
79-
localStorage.setItem(CUSTOM_AGGREGATORS_KEY, JSON.stringify(customAggregators));
36+
dispatch({type: 'deleteSelected', aggregator: props.aggregator});
37+
props.onAggregatorChange(state.availableAggregators.at(0));
8038
}
8139

8240
return (
8341
<>
8442
<AddAggregatorModal
8543
show={showAddModal}
8644
onAdd={addAggregatorSource}
87-
onAskClose={hideAddAggregatorSourceModal} />
45+
onAskClose={() => toggleAddModal(false)} />
8846

8947
<Form.Group as={Col} className={props.className}>
9048
<Form.Label>Aggregator:</Form.Label>
9149
<InputGroup>
92-
<Button variant="outline-success" onClick={showAddAggregatorSourceModal}>
50+
<Button variant="outline-success" onClick={() => toggleAddModal(true)}>
9351
<i className="bi bi-plus-circle"></i>
9452
</Button>
95-
{canRemoveSelected &&
53+
{state.canRemoveSelected &&
9654
<>
9755
<Button variant="outline-danger" onClick={deleteSelectedAggregatorSource}>
9856
<i className="bi bi-dash-circle"></i>
@@ -105,7 +63,7 @@ export default function AggregatorSetter(props) {
10563
</>
10664
}
10765
<Form.Select value={props.aggregator} onChange={e => handleChange(e.target.value)}>
108-
{availableAggregators.map((aggregator, index) =>
66+
{state.availableAggregators.map((aggregator, index) =>
10967
<option key={"agg-" + index} value={aggregator}>{aggregator}</option>
11068
)}
11169
</Form.Select>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
const CUSTOM_AGGREGATORS_KEY = "CUSTOM_AGGREGATORS";
2+
3+
function init(args) {
4+
const selected = args[0];
5+
const defaultAvailableAggregators = args[1] ?? []
6+
let aggregators = [...defaultAvailableAggregators];
7+
8+
if (typeof window !== 'undefined' && localStorage) {
9+
const storedAggregators = JSON.parse(localStorage.getItem(CUSTOM_AGGREGATORS_KEY));
10+
11+
if (storedAggregators) {
12+
aggregators = aggregators.concat(storedAggregators);
13+
}
14+
}
15+
16+
if (!aggregators.includes(selected)) {
17+
aggregators.push(selected);
18+
saveCustomAggregatorSources(aggregators, defaultAvailableAggregators);
19+
}
20+
21+
return {
22+
availableAggregators: aggregators,
23+
defaultAvailableAggregators: defaultAvailableAggregators,
24+
canRemoveSelected: canRemoveSelected(selected, defaultAvailableAggregators),
25+
};
26+
}
27+
28+
function canRemoveSelected(aggregator, defaultAvailableAggregators) {
29+
return !defaultAvailableAggregators.includes(aggregator);
30+
}
31+
32+
function saveCustomAggregatorSources(aggregators, defaultAvailableAggregators) {
33+
if (typeof window !== 'undefined' && localStorage) {
34+
const customAggregators = aggregators.filter(a => !defaultAvailableAggregators.includes(a));
35+
localStorage.setItem(CUSTOM_AGGREGATORS_KEY, JSON.stringify(customAggregators));
36+
}
37+
}
38+
39+
function reducer(state, action) {
40+
switch (action.type) {
41+
case 'aggregatorSelected':
42+
return {
43+
...state,
44+
canRemoveSelected: canRemoveSelected(action.aggregator, state.defaultAvailableAggregators),
45+
};
46+
case 'addAggregator': {
47+
if (state.availableAggregators.includes(action.aggregator)) {
48+
return state;
49+
}
50+
51+
const availableAggregators = [...state.availableAggregators, action.aggregator];
52+
saveCustomAggregatorSources(availableAggregators, state.defaultAvailableAggregators);
53+
return {
54+
...state,
55+
availableAggregators: availableAggregators,
56+
canRemoveSelected: true
57+
};
58+
}
59+
case 'deleteSelected': {
60+
if (!canRemoveSelected(action.aggregator, state.defaultAvailableAggregators)) {
61+
return state;
62+
}
63+
64+
const availableAggregators = state.availableAggregators.filter(a => a !== action.aggregator);
65+
saveCustomAggregatorSources(availableAggregators, state.defaultAvailableAggregators);
66+
return {
67+
...state,
68+
availableAggregators: availableAggregators,
69+
canRemoveSelected: canRemoveSelected(availableAggregators.at(0), state.defaultAvailableAggregators),
70+
};
71+
}
72+
default:
73+
throw new Error("Unknown action");
74+
}
75+
}
76+
77+
module.exports = {
78+
aggregatorListReducer: reducer,
79+
initAggregatorList: init
80+
}

0 commit comments

Comments
 (0)