Add AccountManager with (test) login and syncing dictionaries with DB!
This commit is contained in:
parent
39fe0cbe0a
commit
3d329c8a87
|
@ -0,0 +1,84 @@
|
|||
import Inferno from 'inferno';
|
||||
import Component from 'inferno-component';
|
||||
import PropTypes from 'prop-types';
|
||||
import marked from 'marked';
|
||||
import store from 'store';
|
||||
|
||||
import { Modal } from '../../structure/Modal';
|
||||
import { SearchBox } from '../../management/SearchBox';
|
||||
|
||||
import helpMarkdown from '../../../assets/text/help.md';
|
||||
|
||||
export class AccountManager extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
PropTypes.checkPropTypes({
|
||||
updater: PropTypes.object.isRequired,
|
||||
}, props, 'prop', 'AccountManager');
|
||||
|
||||
this.state = {
|
||||
isLoggedIn: false,
|
||||
};
|
||||
}
|
||||
|
||||
logIn (email, password) {
|
||||
const request = new Request('./api/', {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
redirect: 'follow',
|
||||
headers: new Headers({
|
||||
'Content-Type': 'application/json'
|
||||
}),
|
||||
body: JSON.stringify({
|
||||
action: 'login',
|
||||
email,
|
||||
password,
|
||||
}),
|
||||
});
|
||||
return fetch(request).then(response => response.json()).then(responseJSON => {
|
||||
const {data, error} = responseJSON;
|
||||
if (error) {
|
||||
console.error(data);
|
||||
} else {
|
||||
store.set('LexicongaToken', data);
|
||||
this.setState({ isLoggedIn: true }, () => {
|
||||
this.props.updater.sync();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
logOut () {
|
||||
store.remove('LexicongaToken');
|
||||
this.setState({ isLoggedIn: false });
|
||||
}
|
||||
|
||||
render () {
|
||||
const token = store.get('LexicongaToken');
|
||||
|
||||
if (token) {
|
||||
return (
|
||||
<div>
|
||||
<Modal buttonText='Account' title='My Account'>
|
||||
<div className='content has-text-left'>
|
||||
<p>Hello My Account!</p>
|
||||
</div>
|
||||
</Modal>
|
||||
<a className='button' onClick={this.logOut.bind(this)}>
|
||||
Log Out
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Modal buttonText='Log In/Sign Up' title='Log In/Sign Up'>
|
||||
<div className='content has-text-left'>
|
||||
<a className='button' onClick={() => this.logIn('test1@robbie.com', 'password')}>
|
||||
Test that login!
|
||||
</a>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import marked from 'marked';
|
|||
|
||||
import { Modal } from './Modal';
|
||||
import { SearchBox } from '../management/SearchBox';
|
||||
import { AccountManager } from '../management/AccountManager';
|
||||
|
||||
import helpMarkdown from '../../assets/text/help.md';
|
||||
|
||||
|
@ -15,6 +16,7 @@ export class Header extends Component {
|
|||
PropTypes.checkPropTypes({
|
||||
partsOfSpeech: PropTypes.array.isRequired,
|
||||
search: PropTypes.func.isRequired,
|
||||
updater: PropTypes.object.isRequired,
|
||||
}, props, 'prop', 'Header');
|
||||
|
||||
this.state = {
|
||||
|
@ -47,9 +49,7 @@ export class Header extends Component {
|
|||
<div className={`navbar-menu${ this.state.displayNavMenu ? ' is-active' : '' }`}>
|
||||
<div className='navbar-end'>
|
||||
<span className='navbar-item'>
|
||||
<a className='button'>
|
||||
Login
|
||||
</a>
|
||||
<AccountManager updater={ this.props.updater } />
|
||||
</span>
|
||||
<span className='navbar-item'>
|
||||
<Modal buttonText='Help' title='Lexiconga Help'>
|
||||
|
|
|
@ -180,6 +180,7 @@ class App extends Component {
|
|||
<Header
|
||||
partsOfSpeech={ this.state.partsOfSpeech }
|
||||
search={ (searchConfig) => this.search(searchConfig) }
|
||||
updater={ this.updater }
|
||||
/>
|
||||
|
||||
<MainDisplay
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import store from 'store';
|
||||
|
||||
import { timestampInSeconds } from "../Helpers";
|
||||
|
||||
export class Updater {
|
||||
|
@ -93,7 +95,7 @@ export class Updater {
|
|||
}),
|
||||
body: JSON.stringify({
|
||||
action: 'set-dictionary-details',
|
||||
token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MTUxLCJpc01lbWJlciI6ZmFsc2UsImRpY3Rpb25hcnkiOjM1M30.4HRuWY8arkjjYLgQ0Cq4a6v-eXwLTD24oENL8E4I5o0',
|
||||
token: store.get('LexicongaToken'),
|
||||
details: dictionaryDetails,
|
||||
}),
|
||||
});
|
||||
|
@ -112,12 +114,92 @@ export class Updater {
|
|||
}),
|
||||
body: JSON.stringify({
|
||||
action: 'set-dictionary-words',
|
||||
token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MTUxLCJpc01lbWJlciI6ZmFsc2UsImRpY3Rpb25hcnkiOjM1M30.4HRuWY8arkjjYLgQ0Cq4a6v-eXwLTD24oENL8E4I5o0',
|
||||
words: words,
|
||||
token: store.get('LexicongaToken'),
|
||||
words,
|
||||
}),
|
||||
});
|
||||
return fetch(request).then(response => response.json()).then(responseJSON => {
|
||||
console.log(responseJSON);
|
||||
});
|
||||
}
|
||||
|
||||
sync () {
|
||||
const request = new Request('./api/', {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
redirect: 'follow',
|
||||
headers: new Headers({
|
||||
'Content-Type': 'application/json'
|
||||
}),
|
||||
body: JSON.stringify({
|
||||
action: 'get-current-dictionary',
|
||||
token: store.get('LexicongaToken'),
|
||||
}),
|
||||
});
|
||||
return fetch(request).then(response => response.json()).then(responseJSON => {
|
||||
const {data, error} = responseJSON;
|
||||
if (error) {
|
||||
console.error(data);
|
||||
} else {
|
||||
this.compareDetails(data.details);
|
||||
this.compareWords(data.words);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
compareDetails (externalDetails) {
|
||||
if (externalDetails.lastUpdated) {
|
||||
if (externalDetails.lastUpdated > store.get('Lexiconga').lastUpdated) {
|
||||
this.app.setState(externalDetails, () => {
|
||||
this.dictionary.storedData = externalDetails;
|
||||
console.log('updated local');
|
||||
});
|
||||
} else if (externalDetails.lastUpdated < store.get('Lexiconga').lastUpdated) {
|
||||
this.sendDictionaryDetails(this.app.state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compareWords (externalWords) {
|
||||
const wordsToSend = [];
|
||||
const wordsToAdd = [];
|
||||
const wordsToUpdate = [];
|
||||
const localWordsPromise = this.dictionary.wordsPromise.then(localWords => {
|
||||
externalWords.forEach(externalWord => {
|
||||
if (externalWord.lastUpdated) {
|
||||
const matchingWord = localWords.find(word => word.id === externalWord.id);
|
||||
if (matchingWord) {
|
||||
if (externalWord.lastUpdated > matchingWord.lastUpdated) {
|
||||
wordsToUpdate.push(externalWord);
|
||||
} else if (externalWord.lastUpdated < matchingWord.lastUpdated) {
|
||||
wordsToSend.push(matchingWord);
|
||||
}
|
||||
} else {
|
||||
wordsToAdd.push(externalWord);
|
||||
}
|
||||
}
|
||||
});
|
||||
// Find words not in external database and add them to send.
|
||||
localWords.forEach(localWord => {
|
||||
if (localWord.lastUpdated) {
|
||||
const wordAlreadyChecked = externalWords.some(word => word.id === localWord.id);
|
||||
if (!wordAlreadyChecked) {
|
||||
wordsToSend.push(localWord);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
wordsToAdd.forEach(newWord => {
|
||||
new Word(newWord).create();
|
||||
});
|
||||
wordsToUpdate.forEach(updatedWord => {
|
||||
new Word(updatedWord).update();
|
||||
});
|
||||
if (wordsToSend.length > 0) {
|
||||
this.sendWords(wordsToSend);
|
||||
}
|
||||
}).then(() => {
|
||||
this.app.updateDisplayedWords(() => console.log('synced words'));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ export class Word {
|
|||
}
|
||||
|
||||
create () {
|
||||
this.createdOn = timestampInSeconds();
|
||||
this.createdOn = this.createdOn ? this.createdOn : timestampInSeconds();
|
||||
|
||||
// Delete id if it exists to allow creation of new word.
|
||||
if (this.hasOwnProperty('id')) delete this.id;
|
||||
|
@ -57,7 +57,7 @@ export class Word {
|
|||
}
|
||||
|
||||
update () {
|
||||
this.lastUpdated = timestampInSeconds();
|
||||
this.lastUpdated = this.lastUpdated ? this.lastUpdated : timestampInSeconds();
|
||||
|
||||
return wordDb.words.put(this)
|
||||
.then((id) => {
|
||||
|
@ -89,7 +89,7 @@ export class Word {
|
|||
}),
|
||||
body: JSON.stringify({
|
||||
action: 'set-dictionary-words',
|
||||
token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MTUxLCJpc01lbWJlciI6ZmFsc2UsImRpY3Rpb25hcnkiOjM1M30.4HRuWY8arkjjYLgQ0Cq4a6v-eXwLTD24oENL8E4I5o0',
|
||||
token: store.get('LexicongaToken'),
|
||||
words: [this],
|
||||
}),
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue