Initial database structure and migrations, login flow, refactor main page.

This commit is contained in:
Patrick Fic
2020-10-13 17:45:36 -07:00
parent abfb91d55f
commit 030f0b7a90
71 changed files with 5331 additions and 387 deletions

View File

@@ -0,0 +1,17 @@
import { Menu } from "antd";
import React from "react";
import { connect } from "react-redux";
import { signOutStart } from "../../../redux/user/user.actions";
const mapDispatchToProps = (dispatch) => ({
signOutStart: () => dispatch(signOutStart()),
});
export function SiderSignOut({ signOutStart, ...restProps }) {
return (
<Menu.Item {...restProps} onClick={() => signOutStart()}>
Sign Out
</Menu.Item>
);
}
export default connect(null, mapDispatchToProps)(SiderSignOut);

View File

@@ -0,0 +1,37 @@
import {
DesktopOutlined,
FileOutlined,
PieChartOutlined,
TeamOutlined,
UserOutlined,
} from "@ant-design/icons";
import { Menu } from "antd";
import React from "react";
import { Link } from "react-router-dom";
import SiderSignOut from "../../molecules/sider-sign-out/sider-sign-out.molecule";
const { SubMenu } = Menu;
export default function SiderMenuOrganism() {
return (
<Menu defaultSelectedKeys={["1"]} mode="inline">
<Menu.Item key="1" icon={<PieChartOutlined />}>
<Link to="/">Jobs</Link>
</Menu.Item>
<Menu.Item key="2" icon={<DesktopOutlined />}>
<Link to="/nope">Jobs Not Working</Link>
</Menu.Item>
<SubMenu key="sub1" icon={<UserOutlined />} title="User">
<Menu.Item key="3">Tom</Menu.Item>
<Menu.Item key="4">Bill</Menu.Item>
<Menu.Item key="5">Alex</Menu.Item>
</SubMenu>
<SubMenu key="sub2" icon={<TeamOutlined />} title="Team">
<Menu.Item key="6">Team 1</Menu.Item>
<Menu.Item key="8">Team 2</Menu.Item>
</SubMenu>
<Menu.Item key="9" icon={<FileOutlined />} />
<SiderSignOut />
</Menu>
);
}

View File

@@ -0,0 +1,50 @@
import { Button } from "antd";
import React, { useEffect } from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import ipcTypes from "../../../ipc.types";
const { ipcRenderer } = window.require("electron");
//const settings = window.require("electron-settings");
const mapStateToProps = createStructuredSelector({});
const mapDispatchToProps = (dispatch) => ({});
export function JobsPage() {
useEffect(() => {
ipcRenderer.on("test-success", (event, obj) => {
console.log("Test Success", obj);
});
ipcRenderer.on(ipcTypes.default.filewatcher.startSuccess, (event, obj) => {
console.log(ipcTypes.default.filewatcher.startSuccess, obj);
});
// Cleanup the listener events so that memory leaks are avoided.
return function cleanup() {
ipcRenderer.removeAllListeners(
"test-success",
ipcTypes.default.filewatcher.startSuccess
);
};
}, []);
return (
<div>
<div>Welcome to your new react app. asdas sd</div>
<Button
onClick={() => {
ipcRenderer.send("test", { test: true });
}}
>
TEST Generic IPC
</Button>
<Button
onClick={() => {
ipcRenderer.send(ipcTypes.default.filewatcher.start);
}}
>
Start Watcher
</Button>
</div>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(JobsPage);

View File

@@ -0,0 +1,28 @@
import { Layout } from "antd";
import React from "react";
import { connect } from "react-redux";
import { Route, Switch } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import SiderMenuOrganism from "../../organisms/sider-menu/sider-menu.organism";
import Jobs from "../jobs/jobs.page";
const mapStateToProps = createStructuredSelector({});
const mapDispatchToProps = (dispatch) => ({});
export function RoutesPage() {
return (
<Layout style={{ background: "#fff" }} hasSider>
<Layout.Sider style={{ background: "#fff" }} collapsible>
<SiderMenuOrganism />
</Layout.Sider>
<Layout style={{ background: "#fff" }}>
<Layout.Content style={{ margin: "1rem" }}>
<Switch>
<Route exact path="/" component={Jobs} />
</Switch>
</Layout.Content>
</Layout>
</Layout>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(RoutesPage);

View File

@@ -0,0 +1,59 @@
import { LockOutlined, UserOutlined } from "@ant-design/icons";
import { Alert, Button, Form, Input, Typography } from "antd";
import React from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import ImEXOnlineLogo from "../../../assets/logo192.png";
import { emailSignInStart } from "../../../redux/user/user.actions";
import { selectSignInError } from "../../../redux/user/user.selectors";
import "./sign-in.page.styles.scss";
const mapStateToProps = createStructuredSelector({
signInError: selectSignInError,
});
const mapDispatchToProps = (dispatch) => ({
emailSignInStart: (email, password) =>
dispatch(emailSignInStart({ email, password })),
});
export function SignInPage({ emailSignInStart, signInError }) {
const handleFinish = (values) => {
const { email, password } = values;
emailSignInStart(email, password);
};
const [form] = Form.useForm();
return (
<div className="login-container">
<div className="login-logo-container">
<img src={ImEXOnlineLogo} height="100" width="100" alt="ImEX Online" />
<Typography.Title>ImEX RPS</Typography.Title>
</div>
<Form onFinish={handleFinish} form={form} size="large">
<Form.Item name="email" rules={[{ required: true }]}>
<Input prefix={<UserOutlined />} placeholder="Email" />
</Form.Item>
<Form.Item name="password" rules={[{ required: true }]}>
<Input
prefix={<LockOutlined />}
type="password"
placeholder="Password"
/>
</Form.Item>
{signInError ? (
<Alert type="error" message={signInError.message} />
) : null}
<Button className="login-btn" type="primary" htmlType="submit">
Login
</Button>
</Form>
<Link to={"/resetpassword"}>
<Button>Reset Password</Button>
</Link>
</div>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(SignInPage);

View File

@@ -0,0 +1,29 @@
.login-container {
display: flex;
align-items: center;
flex-direction: column;
padding: 2rem;
form {
width: 75vw;
max-width: 20rem;
}
}
.login-logo-container {
display: flex;
align-items: center;
margin-bottom: 2rem;
h1 {
text-align: center;
margin: 1rem;
}
}
//Required as it is position inside form.
.login-btn {
margin: 1.5rem 0rem;
position: relative;
left: 50%;
transform: translate(-50%, 0);
}

View File

@@ -0,0 +1,64 @@
import { Button, Col, Collapse, Result, Row, Space } from "antd";
import React from "react";
class ErrorBoundary extends React.Component {
constructor() {
super();
this.state = {
hasErrored: false,
error: null,
info: null,
};
}
static getDerivedStateFromError(error) {
console.log("ErrorBoundary -> getDerivedStateFromError -> error", error);
return { hasErrored: true, error: error };
}
componentDidCatch(error, info) {
console.log("Exception Caught by Error Boundary.", error, info);
this.setState({ ...this.state, error, info });
}
render() {
if (this.state.hasErrored === true) {
return (
<div>
<Result
status="500"
title="Error!"
subTitle="Error subtitle"
extra={
<Space>
<Button
type="primary"
onClick={() => {
window.location.reload();
}}
>
Refresh
</Button>
</Space>
}
/>
<Row>
<Col offset={6} span={12}>
<Collapse bordered={false}>
<Collapse.Panel header="Error Details">
<div>
<strong>{this.state.error.message}</strong>
</div>
<div>{this.state.error.stack}</div>
</Collapse.Panel>
</Collapse>
</Col>
</Row>
</div>
);
} else {
return this.props.children;
}
}
}
export default ErrorBoundary;

55
src/components/test.jsx Normal file
View File

@@ -0,0 +1,55 @@
import { Button, Layout } from "antd";
import React, { useEffect } from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import ipcTypes from "../ipc.types";
const { ipcRenderer } = window.require("electron");
//const settings = window.require("electron-settings");
const mapStateToProps = createStructuredSelector({});
const mapDispatchToProps = (dispatch) => ({});
export function App() {
useEffect(() => {
ipcRenderer.on("test-success", (event, obj) => {
console.log("Test Success", obj);
});
ipcRenderer.on(ipcTypes.default.filewatcher.startSuccess, (event, obj) => {
console.log(ipcTypes.default.filewatcher.startSuccess, obj);
});
// Cleanup the listener events so that memory leaks are avoided.
return function cleanup() {
ipcRenderer.removeAllListeners(
"test-success",
ipcTypes.default.filewatcher.startSuccess
);
};
}, []);
return (
<Layout>
<Layout.Header>
<div> Header</div>
</Layout.Header>
<Layout.Content>
<div>Welcome to your new react app. asdas sd</div>
<Button
onClick={() => {
ipcRenderer.send("test", { test: true });
}}
>
TEST Generic IPC
</Button>
<Button
onClick={() => {
ipcRenderer.send(ipcTypes.default.filewatcher.start);
}}
>
Start Watcher
</Button>
</Layout.Content>
</Layout>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(App);