Skip to content

Commit 0c10c86

Browse files
author
Keven Lefebvre
committed
first working version
1 parent 692be72 commit 0c10c86

File tree

20 files changed

+193
-74
lines changed

20 files changed

+193
-74
lines changed

package-lock.json

Lines changed: 0 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: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
"deepmerge": "^2.1.1",
99
"draft-js": "^0.10.5",
1010
"history": "^4.7.2",
11-
"js-cookie": "^2.2.0",
1211
"react": "^16.4.1",
1312
"react-app-state": "github:rodrigocfd/react-app-state#master",
1413
"react-dom": "^16.4.1",

src/components/Menu.jsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ import logo from '../assets/images/logo.svg';
77

88
export default AuthStore.subscribe(
99
class App extends Component {
10+
renderIconItem = (title, icon, url) => (
11+
<Popup
12+
trigger={
13+
<Menu.Item as={Link} to={url}>
14+
<Icon name={icon} />
15+
</Menu.Item>
16+
}
17+
content={title}
18+
inverted
19+
position="right center"
20+
/>
21+
);
22+
1023
render() {
1124
return (
1225
<Menu icon vertical>
@@ -20,19 +33,10 @@ export default AuthStore.subscribe(
2033
</React.Fragment>
2134
) : (
2235
<React.Fragment>
23-
<Popup
24-
trigger={
25-
<Menu.Item as={Link} name="New note" to="/notes/new">
26-
<Icon name="add circle" />
27-
</Menu.Item>
28-
}
29-
content="New note"
30-
inverted
31-
position="right center"
32-
/>
33-
<Menu.Item as={Link} name="Your notes" to="/notes" />
34-
<Menu.Item as={Link} name="Settings" to="/settings" />
35-
<Menu.Item as={Link} name="Logout" to="/auth/logout" />
36+
{this.renderIconItem('Your notes', 'sticky note', '/notes')}
37+
{this.renderIconItem('New note', 'add circle', '/notes/new')}
38+
{this.renderIconItem('Settings', 'settings', '/settings')}
39+
{this.renderIconItem('Logout', 'log out', '/auth/logout')}
3640
</React.Fragment>
3741
)}
3842
</Menu>

src/components/notes/Attributes.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,14 @@ export default EditorStore.subscribe(
4444

4545
handleSave = () => {
4646
EditorStore.set({ loading: true });
47-
Notes.save(this.props.note).then(() => {
47+
Notes.save(this.props.note).then(({ data }) => {
48+
if (this.props.note.id !== data.data.id) {
49+
History.push(`/notes/edit/${data.data.id}`);
50+
}
51+
4852
EditorStore.set({
49-
originalNote: this.props.note,
53+
note: data.data,
54+
originalNote: data.data,
5055
loading: false
5156
});
5257
});

src/components/notes/Editor.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import TextEditor from './editors/TextEditor';
66
import { EditorStore, HelpStore } from '../../stores';
77
import { Notes } from '../../models';
88
import History from '../../helpers/History';
9+
import { checkIfShouldRenderFirstNoteEncryptionNotice } from '../../helpers/Help';
910

1011
export default HelpStore.subscribe(
1112
EditorStore.subscribe(
1213
class extends Component {
1314
componentWillMount = () => {
15+
checkIfShouldRenderFirstNoteEncryptionNotice();
1416
if (this.props.match.params.id) {
1517
EditorStore.set({
1618
type: 'edit',
@@ -30,6 +32,7 @@ export default HelpStore.subscribe(
3032
EditorStore.new();
3133
}
3234
};
35+
3336
componentWillUnmount = () => EditorStore.reset();
3437

3538
renderFirstNoteAlert = () => (

src/components/notes/Finder.jsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import React, { Component } from 'react';
22
import { Header, Menu } from 'semantic-ui-react';
33
import { ViewerStore } from '../../stores';
44
import { Notes } from '../../models';
5-
import History from '../../helpers/History';
6-
import { checkIfShouldRenderFirstNoteEncryptionNotice } from '../../helpers/Help';
75
import RawSegment from '../RawSegment';
86

97
export default ViewerStore.subscribe(
@@ -12,22 +10,30 @@ export default ViewerStore.subscribe(
1210
loading: false
1311
};
1412

15-
componentWillMount = () => {
13+
componentDidUpdate = prevProps => {
14+
if (prevProps.location.pathname !== this.props.location.pathname) {
15+
this.refreshNotes();
16+
}
17+
};
18+
19+
componentDidMount = () => this.refreshNotes();
20+
21+
refreshNotes = () => {
1622
this.setState({ loading: true });
1723
Notes.get().then(({ data }) => {
1824
this.setState({ loading: false });
19-
ViewerStore.set({ notes: data.data }, checkIfShouldRenderFirstNoteEncryptionNotice);
25+
ViewerStore.set({ notes: data.data });
2026
});
2127
};
2228

23-
openNote = note => () => History.push(`/notes/view/${note.id}`);
29+
openNote = note => () => this.props.history.push(`/notes/view/${note.id}`);
2430

2531
renderNotes = () => {
2632
const { notes } = this.props;
2733

2834
if (notes.length === 0) {
2935
return (
30-
<Menu.Item onClick={() => History.push('/notes/new')}>
36+
<Menu.Item onClick={() => this.props.history.push('/notes/new')}>
3137
<p>Your notes will appear here. Click here to start writing one!</p>
3238
</Menu.Item>
3339
);

src/components/notes/Viewer.jsx

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { Component } from 'react';
2-
import { Segment, Menu, Icon, Message } from 'semantic-ui-react';
2+
import { Segment, Menu, Icon, Message, Modal, Button } from 'semantic-ui-react';
33
import SyntaxHighlighter from 'react-syntax-highlighter';
44
import { docco } from 'react-syntax-highlighter/styles/hljs';
55
import CryptoJS from 'crypto-js';
@@ -11,6 +11,10 @@ import History from '../../helpers/History';
1111

1212
export default ViewerStore.subscribe(
1313
class extends Component {
14+
state = {
15+
renderDeleteConfirm: false
16+
};
17+
1418
componentWillMount = () => {
1519
if (this.props.match.params.id) {
1620
ViewerStore.set({ loading: true });
@@ -30,8 +34,39 @@ export default ViewerStore.subscribe(
3034

3135
handleEdit = () => History.push(`/notes/edit/${this.props.note.id}`);
3236

37+
handleDelete = () => this.setState({ renderDeleteConfirm: true });
38+
3339
handleClose = () => History.push('/notes');
3440

41+
renderDeleteConfirmation = () => (
42+
<Modal
43+
open={this.state.renderDeleteConfirm}
44+
onClose={() => this.setState({ renderDeleteConfirm: false })}
45+
>
46+
<Modal.Header>Delete a note</Modal.Header>
47+
<Modal.Content>
48+
<p>Are you sure you want to delete this note? This action is not reversible.</p>
49+
</Modal.Content>
50+
<Modal.Actions>
51+
<Button onClick={() => this.setState({ renderDeleteConfirm: false })}>
52+
Nope, wrong button
53+
</Button>
54+
<Button
55+
onClick={() => {
56+
this.setState({ renderDeleteConfirm: false });
57+
ViewerStore.set({ loading: true });
58+
Notes.delete(this.props.note.id).then(() => {
59+
History.push(`/notes`);
60+
});
61+
}}
62+
negative
63+
icon="warning sign"
64+
content="Yes, delete this note"
65+
/>
66+
</Modal.Actions>
67+
</Modal>
68+
);
69+
3570
renderTopMenu = () => {
3671
return this.props.note ? (
3772
<Menu secondary attached="top">
@@ -50,6 +85,9 @@ export default ViewerStore.subscribe(
5085
<Menu.Item onClick={this.handleEdit}>
5186
<Icon name="pencil" /> Edit
5287
</Menu.Item>
88+
<Menu.Item onClick={this.handleDelete}>
89+
<Icon name="trash" /> Delete
90+
</Menu.Item>
5391
<Menu.Item onClick={this.handleClose}>
5492
<Icon name="times" /> Close
5593
</Menu.Item>
@@ -113,6 +151,7 @@ export default ViewerStore.subscribe(
113151

114152
return (
115153
<Segment loading={loading} className="raw calepin-viewer">
154+
{this.renderDeleteConfirmation()}
116155
{this.renderTopMenu()}
117156
<Segment attached={note ? 'bottom' : null}>{this.renderViewer()}</Segment>
118157
</Segment>

src/helpers/Api.js

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
import axios from 'axios';
2-
import AuthStore from '../stores/Auth';
2+
import { AuthStore, SettingsStore } from '../stores';
33
import history from './History';
44

55
class Api {
66
constructor() {
7-
let service = axios.create({
8-
baseURL: 'https://api.calepin.io/api/v1'
9-
});
10-
7+
let service = axios.create();
118
service.interceptors.response.use(this.handleSuccess, this.handleError);
129
this.service = service;
1310
}
1411

1512
beforeRequest() {
13+
this.service.defaults.baseURL = SettingsStore.get('api_url');
1614
this.service.defaults.headers.common['Authorization'] = AuthStore.get('access_token')
1715
? `Bearer ${AuthStore.get('access_token')}`
1816
: undefined;
@@ -23,19 +21,23 @@ class Api {
2321
}
2422

2523
handleError = error => {
26-
switch (error.response.status) {
27-
case 401:
28-
history.push('/auth/login');
29-
break;
30-
case 404:
31-
history.push('/404');
32-
break;
33-
case 422:
34-
window.alert(Object.values(error.response.data.errors).join('\r\n'));
35-
break;
36-
default:
37-
history.push('/500');
38-
break;
24+
if (error.response && error.response.status) {
25+
switch (error.response.status) {
26+
case 401:
27+
history.push('/auth/login');
28+
break;
29+
case 404:
30+
history.push('/404');
31+
break;
32+
case 422:
33+
window.alert(Object.values(error.response.data.errors).join('\r\n'));
34+
break;
35+
default:
36+
history.push('/500');
37+
break;
38+
}
39+
} else {
40+
history.push('/500');
3941
}
4042
return Promise.reject(error);
4143
};
@@ -64,6 +66,11 @@ class Api {
6466
data: payload
6567
});
6668
}
69+
70+
delete(path, config) {
71+
this.beforeRequest();
72+
return this.service.delete(path, config);
73+
}
6774
}
6875

6976
export default new Api();

src/helpers/Help.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { AuthStore, ViewerStore, HelpStore } from '../stores';
1+
import { AuthStore, HelpStore } from '../stores';
22

33
export const checkIfShouldRenderFirstNoteEncryptionNotice = function() {
4-
if (_checkIfShouldRenderFirstNoteEncryptionNotice === true) {
4+
if (_checkIfShouldRenderFirstNoteEncryptionNotice() === true) {
55
HelpStore.set({
66
renderFirstNoteAlert: true
77
});
@@ -14,12 +14,6 @@ function _checkIfShouldRenderFirstNoteEncryptionNotice() {
1414
}
1515

1616
if (AuthStore.get('user') && !AuthStore.get('user').previous_login) {
17-
console.log(AuthStore.get('user').previous_login);
18-
return true;
19-
}
20-
21-
if (!ViewerStore.get('notes').length) {
22-
console.log(ViewerStore.get('notes').length);
2317
return true;
2418
}
2519

src/models/Notes.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ export default new class {
2222
return Api[method](url, this.encryptNote(note));
2323
}
2424

25+
delete(uuid) {
26+
return Api.delete(`notes/${uuid}`);
27+
}
28+
2529
encryptNote = note => {
2630
// Encrypt if needed
2731
if (note.encrypted) {

0 commit comments

Comments
 (0)