Skip to content

Commit b2c52b2

Browse files
committed
multiple tabs implemented
1 parent 2e18ae9 commit b2c52b2

File tree

10 files changed

+148
-95
lines changed

10 files changed

+148
-95
lines changed

src/app/actions/actions.js

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,14 @@ export const toggleMode = mode => ({
55
payload: mode,
66
});
77

8-
export const addNewSnapshots = snapshots => ({
8+
export const addNewSnapshots = tabsObj => ({
99
type: types.NEW_SNAPSHOTS,
10-
payload: {
11-
snapshots,
12-
sliderIndex: snapshots.length - 1,
13-
},
10+
payload: tabsObj,
1411
});
1512

16-
export const initialConnect = (snapshots, mode) => ({
13+
export const initialConnect = tabsObj => ({
1714
type: types.INITIAL_CONNECT,
18-
payload: {
19-
snapshots,
20-
mode,
21-
sliderIndex: 0,
22-
viewIndex: -1,
23-
},
15+
payload: tabsObj,
2416
});
2517

2618
export const setPort = port => ({
@@ -70,3 +62,8 @@ export const importSnapshots = newSnaps => ({
7062
type: types.IMPORT,
7163
payload: newSnaps,
7264
});
65+
66+
export const setTab = tab => ({
67+
type: types.SET_TAB,
68+
payload: tab,
69+
});

src/app/components/App.jsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,8 @@ import mainReducer from '../reducers/mainReducer';
55

66
const initialState = {
77
port: null,
8-
sliderIndex: 0,
9-
viewIndex: -1,
10-
intervalId: null,
11-
playing: false,
12-
snapshots: [],
13-
mode: {
14-
locked: false,
15-
paused: false,
16-
persist: false,
17-
},
8+
currentTab: null,
9+
tabs: {},
1810
};
1911

2012
function App() {

src/app/components/MainSlider.jsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Tooltip from 'rc-tooltip';
66
import PropTypes from 'prop-types';
77

88
import { changeSlider, pause } from '../actions/actions';
9+
import { useStoreContext } from '../store';
910

1011
const { Handle } = Slider;
1112

@@ -27,7 +28,10 @@ const handle = (props) => {
2728
);
2829
};
2930

30-
function MainSlider({ snapshotsLength, sliderIndex, dispatch }) {
31+
function MainSlider({ snapshotsLength }) {
32+
const [{ tabs, currentTab }, dispatch] = useStoreContext();
33+
const { sliderIndex } = tabs[currentTab];
34+
3135
return (
3236
<Slider
3337
min={0}
@@ -45,8 +49,6 @@ function MainSlider({ snapshotsLength, sliderIndex, dispatch }) {
4549

4650
MainSlider.propTypes = {
4751
snapshotsLength: PropTypes.number.isRequired,
48-
sliderIndex: PropTypes.number.isRequired,
49-
dispatch: PropTypes.func.isRequired,
5052
};
5153

5254
export default MainSlider;

src/app/constants/actionTypes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ export const PAUSE = 'PAUSE';
1010
export const PLAY = 'PLAY';
1111
export const INITIAL_CONNECT = 'INITIAL_CONNECT';
1212
export const NEW_SNAPSHOTS = 'NEW_SNAPSHOTS';
13+
export const SET_TAB = 'SET_TAB';

src/app/containers/ActionContainer.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import { emptySnapshots } from '../actions/actions';
66
import { useStoreContext } from '../store';
77

88
function ActionContainer() {
9-
const [{ snapshots, sliderIndex, viewIndex }, dispatch] = useStoreContext();
9+
const [{ tabs, currentTab }, dispatch] = useStoreContext();
10+
const { snapshots, sliderIndex, viewIndex } = tabs[currentTab];
11+
// const [{ snapshots, sliderIndex, viewIndex }, dispatch] = useStoreContext();
1012
let actionsArr = [];
1113
// build actions array
1214
if (snapshots.length > 0) {

src/app/containers/ButtonsContainer.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ function importHandler(dispatch) {
3636
}
3737

3838
function ButtonsContainer() {
39-
const [{ snapshots, mode: { paused, locked, persist } }, dispatch] = useStoreContext();
39+
const [{ tabs, currentTab }, dispatch] = useStoreContext();
40+
const { snapshots, mode: { paused, locked, persist } } = tabs[currentTab];
41+
// const [{ snapshots, mode: { paused, locked, persist } }, dispatch] = useStoreContext();
4042
return (
4143
<div className="buttons-container">
4244
<button className="pause-button" type="button" onClick={() => dispatch(toggleMode('paused'))}>

src/app/containers/MainContainer.jsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,21 @@ import StateContainer from './StateContainer';
55
import TravelContainer from './TravelContainer';
66
import ButtonsContainer from './ButtonsContainer';
77

8-
import { addNewSnapshots, initialConnect, setPort } from '../actions/actions';
8+
import {
9+
addNewSnapshots, initialConnect, setPort,
10+
} from '../actions/actions';
911
import { useStoreContext } from '../store';
1012

13+
let npmPackageExists = false;
1114

1215
function MainContainer() {
13-
const [mainState, dispatch] = useStoreContext();
16+
const [store, dispatch] = useStoreContext();
17+
const { tabs, currentTab, port: currentPort } = store;
1418

19+
// add event listeners to background script
1520
useEffect(() => {
16-
if (mainState.port) return;
21+
// only open port once
22+
if (currentPort) return;
1723
// open connection with background script
1824
const port = chrome.runtime.connect();
1925

@@ -27,8 +33,8 @@ function MainContainer() {
2733
break;
2834
}
2935
case 'initialConnectSnapshots': {
30-
const { snapshots, mode } = payload;
31-
dispatch(initialConnect(snapshots, mode));
36+
npmPackageExists = true;
37+
dispatch(initialConnect(payload));
3238
break;
3339
}
3440
default:
@@ -41,15 +47,12 @@ function MainContainer() {
4147
});
4248

4349
// assign port to state so it could be used by other components
44-
// this.setState({ port });
4550
dispatch(setPort(port));
4651
});
4752

48-
const {
49-
snapshots,
50-
sliderIndex,
51-
viewIndex,
52-
} = mainState;
53+
if (!npmPackageExists) return <div style={{ color: 'black' }}>please install our npm package in your app</div>;
54+
55+
const { viewIndex, sliderIndex, snapshots } = tabs[currentTab];
5356

5457
// if viewIndex is -1, then use the sliderIndex instead
5558
const snapshotView = (viewIndex === -1) ? snapshots[sliderIndex] : snapshots[viewIndex];

src/app/containers/TravelContainer.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ function play(speed, playing, dispatch, snapshotsLength, sliderIndex) {
3333

3434
function TravelContainer({ snapshotsLength }) {
3535
const [selectedSpeed, setSpeed] = useState(speeds[1]);
36-
const [{ sliderIndex, playing }, dispatch] = useStoreContext();
36+
const [{ tabs, currentTab }, dispatch] = useStoreContext();
37+
const { sliderIndex, playing } = tabs[currentTab];
38+
// const [{ sliderIndex, playing }, dispatch] = useStoreContext();
3739

3840
return (
3941
<div className="travel-container">

src/app/reducers/mainReducer.js

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,71 +2,86 @@ import * as types from '../constants/actionTypes';
22

33
export default function mainReducer(state, action) {
44
const {
5-
sliderIndex, snapshots, viewIndex, port, mode, intervalId,
5+
port, currentTab, tabs,
66
} = state;
7+
const {
8+
snapshots, mode, intervalId, viewIndex, sliderIndex,
9+
} = (tabs[currentTab] || {});
10+
711
switch (action.type) {
812
case types.MOVE_BACKWARD: {
913
if (snapshots.length > 0 && sliderIndex > 0) {
1014
const newIndex = sliderIndex - 1;
11-
clearInterval(intervalId);
15+
1216
port.postMessage({ action: 'jumpToSnap', payload: snapshots[newIndex] });
17+
clearInterval(intervalId);
18+
19+
tabs[currentTab].sliderIndex = newIndex;
20+
tabs[currentTab].playing = false;
21+
1322
return {
1423
...state,
15-
sliderIndex: newIndex,
16-
playing: false,
24+
tabs,
1725
};
1826
}
1927
return state;
2028
}
2129
case types.MOVE_FORWARD: {
2230
if (sliderIndex < snapshots.length - 1) {
2331
const newIndex = sliderIndex + 1;
32+
2433
port.postMessage({ action: 'jumpToSnap', payload: snapshots[newIndex] });
2534

26-
// if payload is true, then message is coming from the setInterval
35+
tabs[currentTab].sliderIndex = newIndex;
36+
37+
// message is coming from the user
2738
if (!action.payload) {
2839
clearInterval(intervalId);
29-
return {
30-
...state,
31-
sliderIndex: newIndex,
32-
playing: false,
33-
};
40+
tabs[currentTab].playing = false;
3441
}
42+
// message is coming from the setInterval
3543
return {
3644
...state,
37-
sliderIndex: newIndex,
45+
tabs,
3846
};
3947
}
4048
return state;
4149
}
4250
case types.CHANGE_VIEW: {
4351
// unselect view if same index was selected
44-
if (viewIndex === action.payload) return { ...state, viewIndex: -1 };
45-
return { ...state, viewIndex: action.payload };
52+
if (viewIndex === action.payload) tabs[currentTab].viewIndex = -1;
53+
else tabs[currentTab].viewIndex = action.payload;
54+
55+
return {
56+
...state,
57+
tabs,
58+
};
4659
}
4760
case types.CHANGE_SLIDER: {
4861
port.postMessage({ action: 'jumpToSnap', payload: snapshots[action.payload] });
49-
return { ...state, sliderIndex: action.payload };
62+
tabs[currentTab].sliderIndex = action.payload;
63+
return { ...state, tabs };
5064
}
5165
case types.EMPTY: {
52-
port.postMessage({ action: 'emptySnap' });
66+
port.postMessage({ action: 'emptySnap', tabd: currentTab });
67+
tabs[currentTab].sliderIndex = 0;
68+
tabs[currentTab].viewIndex = -1;
69+
tabs[currentTab].playing = false;
70+
tabs[currentTab].snapshots = [];
5371
return {
54-
sliderIndex: 0,
55-
viewIndex: -1,
56-
playing: false,
57-
snapshots: [],
72+
...state,
73+
tabs,
5874
};
5975
}
6076
case types.SET_PORT: {
6177
return { ...state, port: action.payload };
6278
}
6379
case types.IMPORT: {
6480
port.postMessage({ action: 'import', payload: action.payload });
81+
tabs[currentTab].snapshots = action.payload;
6582
return {
6683
...state,
67-
snapshots: action.payload,
68-
sliderIndex: 0,
69-
viewIndex: -1,
84+
tabs,
7085
};
7186
}
7287
case types.TOGGLE_MODE: {
@@ -86,35 +101,63 @@ export default function mainReducer(state, action) {
86101
default:
87102
}
88103
port.postMessage({ action: actionText, payload: newMode });
89-
return { ...state, mode };
104+
return { ...state, tabs };
90105
}
91106
case types.PAUSE: {
92107
clearInterval(intervalId);
93-
return { ...state, playing: false, intervalId: null };
108+
tabs[currentTab].playing = false;
109+
tabs[currentTab].intervalId = null;
110+
return { ...state, tabs };
94111
}
95112
case types.PLAY: {
113+
tabs[currentTab].playing = true;
114+
tabs[currentTab].intervalId = action.payload;
96115
return {
97116
...state,
98-
playing: true,
99-
intervalId: action.payload,
117+
tabs,
100118
};
101119
}
102120
case types.INITIAL_CONNECT: {
103121
const { payload } = action;
122+
Object.keys(payload).forEach((tab) => {
123+
payload[tab] = {
124+
...payload[tab],
125+
sliderIndex: 0,
126+
viewIndex: -1,
127+
intervalId: null,
128+
playing: false,
129+
};
130+
});
131+
132+
// only set first tab if current tab is non existent
133+
const firstTab = Object.keys(payload)[0];
104134
return {
105135
...state,
106-
snapshots: payload.snapshots,
107-
mode: payload.mode,
108-
viewIndex: payload.viewIndex,
109-
sliderIndex: payload.sliderIndex,
136+
currentTab: (currentTab === null) ? firstTab : currentTab,
137+
tabs: payload,
110138
};
111139
}
112140
case types.NEW_SNAPSHOTS: {
113141
const { payload } = action;
142+
143+
Object.keys(payload).forEach((tab) => {
144+
const { snapshots: newSnaps } = payload[tab];
145+
payload[tab] = {
146+
...tabs[tab],
147+
...payload[tab],
148+
sliderIndex: newSnaps.length - 1,
149+
};
150+
});
151+
152+
return {
153+
...state,
154+
tabs: payload,
155+
};
156+
}
157+
case types.SET_TAB: {
114158
return {
115159
...state,
116-
snapshots: payload.snapshots,
117-
sliderIndex: payload.sliderIndex,
160+
currentTab: action.payload,
118161
};
119162
}
120163
default:

0 commit comments

Comments
 (0)