WIP Frontend structure & authentication.

This commit is contained in:
Ahmed Bouhuolia
2020-02-17 00:15:07 +02:00
parent b3849e55e9
commit e5c78fe555
56 changed files with 3539 additions and 322 deletions

View File

@@ -0,0 +1,28 @@
import React from 'react';
import PropTypes from 'prop-types';
import {IntlProvider} from 'react-intl';
// import {Switch} from 'react-router-dom';
import PrivateRoute from 'components/PrivateRoute';
import Authentication from 'components/Authentication';
import Dashboard from 'components/Dashboard/Dashboard';
import messages from 'lang/en';
import 'style/App.scss';
function App(props) {
return (
<IntlProvider locale={props.locale} messages={messages}>
<div className="App">
<Authentication isAuthenticated={true} />
<PrivateRoute isAuthenticated={true} component={Dashboard} />
</div>
</IntlProvider>
);
}
App.defaultProps = {
locale: 'en',
};
App.propTypes = {
locale: PropTypes.string,
};
export default App;

View File

@@ -0,0 +1,27 @@
import React from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';
import authenticationRoutes from 'routes/authentication';
export default function({ isAuthenticated =false, ...rest }) {
const to = {pathname: '/dashboard/homepage'};
return isAuthenticated ?
(
<Redirect to={to} />
) : (
<Switch>
<div class="authentication-page">
<div class="authentication-page__form-wrapper">
{ authenticationRoutes.map((route, index) => (
<Route
key={index}
path={route.path}
exact={route.exact}
component={route.component}
/>
))}
</div>
</div>
</Switch>
);
}

View File

@@ -0,0 +1,15 @@
import React from 'react';
import {Route} from 'react-router-dom';
import Sidebar from 'components/Sidebar/Sidebar';
import DashboardContent from 'components/Dashboard/DashboardContent';
export default function() {
return (
<div className="dashboard" id="dashboard">
<Route pathname="/dashboard/">
<Sidebar />
<DashboardContent />
</Route>
</div>
)
}

View File

@@ -0,0 +1,11 @@
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import dashboardRoutes from 'routes/dashboard'
export default function() {
return (
<div className="dashboard-content" id="dashboard">
<h2>dashboard</h2>
</div>
)
}

View File

@@ -1,18 +0,0 @@
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import dashboardRoutes from 'routes/dashboard'
export default function() {
return (
<Switch>
{ dashboardRoutes.map((route, index) => (
<Route
key={index}
path={route.path}
exact={route.exact}
component={route.component}
/>
))}
</Switch>
)
}

View File

@@ -0,0 +1,33 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Route, Redirect } from 'react-router-dom';
const propTypes = {
isAuthenticated: PropTypes.bool,
component: PropTypes.func.isRequired
};
function PrivateRoute({
component: Component,
isAuthenticated = false,
...rest
}) {
return (
<Route
{...rest}
render={_props =>
isAuthenticated ? (<Component {..._props} />) :
(
<Redirect
to={{
pathname: '/auth/login',
}}
/>
)}
/>
);
}
PrivateRoute.propTypes = propTypes;
export default PrivateRoute;

View File

@@ -1,9 +0,0 @@
export default function() {
return (
<div class="sidebar" id="sidebar">
</div>
)
};

View File

@@ -1,19 +0,0 @@
import React from 'react';
export default function() {
return (
<div class="sidebar__head">
<div class="sidebar__head-logo">
</div>
<div class="sidebar__head-company-meta">
<span class="comapny-name">
</span>
<span class="company-meta"></span>
</div>
</div>
);
};

View File

@@ -1,30 +0,0 @@
import React from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
} from 'react-router-dom';
import SidebarContainer from './SidebarContainer';
import SidebarHead from './SidebarHead';
import sidebarRoutes from '../../routes/sidebar';
export default function Sidebar() {
return (
<SidebarContainer>
<SidebarHead />
<div className="sidebar__menu">
<Menu>
{ sidebarRoutes.map((route, index) => (
<Route
key={index}
path={route.path}
exact={route.exact}
children={<route.sidebar />}
/>
))}
</Menu>
</div>
</SidebarContainer>
)
}

View File

@@ -0,0 +1,16 @@
import React from 'react';
import SidebarContainer from 'components/Sidebar/SidebarContainer';
import SidebarHead from 'components/Sidebar/SidebarHead';
import SidebarMenu from 'components/Sidebar/SidebarMenu';
export default function Sidebar() {
return (
<SidebarContainer>
<SidebarHead />
<div className="sidebar__menu">
<SidebarMenu />
</div>
</SidebarContainer>
)
}

View File

@@ -0,0 +1,9 @@
import React from 'react';
export default function SidebarContainer(props) {
return (
<div className="sidebar" id="sidebar">
{props.children}
</div>
)
}

View File

@@ -0,0 +1,19 @@
import React from 'react';
export default function() {
return (
<div className="sidebar__head">
<div className="sidebar__head-logo">
</div>
<div className="sidebar__head-company-meta">
<span className="comapny-name">
</span>
<span className="company-meta"></span>
</div>
</div>
);
};

