unsavedchanges
false
diff --git a/client/public/firebase-messaging-sw.js b/client/public/firebase-messaging-sw.js
index a0ad54337..083f63d12 100644
--- a/client/public/firebase-messaging-sw.js
+++ b/client/public/firebase-messaging-sw.js
@@ -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
diff --git a/client/public/manifest.json b/client/public/manifest.json
index 8577a90e4..d7008ba45 100644
--- a/client/public/manifest.json
+++ b/client/public/manifest.json
@@ -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",
diff --git a/client/src/App/App.container.jsx b/client/src/App/App.container.jsx
index 88cb569d8..0733204cd 100644
--- a/client/src/App/App.container.jsx
+++ b/client/src/App/App.container.jsx
@@ -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 (
-
-
-
-
- );
- }
+export default function AppContainer() {
+ return (
+
+
+
+
+ );
}
diff --git a/client/src/App/App.css b/client/src/App/App.css
deleted file mode 100644
index bc8c8182d..000000000
--- a/client/src/App/App.css
+++ /dev/null
@@ -1 +0,0 @@
-@import "~antd/dist/antd.css";
\ No newline at end of file
diff --git a/client/src/App/App.js b/client/src/App/App.js
index e071f0a85..c232f0efb 100644
--- a/client/src/App/App.js
+++ b/client/src/App/App.js
@@ -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(
);
-});
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(App);
diff --git a/client/src/components/error-boundary/error-boundary.component.jsx b/client/src/components/error-boundary/error-boundary.component.jsx
index 7648ee07c..7a28e5edd 100644
--- a/client/src/components/error-boundary/error-boundary.component.jsx
+++ b/client/src/components/error-boundary/error-boundary.component.jsx
@@ -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 Uh oh, something went wrong.
;
+ return (
+
+
+
+
+
+ }
+ />
+
+
+
+
+ {JSON.stringify(this.state.error || "")}
+
+
+
+
+
+ );
} else {
return this.props.children;
}
}
}
-export default ErrorBoundary;
+export default withTranslation()(ErrorBoundary);
diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx
index 7d5f2b84d..1a49d905f 100644
--- a/client/src/components/header/header.component.jsx
+++ b/client/src/components/header/header.component.jsx
@@ -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 (
-
- {logo ? (
-
-
+
+
+
+
- ) : null}
-
- {landingHeader ? (
-
- ) : (
-
+
+
+
);
}
diff --git a/client/src/components/header/header.container.jsx b/client/src/components/header/header.container.jsx
index 77a5feb4c..0ba66116c 100644
--- a/client/src/components/header/header.container.jsx
+++ b/client/src/components/header/header.container.jsx
@@ -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 (
-
- );
-});
+ return ;
+}
+
+export default connect(null, mapDispatchToProps)(HeaderContainer);
diff --git a/client/src/components/manage-sign-in-button/manage-sign-in-button.component.jsx b/client/src/components/manage-sign-in-button/manage-sign-in-button.component.jsx
index 5b0e60a72..5fa6a359c 100644
--- a/client/src/components/manage-sign-in-button/manage-sign-in-button.component.jsx
+++ b/client/src/components/manage-sign-in-button/manage-sign-in-button.component.jsx
@@ -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 ? (
-
+
Manage
) : (
-
+
Sign In
);
-});
+}
+export default connect(mapStateToProps, null)(ManageSignInButton);
diff --git a/client/src/firebase/firebase.utils.js b/client/src/firebase/firebase.utils.js
index d3bc91fe0..46feef523 100644
--- a/client/src/firebase/firebase.utils.js
+++ b/client/src/firebase/firebase.utils.js
@@ -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);
+};
diff --git a/client/src/pages/landing/landing.page.jsx b/client/src/pages/landing/landing.page.jsx
index ba6914ed5..a7c04163d 100644
--- a/client/src/pages/landing/landing.page.jsx
+++ b/client/src/pages/landing/landing.page.jsx
@@ -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 (
-
-
+
+
-
- ImEX.Online
-
+ ImEX.Online
);
}
diff --git a/client/src/pages/manage-root/manage-root.page.component.jsx b/client/src/pages/manage-root/manage-root.page.component.jsx
index 9cecd0e9c..28daf94c2 100644
--- a/client/src/pages/manage-root/manage-root.page.component.jsx
+++ b/client/src/pages/manage-root/manage-root.page.component.jsx
@@ -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() {
+
- {
- //
- // Send an Email in new Window
- //
- }
);
}
diff --git a/client/src/pages/manage-root/manage-root.page.container.jsx b/client/src/pages/manage-root/manage-root.page.container.jsx
index ffab7ffd0..c8627fc7e 100644
--- a/client/src/pages/manage-root/manage-root.page.container.jsx
+++ b/client/src/pages/manage-root/manage-root.page.container.jsx
@@ -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(() => {
diff --git a/client/src/pages/manage/manage.page.component.jsx b/client/src/pages/manage/manage.page.component.jsx
index 91725ce21..9b9667899 100644
--- a/client/src/pages/manage/manage.page.component.jsx
+++ b/client/src/pages/manage/manage.page.component.jsx
@@ -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 (
-
-
-
-
-
- {conflict ? (
-
- ) : (
-
- }
- >
-
-
-
-
-
-
-
-
+
+
+
+
+
+ {conflict ? (
+
+ ) : (
+
+ }>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )}
-
-
-
@@ -327,4 +312,4 @@ export function Manage({ match, conflict }) {
);
}
-export default connect(mapStateToProps, mapDispatchToProps)(Manage);
+export default connect(mapStateToProps, null)(Manage);
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index 3a8435fac..840300590 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -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": {
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index 8ec75bea0..4c7aee184 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -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": {
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index 787815d96..0fce3ad8c 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -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": {