Compare commits
6 Commits
929d1ca928
...
5aeee0bc01
Author | SHA1 | Date |
---|---|---|
Robbie Antenesse | 5aeee0bc01 | |
Robbie Antenesse | 4498ed002a | |
Robbie Antenesse | cd0baa7605 | |
Robbie Antenesse | d8f0de9ec4 | |
Robbie Antenesse | 43a8c006a1 | |
Robbie Antenesse | bcde0c6dc7 |
|
@ -14,9 +14,11 @@ export const appListeners = (app, state, emitter) => {
|
|||
emitter.on('set-language', newLanguage => {
|
||||
app.setSettingsItem('lang', newLanguage);
|
||||
state.language = newLanguage;
|
||||
emitter.emit('render', () => { });
|
||||
emitter.emit('render');
|
||||
});
|
||||
|
||||
emitter.emit('render'); // This should hopefully only run once after the DOM is loaded. It prevents routing issues where 'render' hasn't been defined yet
|
||||
app.checkIfLoggedIn(state).then(isLoggedIn => {
|
||||
emitter.emit('render'); // This should hopefully only run once after the DOM is loaded. It prevents routing issues where 'render' hasn't been defined yet
|
||||
});
|
||||
});
|
||||
}
|
|
@ -9,6 +9,8 @@ export const appRoutes = (app) => {
|
|||
|
||||
app.route('/login', (state, emit) => globalView(state, emit, loginView));
|
||||
|
||||
app.route('/logout', () => window.location.reload()); // If Choo navigates here, refresh the page instead so the server can handle it and log out
|
||||
|
||||
app.route('/search', (state, emit) => globalView(state, emit, searchView));
|
||||
|
||||
app.route('/404', (state, emit) => globalView(state, emit, errorView));
|
||||
|
|
|
@ -19,4 +19,19 @@ export const appUtilities = (app) => {
|
|||
savedSettings[settingsKey] = value;
|
||||
return window.localStorage.setItem('settings', JSON.stringify(savedSettings));
|
||||
}
|
||||
|
||||
app.checkIfLoggedIn = (appState) => {
|
||||
return fetch('/api/account/validate', { method: 'post' })
|
||||
.then(response => response.json())
|
||||
.then(response => {
|
||||
if (response.error !== false) {
|
||||
console.warn(response);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.info(response.message);
|
||||
appState.isLoggedIn = true;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -7,7 +7,11 @@ export class I18n {
|
|||
default: en,
|
||||
en,
|
||||
};
|
||||
this.language = appState.language;
|
||||
this.appState = appState;
|
||||
}
|
||||
|
||||
get language () {
|
||||
return this.appState.language;
|
||||
}
|
||||
|
||||
translate (section, phrase) {
|
||||
|
|
|
@ -3,10 +3,13 @@
|
|||
"locale": "en",
|
||||
"global": {
|
||||
"menu_search": "Search for Books",
|
||||
"menu_login": "Log In",
|
||||
"menu_about": "About",
|
||||
"menu_login": "Log In / Create Account",
|
||||
"menu_account": "My Profile",
|
||||
"menu_logout": "Log Out",
|
||||
"footer_repo": "Repo",
|
||||
"footer_chat": "Chat"
|
||||
"footer_chat": "Chat",
|
||||
"change_language": "Change Language"
|
||||
},
|
||||
"home": {
|
||||
"logged_out_subtitle": "All the Book Buzz in Once Place",
|
||||
|
@ -16,7 +19,10 @@
|
|||
"logged_out_community_header": "A Look Inside the Hive",
|
||||
"logged_out_recent_reviews": "Recent Reviews",
|
||||
"logged_out_recent_updates": "Recent Updates",
|
||||
"logged_out_join_now": "Join Now!"
|
||||
"logged_out_join_now": "Join Now!",
|
||||
"logged_in_subtitle": "Welcome!",
|
||||
"logged_in_updates": "Updates",
|
||||
"logged_in_interactions": "Interactions"
|
||||
},
|
||||
"404": {
|
||||
"header": "Oops!",
|
||||
|
|
|
@ -19,9 +19,18 @@ export const globalView = (state, emit, view) => {
|
|||
<label for="navMenu" class="burger pseudo button">${'\u2261'}</label>
|
||||
|
||||
<div class="menu">
|
||||
<a href="/search" class="pseudo button"><i class="icon-search" aria-label=${i18n.__('global.menu_search')}></i></a>
|
||||
<a href="/login" class="pseudo button">${i18n.__('global.menu_login')}</a>
|
||||
<a href="/logout" class="pseudo button">${i18n.__('global.menu_logout')}</a>
|
||||
<a href="/search" class="pseudo button">
|
||||
<i class="icon-search" aria-labeledBy="searchLabel"></i> <span id="searchLabel">${i18n.__('global.menu_search')}</span>
|
||||
</a>
|
||||
<a href="/about" class="pseudo button">${i18n.__('global.menu_about')}</a>
|
||||
${
|
||||
state.isLoggedIn === true
|
||||
? [
|
||||
html`<a href="/account" class="pseudo button">${i18n.__('global.menu_account')}</a>`,
|
||||
html`<a href="/logout" class="pseudo button">${i18n.__('global.menu_logout')}</a>`,
|
||||
]
|
||||
: html`<a href="/login" class="pseudo button">${i18n.__('global.menu_login')}</a>`
|
||||
}
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
@ -31,14 +40,30 @@ export const globalView = (state, emit, view) => {
|
|||
</main>
|
||||
|
||||
<footer>
|
||||
<nav>
|
||||
<div class="links">
|
||||
<a href="https://gitlab.com/Alamantus/Readlebee" class="pseudo button">
|
||||
${i18n.__('global.footer_repo')}
|
||||
</a>
|
||||
<a href="https://gitter.im/Readlebee/community" class="pseudo button">
|
||||
${i18n.__('global.footer_chat')}
|
||||
</a>
|
||||
<nav class="flex one">
|
||||
<div class="two-third-600">
|
||||
<div class="links">
|
||||
<a href="https://gitlab.com/Alamantus/Readlebee" class="pseudo button">
|
||||
${i18n.__('global.footer_repo')}
|
||||
</a>
|
||||
<a href="https://gitter.im/Readlebee/community" class="pseudo button">
|
||||
${i18n.__('global.footer_chat')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="third-600">
|
||||
<label class="flex">
|
||||
<span class="third">${i18n.__('global.change_language')}:</span>
|
||||
<select class="two-third" onchange=${e => emit('set-language', e.target.value)}>
|
||||
${Object.keys(i18n.availableLanguages).map(languageKey => {
|
||||
if (languageKey === 'default') return null;
|
||||
const language = i18n.availableLanguages[languageKey];
|
||||
return html`<option value=${language.locale} ${state.language === language.locale ? 'selected' : null}>
|
||||
${language.name}
|
||||
</option>`;
|
||||
})}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</nav>
|
||||
</footer>
|
||||
|
|
|
@ -5,19 +5,18 @@ export class HomeController extends ViewController {
|
|||
// Super passes state, view name, and default state to ViewController,
|
||||
// which stores state in this.appState and the view controller's state to this.state
|
||||
super(state, i18n, 'home', {
|
||||
recentReviews: [],
|
||||
recentUpdates: [],
|
||||
loggedOut: {
|
||||
recentReviews: [],
|
||||
recentUpdates: [],
|
||||
},
|
||||
loggedIn: {
|
||||
updates: [], // statuses, ratings, and reviews from people you follow.
|
||||
interactions: [], // likes, comments, recommendations, etc.
|
||||
},
|
||||
});
|
||||
|
||||
// If using controller methods in an input's onchange or onclick instance,
|
||||
// either bind the class's 'this' instance to the method first...
|
||||
// or use `onclick=${() => controller.submit()}` to maintain the 'this' of the class instead.
|
||||
}
|
||||
|
||||
get recentReviews() {
|
||||
return [...this.state.recentReviews];
|
||||
}
|
||||
get recentUpdates() {
|
||||
return [...this.state.recentUpdates];
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import html from 'choo/html';
|
|||
|
||||
import { HomeController } from './controller'; // The controller for this view, where processing should happen.
|
||||
import { loggedOutView } from './loggedOut';
|
||||
import { loggedInView } from './loggedIn';
|
||||
|
||||
// This is the view function that is exported and used in the view manager.
|
||||
export const homeView = (state, emit, i18n) => {
|
||||
|
@ -12,7 +13,7 @@ export const homeView = (state, emit, i18n) => {
|
|||
return [
|
||||
(!controller.isLoggedIn
|
||||
? loggedOutView(controller, emit)
|
||||
: html`<p>lol wut how are u logged in</p>`
|
||||
: loggedInView(controller, emit)
|
||||
),
|
||||
];
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
import html from 'choo/html';
|
||||
|
||||
export const loggedInView = (homeController, emit) => {
|
||||
const { __ } = homeController.i18n;
|
||||
|
||||
return [
|
||||
html`<section>
|
||||
<h2>${__('home.logged_in_subtitle')}</h2>
|
||||
<div class="flex one two-700">
|
||||
<div>
|
||||
<div class="card">
|
||||
<header>
|
||||
<h3>${__('home.logged_in_updates')}</h3>
|
||||
<button class="small pseudo pull-right tooltip-left" data-tooltip=${__('interaction.reload')}>
|
||||
<i class="icon-reload"></i>
|
||||
</button>
|
||||
</header>
|
||||
<footer>
|
||||
${homeController.state.loggedIn.updates.map(update => reviewCard(homeController, update))}
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="card">
|
||||
<header>
|
||||
<h3>${__('home.logged_in_interactions')}</h3>
|
||||
<button class="small pseudo pull-right tooltip-left" data-tooltip=${__('interaction.reload')}>
|
||||
<i class="icon-reload"></i>
|
||||
</button>
|
||||
</header>
|
||||
<footer>
|
||||
${homeController.state.loggedIn.interactions.map(interaction => reviewCard(homeController, interaction))}
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>`,
|
||||
];
|
||||
}
|
|
@ -57,7 +57,7 @@ export const loggedOutView = (homeController, emit) => {
|
|||
</button>
|
||||
</header>
|
||||
<footer>
|
||||
${homeController.recentReviews.map(review => reviewCard(homeController, review))}
|
||||
${homeController.state.loggedOut.recentReviews.map(review => reviewCard(homeController, review))}
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -70,7 +70,7 @@ export const loggedOutView = (homeController, emit) => {
|
|||
</button>
|
||||
</header>
|
||||
<footer>
|
||||
${homeController.recentUpdates.map(review => reviewCard(homeController, review))}
|
||||
${homeController.state.loggedOut.recentUpdates.map(update => reviewCard(homeController, update))}
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -16,6 +16,7 @@ export class LoginController extends ViewController {
|
|||
},
|
||||
loginError: '',
|
||||
createError: '',
|
||||
loginMessage: '',
|
||||
createMessage: '',
|
||||
pageMessage: '',
|
||||
isChecking: false,
|
||||
|
@ -47,7 +48,7 @@ export class LoginController extends ViewController {
|
|||
|
||||
validateLogin () {
|
||||
const { __ } = this.i18n;
|
||||
this.state.createError = '';
|
||||
this.state.loginError = '';
|
||||
this.state.isChecking = true;
|
||||
|
||||
this.emit('render', () => {
|
||||
|
@ -60,7 +61,7 @@ export class LoginController extends ViewController {
|
|||
loginEmail,
|
||||
loginPassword,
|
||||
].includes('')) {
|
||||
this.state.createError = __('login.create_required_field_blank');
|
||||
this.state.loginError = __('login.login_required_field_blank');
|
||||
this.state.isChecking = false;
|
||||
this.emit('render');
|
||||
return;
|
||||
|
@ -132,6 +133,7 @@ export class LoginController extends ViewController {
|
|||
return;
|
||||
}
|
||||
|
||||
this.appState.isLoggedIn = true;
|
||||
this.state.loginMessage = __(response.message);
|
||||
this.state.isChecking = false;
|
||||
this.clearLoginForm();
|
||||
|
|
|
@ -6,6 +6,28 @@ export const loginView = (state, emit, i18n) => {
|
|||
const controller = new LoginController(state, emit, i18n);
|
||||
const { __ } = controller.i18n;
|
||||
|
||||
if (controller.appState.isLoggedIn === true) {
|
||||
setTimeout(() => {
|
||||
controller.state.loginMessage = '';
|
||||
emit('pushState', '/')
|
||||
}, 3000);
|
||||
|
||||
return html`<div class="modal">
|
||||
<input type="checkbox" checked>
|
||||
<label class="overlay"></label>
|
||||
|
||||
<article class="success card">
|
||||
<header>
|
||||
${
|
||||
controller.state.loginMessage === ''
|
||||
? __('login.already_logged_in')
|
||||
: controller.state.loginMessage
|
||||
}
|
||||
</header>
|
||||
</article>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
return html`<section>
|
||||
|
||||
${
|
||||
|
|
|
@ -147,16 +147,16 @@ async function routes(fastify, options) {
|
|||
}
|
||||
});
|
||||
|
||||
fastify.get('/api/account/login', async (request, reply) => {
|
||||
fastify.post('/api/account/login', async (request, reply) => {
|
||||
const formDataIsValid = Account.loginDataIsValid(request.body);
|
||||
if (formDataIsValid !== true) {
|
||||
return reply.code(400).send(formDataIsValid);
|
||||
}
|
||||
|
||||
const account = new Account(fastify.models.User);
|
||||
const user = account.validateLogin(request.body.email, request.body.password);
|
||||
const user = await account.validateLogin(request.body.email, request.body.password);
|
||||
|
||||
if (user.error !== true) {
|
||||
if (user.error === true) {
|
||||
return reply.code(400).send(user);
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ async function routes(fastify, options) {
|
|||
})
|
||||
.send({
|
||||
error: false,
|
||||
message: 'api.account_create_success',
|
||||
message: 'api.account_login_success',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -209,11 +209,8 @@ async function routes(fastify, options) {
|
|||
});
|
||||
});
|
||||
|
||||
fastify.get('/api/logout', async (request, reply) => {
|
||||
return reply.clearCookie('token', { path: '/' }).send({
|
||||
error: false,
|
||||
message: 'api._account_logout_success',
|
||||
});
|
||||
fastify.get('/logout', async (request, reply) => {
|
||||
return reply.clearCookie('token', { path: '/' }).redirect('/');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue