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

@@ -5186,6 +5186,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>submitticket</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
@@ -5275,6 +5296,48 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>errors</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>exceptiontitle</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>in</name>
<definition_loaded>false</definition_loaded>
@@ -5663,6 +5726,27 @@
<folder_node>
<name>messages</name>
<children>
<concept_node>
<name>exception</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>unsavedchanges</name>
<definition_loaded>false</definition_loaded>

View File

@@ -3,28 +3,28 @@ importScripts(
"https://www.gstatic.com/firebasejs/7.14.2/firebase-messaging.js"
);
// firebase.initializeApp({
// apiKey: "AIzaSyDSezy-jGJreo7ulgpLdlpOwAOrgcaEkhU",
// authDomain: "imex-prod.firebaseapp.com",
// databaseURL: "https://imex-prod.firebaseio.com",
// projectId: "imex-prod",
// storageBucket: "imex-prod.appspot.com",
// messagingSenderId: "253497221485",
// appId: "1:253497221485:web:3c81c483b94db84b227a64",
// measurementId: "G-NTWBKG2L0M",
// });
firebase.initializeApp({
apiKey: "AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc",
authDomain: "imex-dev.firebaseapp.com",
databaseURL: "https://imex-dev.firebaseio.com",
projectId: "imex-dev",
storageBucket: "imex-dev.appspot.com",
messagingSenderId: "759548147434",
appId: "1:759548147434:web:e8239868a48ceb36700993",
measurementId: "G-K5XRBVVB4S",
apiKey: "AIzaSyDSezy-jGJreo7ulgpLdlpOwAOrgcaEkhU",
authDomain: "imex-prod.firebaseapp.com",
databaseURL: "https://imex-prod.firebaseio.com",
projectId: "imex-prod",
storageBucket: "imex-prod.appspot.com",
messagingSenderId: "253497221485",
appId: "1:253497221485:web:3c81c483b94db84b227a64",
measurementId: "G-NTWBKG2L0M",
});
// firebase.initializeApp({
// apiKey: "AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc",
// authDomain: "imex-dev.firebaseapp.com",
// databaseURL: "https://imex-dev.firebaseio.com",
// projectId: "imex-dev",
// storageBucket: "imex-dev.appspot.com",
// messagingSenderId: "759548147434",
// appId: "1:759548147434:web:e8239868a48ceb36700993",
// measurementId: "G-K5XRBVVB4S",
// });
const messaging = firebase.messaging();
//Handles Background Messages

View File

