Skip to content

Commit

Permalink
feat(client/login): implement login
Browse files Browse the repository at this point in the history
  • Loading branch information
sepehrhosseini committed Feb 2, 2020
1 parent 1ac7006 commit 70333b0
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 12 deletions.
34 changes: 33 additions & 1 deletion client/app/containers/LoginPage/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,42 @@
*
*/

import { DEFAULT_ACTION } from './constants';
import Actions, { DEFAULT_ACTION } from './constants';

export function defaultAction() {
return {
type: DEFAULT_ACTION,
};
}

export function loginRequest() {
return {
type: Actions.LOGIN.REQUEST,
};
}

export function loginSucceed() {
return {
type: Actions.LOGIN.SUCCEED,
};
}

export function loginFailed() {
return {
type: Actions.LOGIN.FAILED,
};
}

export function inputEmailChanged({ email }) {
return {
type: Actions.INPUT.EMAIL_CHANGED,
email,
};
}

export function inputPasswordChanged({ password }) {
return {
type: Actions.INPUT.PASSWORD_CHANGED,
password,
};
}
12 changes: 12 additions & 0 deletions client/app/containers/LoginPage/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,15 @@
*/

export const DEFAULT_ACTION = 'app/LoginPage/DEFAULT_ACTION';

export default {
LOGIN: {
REQUEST: 'app/LoginPage/LOGIN_REQUEST',
SUCCEED: 'app/LoginPage/LOGIN_SUCCEED',
FAILED: 'app/LoginPage/LOGIN_FAILED',
},
INPUT: {
EMAIL_CHANGED: 'app/LoginPage/EMAIL_CHANGED',
PASSWORD_CHANGED: 'app/LoginPage/PASSWORD_CHANGED',
},
};
53 changes: 46 additions & 7 deletions client/app/containers/LoginPage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,35 @@ import Typography from '@material-ui/core/Typography';

import { useInjectSaga } from 'utils/injectSaga';
import { useInjectReducer } from 'utils/injectReducer';
import makeSelectLoginPage from './selectors';
import makeSelectLoginPage, {
makeSelectLoginEmail,
makeSelectLoginPassword,
} from './selectors';
import reducer from './reducer';
import saga from './saga';
import messages from './messages';
import {
loginRequest,
inputEmailChanged,
inputPasswordChanged,
} from './actions';

import { Wrapper, Card, TextField, FormRow, CardHeader } from './styled';

export function LoginPage() {
export function LoginPage({ login, dispatch, email, password }) {
useInjectReducer({ key: 'loginPage', reducer });
useInjectSaga({ key: 'loginPage', saga });

const formSubmit = e => {
e.preventDefault();
login();
};

return (
<div>
<Helmet>
<title>Login</title>
<meta name="description" content="Login to currency rate profile" />
<meta name="description" content="Login to Currency Rate profile" />
</Helmet>
<Wrapper>
<Card>
Expand All @@ -43,21 +56,43 @@ export function LoginPage() {
Currency Rate
</Typography>
</CardHeader>
<form noValidate>
<form onSubmit={formSubmit} noValidate>
<Grid container>
<Grid item xs={12}>
<FormRow>
<TextField label="Email" />
<TextField
label="Email"
value={email}
onChange={e =>
dispatch(inputEmailChanged({ email: e.target.value }))
}
/>
</FormRow>
</Grid>
<Grid item xs={12}>
<FormRow>
<TextField label="Password" />
<TextField
label="Password"
value={password}
type="password"
onChange={e =>
dispatch(
inputPasswordChanged({
password: e.target.value,
}),
)
}
/>
</FormRow>
</Grid>
<Grid item xs={12}>
<FormRow>
<Button variant="contained" color="primary">
<Button
variant="contained"
color="primary"
type="submit"
onClick={formSubmit}
>
Login
</Button>
<Button
Expand All @@ -79,15 +114,19 @@ export function LoginPage() {

LoginPage.propTypes = {
dispatch: PropTypes.func.isRequired,
login: PropTypes.func.isRequired,
};

const mapStateToProps = createStructuredSelector({
loginPage: makeSelectLoginPage(),
email: makeSelectLoginEmail(),
password: makeSelectLoginPassword(),
});

function mapDispatchToProps(dispatch) {
return {
dispatch,
login: () => dispatch(loginRequest()),
};
}

Expand Down
25 changes: 22 additions & 3 deletions client/app/containers/LoginPage/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,33 @@
*
*/
import produce from 'immer';
import { DEFAULT_ACTION } from './constants';
import Actions, { DEFAULT_ACTION } from './constants';

export const initialState = {};
export const initialState = {
isLoading: false,
email: '',
password: '',
};

/* eslint-disable default-case, no-param-reassign */
const loginPageReducer = (state = initialState, action) =>
produce(state, (/* draft */) => {
produce(state, draft => {
switch (action.type) {
case Actions.INPUT.EMAIL_CHANGED:
draft.email = action.email;
break;
case Actions.INPUT.PASSWORD_CHANGED:
draft.password = action.password;
break;
case Actions.LOGIN.REQUEST:
draft.isLoading = true;
break;
case Actions.LOGIN.SUCCEED:
draft.isLoading = false;
break;
case Actions.LOGIN.FAILED:
draft.isLoading = false;
break;
case DEFAULT_ACTION:
break;
}
Expand Down
17 changes: 16 additions & 1 deletion client/app/containers/LoginPage/saga.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
// import { take, call, put, select } from 'redux-saga/effects';
import { take, call, put, select, takeEvery } from 'redux-saga/effects';
import { loginSucceed, loginFailed } from './actions';
import Actions from './constants';
import { makeSelectLoginEmail, makeSelectLoginPassword } from './selectors';

function* login() {
try {
const email = yield select(makeSelectLoginEmail());
const password = yield select(makeSelectLoginPassword());

yield put(loginSucceed());
} catch (e) {
yield put(loginFailed());
}
}

// Individual exports for testing
export default function* loginPageSaga() {
yield takeEvery(Actions.LOGIN.REQUEST, login);
// See example in containers/HomePage/saga.js
}
18 changes: 18 additions & 0 deletions client/app/containers/LoginPage/selectors.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createSelector } from 'reselect';
import { get } from 'lodash';
import { initialState } from './reducer';

/**
Expand All @@ -11,6 +12,11 @@ const selectLoginPageDomain = state => state.loginPage || initialState;
* Other specific selectors
*/

const selectLoginEmail = state =>
get(state, 'loginPage.email', initialState.email);
const selectLoginPassword = state =>
get(state, 'loginPage.password', initialState.password);

/**
* Default selector used by LoginPage
*/
Expand All @@ -21,5 +27,17 @@ const makeSelectLoginPage = () =>
substate => substate,
);

export const makeSelectLoginEmail = () =>
createSelector(
selectLoginEmail,
substate => substate,
);

export const makeSelectLoginPassword = () =>
createSelector(
selectLoginPassword,
substate => substate,
);

export default makeSelectLoginPage;
export { selectLoginPageDomain };

0 comments on commit 70333b0

Please sign in to comment.