View File

@@ -0,0 +1,21 @@
import React from 'react';
import {Menu, MenuItem, MenuDivider} from "@blueprintjs/core";
import sidebarMenuList from 'config/sidebarMenu';
export default function SidebarMenu() {
const items = sidebarMenuList.map((item) =>
(item.divider) ?
<MenuDivider
title={item.title} /> :
<MenuItem
icon={item.icon}
text={item.text}
label={item.label}
disabled={item.disabled} />
);
return (
<Menu className="sidebar-menu">
{items}
</Menu>
)
};

View File

@@ -0,0 +1,21 @@
export default [
{
divider: true,
},
{
icon: 'cut',
text: 'cut',
label: '⌘C',
disabled: false,
children: [
{
icon: 'cut',
text: 'cut',
label: '⌘C',
disabled: false,
}
]
},
]

View File

@@ -0,0 +1,45 @@
import * as React from "react";
import {useForm} from 'react-hook-form';
import {Link, Redirect} from 'react-router-dom';
import {Button, InputGroup} from "@blueprintjs/core";
import {FormattedMessage} from 'react-intl';
export default function Login() {
const { register, handleSubmit } = useForm()
const onSubmit = () => {};
return (
<div class="login-page">
<form onSubmit={handleSubmit(onSubmit)}>
<InputGroup
leftIcon="user"
placeholder={<FormattedMessage id="email_or_phone_number" />}
large={true}
ref={register({ required: true })}
className="input-group--email-phone-number"
htmlProps={{name: 'email_or_phone_number'}}
/>
<InputGroup
leftIcon="info-sign"
placeholder={<FormattedMessage id="password" />}
large={true}
ref={register({ required: true })}
htmlProps={{name: 'password'}}
className="input-group--password"
/>
<Button
fill={true}
large={true}>
<FormattedMessage id="login" />
</Button>
</form>
<div class="authentication-page__footer">
<Link to="/reset_password"><FormattedMessage id="reset_password" /></Link>
</div>
</div>
)
}

View File

@@ -0,0 +1,29 @@
import * as React from "react";
import { Link } from 'react-router-dom';
import {Button, InputGroup} from "@blueprintjs/core";
import { FormattedMessage } from 'react-intl';
export default function Login() {
return (
<div class="login-page">
<form>
<InputGroup
leftIcon="user"
placeholder={<FormattedMessage id="email_or_phone_number" />}
large={true}
className="input-group--email"
/>
<Button
fill={true}
large={true}>
<FormattedMessage id="reset_password" />
</Button>
</form>
<div class="authentication-page__footer">
<Link to="/login"><FormattedMessage id="login" /></Link>
</div>
</div>
)
}

View File

@@ -0,0 +1,7 @@
import React from 'react';
export default function DashboardHomepage() {
return (
<div>asdasd</div>
);
}

View File

@@ -1,25 +1,16 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './reducers';
import thunkMiddleware from 'redux-thunk';
import monitorReducerEnhancer from './enhancers/monitorReducer';
// import axios from 'axios';
import App from './pages/App';
import * as serviceWorker from './serviceWorker';
import loggerMiddleware from './middleware/logger'
const middlewareEnhancer = applyMiddleware(loggerMiddleware, thunkMiddleware)
const composedEnhancers = compose(
middlewareEnhancer,
monitorReducerEnhancer,
)
const store = createStore(rootReducer, undefined, composedEnhancers);
import { BrowserRouter } from 'react-router-dom';
import App from 'components/App';
import * as serviceWorker from 'serviceWorker';
import createStore from 'store/createStore';
ReactDOM.render(
<Provider store={store}>
<App />
<Provider store={createStore}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root')
);

View File

@@ -0,0 +1,6 @@
export default {
"login": "Login",
"reset_password": "Reset password",
};

View File

@@ -0,0 +1,5 @@
export default {
'hello_world': 'Hello World',
};

View File

@@ -1,12 +0,0 @@
import React from 'react';
import Authentication from 'pages/Authentication';
function App() {
return (
<div className="App">
<h1>Hello World</h1>
<Authentication />
</div>
);
}
export default App;

View File

@@ -1,25 +0,0 @@
import * as React from "react";
import {
Button,
InputGroup,
} from "@blueprintjs/core";
export default function Login() {
return (
<div class="login-page">
<InputGroup
leftIcon="filter"
placeholder="Email or phone number"
/>
<InputGroup
leftIcon="filter"
placeholder="Password"
/>
<Button>
{"Login"}
</Button>
</div>
)
}

View File

@@ -1,20 +0,0 @@
import * as React from "react";
import {
Button,
InputGroup,
} from "@blueprintjs/core";
export default function Login() {
return (
<div class="login-page">
<InputGroup
leftIcon="filter"
placeholder="Email or phone number"
/>
<Button>
{"Reset password"}
</Button>
</div>
)
}

View File