@@ -1,7 +1,7 @@
{
"short_name": "Bodyshop.app",
"name": "Bodyshop Management System",
"description": "The ultimate bodyshop management system",
"short_name": "ImEX Online",
"name": "ImEX Online",
"description": "The ultimate bodyshop management system.",
"icons": [
{
"src": "favicon.ico",

View File

@@ -10,7 +10,7 @@ import { RetryLink } from "apollo-link-retry";
import { WebSocketLink } from "apollo-link-ws";
import { getMainDefinition } from "apollo-utilities";
import LogRocket from "logrocket";
import React, { Component } from "react";
import React from "react";
import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component";
import { auth } from "../firebase/firebase.utils";
import errorLink from "../graphql/apollo-error-handling";
@@ -28,7 +28,6 @@ const wsLink = new WebSocketLink({
lazy: true,
reconnect: true,
connectionParams: async () => {
//const token = localStorage.getItem("token");
const token =
auth.currentUser && (await auth.currentUser.getIdToken(true));
if (token) {
@@ -110,26 +109,18 @@ if (process.env.NODE_ENV === "development") {
middlewares.push(retryLink.concat(errorLink.concat(authLink.concat(link))));
const cache = new InMemoryCache();
export const client = new ApolloClient({
link: ApolloLink.from(middlewares),
cache,
connectToDevTools: true,
connectToDevTools: process.env.NODE_ENV !== "production",
});
export default class AppContainer extends Component {
constructor() {
super();
this.state = { client };
}
render() {
const { client } = this.state;
return (
<ApolloProvider client={client}>
<GlobalLoadingBar />
<App />
</ApolloProvider>
);
}
export default function AppContainer() {
return (
<ApolloProvider client={client}>
<GlobalLoadingBar />
<App />
</ApolloProvider>
);
}

View File

@@ -1 +0,0 @@
@import "~antd/dist/antd.css";

View File

@@ -8,9 +8,8 @@ import ErrorBoundary from "../components/error-boundary/error-boundary.component
import LoadingSpinner from "../components/loading-spinner/loading-spinner.component";
import { checkUserSession } from "../redux/user/user.actions";
import { selectCurrentUser } from "../redux/user/user.selectors";
// import { QUERY_BODYSHOP } from "../graphql/bodyshop.queries";
import PrivateRoute from "../utils/private-route";
import "./App.css";
import "antd/dist/antd.css";
const LandingPage = lazy(() => import("../pages/landing/landing.page"));
const ManagePage = lazy(() => import("../pages/manage/manage.page.container"));
@@ -27,13 +26,9 @@ const mapDispatchToProps = (dispatch) => ({
checkUserSession: () => dispatch(checkUserSession()),
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(({ checkUserSession, currentUser }) => {
export function App({ checkUserSession, currentUser }) {
useEffect(() => {
checkUserSession();
return () => {};
}, [checkUserSession]);
const { t } = useTranslation();
@@ -61,4 +56,6 @@ export default connect(
</Switch>
</div>
);
});
}
export default connect(mapStateToProps, mapDispatchToProps)(App);

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);

View File

@@ -4,6 +4,7 @@ import "firebase/auth";
import "firebase/database";
import "firebase/analytics";
import "firebase/messaging";
import { store } from "../redux/store";
const config = JSON.parse(process.env.REACT_APP_FIREBASE_CONFIG);
firebase.initializeApp(config);
@@ -45,3 +46,17 @@ try {
}
export { messaging };
export const logImEXEvent = async (eventName, additionalParams) => {
const state = store.getState();
const eventParams = {
shop:
(state.user && state.user.bodyshop && state.user.bodyshop.shopname) ||
null,
user:
(state.user && state.user.currentUser && state.user.currentUser.email) ||
null,
...additionalParams,
};
analytics.logEvent(eventName, eventParams);
};

View File

@@ -1,19 +1,13 @@
import { Layout, Typography } from "antd";
import React from "react";
import { Typography, Layout } from "antd";
import HeaderContainer from "../../components/header/header.container";
import ManageSignInButton from "../../components/manage-sign-in-button/manage-sign-in-button.component";
export default function LandingPage() {
const { Header, Content } = Layout;
return (
<Layout style={{ minHeight: "100vh" }}>
<Header>
<HeaderContainer landingHeader />
</Header>
<Layout style={{ height: "100vh" }}>
<ManageSignInButton />
<Content className='content-container' style={{ padding: "0em 4em 4em" }}>
<Typography.Title>ImEX.Online</Typography.Title>
</Content>
<Typography.Title>ImEX.Online</Typography.Title>
</Layout>
);
}

View File

@@ -1,7 +1,7 @@
import React from "react";
import DashboardGridComponent from "../../components/dashboard-grid/dashboard-grid.component";
import Test from "../../components/_test/test.component";
import { analytics } from "../../firebase/firebase.utils";
import { analytics, logImEXEvent } from "../../firebase/firebase.utils";
export default function ManageRootPageComponent() {
//const client = useApolloClient();
@@ -10,34 +10,26 @@ export default function ManageRootPageComponent() {
<Test />
<button
onClick={() => {
logImEXEvent("IMEXEVENT", { somethignArThare: 5 });
}}>
LogImEXEvent
</button>
<button
onClick={() => {
console.log("Things.");
analytics.logEvent("start_game", {
level: "10",
difficulty: "expert",
});
}}
>
analytics.logEvent("select_content", {
content_type: "image",
content_id: "P12453",
items: [{ name: "Kittens" }],
});
}}>
Click me to start an event
</button>
<DashboardGridComponent />
{
// <SendEmailButton
// MessageOptions={{
// from: {
// name: "Kavia"
// },
// to: "patrickwf@gmail.com",
// replyTo: "patrickwf@gmail.com"
// }}
// Template={PartsOrderEmail}
// QueryConfig={[
// REPORT_QUERY_PARTS_ORDER_BY_PK,
// {
// variables: { id: "ebe0fb6b-6ec4-4ae0-8fdc-49bdf1e37ff3" }
// }
// ]}>
// Send an Email in new Window
// </SendEmailButton>
}
</div>
);
}

View File

@@ -1,6 +1,7 @@
import React, { useEffect } from "react";
import ManageRootPageComponent from "./manage-root.page.component";
import { useTranslation } from "react-i18next";
export default function ManageRootPageContainer() {
const { t } = useTranslation();
useEffect(() => {

View File

@@ -128,7 +128,6 @@ const stripePromise = new Promise((resolve, reject) => {
const mapStateToProps = createStructuredSelector({
conflict: selectInstanceConflict,
});
const mapDispatchToProps = (dispatch) => ({});
export function Manage({ match, conflict }) {
const { t } = useTranslation();
@@ -139,186 +138,172 @@ export function Manage({ match, conflict }) {
return (
<Layout style={{ minHeight: "100vh" }}>
<Header>
<HeaderContainer />
</Header>
<Layout>
<Content
className="content-container"
style={{ padding: "0em 4em 4em" }}
>
<FcmNotification />
<ErrorBoundary>
{conflict ? (
<ConflictComponent />
) : (
<Suspense
fallback={
<LoadingSpinner message={t("general.labels.loadingapp")} />
}
>
<BreadCrumbs />
<EnterInvoiceModalContainer />
<EmailOverlayContainer />
<TimeTicketModalContainer />
<PrintCenterModalContainer />
<Elements stripe={stripePromise}>
<PaymentModalContainer />
</Elements>
<HeaderContainer />
<Content className='content-container' style={{ padding: "0em 4em 4em" }}>
<FcmNotification />
<ErrorBoundary>
{conflict ? (
<ConflictComponent />
) : (
<Suspense
fallback={
<LoadingSpinner message={t("general.labels.loadingapp")} />
}>
<BreadCrumbs />
<EnterInvoiceModalContainer />
<EmailOverlayContainer />
<TimeTicketModalContainer />
<PrintCenterModalContainer />
<Elements stripe={stripePromise}>
<PaymentModalContainer />
</Elements>
<Route exact path={`${match.path}`} component={ManageRootPage} />
<Route exact path={`${match.path}/jobs`} component={JobsPage} />
<Switch>
<Route
exact
path={`${match.path}/jobs/:jobId/intake`}
component={JobIntake}
/>
<Route
exact
path={`${match.path}/jobs/:jobId/close`}
component={JobsClose}
/>
<Route
exact
path={`${match.path}/jobs/all`}
component={AllJobs}
/>
<Route
exact
path={`${match.path}/jobs/new`}
component={JobsCreateContainerPage}
/>
<Route
path={`${match.path}/jobs/:jobId`}
component={JobsDetailPage}
/>
</Switch>
<Route
exact
path={`${match.path}/courtesycars/`}
component={CourtesyCarsPage}
/>
<Switch>
<Route
exact
path={`${match.path}/courtesycars/new`}
component={CourtesyCarCreateContainer}
/>
<Route
exact
path={`${match.path}`}
component={ManageRootPage}
path={`${match.path}/courtesycars/contracts`}
component={ContractsList}
/>
<Route exact path={`${match.path}/jobs`} component={JobsPage} />
<Switch>
<Route
exact
path={`${match.path}/jobs/:jobId/intake`}
component={JobIntake}
/>
<Route
exact
path={`${match.path}/jobs/:jobId/close`}
component={JobsClose}
/>
<Route
exact
path={`${match.path}/jobs/all`}
component={AllJobs}
/>
<Route
exact
path={`${match.path}/jobs/new`}
component={JobsCreateContainerPage}
/>
<Route
path={`${match.path}/jobs/:jobId`}
component={JobsDetailPage}
/>
</Switch>
<Route
exact
path={`${match.path}/courtesycars/`}
component={CourtesyCarsPage}
path={`${match.path}/courtesycars/contracts/new`}
component={ContractCreatePage}
/>
<Route
exact
path={`${match.path}/courtesycars/contracts/:contractId`}
component={ContractDetailPage}
/>
<Switch>
<Route
exact
path={`${match.path}/courtesycars/new`}
component={CourtesyCarCreateContainer}
/>
<Route
exact
path={`${match.path}/courtesycars/contracts`}
component={ContractsList}
/>
<Route
exact
path={`${match.path}/courtesycars/:ccId`}
component={CourtesyCarDetailContainer}
/>
</Switch>
<Route
exact
path={`${match.path}/profile`}
component={ProfilePage}
/>
<Route
exact
path={`${match.path}/vehicles`}
component={VehiclesContainer}
/>
<Route
exact
path={`${match.path}/production/list`}
component={ProductionListPage}
/>
<Route
exact
path={`${match.path}/production/board`}
component={ProductionBoardPage}
/>
<Route
exact
path={`${match.path}/vehicles/:vehId`}
component={VehiclesDetailContainer}
/>
<Route
exact
path={`${match.path}/invoices`}
component={InvoicesListPage}
/>
<Route
exact
path={`${match.path}/owners`}
component={OwnersContainer}
/>
<Route
exact
path={`${match.path}/owners/:ownerId`}
component={OwnersDetailContainer}
/>
<Route
exact
path={`${match.path}/schedule`}
component={ScheduleContainer}
/>
<Route
exact
path={`${match.path}/available`}
component={JobsAvailablePage}
/>
<Route exact path={`${match.path}/shop/`} component={ShopPage} />
<Route
exact
path={`${match.path}/shop/templates`}
component={ShopTemplates}
/>
<Route
exact
path={`${match.path}/shop/vendors`}
component={ShopVendorPageContainer}
/>
<Route
exact
path={`${match.path}/shop/csi`}
component={ShopCsiPageContainer}
/>
<Route
exact
path={`${match.path}/accounting/receivables`}
component={AccountingReceivables}
/>
<Route
exact
path={`${match.path}/accounting/payables`}
component={AccountingPayables}
/>
</Suspense>
)}
</ErrorBoundary>
</Content>
<Route
exact
path={`${match.path}/courtesycars/contracts/new`}
component={ContractCreatePage}
/>
<Route
exact
path={`${match.path}/courtesycars/contracts/:contractId`}
component={ContractDetailPage}
/>
<Route
exact
path={`${match.path}/courtesycars/:ccId`}
component={CourtesyCarDetailContainer}
/>
</Switch>
<Route
exact
path={`${match.path}/profile`}
component={ProfilePage}
/>
<Route
exact
path={`${match.path}/vehicles`}
component={VehiclesContainer}
/>
<Route
exact
path={`${match.path}/production/list`}
component={ProductionListPage}
/>
<Route
exact
path={`${match.path}/production/board`}
component={ProductionBoardPage}
/>
<Route
exact
path={`${match.path}/vehicles/:vehId`}
component={VehiclesDetailContainer}
/>
<Route
exact
path={`${match.path}/invoices`}
component={InvoicesListPage}
/>
<Route
exact
path={`${match.path}/owners`}
component={OwnersContainer}
/>
<Route
exact
path={`${match.path}/owners/:ownerId`}
component={OwnersDetailContainer}
/>
<Route
exact
path={`${match.path}/schedule`}
component={ScheduleContainer}
/>
<Route
exact
path={`${match.path}/available`}
component={JobsAvailablePage}
/>
<Route
exact
path={`${match.path}/shop/`}
component={ShopPage}
/>
<Route
exact
path={`${match.path}/shop/templates`}
component={ShopTemplates}
/>
<Route
exact
path={`${match.path}/shop/vendors`}
component={ShopVendorPageContainer}
/>
<Route
exact
path={`${match.path}/shop/csi`}
component={ShopCsiPageContainer}
/>
<Route
exact
path={`${match.path}/accounting/receivables`}
component={AccountingReceivables}
/>
<Route
exact
path={`${match.path}/accounting/payables`}
component={AccountingPayables}
/>
</Suspense>
)}
</ErrorBoundary>
</Content>
</Layout>
<Footer>
<FooterComponent />
</Footer>
@@ -327,4 +312,4 @@ export function Manage({ match, conflict }) {
</Layout>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(Manage);
export default connect(mapStateToProps, null)(Manage);

View File

@@ -349,13 +349,16 @@
"reset": "Reset to original.",
"save": "Save",
"saveandnew": "Save and New",
"submit": "Submit"
"submit": "Submit",
"submitticket": "Submit a Support Ticket"
},
"labels": {
"actions": "Actions",
"areyousure": "Are you sure?",
"barcode": "Barcode",
"email": "Email",
"errors": "Errors",
"exceptiontitle": "An error has occurred.",
"in": "In",
"instanceconflictext": "Your $t(titles.app) account can only be used on one device at any given time. Refresh your session to take control.",
"instanceconflictitle": "Your account is being used elsewhere.",
@@ -378,6 +381,7 @@
"spanish": "Spanish"
},
"messages": {
"exception": "$t(titles.app) has encountered an error. Please try again. If the problem persists, please submit a support ticket or contact us.",
"unsavedchanges": "You have unsaved changes."
},
"validation": {

View File

@@ -349,13 +349,16 @@
"reset": "Restablecer a original.",
"save": "Salvar",
"saveandnew": "",
"submit": ""
"submit": "",
"submitticket": ""
},
"labels": {
"actions": "Comportamiento",
"areyousure": "",
"barcode": "código de barras",
"email": "",
"errors": "",
"exceptiontitle": "",
"in": "en",
"instanceconflictext": "",
"instanceconflictitle": "",
@@ -378,6 +381,7 @@
"spanish": "español"
},
"messages": {
"exception": "",
"unsavedchanges": "Usted tiene cambios no guardados."
},
"validation": {

View File

@@ -349,13 +349,16 @@
"reset": "Rétablir l'original.",
"save": "sauvegarder",
"saveandnew": "",
"submit": ""
"submit": "",
"submitticket": ""
},
"labels": {
"actions": "actes",
"areyousure": "",
"barcode": "code à barre",
"email": "",
"errors": "",
"exceptiontitle": "",
"in": "dans",
"instanceconflictext": "",
"instanceconflictitle": "",
@@ -378,6 +381,7 @@
"spanish": "Espanol"
},
"messages": {
"exception": "",
"unsavedchanges": "Vous avez des changements non enregistrés."
},
"validation": {