Added better error boundary page. Started some CSS and layout refactoring. **Major Changes**.
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
@import "~antd/dist/antd.css";
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user