@@ -1,25 +0,0 @@
import React from 'react';
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
import authenticationRoutes from 'routes/authentication';
export default function() {
return (
<div class="authentication-page">
<Router>
<Link to="/login">{ "Login" }</Link>
<Link to="/reset_password">{ "Reset Password" }</Link>
<Switch>
{ authenticationRoutes.map((route, index) => (
<Route
key={index}
path={route.path}
exact={route.exact}
component={route.component}
/>
))}
</Switch>
</Router>
</div>
);
}

View File

@@ -1,15 +0,0 @@
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import Sidebar from '../../components/Sidebar';
import DashboardContent from '../../components/DashboardContent';
export default function() {
return (
<div class="dashboard" id="dashboard">
<Router>
<Sidebar />
<DashboardContent />
</Router>
</div>
)
}

View File

@@ -1,14 +1,19 @@
import Login from '../pages/Authentication/Login';
import ResetPassword from '../pages/Authentication/ResetPassword';
import Login from 'containers/Authentication/Login';
import ResetPassword from 'containers/Authentication/ResetPassword';
export default [
// {
// path: '/',
// exact: true,
// component: Login,
// },
{
path: '/login',
path: '/auth/login',
exact: true,
component: Login,
},
{
path: '/reset_password',
path: '/auth/reset_password',
exact: true,
component: ResetPassword,
}

View File

@@ -1,11 +1,18 @@
import AccountsChart from '../pages/Dashboard/AccountsChart';
import Homepage from "containers/Dashboard/Homepage";
// import AccountsChart from 'pages/Dashboard/AccountsChart';
export default [
{
path: '/accounts/list',
component: AccountsChart,
icon: 'cut',
text: 'Chart of Accounts',
label: 'Chart of Accounts'
path: '/homepage',
component: Homepage,
exact: true,
},
// {
// path: '/accounts/list',
// component: AccountsChart,
// icon: 'cut',
// text: 'Chart of Accounts',
// label: 'Chart of Accounts'
// },
];

View File

@@ -0,0 +1,48 @@
import { createStore as createReduxStore, applyMiddleware, compose } from 'redux';
import thunkMiddleware from 'redux-thunk';
import monitorReducerEnhancer from 'store/enhancers/monitorReducer';
import loggerMiddleware from 'middleware/logger'
import rootReducer from 'store/reducers';
const createStore = (initialState = {}) => {
/**
|--------------------------------------------------
| Middleware Configuration
|--------------------------------------------------
*/
const middleware = [
thunkMiddleware,
loggerMiddleware,
];
/**
|--------------------------------------------------
| Store Enhancers
|--------------------------------------------------
*/
const enhancers = [
monitorReducerEnhancer,
];
let composeEnhancers = compose;
if (process.env.NODE_ENV === 'development') {
if (typeof window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ === 'function') {
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
}
}
/**
|--------------------------------------------------
| Store Instantiation and HMR Setup
|--------------------------------------------------
*/
const store = createReduxStore(
rootReducer,
initialState,
composeEnhancers(applyMiddleware(...middleware), ...enhancers)
);
store.asyncReducers = {};
return store;
};
export default createStore();

View File

@@ -0,0 +1,18 @@
import t from 'store/types';
export default function authentication(state = {}, action) {
switch(action.type) {
case t.LOGIN_SUCCESS:
return {
...state,
token: action.token,
}
case t.LOGOUT:
return {
...state,
token: '',
};
default:
return state;
}
}

View File

@@ -1,10 +1,10 @@
import { combineReducers } from 'redux';
import accounts from './accounts';
// import accounts from './accounts';
import authentication from './authentication';
import users from './users';
// import users from './users';
export default combineReducers({
authentication,
users,
accounts,
// users,
// accounts,
});

View File

@@ -0,0 +1,9 @@
const ACTION = {
LOGIN_REQUEST: 'LOGIN_REQUEST',
LOGIN_SUCCESS: 'LOGIN_SUCCESS',
LOGIN_FAILURE: 'LOGIN_FAILURE',
LOGOUT: 'LOGOUT',
};
export default ACTION;

View File

@@ -0,0 +1,5 @@
import authentication from './authentication';
export default {
...authentication,
};

View File

@@ -1,38 +0,0 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

16
client/src/style/App.scss Normal file
View File

@@ -0,0 +1,16 @@
@import "./normalize.scss";
// Blueprint framework.
@import "@blueprintjs/core/src/blueprint.scss";
@import "pages/authentication.scss";
.dashboard{
display: flex;
height: 100vh;
&-content{
}
}

View File

@@ -1,13 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

349
client/src/style/normalize.scss vendored Normal file
View File

@@ -0,0 +1,349 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Render the `main` element consistently in IE.
*/
main {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}

View File

@@ -0,0 +1,26 @@
.authentication-page{
&__form-wrapper{
width: 100%;
max-width: 350px;
padding: 15px;
margin: 0 auto;
}
.login-page{
.input-group{
&--email-phone-number{
margin-bottom: 1rem;
}
&--password{
margin-bottom: 1rem;
}
}
}
&__footer{
margin-top: 1rem;
text-align: center;
}
}