diff --git a/client/src/App/App.container.jsx b/client/src/App/App.container.jsx index 28c6fb838..9566e0626 100644 --- a/client/src/App/App.container.jsx +++ b/client/src/App/App.container.jsx @@ -12,6 +12,7 @@ import GlobalLoadingBar from "../components/global-loading-bar/global-loading-ba import { setDarkMode } from "../redux/application/application.actions"; import { selectDarkMode } from "../redux/application/application.selectors"; import { selectCurrentUser } from "../redux/user/user.selectors.js"; +import { signOutStart } from "../redux/user/user.actions"; import client from "../utils/GraphQLClient"; import App from "./App"; import getTheme from "./themeProvider"; @@ -20,14 +21,13 @@ import getTheme from "./themeProvider"; const config = { core: { authorizationKey: import.meta.env.VITE_APP_SPLIT_API, - key: "anon" // Default key, overridden dynamically by SplitClientProvider + key: "anon" } }; -// Custom provider to manage the Split client key based on imexshopid from Redux function SplitClientProvider({ children }) { - const imexshopid = useSelector((state) => state.user.imexshopid); // Access imexshopid from Redux store - const splitClient = useSplitClient({ key: imexshopid || "anon" }); // Use imexshopid or fallback to "anon" + const imexshopid = useSelector((state) => state.user.imexshopid); + const splitClient = useSplitClient({ key: imexshopid || "anon" }); useEffect(() => { if (splitClient && imexshopid) { console.log(`Split client initialized with key: ${imexshopid}, isReady: ${splitClient.isReady}`); @@ -36,40 +36,66 @@ function SplitClientProvider({ children }) { return children; } -const mapDispatchToProps = (dispatch) => ({ - setDarkMode: (isDarkMode) => dispatch(setDarkMode(isDarkMode)) -}); - const mapStateToProps = createStructuredSelector({ currentUser: selectCurrentUser }); -function AppContainer({ currentUser, setDarkMode }) { +const mapDispatchToProps = (dispatch) => ({ + setDarkMode: (isDarkMode) => dispatch(setDarkMode(isDarkMode)), + signOutStart: () => dispatch(signOutStart()) +}); + +function AppContainer({ currentUser, setDarkMode, signOutStart }) { const { t } = useTranslation(); const isDarkMode = useSelector(selectDarkMode); const theme = useMemo(() => getTheme(isDarkMode), [isDarkMode]); - // Update data-theme attribute when dark mode changes + // Global seamless logout listener with redirect to /signin + useEffect(() => { + const handleSeamlessLogout = (event) => { + if (event.data?.type !== "seamlessLogoutRequest") return; + + const requestOrigin = event.origin; + + if (currentUser?.authorized !== true) { + window.parent.postMessage( + { type: "seamlessLogoutResponse", status: "already_logged_out" }, + requestOrigin || "*" + ); + return; + } + + signOutStart(); + window.parent.postMessage({ type: "seamlessLogoutResponse", status: "logged_out" }, requestOrigin || "*"); + }; + + window.addEventListener("message", handleSeamlessLogout); + return () => { + window.removeEventListener("message", handleSeamlessLogout); + }; + }, [signOutStart, currentUser]); + + // Update data-theme attribute useEffect(() => { document.documentElement.setAttribute("data-theme", isDarkMode ? "dark" : "light"); return () => document.documentElement.removeAttribute("data-theme"); }, [isDarkMode]); - // Sync Redux darkMode with localStorage on user change + // Sync darkMode with localStorage useEffect(() => { if (currentUser?.uid) { const savedMode = localStorage.getItem(`dark-mode-${currentUser.uid}`); if (savedMode !== null) { setDarkMode(JSON.parse(savedMode)); } else { - setDarkMode(false); // default to light mode + setDarkMode(false); } } else { setDarkMode(false); } - }, [currentUser?.uid]); + }, [currentUser?.uid, setDarkMode]); - // Persist darkMode to localStorage when it or user changes + // Persist darkMode useEffect(() => { if (currentUser?.uid) { localStorage.setItem(`dark-mode-${currentUser.uid}`, JSON.stringify(isDarkMode)); diff --git a/client/src/utils/TemplateConstants.js b/client/src/utils/TemplateConstants.js index 867979a0c..d91c1097e 100644 --- a/client/src/utils/TemplateConstants.js +++ b/client/src/utils/TemplateConstants.js @@ -15,21 +15,29 @@ export const EmailSettings = { export const TemplateList = (type, context) => { //const { bodyshop } = store.getState().user; + + const casl = InstanceRenderManager({ + imex: { + casl_authorization: { + title: i18n.t("printcenter.jobs.casl_authorization"), + description: "", + subject: i18n.t("printcenter.jobs.casl_authorization"), + key: "casl_authorization", + disabled: false, + group: "authorization", + regions: { + CA: true + } + } + }, + rome: {} + }); + return { //If there's no type or the type is job, send it back. ...(!type || type === "job" ? { - casl_authorization: { - title: i18n.t("printcenter.jobs.casl_authorization"), - description: "", - subject: i18n.t("printcenter.jobs.casl_authorization"), - key: "casl_authorization", - disabled: false, - group: "authorization", - regions: { - CA: true - } - }, + ...casl, fippa_authorization: { title: i18n.t("printcenter.jobs.fippa_authorization"), description: "", diff --git a/server/job/job-totals-USA.js b/server/job/job-totals-USA.js index dab44bf56..f875c3551 100644 --- a/server/job/job-totals-USA.js +++ b/server/job/job-totals-USA.js @@ -24,7 +24,7 @@ exports.totalsSsu = async function (req, res) { const BearerToken = req.BearerToken; const client = req.userGraphQLClient; - logger.log("job-totals-ssu-USA", "DEBUG", req?.user?.email, id); + logger.log("job-totals-ssu-USA", "debug", req?.user?.email, id); try { const job = await client.setHeaders({ Authorization: BearerToken }).request(queries.GET_JOB_BY_PK, { @@ -49,7 +49,7 @@ exports.totalsSsu = async function (req, res) { res.status(200).send(); } catch (error) { - logger.log("job-totals-ssu-USA-error", "ERROR", req?.user?.email, id, { + logger.log("job-totals-ssu-USA-error", "error", req?.user?.email, id, { jobid: id, error: error.message, stack: error.stack @@ -95,7 +95,7 @@ async function TotalsServerSide(req, res) { ret.totals.subtotal = ret.totals.subtotal.add(ret.totals.ttl_adjustment); ret.totals.total_repairs = ret.totals.total_repairs.add(ret.totals.ttl_adjustment); ret.totals.net_repairs = ret.totals.net_repairs.add(ret.totals.ttl_adjustment); - logger.log("job-totals-USA-ttl-adj", "DEBUG", null, job.id, { + logger.log("job-totals-USA-ttl-adj", "debug", null, job.id, { adjAmount: ttlDifference }); } @@ -116,7 +116,7 @@ async function TotalsServerSide(req, res) { ret.totals.ttl_tax_adjustment = Dinero({ amount: Math.round(ttlTaxDifference * 100) }); ret.totals.total_repairs = ret.totals.total_repairs.add(ret.totals.ttl_tax_adjustment); ret.totals.net_repairs = ret.totals.net_repairs.add(ret.totals.ttl_tax_adjustment); - logger.log("job-totals-USA-ttl-tax-adj", "DEBUG", null, job.id, { + logger.log("job-totals-USA-ttl-tax-adj", "debug", null, job.id, { adjAmount: ttlTaxDifference }); } @@ -124,7 +124,7 @@ async function TotalsServerSide(req, res) { return ret; } catch (error) { - logger.log("job-totals-ssu-USA-error", "ERROR", req.user?.email, job.id, { + logger.log("job-totals-ssu-USA-error", "error", req.user?.email, job.id, { jobid: job.id, error: error.message, stack: error.stack @@ -142,7 +142,7 @@ async function Totals(req, res) { const logger = req.logger; const client = req.userGraphQLClient; - logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, job.id, { + logger.log("job-totals-ssu-USA", "debug", req.user.email, job.id, { jobid: job.id, id: id }); @@ -159,7 +159,7 @@ async function Totals(req, res) { res.status(200).json(ret); } catch (error) { - logger.log("job-totals-ssu-USA-error", "ERROR", req.user.email, job.id, { + logger.log("job-totals-ssu-USA-error", "error", req.user.email, job.id, { jobid: job.id, error: error.message, stack: error.stack @@ -240,7 +240,7 @@ async function AtsAdjustmentsIfRequired({ job, client, user }) { job.joblines.push(newAtsLine); } } catch (error) { - logger.log("job-totals-ssu-ats-error", "ERROR", user?.email, job.id, { + logger.log("job-totals-ssu-ats-error", "error", user?.email, job.id, { jobid: job.id, error: error.message, stack: error.stack @@ -258,7 +258,7 @@ async function AtsAdjustmentsIfRequired({ job, client, user }) { job.joblines[atsLineIndex].act_price = atsAmount; } } catch (error) { - logger.log("job-totals-ssu-ats-error", "ERROR", user?.email, job.id, { + logger.log("job-totals-ssu-ats-error", "error", user?.email, job.id, { jobid: job.id, atsLineIndex: atsLineIndex, atsAmount: atsAmount, @@ -1055,7 +1055,7 @@ function CalculateTaxesTotals(job, otherTotals) { } } } catch (error) { - logger.log("job-totals-USA Key with issue", "error", null, job.id, { + logger.log("job-totals-USA Key with issue", "warn", null, job.id, { key: key, error: error.message, stack: error.stack diff --git a/server/job/job-totals.js b/server/job/job-totals.js index 5f28ac067..b6617b18c 100644 --- a/server/job/job-totals.js +++ b/server/job/job-totals.js @@ -23,7 +23,7 @@ exports.totalsSsu = async function (req, res) { const BearerToken = req.BearerToken; const client = req.userGraphQLClient; - logger.log("job-totals-ssu", "DEBUG", req.user.email, id, null); + logger.log("job-totals-ssu", "debug", req.user.email, id, null); try { const job = await client.setHeaders({ Authorization: BearerToken }).request(queries.GET_JOB_BY_PK, { @@ -49,7 +49,7 @@ exports.totalsSsu = async function (req, res) { res.status(200).send(); } catch (error) { - logger.log("job-totals-ssu-error", "ERROR", req.user.email, id, { + logger.log("job-totals-ssu-error", "error", req.user.email, id, { jobid: id, error: error.message, stack: error.stack @@ -73,7 +73,7 @@ async function TotalsServerSide(req, res) { return ret; } catch (error) { - logger.log("job-totals-ssu-error", "ERROR", req?.user?.email, job.id, { + logger.log("job-totals-ssu-error", "error", req?.user?.email, job.id, { jobid: job.id, error: error.message, stack: error.stack @@ -91,7 +91,7 @@ async function Totals(req, res) { const logger = req.logger; const client = req.userGraphQLClient; - logger.log("job-totals-ssu", "DEBUG", req.user.email, job.id, { + logger.log("job-totals-ssu", "debug", req.user.email, job.id, { jobid: job.id, id: id }); @@ -108,7 +108,7 @@ async function Totals(req, res) { res.status(200).json(ret); } catch (error) { - logger.log("job-totals-ssu-error", "ERROR", req.user.email, job.id, { + logger.log("job-totals-ssu-error", "error", req.user.email, job.id, { jobid: job.id, error: error.message, stack: error.stack @@ -189,7 +189,7 @@ async function AtsAdjustmentsIfRequired({ job, client, user }) { job.joblines.push(newAtsLine); } } catch (error) { - logger.log("job-totals-ssu-ats-error", "ERROR", user?.email, job.id, { + logger.log("job-totals-ssu-ats-error", "error", user?.email, job.id, { jobid: job.id, error: error.message, stack: error.stack @@ -207,7 +207,7 @@ async function AtsAdjustmentsIfRequired({ job, client, user }) { job.joblines[atsLineIndex].act_price = atsAmount; } } catch (error) { - logger.log("job-totals-ssu-ats-error", "ERROR", user?.email, job.id, { + logger.log("job-totals-ssu-ats-error", "error", user?.email, job.id, { jobid: job.id, atsLineIndex: atsLineIndex, atsAmount: atsAmount,