Compare commits

...

22 Commits

Author SHA1 Message Date
Dave Richer
f28653546b Merged in feature/IO-2916-Remove-Beta-Switch-Legacy (pull request #1692)
feature/IO-2916-Remove-Beta-Switch-Legacy - Remove Beta Switch
2024-09-10 17:29:42 +00:00
Dave Richer
e742917876 feature/IO-2916-Remove-Beta-Switch-LEGACY - Remove cookie
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-09-10 13:16:46 -04:00
Dave Richer
04a193ef37 feature/IO-2916-Remove-Beta-Switch-LEGACY - Remove cookie
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-09-10 13:11:23 -04:00
Dave Richer
cf258e9a12 feature/IO-2916-Remove-Beta-Switch-Legacy - Remove Beta Switch
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-09-09 23:45:56 -04:00
Dave Richer
a230e15a66 Merged in release/2024-08-23-LEGACY (pull request #1652)
Release/2024 08 23 LEGACY
2024-08-22 14:44:41 +00:00
Allan Carr
011cb1b349 Merged in feature/IO-2887-Returnfrombill-Parts-Drawer-LEGACY (pull request #1638)
IO-2887 Null out BillData if returnfrombill is not available
2024-08-20 23:16:45 +00:00
Allan Carr
9b2cdddb88 IO-2887 Null out BillData if returnfrombill is not available
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-20 16:17:04 -07:00
Allan Carr
c71db5133d Merged in feature/IO-2887-Returnfrombill-Parts-Drawer-LEGACY (pull request #1636)
IO-2887 Returnfrombill Parts Drawer Legacy
2024-08-20 22:46:36 +00:00
Allan Carr
ee733434e6 IO-2887 Returnfrombill Parts Drawer Legacy
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-20 15:45:21 -07:00
Dave Richer
c2050e7e26 Merged in release/2024-08-16-LEGACY (pull request #1626)
Release/2024 08 16 LEGACY

Approved-by: Allan Carr
2024-08-16 23:31:21 +00:00
Allan Carr
c0096a0dec Merged in feature/IO-2884-Production-List-Filter-LEGACY (pull request #1621)
IO-2884 Production List Filter LEGACY

Approved-by: Dave Richer
2024-08-16 16:16:29 +00:00
Allan Carr
41e40b9165 IO-2884 Production List Filter LEGACY
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-16 09:16:32 -07:00
Dave Richer
1e566c82cd Merged in feature/IO-2878-Enhance-Beta-Switch-legacy (pull request #1608)
- Improve handle beta code (AIO Version)
2024-08-15 15:21:28 +00:00
Dave Richer
d45be60668 - Improve handle beta code (AIO Version)
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-15 11:19:26 -04:00
Allan Carr
62d5511337 Merged in feature/IO-2876-OpenSearch-Sorters-LEGACY (pull request #1604)
IO-2876 OpenSearch Sorters LEGACY

Approved-by: Dave Richer
2024-08-14 19:37:26 +00:00
Allan Carr
ac37074666 IO-2876 OpenSearch Sorters LEGACY
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-14 11:47:34 -07:00
Dave Richer
9467c57c8f Merged in feature/IO-2878-Enhance-Beta-Switch-legacy (pull request #1600)
- Improve handle beta code (AIO Version)
2024-08-14 17:41:59 +00:00
Dave Richer
87f591ce1b - Improve handle beta code (AIO Version)
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-14 13:33:27 -04:00
Allan Carr
c3a950088e Merged in release/2024-08-16-LEGACY (pull request #1592)
Release/2024 08 16 LEGACY

Approved-by: Dave Richer
2024-08-12 23:54:09 +00:00
Allan Carr
704e35e0b0 Merged in feature/IO-2564-LEGACY-Row-Expander-Drawers (pull request #1589)
IO-2564 LEGACY Row Expander Drawers
2024-08-12 22:17:22 +00:00
Allan Carr
d616d204d0 Merged in feature/IO-2861-LEGACY-Disable-Vendor-and-Invoice-#-on-Edit-of-InHouse (pull request #1590)
IO-2861 LEGACY Disable Editing of InHouse Invoice for Vendor and Invoice Number
2024-08-12 22:16:24 +00:00
Allan Carr
492cee29e7 IO-2861 LEGACY Disable Editing of InHouse Invoice for Vendor and Invoice Number
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-12 12:36:31 -07:00
11 changed files with 234 additions and 605 deletions

View File

@@ -16,42 +16,28 @@ import TechPageContainer from "../pages/tech/tech.page.container";
import { setOnline } from "../redux/application/application.actions";
import { selectOnline } from "../redux/application/application.selectors";
import { checkUserSession } from "../redux/user/user.actions";
import {
selectBodyshop,
selectCurrentUser,
} from "../redux/user/user.selectors";
import { selectBodyshop, selectCurrentUser } from "../redux/user/user.selectors";
import PrivateRoute from "../utils/private-route";
import "./App.styles.scss";
import handleBeta from "../utils/handleBeta";
const ResetPassword = lazy(() =>
import("../pages/reset-password/reset-password.component")
);
const ResetPassword = lazy(() => import("../pages/reset-password/reset-password.component"));
const ManagePage = lazy(() => import("../pages/manage/manage.page.container"));
const SignInPage = lazy(() => import("../pages/sign-in/sign-in.page"));
const CsiPage = lazy(() => import("../pages/csi/csi.container.page"));
const MobilePaymentContainer = lazy(() =>
import("../pages/mobile-payment/mobile-payment.container")
);
const MobilePaymentContainer = lazy(() => import("../pages/mobile-payment/mobile-payment.container"));
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
online: selectOnline,
bodyshop: selectBodyshop,
bodyshop: selectBodyshop
});
const mapDispatchToProps = (dispatch) => ({
checkUserSession: () => dispatch(checkUserSession()),
setOnline: (isOnline) => dispatch(setOnline(isOnline)),
setOnline: (isOnline) => dispatch(setOnline(isOnline))
});
export function App({
bodyshop,
checkUserSession,
currentUser,
online,
setOnline,
}) {
export function App({ bodyshop, checkUserSession, currentUser, online, setOnline }) {
const client = useClient();
useEffect(() => {
@@ -108,8 +94,6 @@ export function App({
/>
);
handleBeta();
return (
<Switch>
<Suspense fallback={<LoadingSpinner message="ImEX Online" />}>
@@ -129,32 +113,16 @@ export function App({
<Route exact path="/disclaimer" component={DisclaimerPage} />
</ErrorBoundary>
<ErrorBoundary>
<Route
exact
path="/mp/:paymentIs"
component={MobilePaymentContainer}
/>
<Route exact path="/mp/:paymentIs" component={MobilePaymentContainer} />
</ErrorBoundary>
<ErrorBoundary>
<PrivateRoute
isAuthorized={currentUser.authorized}
path="/manage"
component={ManagePage}
/>
<PrivateRoute isAuthorized={currentUser.authorized} path="/manage" component={ManagePage} />
</ErrorBoundary>
<ErrorBoundary>
<PrivateRoute
isAuthorized={currentUser.authorized}
path="/tech"
component={TechPageContainer}
/>
<PrivateRoute isAuthorized={currentUser.authorized} path="/tech" component={TechPageContainer} />
</ErrorBoundary>
<ErrorBoundary>
<PrivateRoute
isAuthorized={currentUser.authorized}
path="/edit"
component={DocumentEditorContainer}
/>
<PrivateRoute isAuthorized={currentUser.authorized} path="/edit" component={DocumentEditorContainer} />
</ErrorBoundary>
</Suspense>
</Switch>

View File

@@ -164,6 +164,7 @@ export function BillDetailEditcontainer({
if (!search.billid) return <></>; //<div>{t("bills.labels.noneselected")}</div>;
const exported = data && data.bills_by_pk && data.bills_by_pk.exported;
const isinhouse = data && data.bills_by_pk && data.bills_by_pk.isinhouse;
return (
<>
@@ -207,7 +208,7 @@ export function BillDetailEditcontainer({
initialValues={transformData(data)}
layout="vertical"
>
<BillFormContainer form={form} billEdit disabled={exported} />
<BillFormContainer form={form} billEdit disabled={exported} disableInHouse={isinhouse}/>
<Divider orientation="left">{t("general.labels.media")}</Divider>
{bodyshop.uselocalmediaserver ? (
<JobsDocumentsLocalGallery

View File

@@ -47,6 +47,7 @@ export function BillFormComponent({
loadLines,
billEdit,
disableInvNumber,
disableInHouse,
job,
loadOutstandingReturns,
loadInventory,
@@ -198,7 +199,7 @@ export function BillFormComponent({
]}
>
<VendorSearchSelect
disabled={disabled}
disabled={disabled || disableInHouse}
options={vendorAutoCompleteOptions}
preferredMake={preferredMake}
onSelect={handleVendorSelect}
@@ -271,7 +272,7 @@ export function BillFormComponent({
}),
]}
>
<Input disabled={disabled || disableInvNumber} />
<Input disabled={disabled || disableInvNumber || disableInHouse} />
</Form.Item>
<Form.Item
label={t("bills.fields.date")}

View File

@@ -22,6 +22,7 @@ export function BillFormContainer({
billEdit,
disabled,
disableInvNumber,
disableInHouse
}) {
const { Simple_Inventory } = useTreatments(
["Simple_Inventory"],
@@ -57,6 +58,7 @@ export function BillFormContainer({
job={lineData ? lineData.jobs_by_pk : null}
responsibilityCenters={bodyshop.md_responsibility_centers || null}
disableInvNumber={disableInvNumber}
disableInHouse={disableInHouse}
loadOutstandingReturns={loadOutstandingReturns}
loadInventory={loadInventory}
preferredMake={lineData ? lineData.jobs_by_pk.v_make_desc : null}

View File

@@ -11,9 +11,8 @@ import Icon, {
FileAddFilled,
FileAddOutlined,
FileFilled,
//GlobalOutlined,
HomeFilled,
ImportOutlined, InfoCircleOutlined,
ImportOutlined,
LineChartOutlined,
PaperClipOutlined,
PhoneOutlined,
@@ -23,56 +22,39 @@ import Icon, {
TeamOutlined,
ToolFilled,
UnorderedListOutlined,
UserOutlined,
UserOutlined
} from "@ant-design/icons";
import { useTreatments } from "@splitsoftware/splitio-react";
import {Layout, Menu, Switch, Tooltip} from "antd";
import React, {useEffect, useState} from "react";
import { Layout, Menu } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { BsKanban } from "react-icons/bs";
import {
FaCalendarAlt,
FaCarCrash,
FaCreditCard,
FaFileInvoiceDollar,
} from "react-icons/fa";
import { FaCalendarAlt, FaCarCrash, FaCreditCard, FaFileInvoiceDollar } from "react-icons/fa";
import { GiPayMoney, GiPlayerTime, GiSettingsKnobs } from "react-icons/gi";
import { IoBusinessOutline } from "react-icons/io5";
import { RiSurveyLine } from "react-icons/ri";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import {
selectRecentItems,
selectSelectedHeader,
} from "../../redux/application/application.selectors";
import { selectRecentItems, selectSelectedHeader } from "../../redux/application/application.selectors";
import { setModalContext } from "../../redux/modals/modals.actions";
import { signOutStart } from "../../redux/user/user.actions";
import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import {handleBeta, setBeta, checkBeta} from "../../utils/handleBeta";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
recentItems: selectRecentItems,
selectedHeader: selectSelectedHeader,
bodyshop: selectBodyshop,
bodyshop: selectBodyshop
});
const mapDispatchToProps = (dispatch) => ({
setBillEnterContext: (context) =>
dispatch(setModalContext({ context: context, modal: "billEnter" })),
setTimeTicketContext: (context) =>
dispatch(setModalContext({ context: context, modal: "timeTicket" })),
setPaymentContext: (context) =>
dispatch(setModalContext({ context: context, modal: "payment" })),
setReportCenterContext: (context) =>
dispatch(setModalContext({ context: context, modal: "reportCenter" })),
setBillEnterContext: (context) => dispatch(setModalContext({ context: context, modal: "billEnter" })),
setTimeTicketContext: (context) => dispatch(setModalContext({ context: context, modal: "timeTicket" })),
setPaymentContext: (context) => dispatch(setModalContext({ context: context, modal: "payment" })),
setReportCenterContext: (context) => dispatch(setModalContext({ context: context, modal: "reportCenter" })),
signOutStart: () => dispatch(signOutStart()),
setCardPaymentContext: (context) =>
dispatch(setModalContext({ context: context, modal: "cardPayment" })),
setCardPaymentContext: (context) => dispatch(setModalContext({ context: context, modal: "cardPayment" }))
});
function Header({
@@ -86,37 +68,26 @@ function Header({
setPaymentContext,
setReportCenterContext,
recentItems,
setCardPaymentContext,
setCardPaymentContext
}) {
const { Simple_Inventory } = useTreatments(
["Simple_Inventory"],
{},
bodyshop && bodyshop.imexshopid
);
const { DmsAp } = useTreatments(
["DmsAp"],
{},
bodyshop && bodyshop.imexshopid
);
const { ImEXPay } = useTreatments(
["ImEXPay"],
{},
bodyshop && bodyshop.imexshopid
);
const [betaSwitch, setBetaSwitch] = useState(false);
const { Simple_Inventory } = useTreatments(["Simple_Inventory"], {}, bodyshop && bodyshop.imexshopid);
const { DmsAp } = useTreatments(["DmsAp"], {}, bodyshop && bodyshop.imexshopid);
const { ImEXPay } = useTreatments(["ImEXPay"], {}, bodyshop && bodyshop.imexshopid);
const { t } = useTranslation();
useEffect(() => {
const isBeta = checkBeta();
setBetaSwitch(isBeta);
}, []);
const deleteBetaCookie = () => {
const cookieExists = document.cookie.split("; ").some((row) => row.startsWith(`betaSwitchImex=`));
if (cookieExists) {
const domain = window.location.hostname.split(".").slice(-2).join(".");
document.cookie = `betaSwitchImex=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`;
console.log(`betaSwitchImex cookie deleted`);
} else {
console.log(`betaSwitchImex cookie does not exist`);
}
};
const betaSwitchChange = (checked) => {
setBeta(checked);
setBetaSwitch(checked);
handleBeta();
}
deleteBetaCookie();
return (
<Layout.Header>
@@ -134,11 +105,7 @@ function Header({
<Menu.Item key="schedule" icon={<Icon component={FaCalendarAlt} />}>
<Link to="/manage/schedule">{t("menus.header.schedule")}</Link>
</Menu.Item>
<Menu.SubMenu
key="jobssubmenu"
icon={<Icon component={FaCarCrash} />}
title={t("menus.header.jobs")}
>
<Menu.SubMenu key="jobssubmenu" icon={<Icon component={FaCarCrash} />} title={t("menus.header.jobs")}>
<Menu.Item key="activejobs" icon={<FileFilled />}>
<Link to="/manage/jobs">{t("menus.header.activejobs")}</Link>
</Menu.Item>
@@ -149,9 +116,7 @@ function Header({
<Link to="/manage/partsqueue">{t("menus.header.parts-queue")}</Link>
</Menu.Item>
<Menu.Item key="availablejobs" icon={<ImportOutlined />}>
<Link to="/manage/available">
{t("menus.header.availablejobs")}
</Link>
<Link to="/manage/available">{t("menus.header.availablejobs")}</Link>
</Menu.Item>
<Menu.Item key="newjob" icon={<FileAddOutlined />}>
<Link to="/manage/jobs/new">{t("menus.header.newjob")}</Link>
@@ -162,25 +127,17 @@ function Header({
</Menu.Item>
<Menu.Divider key="div2" />
<Menu.Item key="productionlist" icon={<ScheduleOutlined />}>
<Link to="/manage/production/list">
{t("menus.header.productionlist")}
</Link>
<Link to="/manage/production/list">{t("menus.header.productionlist")}</Link>
</Menu.Item>
<Menu.Item key="productionboard" icon={<Icon component={BsKanban} />}>
<Link to="/manage/production/board">
{t("menus.header.productionboard")}
</Link>
<Link to="/manage/production/board">{t("menus.header.productionboard")}</Link>
</Menu.Item>
<Menu.Divider key="div3" />
<Menu.Item key="scoreboard" icon={<LineChartOutlined />}>
<Link to="/manage/scoreboard">{t("menus.header.scoreboard")}</Link>
</Menu.Item>
</Menu.SubMenu>
<Menu.SubMenu
key="customers"
icon={<UserOutlined />}
title={t("menus.header.customers")}
>
<Menu.SubMenu key="customers" icon={<UserOutlined />} title={t("menus.header.customers")}>
<Menu.Item key="owners" icon={<TeamOutlined />}>
<Link to="/manage/owners">{t("menus.header.owners")}</Link>
</Menu.Item>
@@ -188,36 +145,19 @@ function Header({
<Link to="/manage/vehicles">{t("menus.header.vehicles")}</Link>
</Menu.Item>
</Menu.SubMenu>
<Menu.SubMenu
key="ccs"
icon={<CarFilled />}
title={t("menus.header.courtesycars")}
>
<Menu.SubMenu key="ccs" icon={<CarFilled />} title={t("menus.header.courtesycars")}>
<Menu.Item key="courtesycarsall" icon={<CarFilled />}>
<Link to="/manage/courtesycars">
{t("menus.header.courtesycars-all")}
</Link>
<Link to="/manage/courtesycars">{t("menus.header.courtesycars-all")}</Link>
</Menu.Item>
<Menu.Item key="contracts" icon={<FileFilled />}>
<Link to="/manage/courtesycars/contracts">
{t("menus.header.courtesycars-contracts")}
</Link>
<Link to="/manage/courtesycars/contracts">{t("menus.header.courtesycars-contracts")}</Link>
</Menu.Item>
<Menu.Item key="newcontract" icon={<FileAddFilled />}>
<Link to="/manage/courtesycars/contracts/new">
{t("menus.header.courtesycars-newcontract")}
</Link>
<Link to="/manage/courtesycars/contracts/new">{t("menus.header.courtesycars-newcontract")}</Link>
</Menu.Item>
</Menu.SubMenu>
<Menu.SubMenu
key="accounting"
icon={<DollarCircleFilled />}
title={t("menus.header.accounting")}
>
<Menu.Item
key="bills"
icon={<Icon component={FaFileInvoiceDollar} />}
>
<Menu.SubMenu key="accounting" icon={<DollarCircleFilled />} title={t("menus.header.accounting")}>
<Menu.Item key="bills" icon={<Icon component={FaFileInvoiceDollar} />}>
<Link to="/manage/bills">{t("menus.header.bills")}</Link>
</Menu.Item>
<Menu.Item
@@ -226,7 +166,7 @@ function Header({
onClick={() => {
setBillEnterContext({
actions: {},
context: {},
context: {}
});
}}
>
@@ -235,13 +175,8 @@ function Header({
{Simple_Inventory.treatment === "on" && (
<>
<Menu.Divider key="div4" />
<Menu.Item
key="inventory"
icon={<Icon component={FaFileInvoiceDollar} />}
>
<Link to="/manage/inventory">
{t("menus.header.inventory")}
</Link>
<Menu.Item key="inventory" icon={<Icon component={FaFileInvoiceDollar} />}>
<Link to="/manage/inventory">{t("menus.header.inventory")}</Link>
</Menu.Item>
</>
)}
@@ -254,7 +189,7 @@ function Header({
onClick={() => {
setPaymentContext({
actions: {},
context: null,
context: null
});
}}
icon={<Icon component={FaCreditCard} />}
@@ -267,7 +202,7 @@ function Header({
onClick={() => {
setCardPaymentContext({
actions: {},
context: {},
context: {}
});
}}
icon={<Icon component={FaCreditCard} />}
@@ -277,9 +212,7 @@ function Header({
)}
<Menu.Divider key="div5" />
<Menu.Item key="timetickets" icon={<FieldTimeOutlined />}>
<Link to="/manage/timetickets">
{t("menus.header.timetickets")}
</Link>
<Link to="/manage/timetickets">{t("menus.header.timetickets")}</Link>
</Menu.Item>
<Menu.Item
key="entertimetickets"
@@ -290,49 +223,31 @@ function Header({
context: {
created_by: currentUser.displayName
? currentUser.email.concat(" | ", currentUser.displayName)
: currentUser.email,
},
: currentUser.email
}
});
}}
>
{t("menus.header.entertimeticket")}
</Menu.Item>
<Menu.Divider key="div6" />
<Menu.SubMenu
key="accountingexport"
title={t("menus.header.export")}
icon={<ExportOutlined />}
>
<Menu.SubMenu key="accountingexport" title={t("menus.header.export")} icon={<ExportOutlined />}>
<Menu.Item key="receivables">
<Link to="/manage/accounting/receivables">
{t("menus.header.accounting-receivables")}
</Link>
<Link to="/manage/accounting/receivables">{t("menus.header.accounting-receivables")}</Link>
</Menu.Item>
{(!(
(bodyshop && bodyshop.cdk_dealerid) ||
(bodyshop && bodyshop.pbs_serialnumber)
) ||
{(!((bodyshop && bodyshop.cdk_dealerid) || (bodyshop && bodyshop.pbs_serialnumber)) ||
DmsAp.treatment === "on") && (
<Menu.Item key="payables">
<Link to="/manage/accounting/payables">
{t("menus.header.accounting-payables")}
</Link>
<Link to="/manage/accounting/payables">{t("menus.header.accounting-payables")}</Link>
</Menu.Item>
)}
{!(
(bodyshop && bodyshop.cdk_dealerid) ||
(bodyshop && bodyshop.pbs_serialnumber)
) && (
{!((bodyshop && bodyshop.cdk_dealerid) || (bodyshop && bodyshop.pbs_serialnumber)) && (
<Menu.Item key="payments">
<Link to="/manage/accounting/payments">
{t("menus.header.accounting-payments")}
</Link>
<Link to="/manage/accounting/payments">{t("menus.header.accounting-payments")}</Link>
</Menu.Item>
)}
<Menu.Item key="export-logs">
<Link to="/manage/accounting/exportlogs">
{t("menus.header.export-logs")}
</Link>
<Link to="/manage/accounting/exportlogs">{t("menus.header.export-logs")}</Link>
</Menu.Item>
</Menu.SubMenu>
</Menu.SubMenu>
@@ -340,19 +255,11 @@ function Header({
<Link to="/manage/phonebook">{t("menus.header.phonebook")}</Link>
</Menu.Item>
<Menu.Item key="temporarydocs" icon={<PaperClipOutlined />}>
<Link to="/manage/temporarydocs">
{t("menus.header.temporarydocs")}
</Link>
<Link to="/manage/temporarydocs">{t("menus.header.temporarydocs")}</Link>
</Menu.Item>
<Menu.SubMenu
key="shopsubmenu"
title={t("menus.header.shop")}
icon={<SettingOutlined />}
>
<Menu.SubMenu key="shopsubmenu" title={t("menus.header.shop")} icon={<SettingOutlined />}>
<Menu.Item key="shop" icon={<Icon component={GiSettingsKnobs} />}>
<Link to="/manage/shop?tab=info">
{t("menus.header.shop_config")}
</Link>
<Link to="/manage/shop?tab=info">{t("menus.header.shop_config")}</Link>
</Menu.Item>
<Menu.Item key="dashboard" icon={<DashboardFilled />}>
<Link to="/manage/dashboard">{t("menus.header.dashboard")}</Link>
@@ -363,32 +270,20 @@ function Header({
onClick={() => {
setReportCenterContext({
actions: {},
context: {},
context: {}
});
}}
>
{t("menus.header.reportcenter")}
</Menu.Item>
<Menu.Item
key="shop-vendors"
icon={<Icon component={IoBusinessOutline} />}
>
<Link to="/manage/shop/vendors">
{t("menus.header.shop_vendors")}
</Link>
<Menu.Item key="shop-vendors" icon={<Icon component={IoBusinessOutline} />}>
<Link to="/manage/shop/vendors">{t("menus.header.shop_vendors")}</Link>
</Menu.Item>
<Menu.Item key="shop-csi" icon={<Icon component={RiSurveyLine} />}>
<Link to="/manage/shop/csi">{t("menus.header.shop_csi")}</Link>
</Menu.Item>
</Menu.SubMenu>
<Menu.SubMenu
key="user"
title={
currentUser.displayName ||
currentUser.email ||
t("general.labels.unknown")
}
>
<Menu.SubMenu key="user" title={currentUser.displayName || currentUser.email || t("general.labels.unknown")}>
<Menu.Item key="signout" danger onClick={() => signOutStart()}>
{t("user.actions.signout")}
</Menu.Item>
@@ -444,17 +339,6 @@ function Header({
</Menu.Item>
))}
</Menu.SubMenu>
<Menu.Item style={{marginLeft: 'auto'}} key="profile">
<Tooltip title="A more modern ImEX Online is ready for you to try! You can switch back at any time.">
<InfoCircleOutlined/>
<span style={{marginRight: 8}}>Try the new ImEX Online</span>
<Switch
checked={betaSwitch}
onChange={betaSwitchChange}
/>
</Tooltip>
</Menu.Item>
</Menu>
</Layout.Header>
);

View File

@@ -11,6 +11,7 @@ import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { pageLimit } from "../../utils/config";
import { alphaSort, statusSort } from "../../utils/sorters";
import useLocalStorage from "../../utils/useLocalStorage";
import StartChatButton from "../chat-open-button/chat-open-button.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
@@ -36,7 +37,10 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.ro_number"),
dataIndex: "ro_number",
key: "ro_number",
sorter: true, //(a, b) => alphaSort(a.ro_number, b.ro_number),
sorter: search?.search
? (a, b) =>
parseInt((a.ro_number || "0").replace(/\D/g, "")) - parseInt((b.ro_number || "0").replace(/\D/g, ""))
: true,
sortOrder: sortcolumn === "ro_number" && sortorder,
render: (text, record) => (
<Link to={"/manage/jobs/" + record.id}>
@@ -50,7 +54,6 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
key: "ownr_ln",
ellipsis: true,
//sorter: true, // (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
//sortOrder: sortcolumn === "ownr_ln" && sortorder,
render: (text, record) => {
return record.ownerid ? (
@@ -68,7 +71,6 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.ownr_ph1"),
dataIndex: "ownr_ph1",
key: "ownr_ph1",
ellipsis: true,
render: (text, record) => (
<StartChatButton phone={record.ownr_ph1} jobid={record.id} />
@@ -78,7 +80,6 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.ownr_ph2"),
dataIndex: "ownr_ph2",
key: "ownr_ph2",
ellipsis: true,
render: (text, record) => (
<StartChatButton phone={record.ownr_ph2} jobid={record.id} />
@@ -88,9 +89,8 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.status"),
dataIndex: "status",
key: "status",
ellipsis: true,
sorter: true, // (a, b) => alphaSort(a.status, b.status),
sorter: search?.search ? (a, b) => statusSort(a.status, b.status, bodyshop.md_ro_statuses.active_statuses) : true,
sortOrder: sortcolumn === "status" && sortorder,
render: (text, record) => {
return record.status || t("general.labels.na");
@@ -106,7 +106,6 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.vehicle"),
dataIndex: "vehicle",
key: "vehicle",
ellipsis: true,
render: (text, record) => {
return record.vehicleid ? (
@@ -127,7 +126,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
dataIndex: "plate_no",
key: "plate_no",
ellipsis: true,
sorter: true, //(a, b) => alphaSort(a.plate_no, b.plate_no),
sorter: search?.search ? (a, b) => alphaSort(a.plate_no, b.plate_no) : true,
sortOrder: sortcolumn === "plate_no" && sortorder,
render: (text, record) => {
return record.plate_no ? record.plate_no : "";
@@ -138,7 +137,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
dataIndex: "clm_no",
key: "clm_no",
ellipsis: true,
sorter: true, //(a, b) => alphaSort(a.clm_no, b.clm_no),
sorter: search?.search ? (a, b) => alphaSort(a.clm_no, b.clm_no) : true,
sortOrder: sortcolumn === "clm_no" && sortorder,
render: (text, record) =>
`${record.clm_no || ""}${
@@ -156,7 +155,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
dataIndex: "clm_total",
key: "clm_total",
sorter: true, //(a, b) => a.clm_total - b.clm_total,
sorter: search?.search ? (a, b) => a.clm_total - b.clm_total : true,
sortOrder: sortcolumn === "clm_total" && sortorder,
render: (text, record) => {
return record.clm_total ? (
@@ -170,7 +169,6 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.owner_owing"),
dataIndex: "owner_owing",
key: "owner_owing",
render: (text, record) => (
<CurrencyFormatter>{record.owner_owing}</CurrencyFormatter>
),

View File

@@ -1,4 +1,4 @@
import { DeleteFilled, EyeFilled } from "@ant-design/icons";
import { DeleteFilled } from "@ant-design/icons";
import { useLazyQuery, useMutation } from "@apollo/client";
import {
Button,
@@ -12,7 +12,6 @@ import {
import queryString from "query-string";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { FaTasks } from "react-icons/fa";
import { connect } from "react-redux";
import { useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
@@ -55,8 +54,6 @@ const mapDispatchToProps = (dispatch) => ({
modal: "partsReceive",
})
),
setTaskUpsertContext: (context) =>
dispatch(setModalContext({ context, modal: "taskUpsert" })),
});
export function PartsOrderListTableDrawerComponent({
@@ -67,7 +64,6 @@ export function PartsOrderListTableDrawerComponent({
billsQuery,
handleOnRowClick,
setPartsReceiveContext,
setTaskUpsertContext,
}) {
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1])
@@ -92,8 +88,7 @@ export function PartsOrderListTableDrawerComponent({
sortedInfo: {},
});
const [returnfrombill, setReturnFromBill] = useState();
const [billData, setBillData] = useState();
const [billData, setBillData] = useState(null);
const search = queryString.parse(useLocation().search);
const selectedpartsorder = search.partsorderid;
@@ -102,37 +97,28 @@ export function PartsOrderListTableDrawerComponent({
const parts_orders = billsQuery.data ? billsQuery.data.parts_orders : [];
const { refetch } = billsQuery;
const selectedPartsOrderRecord = parts_orders.find(
(r) => r.id === selectedpartsorder
);
useEffect(() => {
if (returnfrombill === null) {
setBillData(null);
} else {
const fetchData = async () => {
const result = await billQuery({
variables: { billid: returnfrombill },
});
setBillData(result.data);
};
fetchData();
}
}, [returnfrombill, billQuery]);
const fetchData = async () => {
if (selectedPartsOrderRecord?.returnfrombill) {
try {
const { data } = await billQuery({
variables: { billid: selectedPartsOrderRecord.returnfrombill },
});
setBillData(data);
} catch (error) {
console.error("Error fetching bill data:", error);
}
} else setBillData(null);
};
fetchData();
}, [selectedPartsOrderRecord, billQuery]);
const recordActions = (record, showView = false) => (
const recordActions = (record) => (
<Space direction="horizontal" wrap>
{showView && (
<Button
onClick={() => {
if (record.returnfrombill) {
setReturnFromBill(record.returnfrombill);
} else {
setReturnFromBill(null);
}
handleOnRowClick(record);
}}
>
<EyeFilled />
</Button>
)}
<Button
disabled={
jobRO ||
@@ -146,41 +132,25 @@ export function PartsOrderListTableDrawerComponent({
context: {
jobId: job.id,
job: job,
partsorderlines: record.parts_order_lines.map((pol) => {
return {
joblineid: pol.job_line_id,
id: pol.id,
line_desc: pol.line_desc,
quantity: pol.quantity,
act_price: pol.act_price,
oem_partno: pol.oem_partno,
};
}),
partsorderlines: record.parts_order_lines.map((pol) => ({
joblineid: pol.job_line_id,
id: pol.id,
line_desc: pol.line_desc,
quantity: pol.quantity,
act_price: pol.act_price,
oem_partno: pol.oem_partno,
})),
},
});
}}
>
{t("parts_orders.actions.receive")}
</Button>
<Button
title={t("tasks.buttons.create")}
onClick={() => {
setTaskUpsertContext({
context: {
jobid: job.id,
partsorderid: record.id,
},
});
}}
>
<FaTasks />
</Button>
<Popconfirm
title={t("parts_orders.labels.confirmdelete")}
disabled={jobRO}
onConfirm={async () => {
//Delete the parts return.!
await deletePartsOrder({
variables: { partsOrderId: record.id },
update(cache) {
@@ -209,7 +179,6 @@ export function PartsOrderListTableDrawerComponent({
}
onClick={() => {
logImEXEvent("parts_order_receive_bill");
setBillEnterContext({
actions: { refetch: refetch },
context: {
@@ -217,27 +186,23 @@ export function PartsOrderListTableDrawerComponent({
bill: {
vendorid: record.vendor.id,
is_credit_memo: record.return,
billlines: record.parts_order_lines.map((pol) => {
return {
joblineid: pol.job_line_id || "noline",
line_desc: pol.line_desc,
quantity: pol.quantity,
actual_price: pol.act_price,
cost_center: pol.jobline?.part_type
? bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid
? pol.jobline.part_type !== "PAE"
? pol.jobline.part_type
: null
: responsibilityCenters.defaults &&
(responsibilityCenters.defaults.costs[
pol.jobline.part_type
] ||
null)
: null,
};
}),
billlines: record.parts_order_lines.map((pol) => ({
joblineid: pol.job_line_id || "noline",
line_desc: pol.line_desc,
quantity: pol.quantity,
actual_price: pol.act_price,
cost_center: pol.jobline?.part_type
? bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid
? pol.jobline.part_type !== "PAE"
? pol.jobline.part_type
: null
: responsibilityCenters.defaults &&
(responsibilityCenters.defaults.costs[
pol.jobline.part_type
] ||
null)
: null,
})),
},
},
});
@@ -268,10 +233,6 @@ export function PartsOrderListTableDrawerComponent({
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
const selectedPartsOrderRecord = parts_orders.find(
(r) => r.id === selectedpartsorder
);
const rowExpander = (record) => {
const columns = [
{

View File

@@ -9,9 +9,7 @@ import { onlyUnique } from "../../utils/arrayHelper";
import { alphaSort, dateSort, statusSort } from "../../utils/sorters";
import JobAltTransportChange from "../job-at-change/job-at-change.component";
import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component";
import OwnerNameDisplay, {
OwnerNameDisplayFunction,
} from "../owner-name-display/owner-name-display.component";
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
import ProductionListColumnAlert from "./production-list-columns.alert.component";
import ProductionListColumnBodyPriority from "./production-list-columns.bodypriority.component";
@@ -34,11 +32,7 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
dataIndex: "viewdetail",
key: "viewdetail",
ellipsis: true,
render: (text, record) => (
<Link to={{ search: `?selected=${record.id}` }}>
{i18n.t("general.labels.view")}
</Link>
),
render: (text, record) => <Link to={{ search: `?selected=${record.id}` }}>{i18n.t("general.labels.view")}</Link>
},
{
title: i18n.t("jobs.fields.ro_number"),
@@ -46,23 +40,18 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "ro_number",
ellipsis: true,
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
sortOrder:
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
sortOrder: state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
render: (text, record) =>
technician ? (
<Link to={`/tech/joblookup?selected=${record.id}`}>
{record.ro_number}
{record.suspended && (
<PauseCircleOutlined style={{ color: "orangered" }} />
)}
{record.suspended && <PauseCircleOutlined style={{ color: "orangered" }} />}
</Link>
) : (
<Link to={`/manage/jobs/${record.id}`}>
<Space>
{record.ro_number}
{record.suspended && (
<PauseCircleOutlined style={{ color: "orangered" }} />
)}
{record.suspended && <PauseCircleOutlined style={{ color: "orangered" }} />}
{record.iouparent && (
<Tooltip title={i18n.t("jobs.labels.iou")}>
<BranchesOutlined style={{ color: "orangered" }} />
@@ -70,7 +59,7 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
)}
</Space>
</Link>
),
)
},
{
title: i18n.t("jobs.fields.owner"),
@@ -85,10 +74,8 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
<OwnerNameDisplay ownerObject={record} />
</Link>
),
sorter: (a, b) =>
alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
sortOrder:
state.sortedInfo.columnKey === "ownr" && state.sortedInfo.order,
sorter: (a, b) => alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
sortOrder: state.sortedInfo.columnKey === "ownr" && state.sortedInfo.order
},
{
title: i18n.t("jobs.fields.vehicle"),
@@ -97,13 +84,10 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
ellipsis: true,
sorter: (a, b) =>
alphaSort(
`${a.v_model_yr || ""} ${a.v_make_desc || ""} ${
a.v_model_desc || ""
}`,
`${a.v_model_yr || ""} ${a.v_make_desc || ""} ${a.v_model_desc || ""}`,
`${b.v_model_yr || ""} ${b.v_make_desc || ""} ${b.v_model_desc || ""}`
),
sortOrder:
state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
sortOrder: state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
render: (text, record) =>
technician ? (
<>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
@@ -115,7 +99,7 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
} ${record.v_make_desc || ""} ${record.v_model_desc || ""} ${
record.v_color || ""
} ${record.plate_no || ""}`}</Link>
),
)
},
{
title: i18n.t("jobs.fields.actual_in"),
@@ -123,11 +107,8 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "actual_in",
ellipsis: true,
sorter: (a, b) => dateSort(a.actual_in, b.actual_in),
sortOrder:
state.sortedInfo.columnKey === "actual_in" && state.sortedInfo.order,
render: (text, record) => (
<ProductionListDate record={record} field="actual_in" time />
),
sortOrder: state.sortedInfo.columnKey === "actual_in" && state.sortedInfo.order,
render: (text, record) => <ProductionListDate record={record} field="actual_in" time />
},
{
title: i18n.t("jobs.fields.actual_in") + " (HH:MM)",
@@ -135,28 +116,16 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "actual_in_time",
ellipsis: true,
render: (text, record) => (
<TimeFormatter>{record.actual_in}</TimeFormatter>
),
render: (text, record) => <TimeFormatter>{record.actual_in}</TimeFormatter>
},
{
title: i18n.t("jobs.fields.scheduled_completion"),
dataIndex: "scheduled_completion",
key: "scheduled_completion",
ellipsis: true,
sorter: (a, b) =>
dateSort(a.scheduled_completion, b.scheduled_completion),
sortOrder:
state.sortedInfo.columnKey === "scheduled_completion" &&
state.sortedInfo.order,
render: (text, record) => (
<ProductionListDate
record={record}
field="scheduled_completion"
pastIndicator
time
/>
),
sorter: (a, b) => dateSort(a.scheduled_completion, b.scheduled_completion),
sortOrder: state.sortedInfo.columnKey === "scheduled_completion" && state.sortedInfo.order,
render: (text, record) => <ProductionListDate record={record} field="scheduled_completion" pastIndicator time />
},
{
title: i18n.t("jobs.fields.scheduled_completion") + " (HH:MM)",
@@ -164,9 +133,7 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "scheduled_completion_time",
ellipsis: true,
render: (text, record) => (
<TimeFormatter>{record.scheduled_completion}</TimeFormatter>
),
render: (text, record) => <TimeFormatter>{record.scheduled_completion}</TimeFormatter>
},
{
title: i18n.t("jobs.fields.date_last_contacted"),
@@ -174,10 +141,8 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "date_last_contacted",
ellipsis: true,
sorter: (a, b) => dateSort(a.date_last_contacted, b.date_last_contacted),
sortOrder:
state.sortedInfo.columnKey === "date_last_contacted" &&
state.sortedInfo.order,
render: (text, record) => <ProductionListLastContacted record={record} />,
sortOrder: state.sortedInfo.columnKey === "date_last_contacted" && state.sortedInfo.order,
render: (text, record) => <ProductionListLastContacted record={record} />
},
{
title: i18n.t("jobs.fields.date_next_contact"),
@@ -185,17 +150,8 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "date_next_contact",
ellipsis: true,
sorter: (a, b) => dateSort(a.date_next_contact, b.date_next_contact),
sortOrder:
state.sortedInfo.columnKey === "date_next_contact" &&
state.sortedInfo.order,
render: (text, record) => (
<ProductionListDate
record={record}
field="date_next_contact"
pastIndicator
time
/>
),
sortOrder: state.sortedInfo.columnKey === "date_next_contact" && state.sortedInfo.order,
render: (text, record) => <ProductionListDate record={record} field="date_next_contact" pastIndicator time />
},
{
title: i18n.t("jobs.fields.scheduled_delivery"),
@@ -203,17 +159,8 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "scheduled_delivery",
ellipsis: true,
sorter: (a, b) => dateSort(a.scheduled_delivery, b.scheduled_delivery),
sortOrder:
state.sortedInfo.columnKey === "scheduled_delivery" &&
state.sortedInfo.order,
render: (text, record) => (
<ProductionListDate
record={record}
field="scheduled_delivery"
pastIndicator
time
/>
),
sortOrder: state.sortedInfo.columnKey === "scheduled_delivery" && state.sortedInfo.order,
render: (text, record) => <ProductionListDate record={record} field="scheduled_delivery" pastIndicator time />
},
{
title: i18n.t("jobs.fields.scheduled_delivery") + " (HH:MM)",
@@ -221,9 +168,7 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "scheduled_delivery_time",
ellipsis: true,
render: (text, record) => (
<TimeFormatter>{record.scheduled_delivery}</TimeFormatter>
),
render: (text, record) => <TimeFormatter>{record.scheduled_delivery}</TimeFormatter>
},
{
title: i18n.t("jobs.fields.ins_co_nm"),
@@ -231,8 +176,7 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "ins_co_nm",
ellipsis: true,
sorter: (a, b) => alphaSort(a.ins_co_nm, b.ins_co_nm),
sortOrder:
state.sortedInfo.columnKey === "ins_co_nm" && state.sortedInfo.order,
sortOrder: state.sortedInfo.columnKey === "ins_co_nm" && state.sortedInfo.order
},
{
title: i18n.t("jobs.fields.clm_no"),
@@ -240,8 +184,7 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "clm_no",
ellipsis: true,
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
sortOrder:
state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
sortOrder: state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order
},
{
title: i18n.t("jobs.fields.clm_total"),
@@ -249,11 +192,8 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "clm_total",
ellipsis: true,
sorter: (a, b) => a.clm_total - b.clm_total,
sortOrder:
state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
render: (text, record) => (
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
),
sortOrder: state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
render: (text, record) => <CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
},
{
title: i18n.t("jobs.fields.owner_owing"),
@@ -261,49 +201,36 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "owner_owing",
ellipsis: true,
sorter: (a, b) => a.owner_owing - b.owner_owing,
sortOrder:
state.sortedInfo.columnKey === "owner_owing" && state.sortedInfo.order,
render: (text, record) => (
<CurrencyFormatter>{record.owner_owing}</CurrencyFormatter>
),
sortOrder: state.sortedInfo.columnKey === "owner_owing" && state.sortedInfo.order,
render: (text, record) => <CurrencyFormatter>{record.owner_owing}</CurrencyFormatter>
},
{
title: i18n.t("jobs.fields.ownr_ph1"),
dataIndex: "ownr_ph1",
key: "ownr_ph1",
ellipsis: true,
render: (text, record) => (
<PhoneFormatter>{record.ownr_ph1}</PhoneFormatter>
),
render: (text, record) => <PhoneFormatter>{record.ownr_ph1}</PhoneFormatter>
},
{
title: i18n.t("jobs.fields.ownr_ph2"),
dataIndex: "ownr_ph2",
key: "ownr_ph2",
ellipsis: true,
render: (text, record) => (
<PhoneFormatter>{record.ownr_ph2}</PhoneFormatter>
),
render: (text, record) => <PhoneFormatter>{record.ownr_ph2}</PhoneFormatter>
},
{
title: i18n.t("jobs.fields.specialcoveragepolicy"),
dataIndex: "special_coverage_policy",
key: "special_coverage_policy",
ellipsis: true,
sorter: (a, b) =>
Number(a.special_coverage_policy) - Number(b.special_coverage_policy),
sortOrder:
state.sortedInfo.columnKey === "special_coverage_policy" &&
state.sortedInfo.order,
sorter: (a, b) => Number(a.special_coverage_policy) - Number(b.special_coverage_policy),
sortOrder: state.sortedInfo.columnKey === "special_coverage_policy" && state.sortedInfo.order,
filters: [
{ text: "True", value: true },
{ text: "False", value: false },
{ text: "False", value: false }
],
onFilter: (value, record) =>
value.includes(record.special_coverage_policy),
render: (text, record) => (
<Checkbox checked={record.special_coverage_policy} />
),
onFilter: (value, record) => value === record.special_coverage_policy,
render: (text, record) => <Checkbox checked={record.special_coverage_policy} />
},
{
@@ -312,15 +239,13 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "alt_transport",
ellipsis: true,
sorter: (a, b) => alphaSort(a.alt_transport, b.alt_transport),
sortOrder:
state.sortedInfo.columnKey === "alt_transport" &&
state.sortedInfo.order,
sortOrder: state.sortedInfo.columnKey === "alt_transport" && state.sortedInfo.order,
filters:
(bodyshop &&
bodyshop.appt_alt_transport.map((s) => {
return {
text: s,
value: [s],
value: [s]
};
})) ||
[],
@@ -330,7 +255,7 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
{record.alt_transport}
<JobAltTransportChange job={record} />
</div>
),
)
},
{
title: i18n.t("jobs.fields.status"),
@@ -338,9 +263,8 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "status",
ellipsis: true,
sorter: (a, b) => statusSort(a.status, b.status, activeStatuses),
sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
render: (text, record) => <ProductionListColumnStatus record={record} />,
sortOrder: state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
render: (text, record) => <ProductionListColumnStatus record={record} />
},
{
title: i18n.t("jobs.fields.category"),
@@ -353,37 +277,30 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
bodyshop.md_categories.map((s) => {
return {
text: s,
value: [s],
value: [s]
};
})) ||
[],
onFilter: (value, record) => value.includes(record.category),
sorter: (a, b) => alphaSort(a.category, b.category),
sortOrder:
state.sortedInfo.columnKey === "category" && state.sortedInfo.order,
render: (text, record) => (
<ProductionListColumnCategory record={record} />
),
sortOrder: state.sortedInfo.columnKey === "category" && state.sortedInfo.order,
render: (text, record) => <ProductionListColumnCategory record={record} />
},
{
title: i18n.t("production.labels.bodyhours"),
dataIndex: "labhrs",
key: "labhrs",
sorter: (a, b) =>
a.labhrs.aggregate.sum.mod_lb_hrs - b.labhrs.aggregate.sum.mod_lb_hrs,
sortOrder:
state.sortedInfo.columnKey === "labhrs" && state.sortedInfo.order,
render: (text, record) => record.labhrs.aggregate.sum.mod_lb_hrs,
sorter: (a, b) => a.labhrs.aggregate.sum.mod_lb_hrs - b.labhrs.aggregate.sum.mod_lb_hrs,
sortOrder: state.sortedInfo.columnKey === "labhrs" && state.sortedInfo.order,
render: (text, record) => record.labhrs.aggregate.sum.mod_lb_hrs
},
{
title: i18n.t("production.labels.refinishhours"),
dataIndex: "larhrs",
key: "larhrs",
sorter: (a, b) =>
a.larhrs.aggregate.sum.mod_lb_hrs - b.larhrs.aggregate.sum.mod_lb_hrs,
sortOrder:
state.sortedInfo.columnKey === "larhrs" && state.sortedInfo.order,
render: (text, record) => record.larhrs.aggregate.sum.mod_lb_hrs,
sorter: (a, b) => a.larhrs.aggregate.sum.mod_lb_hrs - b.larhrs.aggregate.sum.mod_lb_hrs,
sortOrder: state.sortedInfo.columnKey === "larhrs" && state.sortedInfo.order,
render: (text, record) => record.larhrs.aggregate.sum.mod_lb_hrs
},
{
title: i18n.t("production.labels.totalhours"),
@@ -393,38 +310,36 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
a.labhrs.aggregate.sum.mod_lb_hrs +
a.larhrs.aggregate.sum.mod_lb_hrs -
(b.labhrs.aggregate.sum.mod_lb_hrs + b.larhrs.aggregate.sum.mod_lb_hrs),
sortOrder:
state.sortedInfo.columnKey === "totalhours" && state.sortedInfo.order,
sortOrder: state.sortedInfo.columnKey === "totalhours" && state.sortedInfo.order,
render: (text, record) =>
(
record.labhrs.aggregate.sum.mod_lb_hrs +
record.larhrs.aggregate.sum.mod_lb_hrs
).toFixed(1),
(record.labhrs.aggregate.sum.mod_lb_hrs + record.larhrs.aggregate.sum.mod_lb_hrs).toFixed(1)
},
{
title: i18n.t("production.labels.alert"),
dataIndex: "alert",
key: "alert",
sorter: (a, b) =>
Number(a.production_vars?.alert || false) -
Number(b.production_vars?.alert || false),
sortOrder:
state.sortedInfo.columnKey === "alert" && state.sortedInfo.order,
render: (text, record) => <ProductionListColumnAlert record={record} />,
sorter: (a, b) => Number(a.production_vars?.alert || false) - Number(b.production_vars?.alert || false),
sortOrder: state.sortedInfo.columnKey === "alert" && state.sortedInfo.order,
filters: [
{ text: "True", value: true },
{ text: "False", value: false }
],
onFilter: (value, record) => value === (record.production_vars?.alert || false),
render: (text, record) => <ProductionListColumnAlert record={record} />
},
{
title: i18n.t("production.labels.note"),
dataIndex: "note",
key: "note",
ellipsis: true,
render: (text, record) => <ProductionListColumnNote record={record} />,
render: (text, record) => <ProductionListColumnNote record={record} />
},
{
title: i18n.t("production.labels.comment"),
dataIndex: "comment",
key: "comment",
ellipsis: true,
render: (text, record) => <ProductionListColumnComment record={record} />,
render: (text, record) => <ProductionListColumnComment record={record} />
},
{
title: i18n.t("production.labels.touchtime"),
@@ -432,7 +347,7 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "tt",
render: (text, record) => {
return <ProductionlistColumnTouchTime job={record} />;
},
}
},
{
title: i18n.t("production.labels.bodypriority"),
@@ -442,11 +357,8 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
sorter: (a, b) =>
((a.production_vars && a.production_vars.bodypriority) || 11) -
((b.production_vars && b.production_vars.bodypriority) || 11),
sortOrder:
state.sortedInfo.columnKey === "bodypriority" && state.sortedInfo.order,
render: (text, record) => (
<ProductionListColumnBodyPriority record={record} />
),
sortOrder: state.sortedInfo.columnKey === "bodypriority" && state.sortedInfo.order,
render: (text, record) => <ProductionListColumnBodyPriority record={record} />
},
{
title: i18n.t("production.labels.paintpriority"),
@@ -456,12 +368,8 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
sorter: (a, b) =>
((a.production_vars && a.production_vars.paintpriority) || 11) -
((b.production_vars && b.production_vars.paintpriority) || 11),
sortOrder:
state.sortedInfo.columnKey === "paintpriority" &&
state.sortedInfo.order,
render: (text, record) => (
<ProductionListColumnPaintPriority record={record} />
),
sortOrder: state.sortedInfo.columnKey === "paintpriority" && state.sortedInfo.order,
render: (text, record) => <ProductionListColumnPaintPriority record={record} />
},
{
title: i18n.t("production.labels.detailpriority"),
@@ -471,110 +379,74 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
sorter: (a, b) =>
((a.production_vars && a.production_vars.detailpriority) || 11) -
((b.production_vars && b.production_vars.detailpriority) || 11),
sortOrder:
state.sortedInfo.columnKey === "detailpriority" &&
state.sortedInfo.order,
render: (text, record) => (
<ProductionListColumnDetailPriority record={record} />
),
sortOrder: state.sortedInfo.columnKey === "detailpriority" && state.sortedInfo.order,
render: (text, record) => <ProductionListColumnDetailPriority record={record} />
},
{
title: i18n.t("production.labels.sublets"),
dataIndex: "sublets",
key: "sublets",
render: (text, record) => (
<ProductionSubletsManageComponent subletJobLines={record.subletLines} />
),
render: (text, record) => <ProductionSubletsManageComponent subletJobLines={record.subletLines} />
},
{
title: i18n.t("jobs.fields.employee_body"),
dataIndex: "employee_body",
key: "employee_body",
sortOrder:
state.sortedInfo.columnKey === "employee_body" &&
state.sortedInfo.order,
sortOrder: state.sortedInfo.columnKey === "employee_body" && state.sortedInfo.order,
sorter: (a, b) =>
alphaSort(
bodyshop.employees?.find((e) => e.id === a.employee_body)?.first_name,
bodyshop.employees?.find((e) => e.id === b.employee_body)?.first_name
),
render: (text, record) => (
<ProductionListEmployeeAssignment
record={record}
type="employee_body"
/>
),
render: (text, record) => <ProductionListEmployeeAssignment record={record} type="employee_body" />
},
{
title: i18n.t("jobs.fields.employee_prep"),
dataIndex: "employee_prep",
key: "employee_prep",
sortOrder:
state.sortedInfo.columnKey === "employee_prep" &&
state.sortedInfo.order,
sortOrder: state.sortedInfo.columnKey === "employee_prep" && state.sortedInfo.order,
sorter: (a, b) =>
alphaSort(
bodyshop.employees?.find((e) => e.id === a.employee_prep)?.first_name,
bodyshop.employees?.find((e) => e.id === b.employee_prep)?.first_name
),
render: (text, record) => (
<ProductionListEmployeeAssignment
record={record}
type="employee_prep"
/>
),
render: (text, record) => <ProductionListEmployeeAssignment record={record} type="employee_prep" />
},
{
title: i18n.t("jobs.fields.employee_csr"),
dataIndex: "employee_csr",
key: "employee_csr",
sortOrder:
state.sortedInfo.columnKey === "employee_csr" && state.sortedInfo.order,
sortOrder: state.sortedInfo.columnKey === "employee_csr" && state.sortedInfo.order,
sorter: (a, b) =>
alphaSort(
bodyshop.employees?.find((e) => e.id === a.employee_csr)?.first_name,
bodyshop.employees?.find((e) => e.id === b.employee_csr)?.first_name
),
render: (text, record) => (
<ProductionListEmployeeAssignment record={record} type="employee_csr" />
),
render: (text, record) => <ProductionListEmployeeAssignment record={record} type="employee_csr" />
},
{
title: i18n.t("jobs.fields.employee_refinish"),
dataIndex: "employee_refinish",
key: "employee_refinish",
sortOrder:
state.sortedInfo.columnKey === "employee_refinish" &&
state.sortedInfo.order,
sortOrder: state.sortedInfo.columnKey === "employee_refinish" && state.sortedInfo.order,
sorter: (a, b) =>
alphaSort(
bodyshop.employees?.find((e) => e.id === a.employee_refinish)
?.first_name,
bodyshop.employees?.find((e) => e.id === b.employee_refinish)
?.first_name
bodyshop.employees?.find((e) => e.id === a.employee_refinish)?.first_name,
bodyshop.employees?.find((e) => e.id === b.employee_refinish)?.first_name
),
render: (text, record) => (
<ProductionListEmployeeAssignment
record={record}
type="employee_refinish"
/>
),
render: (text, record) => <ProductionListEmployeeAssignment record={record} type="employee_refinish" />
},
{
title: i18n.t("jobs.labels.parts_received"),
dataIndex: "parts_received",
key: "parts_received",
render: (text, record) => (
<ProductionListColumnPartsReceived record={record} />
),
render: (text, record) => <ProductionListColumnPartsReceived record={record} />
},
{
title: i18n.t("jobs.fields.partsstatus"),
dataIndex: "partsstatus",
key: "partsstatus",
render: (text, record) => (
<JobPartsQueueCount parts={record.joblines_status} record={record} />
),
render: (text, record) => <JobPartsQueueCount parts={record.joblines_status} record={record} />
},
{
title: i18n.t("jobs.labels.estimator"),
@@ -585,8 +457,7 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
`${a.est_ct_fn || ""} ${a.est_ct_ln || ""}`.trim(),
`${b.est_ct_fn || ""} ${b.est_ct_ln || ""}`.trim()
),
sortOrder:
state.sortedInfo.columnKey === "estimator" && state.sortedInfo.order,
sortOrder: state.sortedInfo.columnKey === "estimator" && state.sortedInfo.order,
filters:
(data &&
data
@@ -595,16 +466,12 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
.map((s) => {
return {
text: s || "N/A",
value: [s],
value: [s]
};
})) ||
[],
onFilter: (value, record) =>
value.includes(
`${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim()
),
render: (text, record) =>
`${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim(),
onFilter: (value, record) => value.includes(`${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim()),
render: (text, record) => `${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim()
},
//Added as a place holder for St Claude. Not implemented as it requires another join for a field used by only 1 client.
@@ -634,12 +501,8 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "date_repairstarted",
ellipsis: true,
sorter: (a, b) => dateSort(a.date_repairstarted, b.date_repairstarted),
sortOrder:
state.sortedInfo.columnKey === "date_repairstarted" &&
state.sortedInfo.order,
render: (text, record) => (
<ProductionListDate record={record} field="date_repairstarted" time />
),
sortOrder: state.sortedInfo.columnKey === "date_repairstarted" && state.sortedInfo.order,
render: (text, record) => <ProductionListDate record={record} field="date_repairstarted" time />
},
{
title: i18n.t("jobs.fields.date_repairstarted") + " (HH:MM)",
@@ -647,10 +510,8 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
key: "date_repairstarted_time",
ellipsis: true,
render: (text, record) => (
<TimeFormatter>{record.date_repairstarted}</TimeFormatter>
),
},
render: (text, record) => <TimeFormatter>{record.date_repairstarted}</TimeFormatter>
}
];
};
export default r;

View File

@@ -5,7 +5,6 @@ import { getFirestore } from "firebase/firestore";
import { getMessaging, getToken, onMessage } from "firebase/messaging";
import { store } from "../redux/store";
import axios from "axios";
import { checkBeta } from "../utils/handleBeta";
const config = JSON.parse(process.env.REACT_APP_FIREBASE_CONFIG);
initializeApp(config);
@@ -51,7 +50,7 @@ export { messaging };
export const requestForToken = () => {
return getToken(messaging, {
vapidKey: process.env.REACT_APP_FIREBASE_PUBLIC_VAPID_KEY,
vapidKey: process.env.REACT_APP_FIREBASE_PUBLIC_VAPID_KEY
})
.then((currentToken) => {
if (currentToken) {
@@ -59,9 +58,7 @@ export const requestForToken = () => {
// Perform any other necessary action with the token
} else {
// Show permission request UI
console.log(
"No registration token available. Request permission to generate one."
);
console.log("No registration token available. Request permission to generate one.");
}
})
.catch((err) => {
@@ -80,24 +77,17 @@ export const onMessageListener = () =>
export const logImEXEvent = (eventName, additionalParams, stateProp = null) => {
const state = stateProp || 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,
shop: (state.user && state.user.bodyshop && state.user.bodyshop.shopname) || null,
user: (state.user && state.user.currentUser && state.user.currentUser.email) || null,
...additionalParams
};
axios.post("/ioevent", {
useremail:
(state.user && state.user.currentUser && state.user.currentUser.email) ||
null,
bodyshopid:
(state.user && state.user.bodyshop && state.user.bodyshop.id) || null,
useremail: (state.user && state.user.currentUser && state.user.currentUser.email) || null,
bodyshopid: (state.user && state.user.bodyshop && state.user.bodyshop.id) || null,
operationName: eventName,
variables: additionalParams,
dbevent: false,
env: checkBeta() ? "beta" : "master",
env: "master"
});
// console.log(

View File

@@ -1,7 +1,7 @@
import { gql } from "@apollo/client";
export const QUERY_ALL_ACTIVE_JOBS_PAGINATED = gql`
query QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED(
query QUERY_ALL_ACTIVE_JOBS_PAGINATED(
$offset: Int
$limit: Int
$order: [jobs_order_by!]

View File

@@ -1,37 +0,0 @@
export const BETA_KEY = 'betaSwitchImex';
export const checkBeta = () => {
const cookie = document.cookie.split('; ').find(row => row.startsWith(BETA_KEY));
return cookie ? cookie.split('=')[1] === 'true' : false;
}
export const setBeta = (value) => {
const domain = window.location.hostname.split('.').slice(-2).join('.');
document.cookie = `${BETA_KEY}=${value}; path=/; domain=.${domain}`;
}
export const handleBeta = () => {
// If the current host name does not start with beta or test, then we don't need to do anything.
if (window.location.hostname.startsWith('localhost')) {
console.log('Not on beta or test, so no need to handle beta.');
return;
}
const isBeta = checkBeta();
const currentHostName = window.location.hostname;
// Beta is enabled, but the current host name does start with beta.
if (isBeta && !currentHostName.startsWith('beta')) {
const href= `${window.location.protocol}//beta.${currentHostName}${window.location.pathname}${window.location.search}${window.location.hash}`;
window.location.replace(href);
}
// Beta is not enabled, but the current host name does start with beta.
else if (!isBeta && currentHostName.startsWith('beta')) {
const href = `${window.location.protocol}//${currentHostName.replace('beta.', '')}${window.location.pathname}${window.location.search}${window.location.hash}`;
window.location.replace(href);
}
}
export default handleBeta;