Added better error boundary page. Started some CSS and layout refactoring. **Major Changes**.

This commit is contained in:
Patrick Fic
2020-06-10 17:52:38 -07:00
parent 52849e1af7
commit afbec7d79e
18 changed files with 475 additions and 455 deletions

View File

@@ -1,31 +1,65 @@
import React from "react";
import { withTranslation } from "react-i18next";
import { Result, Button, Collapse, Row, Col, Space } from "antd";
class ErrorBoundary extends React.Component {
constructor() {
super();
this.state = {
hasErrored: false,
error: null
error: null,
};
}
static getDerivedStateFromError(error) {
//process the error
console.log("error", error);
return { hasErrored: true, error };
}
componentDidCatch(error, info) {
console.log("error", error);
console.log("info", info);
console.log("Exception Caught by Error Boundary.", error, info);
}
render() {
const { t } = this.props;
if (this.state.hasErrored === true) {
return <div>Uh oh, something went wrong.</div>;
return (
<div>
<Result
status='500'
title={t("general.labels.exceptiontitle")}
subTitle={t("general.messages.exception")}
extra={
<Space>
<Button
type='primary'
onClick={() => {
window.location.reload();
}}>
{t("general.actions.refresh")}
</Button>
<Button
onClick={() => {
alert("Not implemented yet.");
}}>
{t("general.actions.submitticket")}
</Button>
</Space>
}
/>
<Row>
<Col offset={6} span={12}>
<Collapse bordered={false}>
<Collapse.Panel header={t("general.labels.errors")}>
{JSON.stringify(this.state.error || "")}
</Collapse.Panel>
</Collapse>
</Col>
</Row>
</div>
);
} else {
return this.props.children;
}
}
}
export default ErrorBoundary;
export default withTranslation()(ErrorBoundary);

View File

@@ -1,26 +1,32 @@
import Icon, {
CarFilled,
DollarCircleFilled,
FileAddFilled,
FileFilled,
GlobalOutlined,
HomeFilled,
TeamOutlined,
DollarCircleFilled,
} from "@ant-design/icons";
import { Avatar, Col, Menu, Row } from "antd";
import { Avatar, Col, Menu, Row, Layout } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { FaCalendarAlt, FaCarCrash } from "react-icons/fa";
import { Link } from "react-router-dom";
import UserImage from "../../assets/User.svg";
import ManageSignInButton from "../manage-sign-in-button/manage-sign-in-button.component";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import UserImage from "../../assets/User.svg";
import { setModalContext } from "../../redux/modals/modals.actions";
import { signOutStart } from "../../redux/user/user.actions";
import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
currentUser: selectCurrentUser,
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
setInvoiceEnterContext: (context) =>
dispatch(setModalContext({ context: context, modal: "invoiceEnter" })),
@@ -28,12 +34,11 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(setModalContext({ context: context, modal: "timeTicket" })),
setPaymentContext: (context) =>
dispatch(setModalContext({ context: context, modal: "payment" })),
signOutStart: () => dispatch(signOutStart()),
});
function Header({
landingHeader,
selectedNavItem,
logo,
bodyshop,
handleMenuClick,
currentUser,
signOutStart,
@@ -42,79 +47,24 @@ function Header({
setPaymentContext,
}) {
const { t } = useTranslation();
//TODO Add
return (
<Row type="flex" justify="space-around" align="middle">
{logo ? (
<Col span={3}>
<img alt="Shop Logo" src={logo} style={{ height: "40px" }} />
<Layout.Header>
<Row align='middle'>
<Col span={4}>
<img
alt={bodyshop ? bodyshop.shopname : "ImEX Online Logo"}
src={
bodyshop && bodyshop.logo_img_path
? bodyshop.logo_img_path
: "./logo192.png"
}
/>
</Col>
) : null}
<Col span={21}>
{landingHeader ? (
<Menu
theme="dark"
className="header"
selectedKeys={selectedNavItem}
mode="horizontal"
onClick={handleMenuClick}
>
<ManageSignInButton />
<Menu.SubMenu
title={
<div>
<Avatar
size="medium"
alt="Avatar"
src={
currentUser.photoURL ? currentUser.photoURL : UserImage
}
style={{ margin: "10px" }}
/>
{currentUser.displayName || t("general.labels.unknown")}
</div>
}
>
<Menu.Item onClick={() => signOutStart()}>
{t("user.actions.signout")}
</Menu.Item>
<Menu.Item>
<Link to="/manage/profile">
{t("menus.currentuser.profile")}
</Link>
</Menu.Item>
<Menu.SubMenu
title={
<span>
<GlobalOutlined />
<span>{t("menus.currentuser.languageselector")}</span>
</span>
}
>
<Menu.Item actiontype="lang-select" key="en-US">
{t("general.languages.english")}
</Menu.Item>
<Menu.Item actiontype="lang-select" key="fr-CA">
{t("general.languages.french")}
</Menu.Item>
<Menu.Item actiontype="lang-select" key="es-MX">
{t("general.languages.spanish")}
</Menu.Item>
</Menu.SubMenu>
</Menu.SubMenu>
</Menu>
) : (
<Menu
theme="dark"
className="header"
selectedKeys={selectedNavItem}
mode="horizontal"
onClick={handleMenuClick}
>
<Menu.Item key="home">
<Link to="/manage">
<Col span={16}>
<Menu mode='horizontal' onClick={handleMenuClick}>
<Menu.Item key='home'>
<Link to='/manage'>
<HomeFilled />
{t("menus.header.home")}
</Link>
@@ -125,41 +75,40 @@ function Header({
<Icon component={FaCarCrash} />
<span>{t("menus.header.jobs")}</span>
</span>
}
>
<Menu.Item key="schedule">
<Link to="/manage/schedule">
}>
<Menu.Item key='schedule'>
<Link to='/manage/schedule'>
<Icon component={FaCalendarAlt} />
{t("menus.header.schedule")}
</Link>
</Menu.Item>
<Menu.Item key="production">
<Link to="/manage/production/list">
<Menu.Item key='production'>
<Link to='/manage/production/list'>
<Icon component={FaCalendarAlt} />
{t("menus.header.productionlist")}
</Link>
</Menu.Item>
<Menu.Item key="activejobs">
<Link to="/manage/jobs">{t("menus.header.activejobs")}</Link>
<Menu.Item key='activejobs'>
<Link to='/manage/jobs'>{t("menus.header.activejobs")}</Link>
</Menu.Item>
<Menu.Item key="alljobs">
<Link to="/manage/jobs/all">{t("menus.header.alljobs")}</Link>
<Menu.Item key='alljobs'>
<Link to='/manage/jobs/all'>{t("menus.header.alljobs")}</Link>
</Menu.Item>
<Menu.Item key="availablejobs">
<Link to="/manage/available">
<Menu.Item key='availablejobs'>
<Link to='/manage/available'>
{t("menus.header.availablejobs")}
</Link>
</Menu.Item>
</Menu.SubMenu>
<Menu.SubMenu title={t("menus.header.customers")}>
<Menu.Item key="owners">
<Link to="/manage/owners">
<Menu.Item key='owners'>
<Link to='/manage/owners'>
<TeamOutlined />
{t("menus.header.owners")}
</Link>
</Menu.Item>
<Menu.Item key="vehicles">
<Link to="/manage/vehicles">
<Menu.Item key='vehicles'>
<Link to='/manage/vehicles'>
<CarFilled />
{t("menus.header.vehicles")}
</Link>
@@ -172,22 +121,21 @@ function Header({
<CarFilled />
<span>{t("menus.header.courtesycars")}</span>
</span>
}
>
<Menu.Item key="courtesycarsall">
<Link to="/manage/courtesycars">
}>
<Menu.Item key='courtesycarsall'>
<Link to='/manage/courtesycars'>
<CarFilled />
{t("menus.header.courtesycars-all")}
</Link>
</Menu.Item>
<Menu.Item key="contracts">
<Link to="/manage/courtesycars/contracts">
<Menu.Item key='contracts'>
<Link to='/manage/courtesycars/contracts'>
<FileFilled />
{t("menus.header.courtesycars-contracts")}
</Link>
</Menu.Item>
<Menu.Item key="newcontract">
<Link to="/manage/courtesycars/contracts/new">
<Menu.Item key='newcontract'>
<Link to='/manage/courtesycars/contracts/new'>
<FileAddFilled />
{t("menus.header.courtesycars-newcontract")}
</Link>
@@ -200,82 +148,81 @@ function Header({
<DollarCircleFilled />
<span>{t("menus.header.accounting")}</span>
</span>
}
>
}>
<Menu.Item
key="enterpayments"
key='enterpayments'
onClick={() => {
setPaymentContext({
actions: {},
context: {},
});
}}
>
}}>
{t("menus.header.enterpayment")}
</Menu.Item>
<Menu.Item
key="enterinvoices"
key='enterinvoices'
onClick={() => {
setInvoiceEnterContext({
actions: {},
context: {},
});
}}
>
}}>
{t("menus.header.enterinvoices")}
</Menu.Item>
<Menu.Item key="invoices">
<Link to="/manage/invoices">{t("menus.header.invoices")}</Link>
<Menu.Item key='invoices'>
<Link to='/manage/invoices'>{t("menus.header.invoices")}</Link>
</Menu.Item>
<Menu.Item
key="entertimetickets"
key='entertimetickets'
onClick={() => {
setTimeTicketContext({
actions: {},
context: {},
});
}}
>
}}>
{t("menus.header.entertimeticket")}
</Menu.Item>
<Menu.Item key="receivables">
<Link to="/manage/accounting/receivables">
<Menu.Item key='receivables'>
<Link to='/manage/accounting/receivables'>
{t("menus.header.accounting-receivables")}
</Link>
</Menu.Item>
<Menu.Item key="payables">
<Link to="/manage/accounting/payables">
<Menu.Item key='payables'>
<Link to='/manage/accounting/payables'>
{t("menus.header.accounting-payables")}
</Link>
</Menu.Item>
</Menu.SubMenu>
<Menu.SubMenu title={t("menus.header.shop")}>
<Menu.Item key="shop">
<Link to="/manage/shop">{t("menus.header.shop_config")}</Link>
<Menu.Item key='shop'>
<Link to='/manage/shop'>{t("menus.header.shop_config")}</Link>
</Menu.Item>
<Menu.Item key="shop-templates">
<Link to="/manage/shop/templates">
<Menu.Item key='shop-templates'>
<Link to='/manage/shop/templates'>
{t("menus.header.shop_templates")}
</Link>
</Menu.Item>
<Menu.Item key="shop-vendors">
<Link to="/manage/shop/vendors">
<Menu.Item key='shop-vendors'>
<Link to='/manage/shop/vendors'>
{t("menus.header.shop_vendors")}
</Link>
</Menu.Item>
<Menu.Item key="shop-csi">
<Link to="/manage/shop/csi">{t("menus.header.shop_csi")}</Link>
<Menu.Item key='shop-csi'>
<Link to='/manage/shop/csi'>{t("menus.header.shop_csi")}</Link>
</Menu.Item>
</Menu.SubMenu>
</Menu>
</Col>
<Col span={4}>
<Menu>
<Menu.SubMenu
title={
<div>
<Avatar
size="medium"
alt="Avatar"
size='medium'
alt='Avatar'
src={
currentUser.photoURL ? currentUser.photoURL : UserImage
}
@@ -283,13 +230,12 @@ function Header({
/>
{currentUser.displayName || t("general.labels.unknown")}
</div>
}
>
}>
<Menu.Item onClick={() => signOutStart()}>
{t("user.actions.signout")}
</Menu.Item>
<Menu.Item>
<Link to="/manage/profile">
<Link to='/manage/profile'>
{t("menus.currentuser.profile")}
</Link>
</Menu.Item>
@@ -299,23 +245,22 @@ function Header({
<GlobalOutlined />
<span>{t("menus.currentuser.languageselector")}</span>
</span>
}
>
<Menu.Item actiontype="lang-select" key="en-US">
}>
<Menu.Item actiontype='lang-select' key='en-US'>
{t("general.languages.english")}
</Menu.Item>
<Menu.Item actiontype="lang-select" key="fr-CA">
<Menu.Item actiontype='lang-select' key='fr-CA'>
{t("general.languages.french")}
</Menu.Item>
<Menu.Item actiontype="lang-select" key="es-MX">
<Menu.Item actiontype='lang-select' key='es-MX'>
{t("general.languages.spanish")}
</Menu.Item>
</Menu.SubMenu>
</Menu.SubMenu>
</Menu>
)}
</Col>
</Row>
</Col>
</Row>
</Layout.Header>
);
}

View File

@@ -1,35 +1,15 @@
import React from "react";
import HeaderComponent from "./header.component";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import i18next from "i18next";
import { setUserLanguage, signOutStart } from "../../redux/user/user.actions";
import {
selectCurrentUser,
selectBodyshop
} from "../../redux/user/user.selectors";
import React from "react";
import { connect } from "react-redux";
import { setUserLanguage } from "../../redux/user/user.actions";
import HeaderComponent from "./header.component";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
bodyshop: selectBodyshop
const mapDispatchToProps = (dispatch) => ({
setUserLanguage: (language) => dispatch(setUserLanguage(language)),
});
const mapDispatchToProps = dispatch => ({
signOutStart: () => dispatch(signOutStart()),
setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(function HeaderContainer({
landingHeader,
currentUser,
bodyshop,
signOutStart,
setUserLanguage
}) {
const handleMenuClick = e => {
export function HeaderContainer({ setUserLanguage }) {
const handleMenuClick = (e) => {
if (e.item.props.actiontype === "lang-select") {
i18next.changeLanguage(e.key, (err, t) => {
if (err)
@@ -39,14 +19,7 @@ export default connect(
}
};
return (
<HeaderComponent
handleMenuClick={handleMenuClick}
signOutStart={signOutStart}
landingHeader={landingHeader}
selectedNavItem={null}
currentUser={currentUser}
logo={bodyshop ? bodyshop.logo_img_path : null}
/>
);
});
return <HeaderComponent handleMenuClick={handleMenuClick} />;
}
export default connect(null, mapDispatchToProps)(HeaderContainer);

View File

@@ -6,22 +6,20 @@ import { createStructuredSelector } from "reselect";
import { selectCurrentUser } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser
currentUser: selectCurrentUser,
});
export default connect(
mapStateToProps,
null
)(function ManageSignInButton({ currentUser }) {
export function ManageSignInButton({ currentUser }) {
return currentUser.authorized ? (
<Link to="/manage">
<Link to='/manage'>
<BuildFilled />
Manage
</Link>
) : (
<Link to="/signin">
<Link to='/signin'>
<LoginOutlined />
Sign In
</Link>
);
});
}
export default connect(mapStateToProps, null)(ManageSignInButton);