mirror of
https://github.com/Alamantus/Lexiconga.git
synced 2025-10-06 05:15:47 +02:00
Add AccountManager with (test) login and syncing dictionaries with DB!
This commit is contained in:
parent
39fe0cbe0a
commit
3d329c8a87
5 changed files with 176 additions and 9 deletions
84
src/components/management/AccountManager/index.jsx
Normal file
84
src/components/management/AccountManager/index.jsx
Normal file
|
@ -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 { Modal } from './Modal';
|
||||||
import { SearchBox } from '../management/SearchBox';
|
import { SearchBox } from '../management/SearchBox';
|
||||||
|
import { AccountManager } from '../management/AccountManager';
|
||||||
|
|
||||||
import helpMarkdown from '../../assets/text/help.md';
|
import helpMarkdown from '../../assets/text/help.md';
|
||||||
|
|
||||||
|
@ -15,6 +16,7 @@ export class Header extends Component {
|
||||||
PropTypes.checkPropTypes({
|
PropTypes.checkPropTypes({
|
||||||
partsOfSpeech: PropTypes.array.isRequired,
|
partsOfSpeech: PropTypes.array.isRequired,
|
||||||
search: PropTypes.func.isRequired,
|
search: PropTypes.func.isRequired,
|
||||||
|
updater: PropTypes.object.isRequired,
|
||||||
}, props, 'prop', 'Header');
|
}, props, 'prop', 'Header');
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -47,9 +49,7 @@ export class Header extends Component {
|
||||||
<div className={`navbar-menu${ this.state.displayNavMenu ? ' is-active' : '' }`}>
|
<div className={`navbar-menu${ this.state.displayNavMenu ? ' is-active' : '' }`}>
|
||||||
<div className='navbar-end'>
|
<div className='navbar-end'>
|
||||||
<span className='navbar-item'>
|
<span className='navbar-item'>
|
||||||
<a className='button'>
|
<AccountManager updater={ this.props.updater } />
|
||||||
Login
|
|
||||||
</a>
|
|
||||||
</span>
|
</span>
|
||||||
<span className='navbar-item'>
|
<span className='navbar-item'>
|
||||||
<Modal buttonText='Help' title='Lexiconga Help'>
|
<Modal buttonText='Help' title='Lexiconga Help'>
|
||||||
|
|
|
@ -180,6 +180,7 @@ class App extends Component {
|
||||||
<Header
|
<Header
|
||||||
partsOfSpeech={ this.state.partsOfSpeech }
|
partsOfSpeech={ this.state.partsOfSpeech }
|
||||||
search={ (searchConfig) => this.search(searchConfig) }
|
search={ (searchConfig) => this.search(searchConfig) }
|
||||||
|
updater={ this.updater }
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MainDisplay
|
<MainDisplay
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import store from 'store';
|
||||||
|
|
||||||
import { timestampInSeconds } from "../Helpers";
|
import { timestampInSeconds } from "../Helpers";
|
||||||
|
|
||||||
export class Updater {
|
export class Updater {
|
||||||
|
@ -93,7 +95,7 @@ export class Updater {
|
||||||
}),
|
}),
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
action: 'set-dictionary-details',
|
action: 'set-dictionary-details',
|
||||||
token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MTUxLCJpc01lbWJlciI6ZmFsc2UsImRpY3Rpb25hcnkiOjM1M30.4HRuWY8arkjjYLgQ0Cq4a6v-eXwLTD24oENL8E4I5o0',
|
token: store.get('LexicongaToken'),
|
||||||
details: dictionaryDetails,
|
details: dictionaryDetails,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
@ -112,12 +114,92 @@ export class Updater {
|
||||||
}),
|
}),
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
action: 'set-dictionary-words',
|
action: 'set-dictionary-words',
|
||||||
token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MTUxLCJpc01lbWJlciI6ZmFsc2UsImRpY3Rpb25hcnkiOjM1M30.4HRuWY8arkjjYLgQ0Cq4a6v-eXwLTD24oENL8E4I5o0',
|
token: store.get('LexicongaToken'),
|
||||||
words: words,
|
words,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
return fetch(request).then(response => response.json()).then(responseJSON => {
|
return fetch(request).then(response => response.json()).then(responseJSON => {
|
||||||
console.log(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 () {
|
create () {
|
||||||
this.createdOn = timestampInSeconds();
|
this.createdOn = this.createdOn ? this.createdOn : timestampInSeconds();
|
||||||
|
|
||||||
// Delete id if it exists to allow creation of new word.
|
// Delete id if it exists to allow creation of new word.
|
||||||
if (this.hasOwnProperty('id')) delete this.id;
|
if (this.hasOwnProperty('id')) delete this.id;
|
||||||
|
@ -57,7 +57,7 @@ export class Word {
|
||||||
}
|
}
|
||||||
|
|
||||||
update () {
|
update () {
|
||||||
this.lastUpdated = timestampInSeconds();
|
this.lastUpdated = this.lastUpdated ? this.lastUpdated : timestampInSeconds();
|
||||||
|
|
||||||
return wordDb.words.put(this)
|
return wordDb.words.put(this)
|
||||||
.then((id) => {
|
.then((id) => {
|
||||||
|
@ -89,7 +89,7 @@ export class Word {
|
||||||
}),
|
}),
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
action: 'set-dictionary-words',
|
action: 'set-dictionary-words',
|
||||||
token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MTUxLCJpc01lbWJlciI6ZmFsc2UsImRpY3Rpb25hcnkiOjM1M30.4HRuWY8arkjjYLgQ0Cq4a6v-eXwLTD24oENL8E4I5o0',
|
token: store.get('LexicongaToken'),
|
||||||
words: [this],
|
words: [this],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue