Implement login
This commit is contained in:
parent
01ed5b6109
commit
738fc96359
@ -1,6 +1,11 @@
|
|||||||
|
@import "themes/form/foundation";
|
||||||
|
@import "themes/form/labels/linus";
|
||||||
|
@import "themes/form/validation/linus";
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timer {
|
.timer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -10,3 +15,25 @@ h1 {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
padding: 40px;
|
||||||
|
border: 1px solid black;
|
||||||
|
h1:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
z-index: 9999;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
background: white;
|
||||||
|
transform: translateX(-50%) translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
@import "variables";
|
||||||
|
|||||||
45
assets/less/variables.less
Normal file
45
assets/less/variables.less
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
@base-font-size: 16px;
|
||||||
|
|
||||||
|
@default-float: left;
|
||||||
|
@opposite-direction: right;
|
||||||
|
// @text-direction: left;
|
||||||
|
|
||||||
|
|
||||||
|
@base-color: #671637;
|
||||||
|
@color-1: #00002d;
|
||||||
|
@color-2: #0066c6;
|
||||||
|
@color-3: #0066c6;
|
||||||
|
@color-message: #333;
|
||||||
|
@color-error: @base-color;
|
||||||
|
@color-success: @color-1;
|
||||||
|
|
||||||
|
|
||||||
|
// This needs to be a px value since rem and em-calc use it. It is translated
|
||||||
|
// to a percante unit for html and body font-sizing like so: strip-unit(@base-font-size) / 16 * 100%;
|
||||||
|
@base-line-height: 1.6;
|
||||||
|
@base-line-height-computed: @base-line-height * 1rem;
|
||||||
|
|
||||||
|
@body-font-color: #fff;
|
||||||
|
@body-font-family: 'Open Sans', sans-serif;
|
||||||
|
@body-font-weight: 300;
|
||||||
|
@body-font-style: normal;
|
||||||
|
@body-bg: @color-1;
|
||||||
|
|
||||||
|
@font-smoothing: subpixel-antialiased;
|
||||||
|
|
||||||
|
@input-padding: 14px 12px;
|
||||||
|
@input-font-weight: 300;
|
||||||
|
|
||||||
|
// Colors
|
||||||
|
// @form-valid-color: @base-color;
|
||||||
|
// @form-invalid-color: #ffae00;
|
||||||
|
@form-valid-color: @color-success;
|
||||||
|
@form-invalid-color: @color-error;
|
||||||
|
@form-icon-width: 20px;
|
||||||
|
@form-icon-height: 20px;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Custom
|
||||||
|
//
|
||||||
|
|
||||||
33
client/actions/ui.js
Normal file
33
client/actions/ui.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
export const SHOW_LOGIN_MODAL = 'SHOW_LOGIN_MODAL';
|
||||||
|
|
||||||
|
export function showLoginModal() {
|
||||||
|
return {
|
||||||
|
type: SHOW_LOGIN_MODAL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const HIDE_LOGIN_MODAL = 'HIDE_LOGIN_MODAL';
|
||||||
|
|
||||||
|
export function hideLoginModal() {
|
||||||
|
return {
|
||||||
|
type: HIDE_LOGIN_MODAL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SHOW_FLAG_FORM = 'SHOW_FLAG_FORM';
|
||||||
|
|
||||||
|
export function showFlagForm(id) {
|
||||||
|
return {
|
||||||
|
type: SHOW_FLAG_FORM,
|
||||||
|
id: id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const HIDE_FLAG_FORM = 'HIDE_FLAG_FORM';
|
||||||
|
|
||||||
|
export function hideFlagForm(id) {
|
||||||
|
return {
|
||||||
|
type: HIDE_FLAG_FORM,
|
||||||
|
id: id,
|
||||||
|
}
|
||||||
|
}
|
||||||
45
client/actions/user.js
Normal file
45
client/actions/user.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { hideLoginModal } from './ui';
|
||||||
|
|
||||||
|
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
|
||||||
|
|
||||||
|
export const LOGIN_FAILURE = 'LOGIN_FAILURE';
|
||||||
|
|
||||||
|
export function login(credentials) {
|
||||||
|
return (dispatch) => {
|
||||||
|
fetch('/auth/local', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(credentials),
|
||||||
|
credentials: 'same-origin',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((json) => {
|
||||||
|
dispatch(hideLoginModal());
|
||||||
|
dispatch({
|
||||||
|
type: LOGIN_SUCCESS,
|
||||||
|
payload: json,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => dispatch({
|
||||||
|
type: LOGIN_FAILURE,
|
||||||
|
err,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LOGOUT = 'LOGOUT';
|
||||||
|
|
||||||
|
export function logout() {
|
||||||
|
return (dispatch) => {
|
||||||
|
fetch('/auth/logout', {
|
||||||
|
credentials: 'same-origin',
|
||||||
|
})
|
||||||
|
.then(() => dispatch({
|
||||||
|
type: LOGOUT,
|
||||||
|
}))
|
||||||
|
.catch((err) => console.error('error logging out', err));
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -12,4 +12,4 @@ if (Notification.permission !== 'granted') {
|
|||||||
|
|
||||||
render((
|
render((
|
||||||
<Layout />
|
<Layout />
|
||||||
), null, document.getElementById('app'));
|
), document.body);
|
||||||
|
|||||||
67
client/components/Form.jsx
Normal file
67
client/components/Form.jsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { h, Component } from 'preact';
|
||||||
|
|
||||||
|
// modules > lodas
|
||||||
|
import set from 'set-value';
|
||||||
|
import { forEach, bindAll } from 'lowline';
|
||||||
|
|
||||||
|
// import Input from '../components/Input.jsx'
|
||||||
|
|
||||||
|
export default class Form extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
bindAll(this, ['register', 'validate']);
|
||||||
|
|
||||||
|
this.inputs = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
const attrs = {};
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
for (let name in this.inputs) {
|
||||||
|
const input = this.inputs[name];
|
||||||
|
|
||||||
|
const value = input.getValue();
|
||||||
|
|
||||||
|
if (value) set(attrs, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
validate() {
|
||||||
|
let errorCount = 0;
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
for (let name in this.inputs) {
|
||||||
|
const input = this.inputs[name];
|
||||||
|
|
||||||
|
if (!input.isValid()) {
|
||||||
|
if (errorCount === 0) {
|
||||||
|
input.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorCount += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !errorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
register(name) {
|
||||||
|
return (input) => {
|
||||||
|
if (input) {
|
||||||
|
input.validation = this.validation[input.props.name];
|
||||||
|
|
||||||
|
this.inputs[name] = input;
|
||||||
|
} else {
|
||||||
|
delete this.inputs[name];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
forEach(this.inputs, (input) => input.reset());
|
||||||
|
}
|
||||||
|
}
|
||||||
98
client/components/FormElement.jsx
Normal file
98
client/components/FormElement.jsx
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import { h, Component } from 'preact';
|
||||||
|
|
||||||
|
import { bindAll, startCase } from 'lowline';
|
||||||
|
|
||||||
|
export default class Input extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
bindAll(this, ['reset', 'validate', 'onChange', 'onBlur', 'onFocus']);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
value: this.props.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onChange(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (document.activeElement !== e.target && !e.target.value) return;
|
||||||
|
|
||||||
|
this.setValue(e.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlur(e) {
|
||||||
|
this.setState({
|
||||||
|
focus: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setValue(e.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
onFocus() {
|
||||||
|
this.setState({
|
||||||
|
focus: true,
|
||||||
|
touched: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
this.input.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid() {
|
||||||
|
this.setValue(this.input.value);
|
||||||
|
|
||||||
|
return !this.state.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
return this.state.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.setState({
|
||||||
|
value: this.props.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(value) {
|
||||||
|
value = value || undefined;
|
||||||
|
|
||||||
|
const result = this.validate(value);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
error: result !== true ? typeof result === 'string' && result || 'Error!' : false,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(value) {
|
||||||
|
const validation = this.validation;
|
||||||
|
|
||||||
|
if (!validation) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validation.required) {
|
||||||
|
if (value == null || value === '') {
|
||||||
|
return typeof validation.required === 'string' ? validation.required : 'Required';
|
||||||
|
}
|
||||||
|
} else if (value == null || value === '') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validation.tests) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < validation.tests.length; i += 1) {
|
||||||
|
const [fnc, msg] = validation.tests[i];
|
||||||
|
|
||||||
|
if (!fnc(value)) return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
client/components/Input.jsx
Normal file
38
client/components/Input.jsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { h, Component } from 'preact';
|
||||||
|
|
||||||
|
import { omit } from 'lowline';
|
||||||
|
|
||||||
|
import FormElement from './FormElement.jsx';
|
||||||
|
|
||||||
|
export default class Input extends FormElement {
|
||||||
|
render({ type = 'text', disabled, placeholder }, state = {}) {
|
||||||
|
const classes = Object.assign({
|
||||||
|
'field-container': true,
|
||||||
|
empty: !state.value,
|
||||||
|
filled: state.value,
|
||||||
|
focus: state.focus,
|
||||||
|
invalid: state.error,
|
||||||
|
touched: state.touched,
|
||||||
|
valid: state.value && !state.error,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={classes}>
|
||||||
|
<label className="placeholder">{placeholder}</label>
|
||||||
|
<input
|
||||||
|
disabled={disabled}
|
||||||
|
onBlur={this.onBlur}
|
||||||
|
onChange={this.onChange}
|
||||||
|
onFocus={this.onFocus}
|
||||||
|
onInput={this.onChange}
|
||||||
|
placeholder={placeholder}
|
||||||
|
ref={(input) => { this.input = input; }}
|
||||||
|
type={type}
|
||||||
|
value={state.value}
|
||||||
|
/>
|
||||||
|
<label class="icon" />
|
||||||
|
{state.error && <label class="error">{state.error}</label>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,13 +1,17 @@
|
|||||||
import { h } from 'preact';
|
import { h } from 'preact';
|
||||||
|
|
||||||
import Timer from './Timer.jsx';
|
import Timer from './Timer.jsx';
|
||||||
|
import LoginForm from './LoginForm.jsx';
|
||||||
|
import User from './User.jsx';
|
||||||
|
|
||||||
export default () => (
|
export default () => (
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<main>
|
<main>
|
||||||
<h1>Pomodoro Time!</h1>
|
<h1>Pomodoro Time!</h1>
|
||||||
|
<User />
|
||||||
<Timer type="pomodoro" time={25 * 60 * 1000} />
|
<Timer type="pomodoro" time={25 * 60 * 1000} />
|
||||||
<Timer type="break" time={5 * 60 * 1000} />
|
<Timer type="break" time={5 * 60 * 1000} />
|
||||||
|
<LoginForm />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
67
client/components/LoginForm.jsx
Normal file
67
client/components/LoginForm.jsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { h, Component } from 'preact';
|
||||||
|
import isEmail from 'validator/lib/isEmail';
|
||||||
|
|
||||||
|
import store from '../store';
|
||||||
|
|
||||||
|
import Form from './Form.jsx';
|
||||||
|
import Input from './Input.jsx';
|
||||||
|
|
||||||
|
import { login } from '../actions/user';
|
||||||
|
import { hideLoginModal } from '../actions/ui';
|
||||||
|
|
||||||
|
export default class LoginForm extends Form {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.validation = {
|
||||||
|
email: {
|
||||||
|
required: true,
|
||||||
|
tests: [
|
||||||
|
[isEmail, 'Not a valid email'],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
className: ['login-form', 'modal', 'enter', 'animate'],
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onSubmit = this.onSubmit.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
this.unsubscribe = store.subscribe(() => this.forceUpdate());
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!this.validate()) return;
|
||||||
|
|
||||||
|
store.dispatch(login(this.toJSON()));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { ui } = store.getState();
|
||||||
|
|
||||||
|
return ui.showLoginModal ? (
|
||||||
|
<form
|
||||||
|
className={this.state.className.join(' ')}
|
||||||
|
onSubmit={this.onSubmit}
|
||||||
|
>
|
||||||
|
<button type="button" onClick={() => store.dispatch(hideLoginModal())}>Close</button>
|
||||||
|
<h1>Login</h1>
|
||||||
|
<Input ref={this.register('email')} type="text" name="email" placeholder="Email" />
|
||||||
|
<Input ref={this.register('password')} type="password" name="password" placeholder="Password" />
|
||||||
|
<button>Login</button>
|
||||||
|
</form>
|
||||||
|
) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -85,6 +85,7 @@ export default class Timer extends Component {
|
|||||||
fetch('/api/pomodoros', {
|
fetch('/api/pomodoros', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
|
credentials: 'same-origin',
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|||||||
29
client/components/User.jsx
Normal file
29
client/components/User.jsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { h, Component } from 'preact';
|
||||||
|
|
||||||
|
import store from '../store';
|
||||||
|
|
||||||
|
import { logout } from '../actions/user';
|
||||||
|
import { showLoginModal } from '../actions/ui';
|
||||||
|
|
||||||
|
export default class User extends Component {
|
||||||
|
componentWillMount() {
|
||||||
|
this.unsubscribe = store.subscribe(() => this.forceUpdate());
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { user } = store.getState();
|
||||||
|
|
||||||
|
return (user &&
|
||||||
|
<div>
|
||||||
|
<div>Logged in as {user.email}</div>
|
||||||
|
<button onClick={() => store.dispatch(logout())}>Logout</button>
|
||||||
|
</div> ||
|
||||||
|
<div>
|
||||||
|
<button onClick={() => store.dispatch(showLoginModal())}>Login</button>
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,4 @@
|
|||||||
import Layout from './components/Layout.jsx';
|
export default ({ INITIAL_STATE, css, js }) => (
|
||||||
|
|
||||||
export default ({ css, js }) => (
|
|
||||||
'<!doctype html>' + (
|
'<!doctype html>' + (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
@ -16,8 +14,9 @@ export default ({ css, js }) => (
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<Layout />
|
<script>
|
||||||
|
var INITIAL_STATE = {INITIAL_STATE};
|
||||||
|
</script>
|
||||||
<script src={`/js/app${js ? js.suffix : ''}.js`} />
|
<script src={`/js/app${js ? js.suffix : ''}.js`} />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
9
client/reducers/root.js
Normal file
9
client/reducers/root.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { combineReducers } from 'redux';
|
||||||
|
|
||||||
|
import user from './user';
|
||||||
|
import ui from './ui';
|
||||||
|
|
||||||
|
export default combineReducers({
|
||||||
|
user,
|
||||||
|
ui,
|
||||||
|
});
|
||||||
24
client/reducers/ui.js
Normal file
24
client/reducers/ui.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {
|
||||||
|
SHOW_LOGIN_MODAL,
|
||||||
|
HIDE_LOGIN_MODAL,
|
||||||
|
} from '../actions/ui';
|
||||||
|
|
||||||
|
const defaultState = {
|
||||||
|
showLoginModal: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default (state = defaultState, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case SHOW_LOGIN_MODAL:
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
showLoginModal: true,
|
||||||
|
});
|
||||||
|
case HIDE_LOGIN_MODAL:
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
showLoginModal: false,
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
13
client/reducers/user.js
Normal file
13
client/reducers/user.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { LOGIN_SUCCESS, LOGOUT } from '../actions/user';
|
||||||
|
|
||||||
|
export default (state = null, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case LOGIN_SUCCESS:
|
||||||
|
return action.payload;
|
||||||
|
case LOGOUT:
|
||||||
|
return null;
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
16
client/store.js
Normal file
16
client/store.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import thunkMiddleware from 'redux-thunk';
|
||||||
|
import createLogger from 'redux-logger';
|
||||||
|
import { createStore, applyMiddleware } from 'redux';
|
||||||
|
|
||||||
|
const loggerMiddleware = createLogger();
|
||||||
|
|
||||||
|
import rootReducer from './reducers/root';
|
||||||
|
|
||||||
|
export default createStore(
|
||||||
|
rootReducer,
|
||||||
|
INITIAL_STATE,
|
||||||
|
applyMiddleware(
|
||||||
|
thunkMiddleware,
|
||||||
|
loggerMiddleware
|
||||||
|
)
|
||||||
|
);
|
||||||
@ -26,6 +26,7 @@
|
|||||||
"express": "^4.14.0",
|
"express": "^4.14.0",
|
||||||
"express-service-errors": "github:thecodebureau/express-service-errors",
|
"express-service-errors": "github:thecodebureau/express-service-errors",
|
||||||
"express-session": "^1.14.2",
|
"express-session": "^1.14.2",
|
||||||
|
"get-value": "^2.0.6",
|
||||||
"hyperscript-jsx": "0.0.2",
|
"hyperscript-jsx": "0.0.2",
|
||||||
"jsx-node": "^0.1.0",
|
"jsx-node": "^0.1.0",
|
||||||
"lodash": "^4.16.6",
|
"lodash": "^4.16.6",
|
||||||
@ -40,7 +41,13 @@
|
|||||||
"passport": "^0.3.2",
|
"passport": "^0.3.2",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"preact": "^6.4.0",
|
"preact": "^6.4.0",
|
||||||
"require-dir": "^0.3.1"
|
"redux": "^3.6.0",
|
||||||
|
"redux-logger": "^2.7.4",
|
||||||
|
"redux-thunk": "^2.1.0",
|
||||||
|
"require-dir": "^0.3.1",
|
||||||
|
"set-value": "^0.4.0",
|
||||||
|
"spineless": "^0.1.2",
|
||||||
|
"validator": "^6.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^6.5.1",
|
"autoprefixer": "^6.5.1",
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const bootstrap = require('midwest/factories/bootstrap');
|
||||||
const masterTemplate = require('../../build/master.jsx');
|
const masterTemplate = require('../../build/master.jsx');
|
||||||
|
|
||||||
const router = new (require('express')).Router();
|
const router = new (require('express')).Router();
|
||||||
@ -7,7 +8,9 @@ const router = new (require('express')).Router();
|
|||||||
router.get('/', (req, res, next) => {
|
router.get('/', (req, res, next) => {
|
||||||
res.template = masterTemplate;
|
res.template = masterTemplate;
|
||||||
|
|
||||||
|
res.locals.user = req.user;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
}, bootstrap());
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user