Merged in feature/IO-2916-Remove-Beta-Switch-Legacy (pull request #1692)

feature/IO-2916-Remove-Beta-Switch-Legacy - Remove Beta Switch
This commit is contained in:
Dave Richer
2024-09-10 17:29:42 +00:00
4 changed files with 79 additions and 284 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

@@ -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

@@ -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,47 +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 (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;
// Determine if the host name starts with "beta" or "www.beta"
const isBetaHost = currentHostName.startsWith("beta.");
const isBetaHostWithWWW = currentHostName.startsWith("www.beta.");
if (isBeta) {
// If beta is on and we are not on a beta domain, redirect to the beta version
if (!isBetaHost && !isBetaHostWithWWW) {
const newHostName = currentHostName.startsWith("www.")
? `www.beta.${currentHostName.replace(/^www\./, "")}`
: `beta.${currentHostName}`;
const href = `${window.location.protocol}//${newHostName}${window.location.pathname}${window.location.search}${window.location.hash}`;
window.location.replace(href);
}
// Otherwise, if beta is on and we're already on a beta domain, stay there
} else {
// If beta is off and we are on a beta domain, redirect to the non-beta version
if (isBetaHost || isBetaHostWithWWW) {
const newHostName = currentHostName.replace(/^www\.beta\./, "www.").replace(/^beta\./, "");
const href = `${window.location.protocol}//${newHostName}${window.location.pathname}${window.location.search}${window.location.hash}`;
window.location.replace(href);
}
// Otherwise, if beta is off and we're not on a beta domain, stay there
}
};
export default handleBeta;