Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/Sly777/ran
Browse files Browse the repository at this point in the history
  • Loading branch information
Sly777 committed Jul 22, 2017
2 parents 34b1dd1 + 0a07131 commit 008883e
Show file tree
Hide file tree
Showing 33 changed files with 741 additions and 86 deletions.
2 changes: 2 additions & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ ratings:
- "**.jsx"
exclude_paths:
- node_modules/
- .next/
- .gitattributes
42 changes: 42 additions & 0 deletions .yarnclean
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# test directories
__tests__
test
tests
powered-test

# asset directories
docs
doc
website
images
assets

# examples
example
examples

# code coverage directories
coverage
.nyc_output

# build scripts
Makefile
Gulpfile.js
Gruntfile.js

# configs
.tern-project
.gitattributes
.editorconfig
.*ignore
.eslintrc
.jshintrc
.flowconfig
.documentup.json
.yarn-metadata.json
.*.yml
*.yml

# misc
*.gz
*.md
53 changes: 53 additions & 0 deletions components/AuthFields/index.data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import persist from '../../libraries/persist';

// Actions Naming
export const AUTH_SIGNIN = 'AUTH_SIGNIN';
export const AUTH_SIGNOUT = 'AUTH_SIGNOUT';
export const AUTH_SERVERERROR = 'AUTH_SERVERERROR';

// Initial State
const initialState = {
authenticated: false,
token: null,
error: null
};

// Reducer
const reducer = (state = initialState, action) => {
switch (action.type) {
case AUTH_SIGNIN:
return {
...state,
authenticated: true,
token: action.token,
error: null
};
case AUTH_SIGNOUT:
return { ...state, authenticated: false, token: null, error: null };
case AUTH_SERVERERROR:
return { ...state, authenticated: false, error: action.error };
default:
return state;
}
};

// Actions
const actions = {};

actions.signIn = token => ({ type: AUTH_SIGNIN, token });
actions.signOut = () => ({ type: AUTH_SIGNOUT });

// Discpatchers
const dispatchers = {};

dispatchers.signIn = token => {
persist.willSetAccessToken(token);
return actions.signIn(token);
};

dispatchers.signOut = () => {
persist.willRemoveAccessToken();
return actions.signOut();
};

export { actions, reducer, dispatchers };
31 changes: 31 additions & 0 deletions components/AuthFields/index.gql.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { gql } from 'react-apollo';

export default {};

export const signIn = gql`
mutation signinUser($email: String!, $password: String!) {
signinUser(email: { email: $email, password: $password }) {
token
}
}
`;

export const createUser = gql`
mutation createUser(
$firstName: String!
$lastName: String!
$email: String!
$password: String!
) {
createUser(
firstName: $firstName
lastName: $lastName
authProvider: { email: { email: $email, password: $password } }
) {
id
}
signinUser(email: { email: $email, password: $password }) {
token
}
}
`;
75 changes: 75 additions & 0 deletions components/AuthFields/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from 'react';
import styled from 'styled-components';
import PropTypes from 'prop-types';

const AuthFields = props => {
const {
selectFields,
fields,
handleTouch,
handleChange,
handleSubmit,
touched,
errors
} = props;
const mapFields = fields.map(field =>
<div key={field.key}>
<input
name={field.attr.name}
type={field.attr.type}
placeholder={field.attr.label}
onChange={handleChange}
onFocus={handleTouch}
/>
{errors &&
<div>
{errors[field.attr.name]}
</div>}
</div>
);
const authMethod =
(selectFields === 'signinFields' && 'Sign In') || 'Sign Up';
return (
<div>
<h1>
{authMethod}
</h1>
<form>
{mapFields}
<br />
<button
onClick={handleSubmit}
style={!touched ? { opacity: 0.5 } : { opacity: 1 }}
disabled={!touched}
>
{authMethod}
</button>
</form>
</div>
);
};

AuthFields.propTypes = {
selectFields: PropTypes.string.isRequired,
fields: PropTypes.array.isRequired,
handleTouch: PropTypes.func.isRequired,
handleChange: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
touched: PropTypes.bool.isRequired,
errors: PropTypes.object.isRequired
};

export default styled(AuthFields)`
border-bottom: 1px solid #ececec;
padding-bottom: 20px;
margin-bottom: 20px;
> h1 {
font-size: 20px;
}
>input {
display: block;
margin-bottom: 10px;
}
`;
28 changes: 28 additions & 0 deletions components/AuthFields/index.validation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { isStringEmpty, isEmail } from '../../libraries/validations';

