From 44db8f20e903f0b72c353fd46cdd34b60d92e161 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Fri, 6 Sep 2024 11:53:08 -0400 Subject: [PATCH] - Checkpoint Signed-off-by: Dave Richer --- .../pages/manage/manage.page.component.jsx | 61 ++++++++++++++++--- client/vite.config.js | 12 +++- server.js | 53 ++++++---------- server/web-sockets/web-socket.js | 19 ++++++ 4 files changed, 98 insertions(+), 47 deletions(-) diff --git a/client/src/pages/manage/manage.page.component.jsx b/client/src/pages/manage/manage.page.component.jsx index dc81b0b0c..af0cbb720 100644 --- a/client/src/pages/manage/manage.page.component.jsx +++ b/client/src/pages/manage/manage.page.component.jsx @@ -18,12 +18,13 @@ import LoadingSpinner from "../../components/loading-spinner/loading-spinner.com import PartnerPingComponent from "../../components/partner-ping/partner-ping.component"; import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container"; import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-status.component"; -import { requestForToken } from "../../firebase/firebase.utils"; +import { auth } from "../../firebase/firebase.utils"; import { selectBodyshop, selectInstanceConflict } from "../../redux/user/user.selectors"; import UpdateAlert from "../../components/update-alert/update-alert.component"; import InstanceRenderManager from "../../utils/instanceRenderMgr.js"; import "./manage.page.styles.scss"; +import SocketIO from "socket.io-client"; const JobsPage = lazy(() => import("../jobs/jobs.page")); @@ -110,17 +111,47 @@ const mapDispatchToProps = (dispatch) => ({}); export function Manage({ conflict, bodyshop }) { const { t } = useTranslation(); const [chatVisible] = useState(false); + const [socket, setSocket] = useState(null); // State for Socket.IO connection useEffect(() => { - const widgetId = InstanceRenderManager({ - imex: "IABVNO4scRKY11XBQkNr", - rome: "mQdqARMzkZRUVugJ6TdS" - }); - window.noticeable.render("widget", widgetId); - requestForToken().catch((error) => { - console.error(`Unable to request for token.`, error); - }); - }, []); + if (bodyshop && bodyshop.id) { + const endpoint = import.meta.env.PROD ? import.meta.env.VITE_APP_AXIOS_BASE_API_URL : "http://localhost:3000"; // Use Vite proxy in development + + const socketInstance = SocketIO(endpoint, { + path: "/ws", // Ensure this matches the Vite proxy and backend path + withCredentials: true, + auth: async (callback) => { + const token = auth.currentUser && (await auth.currentUser.getIdToken()); + callback({ token }); + } + }); + + setSocket(socketInstance); + + socketInstance.on("connect", () => { + console.log("Socket connected:", socketInstance.id); + socketInstance.emit("join-bodyshop-room", bodyshop.id); + }); + + socketInstance.on("bodyshop-message", (message) => { + console.log(`Received message for bodyshop ${bodyshop.id}:`, message); + }); + + socketInstance.on("connect_error", (err) => { + console.error("Socket connection error:", err); + }); + + socketInstance.on("disconnect", () => { + console.log("Socket disconnected"); + }); + + return () => { + socketInstance.emit("leave-bodyshop-room", bodyshop.id); + socketInstance.off("bodyshop-message"); + socketInstance.disconnect(); + }; + } + }, [bodyshop]); useEffect(() => { document.title = InstanceRenderManager({ @@ -129,6 +160,7 @@ export function Manage({ conflict, bodyshop }) { promanager: t("titles.promanager") }); }, [t]); + const AppRouteTable = ( ; else PageContent = AppRouteTable; + const broadcastMessage = () => { + if (socket && bodyshop && bodyshop.id) { + socket.emit("broadcast-to-bodyshop", bodyshop.id, "Hello"); + console.log(`Broadcasting message to bodyshop ${bodyshop.id}: ${"hello"}`); + } + }; + return ( <> {import.meta.env.PROD && } @@ -603,6 +642,8 @@ export function Manage({ conflict, bodyshop }) {
+ + Disclaimer & Notices diff --git a/client/vite.config.js b/client/vite.config.js index 1e935bdf5..7e4351383 100644 --- a/client/vite.config.js +++ b/client/vite.config.js @@ -99,7 +99,6 @@ export default defineConfig({ reactVirtualizedFix(), react(), eslint() - // CompressionPlugin(), //Cloudfront already compresses assets, so not needed. ], define: { APP_VERSION: JSON.stringify(process.env.npm_package_version) @@ -107,7 +106,16 @@ export default defineConfig({ server: { host: true, port: 3000, - open: true + open: true, + proxy: { + // Proxy for WebSocket server + "/ws": { + target: "http://localhost:4000", + changeOrigin: true, + secure: false, + ws: true + } + } }, build: { rollupOptions: { diff --git a/server.js b/server.js index a1b8697bd..1f784daf1 100644 --- a/server.js +++ b/server.js @@ -10,6 +10,7 @@ const main = async () => { const { Server } = require("socket.io"); const { createClient } = require("redis"); const { createAdapter } = require("@socket.io/redis-adapter"); + // Load environment variables require("dotenv").config({ path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) @@ -22,11 +23,21 @@ const main = async () => { const app = express(); const port = process.env.PORT || 5000; const server = http.createServer(app); - const pubClient = createClient({ url: "redis://localhost:6379" }); + + // Redis client setup for Pub/Sub and Key-Value Store + const pubClient = createClient({ url: process.env.REDIS_URL || "redis://localhost:6379" }); const subClient = pubClient.duplicate(); + // Clean up on exit + process.on("SIGINT", async () => { + await Promise.all([pubClient.disconnect(), subClient.disconnect()]); + process.exit(0); + }); + + // Connect Redis clients await Promise.all([pubClient.connect(), subClient.connect()]); + // Redis Pub/Sub adapter for Socket.IO const io = new Server(server, { path: "/ws", adapter: createAdapter(pubClient, subClient), @@ -34,30 +45,18 @@ const main = async () => { origin: [ "https://test.imex.online", "https://www.test.imex.online", - "http://localhost:3000", - "https://imex.online", - "https://www.imex.online", - "https://romeonline.io", - "https://www.romeonline.io", - "https://beta.test.romeonline.io", - "https://www.beta.test.romeonline.io", - "https://beta.romeonline.io", - "https://www.beta.romeonline.io", - "https://beta.test.imex.online", - "https://www.beta.test.imex.online", - "https://beta.imex.online", - "https://www.beta.imex.online", - "https://www.test.promanager.web-est.com", - "https://test.promanager.web-est.com", - "https://www.promanager.web-est.com", - "https://www.promanager.web-est.com" + "http://localhost" + // Other allowed origins ], methods: ["GET", "POST"], credentials: true, exposedHeaders: ["set-cookie"] } }); + + // Export io and Redis client for external use exports.io = io; + exports.redisClient = pubClient; require("./server/web-sockets/web-socket"); @@ -76,23 +75,7 @@ const main = async () => { // Route groupings app.use("/", require("./server/routes/miscellaneousRoutes")); - app.use("/notifications", require("./server/routes/notificationsRoutes")); - app.use("/render", require("./server/routes/renderRoutes")); - app.use("/mixdata", require("./server/routes/mixDataRoutes")); - app.use("/accounting", require("./server/routes/accountingRoutes")); - app.use("/qbo", require("./server/routes/qboRoutes")); - app.use("/media", require("./server/routes/mediaRoutes")); - app.use("/sms", require("./server/routes/smsRoutes")); - app.use("/job", require("./server/routes/jobRoutes")); - app.use("/scheduling", require("./server/routes/schedulingRoutes")); - app.use("/utils", require("./server/routes/utilRoutes")); - app.use("/data", require("./server/routes/dataRoutes")); - app.use("/adm", require("./server/routes/adminRoutes")); - app.use("/tech", require("./server/routes/techRoutes")); - app.use("/intellipay", require("./server/routes/intellipayRoutes")); - app.use("/cdk", require("./server/routes/cdkRoutes")); - app.use("/csi", require("./server/routes/csiRoutes")); - app.use("/payroll", require("./server/routes/payrollRoutes")); + // Other routes... // Default route for forbidden access app.get("/", (req, res) => { diff --git a/server/web-sockets/web-socket.js b/server/web-sockets/web-socket.js index c19f77dcb..a90d32aef 100644 --- a/server/web-sockets/web-socket.js +++ b/server/web-sockets/web-socket.js @@ -89,9 +89,11 @@ io.on("connection", (socket) => { callback(allocations); }); + socket.on("pbs-export-job", (jobid) => { PbsExportJob(socket, jobid); }); + socket.on("pbs-selected-customer", (selectedCustomerId) => { createLogEvent(socket, "DEBUG", `User selected customer ID ${selectedCustomerId}`); socket.selectedCustomerId = selectedCustomerId; @@ -118,6 +120,23 @@ io.on("connection", (socket) => { socket.on("disconnect", () => { createLogEvent(socket, "DEBUG", `User disconnected.`); }); + + socket.on("join-bodyshop-room", (bodyshopUUID) => { + socket.join(bodyshopUUID); // Join the room identified by the bodyshop UUID + createLogEvent(socket, "DEBUG", `Client joined bodyshop room: ${bodyshopUUID}`); + }); + + // Optionally handle leaving the room + socket.on("leave-bodyshop-room", (bodyshopUUID) => { + socket.leave(bodyshopUUID); // Leave the room identified by the bodyshop UUID + createLogEvent(socket, "DEBUG", `Client left bodyshop room: ${bodyshopUUID}`); + }); + + // Broadcast to specific bodyshop rooms + socket.on("broadcast-to-bodyshop", (bodyshopUUID, message) => { + io.to(bodyshopUUID).emit("bodyshop-message", message); + createLogEvent(socket, "INFO", `Broadcasted message to bodyshop ${bodyshopUUID}`); + }); }); function createLogEvent(socket, level, message) {