Skip to content

Commit d0eb54c

Browse files
committed
Refactoring 'current' reducer
1 parent 49d000b commit d0eb54c

File tree

8 files changed

+155
-100
lines changed

8 files changed

+155
-100
lines changed

src/backend/controllers/categories.js renamed to src/backend/controllers/algorithms.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,10 @@ router.route('/:categoryKey/:algorithmKey')
112112
const algorithm = category.algorithms.find(algorithm => algorithm.key === algorithmKey);
113113
if (!algorithm) return next(new NotFoundError());
114114

115-
const titles = [category.name, algorithm.name];
115+
const categoryName = category.name;
116+
const algorithmName = algorithm.name;
116117
const files = algorithm.files.map(({ name, content, contributors }) => ({ name, content, contributors }));
117-
res.json({ algorithm: { titles, files } });
118+
res.json({ algorithm: { categoryKey, categoryName, algorithmKey, algorithmName, files } });
118119
});
119120

120-
export default router;
121+
export default router;

src/backend/controllers/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export { default as auth } from './auth';
2-
export { default as categories } from './categories';
2+
export { default as algorithms } from './algorithms';
33
export { default as tracers } from './tracers';

src/frontend/apis/index.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ const PATCH = URL => {
5656
});
5757
};
5858

59-
const CategoryApi = {
60-
getCategories: GET('/categories'),
61-
getAlgorithm: GET('/categories/:categoryKey/:algorithmKey'),
59+
const AlgorithmApi = {
60+
getCategories: GET('/algorithms'),
61+
getAlgorithm: GET('/algorithms/:categoryKey/:algorithmKey'),
6262
};
6363

6464
const GitHubApi = {
@@ -95,7 +95,7 @@ const TracerApi = {
9595
};
9696

9797
export {
98-
CategoryApi,
98+
AlgorithmApi,
9999
GitHubApi,
100100
TracerApi,
101101
};

src/frontend/common/util.js

+18-2
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,29 @@ const extension = fileName => /(?:\.([^.]+))?$/.exec(fileName)[1];
1010

1111
const refineGist = gist => {
1212
const gistId = gist.id;
13-
const titles = ['Scratch Paper', gist.description];
13+
const title = gist.description;
1414
delete gist.files['algorithm-visualizer'];
1515
const { login, avatar_url } = gist.owner;
1616
const files = Object.values(gist.files).map(file => ({
1717
name: file.filename,
1818
content: file.content,
1919
contributors: [{ login, avatar_url }],
2020
}));
21-
return { gistId, titles, files, gist };
21+
return { gistId, title, files, gist };
22+
};
23+
24+
const getFiles = current => {
25+
const { algorithm, scratchPaper } = current;
26+
if (algorithm) return algorithm.files;
27+
if (scratchPaper) return scratchPaper.files;
28+
return [];
29+
};
30+
31+
const getTitleArray = current => {
32+
const { algorithm, scratchPaper } = current;
33+
if (algorithm) return [algorithm.categoryName, algorithm.algorithmName];
34+
if (scratchPaper) return ['Scratch Paper', scratchPaper.title];
35+
return ['Algorithm Visualizer'];
2236
};
2337

2438
const handleError = function (error) {
@@ -31,5 +45,7 @@ export {
3145
distance,
3246
extension,
3347
refineGist,
48+
getFiles,
49+
getTitleArray,
3450
handleError,
3551
};

src/frontend/components/App/index.jsx

+39-27
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import {
1717
ToastContainer,
1818
VisualizationViewer,
1919
} from '/components';
20-
import { CategoryApi, GitHubApi } from '/apis';
20+
import { AlgorithmApi, GitHubApi } from '/apis';
2121
import { actions } from '/reducers';
22-
import { extension, handleError, refineGist } from '/common/util';
22+
import { extension, getFiles, getTitleArray, handleError, refineGist } from '/common/util';
2323
import { exts, languages, us } from '/common/config';
2424
import { README_MD, SCRATCH_PAPER_MD } from '/skeletons';
2525
import styles from './stylesheet.scss';
@@ -49,7 +49,7 @@ class App extends React.Component {
4949
const accessToken = Cookies.get('access_token');
5050
if (accessToken) this.signIn(accessToken);
5151

52-
CategoryApi.getCategories()
52+
AlgorithmApi.getCategories()
5353
.then(({ categories }) => this.props.setCategories(categories))
5454
.catch(handleError.bind(this));
5555

@@ -65,7 +65,12 @@ class App extends React.Component {
6565

6666
componentWillReceiveProps(nextProps) {
6767
const { params } = nextProps.match;
68-
const { categoryKey, algorithmKey, gistId } = nextProps.current;
68+
const { algorithm, scratchPaper } = nextProps.current;
69+
70+
const categoryKey = algorithm && algorithm.categoryKey;
71+
const algorithmKey = algorithm && algorithm.algorithmKey;
72+
const gistId = scratchPaper && scratchPaper.gistId;
73+
6974
if (params.categoryKey !== categoryKey ||
7075
params.algorithmKey !== algorithmKey ||
7176
params.gistId !== gistId) {
@@ -135,13 +140,14 @@ class App extends React.Component {
135140
const { ext } = this.props.env;
136141
let fetchPromise = null;
137142
if (categoryKey && algorithmKey) {
138-
fetchPromise = CategoryApi.getAlgorithm(categoryKey, algorithmKey)
139-
.then(({ algorithm }) => algorithm);
143+
fetchPromise = AlgorithmApi.getAlgorithm(categoryKey, algorithmKey)
144+
.then(({ algorithm }) => this.props.setAlgorithm(algorithm));
140145
} else if (['new', 'forked'].includes(gistId)) {
141146
gistId = 'new';
142147
const language = languages.find(language => language.ext === ext);
143-
fetchPromise = Promise.resolve({
144-
titles: ['Scratch Paper', 'Untitled'],
148+
fetchPromise = Promise.resolve(this.props.setScratchPaper({
149+
gistId,
150+
title: 'Untitled',
145151
files: [{
146152
name: 'README.md',
147153
content: SCRATCH_PAPER_MD,
@@ -151,24 +157,29 @@ class App extends React.Component {
151157
content: language.skeleton,
152158
contributors: undefined,
153159
}],
154-
});
160+
}));
155161
} else if (gistId) {
156-
fetchPromise = GitHubApi.getGist(gistId, { timestamp: Date.now() }).then(refineGist);
162+
fetchPromise = GitHubApi.getGist(gistId, { timestamp: Date.now() })
163+
.then(refineGist)
164+
.then(this.props.setScratchPaper);
157165
} else {
158166
fetchPromise = Promise.reject(new Error());
159167
}
160168
fetchPromise
161-
.then(algorithm => this.props.setCurrent(categoryKey, algorithmKey, gistId, algorithm.titles, algorithm.files, algorithm.gist))
162169
.catch(error => {
163170
if (error.message) handleError.bind(this)(error);
164-
this.props.setCurrent(undefined, undefined, undefined, ['Algorithm Visualizer'], [{
165-
name: 'README.md',
166-
content: README_MD,
167-
contributors: [us],
168-
}], undefined);
171+
this.props.setAlgorithm({
172+
categoryName: 'Algorithm Visualizer',
173+
algorithmName: 'Home',
174+
files: [{
175+
name: 'README.md',
176+
content: README_MD,
177+
contributors: [us],
178+
}],
179+
});
169180
})
170181
.finally(() => {
171-
const { files } = this.props.current;
182+
const files = getFiles(this.props.current);
172183
let editorTabIndex = files.findIndex(file => extension(file.name) === ext);
173184
if (!~editorTabIndex) editorTabIndex = files.findIndex(file => exts.includes(extension(file.name)));
174185
if (!~editorTabIndex) editorTabIndex = Math.min(0, files.length - 1);
@@ -182,15 +193,15 @@ class App extends React.Component {
182193
}
183194

184195
handleChangeEditorTabIndex(editorTabIndex) {
185-
const { files } = this.props.current;
196+
const files = getFiles(this.props.current);
186197
if (editorTabIndex === files.length) this.handleAddFile();
187198
this.setState({ editorTabIndex });
188199
this.props.shouldBuild();
189200
}
190201

191202
handleAddFile() {
192203
const { ext } = this.props.env;
193-
const { files } = this.props.current;
204+
const files = getFiles(this.props.current);
194205
let name = `code.${ext}`;
195206
let count = 0;
196207
while (files.some(file => file.name === name)) name = `code-${++count}.${ext}`;
@@ -210,7 +221,7 @@ class App extends React.Component {
210221

211222
handleDeleteFile() {
212223
const { editorTabIndex } = this.state;
213-
const { files } = this.props.current;
224+
const files = getFiles(this.props.current);
214225
this.handleChangeEditorTabIndex(Math.min(editorTabIndex, files.length - 2));
215226
this.props.deleteFile(editorTabIndex);
216227
}
@@ -220,15 +231,15 @@ class App extends React.Component {
220231
}
221232

222233
isGistSaved() {
223-
const { titles, files, lastTitles, lastFiles } = this.props.current;
224-
const serializeTitles = titles => JSON.stringify(titles);
234+
const { scratchPaper } = this.props.current;
235+
if (!scratchPaper) return true;
236+
const { title, files, lastTitle, lastFiles } = scratchPaper;
225237
const serializeFiles = files => JSON.stringify(files.map(({ name, content }) => ({ name, content })));
226-
return serializeTitles(titles) === serializeTitles(lastTitles) &&
227-
serializeFiles(files) === serializeFiles(lastFiles);
238+
return title === lastTitle && serializeFiles(files) === serializeFiles(lastFiles);
228239
}
229240

230241
getDescription() {
231-
const { files } = this.props.current;
242+
const files = getFiles(this.props.current);
232243
const readmeFile = files.find(file => file.name === 'README.md');
233244
if (!readmeFile) return '';
234245
const groups = /^\s*# .*\n+([^\n]+)/.exec(readmeFile.content);
@@ -237,7 +248,8 @@ class App extends React.Component {
237248

238249
render() {
239250
const { navigatorOpened, workspaceWeights, editorTabIndex } = this.state;
240-
const { titles, files } = this.props.current;
251+
const files = getFiles(this.props.current);
252+
const titleArray = getTitleArray(this.props.current);
241253

242254
const gistSaved = this.isGistSaved();
243255
const description = this.getDescription();
@@ -257,7 +269,7 @@ class App extends React.Component {
257269
return (
258270
<div className={styles.app}>
259271
<Helmet>
260-
<title>{gistSaved ? '' : '(Unsaved) '}{titles.join(' - ')}</title>
272+
<title>{gistSaved ? '' : '(Unsaved) '}{titleArray.join(' - ')}</title>
261273
<meta name="description" content={description} />
262274
</Helmet>
263275
<Header className={styles.header} onClickTitleBar={() => this.toggleNavigatorOpened()}

src/frontend/components/Header/index.jsx

+16-12
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { actions } from '/reducers';
1919
import { languages } from '/common/config';
2020
import { Button, Ellipsis, ListItem, Player } from '/components';
2121
import styles from './stylesheet.scss';
22+
import { getTitleArray } from '../../common/util';
2223

2324
@connect(({ current, env }) => ({ current, env }), actions)
2425
class Header extends React.Component {
@@ -34,14 +35,15 @@ class Header extends React.Component {
3435

3536
handleChangeTitle(e) {
3637
const { value } = e.target;
37-
this.props.renameScratchPaper(value);
38+
this.props.modifyTitle(value);
3839
}
3940

4041
saveGist() {
4142
const { user } = this.props.env;
42-
const { categoryKey, algorithmKey, gistId, titles, files, lastFiles, lastGist } = this.props.current;
43+
const { scratchPaper } = this.props.current;
44+
const { gistId, title, files, lastFiles, lastGist } = scratchPaper;
4345
const gist = {
44-
description: titles[1],
46+
description: title,
4547
files: {},
4648
};
4749
files.forEach(file => {
@@ -67,13 +69,14 @@ class Header extends React.Component {
6769
};
6870
save(gist)
6971
.then(refineGist)
70-
.then(algorithm => this.props.setCurrent(categoryKey, algorithmKey, algorithm.gistId, algorithm.titles, algorithm.files, algorithm.gist))
72+
.then(this.props.setScratchPaper)
7173
.then(this.props.loadScratchPapers)
7274
.catch(handleError.bind(this));
7375
}
7476

7577
deleteGist() {
76-
const { gistId } = this.props.current;
78+
const { scratchPaper } = this.props.current;
79+
const { gistId } = scratchPaper;
7780
const deletePromise = ['new', 'forked'].includes(gistId) ? Promise.resolve() : GitHubApi.deleteGist(gistId);
7881
deletePromise
7982
.then(() => this.props.loadAlgorithm({}, true))
@@ -83,7 +86,8 @@ class Header extends React.Component {
8386

8487
render() {
8588
const { className, onClickTitleBar, navigatorOpened, gistSaved, file } = this.props;
86-
const { gistId, titles } = this.props.current;
89+
const { scratchPaper } = this.props.current;
90+
const titleArray = getTitleArray(this.props.current);
8791
const { ext, user } = this.props.env;
8892

8993
return (
@@ -92,12 +96,12 @@ class Header extends React.Component {
9296
<div className={styles.section}>
9397
<Button className={styles.title_bar} onClick={onClickTitleBar}>
9498
{
95-
titles.map((title, i) => [
96-
gistId && i === 1 ?
99+
titleArray.map((title, i) => [
100+
scratchPaper && i === 1 ?
97101
<AutosizeInput className={styles.input_title} key={`title-${i}`} value={title}
98102
onClick={e => e.stopPropagation()} onChange={e => this.handleChangeTitle(e)} /> :
99103
<Ellipsis key={`title-${i}`}>{title}</Ellipsis>,
100-
i < titles.length - 1 &&
104+
i < titleArray.length - 1 &&
101105
<FontAwesomeIcon className={styles.nav_arrow} fixedWidth icon={faAngleRight} key={`arrow-${i}`} />,
102106
])
103107
}
@@ -106,11 +110,11 @@ class Header extends React.Component {
106110
</Button>
107111
</div>
108112
<div className={styles.section}>
109-
<Button icon={faSave} primary disabled={!gistId || gistSaved}
113+
<Button icon={faSave} primary disabled={!scratchPaper || gistSaved}
110114
onClick={() => this.saveGist()}>Save</Button>
111-
<Button icon={faTrashAlt} primary disabled={!gistId} onClick={() => this.deleteGist()}
115+
<Button icon={faTrashAlt} primary disabled={!scratchPaper} onClick={() => this.deleteGist()}
112116
confirmNeeded>Delete</Button>
113-
<Button icon={faFacebook} primary disabled={['new', 'forked'].includes(gistId)}
117+
<Button icon={faFacebook} primary disabled={scratchPaper && ['new', 'forked'].includes(scratchPaper.gistId)}
114118
href={`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(window.location.href)}`}>Share</Button>
115119
<Button icon={faExpandArrowsAlt} primary
116120
onClick={() => this.handleClickFullScreen()}>Fullscreen</Button>

src/frontend/components/Navigator/index.jsx

+12-9
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,16 @@ class Navigator extends React.Component {
2323
}
2424

2525
componentDidMount() {
26-
const { categoryKey } = this.props.current;
27-
if (categoryKey) {
28-
this.toggleCategory(categoryKey, true);
26+
const { algorithm } = this.props.current;
27+
if (algorithm) {
28+
this.toggleCategory(algorithm.categoryKey, true);
2929
}
3030
}
3131

3232
componentWillReceiveProps(nextProps) {
33-
const { categoryKey } = nextProps.current;
34-
if (categoryKey) {
35-
this.toggleCategory(categoryKey, true);
33+
const { algorithm } = nextProps.current;
34+
if (algorithm) {
35+
this.toggleCategory(algorithm.categoryKey, true);
3636
}
3737
}
3838

@@ -69,8 +69,11 @@ class Navigator extends React.Component {
6969
const { categoriesOpened, scratchPaperOpened, query } = this.state;
7070
const { className, loadAlgorithm } = this.props;
7171
const { categories, scratchPapers } = this.props.directory;
72-
const { categoryKey, algorithmKey, gistId } = this.props.current;
73-
const { user } = this.props.env;
72+
const { algorithm, scratchPaper } = this.props.current;
73+
74+
const categoryKey = algorithm && algorithm.categoryKey;
75+
const algorithmKey = algorithm && algorithm.algorithmKey;
76+
const gistId = scratchPaper && scratchPaper.gistId;
7477

7578
return (
7679
<nav className={classes(styles.navigator, className)}>
@@ -128,4 +131,4 @@ class Navigator extends React.Component {
128131
}
129132
}
130133

131-
export default Navigator;
134+
export default Navigator;

0 commit comments

Comments
 (0)