export default values => {
const errors = {};
const touched = true;

if (isStringEmpty(values.firstName)) {
errors.firstName = 'Required';
}

if (isStringEmpty(values.lastName)) {
errors.lastName = 'Required';
}

if (isStringEmpty(values.email)) {
errors.email = 'Required';
} else if (!isEmail(values.email)) {
errors.email = 'Invalid email address';
}

if (isStringEmpty(values.password)) {
errors.password = 'Required';
} else if (values.password.length <= 3) {
errors.password = 'Must be at least 4 characters';
}

return { errors, touched };
};
17 changes: 0 additions & 17 deletions components/Header.js

This file was deleted.

14 changes: 14 additions & 0 deletions components/Header/index.data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { connect } from 'react-redux';
import { actions } from '../SignInForm/index.data';

const mapStateToProps = state => ({
authenticated: state.auth.authenticated
});

const mapDispatchToProps = dispatch => ({
logout() {
dispatch(actions.signout());
}
});

export default comp => connect(mapStateToProps, mapDispatchToProps)(comp);
28 changes: 28 additions & 0 deletions components/Header/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import PropTypes from 'prop-types';
import styled from 'styled-components';
import LinkList from '../LinkList';
import connect from './index.data';

const Header = ({ className, pathname, authenticated, logout }) =>
<header className={className}>
<LinkList
pathname={pathname}
authenticated={authenticated}
logout={logout}
/>
</header>;

Header.defaultProps = {
authenticated: false
};

Header.propTypes = {
pathname: PropTypes.string.isRequired,
className: PropTypes.string.isRequired,
authenticated: PropTypes.bool.isRequired,
logout: PropTypes.func.isRequired
};

export default connect(styled(Header)`
margin-bottom: 25px;
`);
29 changes: 27 additions & 2 deletions components/LinkList.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,31 @@ import PropTypes from 'prop-types';
import styled from 'styled-components';
import { Router } from '../routes';

const LinkList = ({ className, pathname }) =>
const LinkList = ({ className, pathname, authenticated, logout }) =>
<nav className={className}>
<Link prefetch href="/">
<a className={pathname === '/' && 'is-active'}>Main Page</a>
</Link>
<Link prefetch route={Router.linkPage('create')}>
<a className={pathname === '/create_post' && 'is-active'}>Create</a>
</Link>
{!authenticated &&
<Link prefetch route={Router.linkPage('signin')}>
<a className={pathname === '/sign_in' && 'is-active'}>SignIn</a>
</Link>}
{!authenticated &&
<Link prefetch route={Router.linkPage('signup')}>
<a className={pathname === '/sign_up' && 'is-active'}>SignUp</a>
</Link>}
{authenticated &&
<button
role="link"
href="#"
onClick={() => logout()}
className={pathname === '/sign_up' && 'is-active'}
>
LogOut
</button>}
<a
href="https://github.com/Sly777/ran"
rel="noopener noreferrer"
Expand All @@ -22,17 +39,25 @@ const LinkList = ({ className, pathname }) =>

LinkList.propTypes = {
pathname: PropTypes.string.isRequired,
className: PropTypes.string.isRequired
className: PropTypes.string.isRequired,
authenticated: PropTypes.bool.isRequired,
logout: PropTypes.func.isRequired
};

export default styled(LinkList)`
a {
font-size: 14px;
margin-right: 15px;
text-decoration: none;
cursor: pointer;
&.is-active {
text-decoration: underline;
}
}
button {
display: inline-block;
margin-right: 15px;
cursor: pointer;
}
`;
29 changes: 29 additions & 0 deletions components/SignInForm/index.data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { graphql } from 'react-apollo';
import { connect } from 'react-redux';
import { dispatchers } from '../AuthFields/index.data';
import { signIn as signInGql } from '../AuthFields/index.gql';

function signinUserWrapper(AuthForm) {
const signinUserWithData = graphql(signInGql, {
props: ({ mutate }) => ({
signinUser: ({ email, password }) =>
mutate({
variables: { email, password }
})
})
})(AuthForm);

const mapDispatchToProps = dispatch => ({
signIn(token) {
dispatch(dispatchers.signIn(token));
}
});

const signinUserWithDataAndDispatch = connect(null, mapDispatchToProps)(
signinUserWithData
);

return signinUserWithDataAndDispatch;
}

export default signinUserWrapper;
Loading

0 comments on commit 008883e

Please sign in to comment.