@@ -1,7 +1,7 @@
|
||||
import {useSplitClient} from "@splitsoftware/splitio-react";
|
||||
import {Button, Result} from "antd";
|
||||
import LogRocket from "logrocket";
|
||||
import React, {lazy, Suspense, useEffect} from "react";
|
||||
import React, {lazy, Suspense, useEffect, useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {Route, Routes} from "react-router-dom";
|
||||
@@ -19,6 +19,7 @@ import {checkUserSession} from "../redux/user/user.actions";
|
||||
import {selectBodyshop, selectCurrentUser,} from "../redux/user/user.selectors";
|
||||
import PrivateRoute from "../components/PrivateRoute";
|
||||
import "./App.styles.scss";
|
||||
import handleBeta from "../utils/betaHandler";
|
||||
|
||||
const ResetPassword = lazy(() =>
|
||||
import("../pages/reset-password/reset-password.component")
|
||||
@@ -40,14 +41,16 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
setOnline: (isOnline) => dispatch(setOnline(isOnline)),
|
||||
});
|
||||
|
||||
export function App({
|
||||
bodyshop,
|
||||
checkUserSession,
|
||||
currentUser,
|
||||
online,
|
||||
setOnline,
|
||||
}) {
|
||||
export function App({bodyshop, checkUserSession, currentUser, online, setOnline}) {
|
||||
|
||||
const client = useSplitClient().client;
|
||||
const [listenersAdded, setListenersAdded] = useState(false)
|
||||
const {t} = useTranslation();
|
||||
|
||||
// Handle The Beta Switch.
|
||||
useEffect(() => {
|
||||
handleBeta();
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!navigator.onLine) {
|
||||
@@ -60,15 +63,28 @@ export function App({
|
||||
//const b = Grid.useBreakpoint();
|
||||
// console.log("Breakpoints:", b);
|
||||
|
||||
const {t} = useTranslation();
|
||||
|
||||
window.addEventListener("offline", function (e) {
|
||||
const offlineListener = (e) => {
|
||||
setOnline(false);
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener("online", function (e) {
|
||||
const onlineListener = (e) => {
|
||||
setOnline(true);
|
||||
});
|
||||
}
|
||||
|
||||
// Associate event listeners, memoize to prevent multiple listeners being added
|
||||
useEffect(() => {
|
||||
if (!listenersAdded) {
|
||||
console.log('Added events for offline and online');
|
||||
window.addEventListener("offline", offlineListener);
|
||||
window.addEventListener("online", onlineListener);
|
||||
setListenersAdded(true);
|
||||
}
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("offline", offlineListener);
|
||||
window.removeEventListener("online", onlineListener);
|
||||
}
|
||||
}, [listenersAdded]);
|
||||
|
||||
useEffect(() => {
|
||||
if (currentUser.authorized && bodyshop) {
|
||||
|
||||
@@ -4,20 +4,11 @@ import { Button, notification, Space } from "antd";
|
||||
import axios from "axios";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { messaging, requestForToken } from "../../firebase/firebase.utils";
|
||||
import { selectChatVisible } from "../../redux/messaging/messaging.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import FcmHandler from "../../utils/fcm-handler";
|
||||
import ChatPopupComponent from "../chat-popup/chat-popup.component";
|
||||
import "./chat-affix.styles.scss";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
chatVisible: selectChatVisible,
|
||||
});
|
||||
|
||||
export function ChatAffixContainer({ bodyshop, chatVisible }) {
|
||||
const { t } = useTranslation();
|
||||
const client = useApolloClient();
|
||||
@@ -47,7 +38,6 @@ export function ChatAffixContainer({ bodyshop, chatVisible }) {
|
||||
<Button
|
||||
onClick={async () => {
|
||||
await requestForToken();
|
||||
|
||||
SubscribeToTopic();
|
||||
}}
|
||||
>
|
||||
@@ -81,16 +71,16 @@ export function ChatAffixContainer({ bodyshop, chatVisible }) {
|
||||
payload: (payload && payload.data && payload.data.data) || payload.data,
|
||||
});
|
||||
}
|
||||
let stopMessageListenr, channel;
|
||||
let stopMessageListener, channel;
|
||||
try {
|
||||
stopMessageListenr = onMessage(messaging, handleMessage);
|
||||
stopMessageListener = onMessage(messaging, handleMessage);
|
||||
channel = new BroadcastChannel("imex-sw-messages");
|
||||
channel.addEventListener("message", handleMessage);
|
||||
} catch (error) {
|
||||
console.log("Unable to set event listeners.");
|
||||
}
|
||||
return () => {
|
||||
stopMessageListenr && stopMessageListenr();
|
||||
stopMessageListener && stopMessageListener();
|
||||
channel && channel.removeEventListener("message", handleMessage);
|
||||
};
|
||||
}, [client]);
|
||||
@@ -103,4 +93,5 @@ export function ChatAffixContainer({ bodyshop, chatVisible }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(mapStateToProps, null)(ChatAffixContainer);
|
||||
|
||||
export default ChatAffixContainer;
|
||||
@@ -12,7 +12,7 @@ import Icon, {
|
||||
FileAddOutlined,
|
||||
FileFilled,
|
||||
HomeFilled,
|
||||
ImportOutlined,
|
||||
ImportOutlined, InfoCircleOutlined,
|
||||
LineChartOutlined,
|
||||
PaperClipOutlined,
|
||||
PhoneOutlined,
|
||||
@@ -25,8 +25,8 @@ import Icon, {
|
||||
UserOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
||||
import {Layout, Menu} from "antd";
|
||||
import React from "react";
|
||||
import {Layout, Menu, Switch, Tooltip} from "antd";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {BsKanban} from "react-icons/bs";
|
||||
import {FaCalendarAlt, FaCarCrash, FaCreditCard, FaFileInvoiceDollar,} from "react-icons/fa";
|
||||
@@ -41,6 +41,7 @@ import {setModalContext} from "../../redux/modals/modals.actions";
|
||||
import {signOutStart} from "../../redux/user/user.actions";
|
||||
import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
|
||||
import {FiLogOut} from "react-icons/fi";
|
||||
import handleBeta, {checkBeta, setBeta} from "../../utils/betaHandler";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
@@ -70,9 +71,21 @@ function Header({handleMenuClick, currentUser, bodyshop, selectedHeader, signOut
|
||||
names: ["ImEXPay", "DmsAp", "Simple_Inventory"],
|
||||
splitKey: bodyshop && bodyshop.imexshopid,
|
||||
});
|
||||
|
||||
const [betaSwitch, setBetaSwitch] = useState(false);
|
||||
const {t} = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
const isBeta = checkBeta();
|
||||
setBetaSwitch(isBeta );
|
||||
}, []);
|
||||
|
||||
|
||||
const betaSwitchChange = (checked) => {
|
||||
setBeta(checked);
|
||||
setBetaSwitch(checked);
|
||||
handleBeta();
|
||||
}
|
||||
|
||||
const accountingChildren = [
|
||||
{
|
||||
key: 'bills',
|
||||
@@ -451,13 +464,28 @@ function Header({handleMenuClick, currentUser, bodyshop, selectedHeader, signOut
|
||||
|
||||
})),
|
||||
}
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
menuItems.push({
|
||||
key: 'beta-switch',
|
||||
style: { marginLeft: 'auto' },
|
||||
label: (
|
||||
<Tooltip title="A faster 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>
|
||||
)
|
||||
});
|
||||
|
||||
return (
|
||||
<Layout.Header>
|
||||
<Menu
|
||||
mode="horizontal"
|
||||
//theme="light"
|
||||
theme={"dark"}
|
||||
selectedKeys={[selectedHeader]}
|
||||
onClick={handleMenuClick}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {FloatButton, Layout} from "antd";
|
||||
import preval from "preval.macro";
|
||||
import React, {lazy, Suspense, useEffect} from "react";
|
||||
import React, {lazy, Suspense, useEffect, useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {Link, Route, Routes} from "react-router-dom";
|
||||
@@ -177,6 +177,8 @@ const mapStateToProps = createStructuredSelector({
|
||||
|
||||
export function Manage({conflict, bodyshop}) {
|
||||
const {t} = useTranslation();
|
||||
const [chatVisible, setChatVisible] = useState(false);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const widgetId = "IABVNO4scRKY11XBQkNr";
|
||||
@@ -360,7 +362,7 @@ export function Manage({conflict, bodyshop}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ChatAffixContainer/>
|
||||
<ChatAffixContainer bodyshop={bodyshop} chatVisible={chatVisible} />
|
||||
<Layout className="layout-container">
|
||||
<UpdateAlert/>
|
||||
<HeaderContainer/>
|
||||
|
||||
@@ -42,9 +42,7 @@ if (process.env.NODE_ENV === "development") {
|
||||
export const store = configureStore({
|
||||
reducer: rootReducer,
|
||||
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
|
||||
serializableCheck: {
|
||||
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
|
||||
},
|
||||
serializableCheck: false,
|
||||
}).concat(middlewares),
|
||||
// middleware: middlewares,
|
||||
devTools: process.env.NODE_ENV !== 'production',
|
||||
|
||||
32
client/src/utils/betaHandler.js
Normal file
32
client/src/utils/betaHandler.js
Normal file
@@ -0,0 +1,32 @@
|
||||
export const BETA_KEY = 'betaSwitchImex';
|
||||
|
||||
export const checkBeta = () => document.cookie.split('; ').find(row => row.startsWith(BETA_KEY)).split('=')[1] === 'true';
|
||||
|
||||
|
||||
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')) {
|
||||
window.location.href = `${window.location.protocol}//beta.${currentHostName}${window.location.pathname}${window.location.search}${window.location.hash}`;
|
||||
}
|
||||
|
||||
// Beta is not enabled, but the current host name does start with beta.
|
||||
else if (!isBeta && currentHostName.startsWith('beta')) {
|
||||
window.location.href = `${window.location.protocol}//${currentHostName.replace('beta.', '')}${window.location.pathname}${window.location.search}${window.location.hash}`;
|
||||
}
|
||||
}
|
||||
export default handleBeta;
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useCallback, useReducer } from "react";
|
||||
import {useCallback, useEffect, useReducer, useState} from "react";
|
||||
//Based on https://www.fullstacklabs.co/blog/keyboard-shortcuts-with-react-hooks
|
||||
const blacklistedTargets = []; // ["INPUT", "TEXTAREA"];
|
||||
export const useKeyboardSaveShortcut = (callback) =>
|
||||
@@ -43,6 +43,7 @@ const useKeyboardShortcut = (shortcutKeys, callback, options) => {
|
||||
}, {});
|
||||
|
||||
const [keys, setKeys] = useReducer(keysReducer, initalKeyMapping);
|
||||
const [listenersAdded, setListenersAdded] = useState(false);
|
||||
|
||||
const keydownListener = useCallback(
|
||||
(assignedKey) => (keydownEvent) => {
|
||||
@@ -94,26 +95,24 @@ const useKeyboardShortcut = (shortcutKeys, callback, options) => {
|
||||
}, [callback, keys]);
|
||||
|
||||
useEffect(() => {
|
||||
shortcutKeys.forEach((k) =>
|
||||
window.addEventListener("keydown", keydownListener(k))
|
||||
);
|
||||
return () =>
|
||||
shortcutKeys.forEach((k) =>
|
||||
window.removeEventListener("keydown", keydownListener(k))
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
shortcutKeys.forEach((k) =>
|
||||
if (!listenersAdded) {
|
||||
console.log('Added events for keyup and keydown');
|
||||
shortcutKeys.forEach((k) => {
|
||||
window.addEventListener("keydown", keydownListener(k));
|
||||
window.addEventListener("keyup", keyupListener(k))
|
||||
);
|
||||
return () =>
|
||||
shortcutKeys.forEach((k) =>
|
||||
window.removeEventListener("keyup", keyupListener(k))
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
});
|
||||
}
|
||||
|
||||
setListenersAdded(true);
|
||||
|
||||
return () => {
|
||||
shortcutKeys.forEach((k) => {
|
||||
window.removeEventListener("keydown", keydownListener(k));
|
||||
window.removeEventListener("keyup", keyupListener(k));
|
||||
});
|
||||
}
|
||||
}, [listenersAdded]);
|
||||
|
||||
};
|
||||
|
||||
export default useKeyboardShortcut;
|
||||
|
||||
Reference in New Issue
Block a user