From 3b647dfd3796502177e0848b4ec5233835bd8caa Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 25 Sep 2024 17:44:53 -0400 Subject: [PATCH] IO-2924-Refactor-Production-board-to-use-Socket-Provider: rough in split logic / production-board-kanban.container.jsx logic Signed-off-by: Dave Richer --- .../production-board-kanban.container.jsx | 89 ++++++++++++++++--- 1 file changed, 75 insertions(+), 14 deletions(-) diff --git a/client/src/components/production-board-kanban/production-board-kanban.container.jsx b/client/src/components/production-board-kanban/production-board-kanban.container.jsx index 45bfb353c..d6a04fedd 100644 --- a/client/src/components/production-board-kanban/production-board-kanban.container.jsx +++ b/client/src/components/production-board-kanban/production-board-kanban.container.jsx @@ -1,15 +1,18 @@ -import React, { useEffect, useMemo, useRef } from "react"; -import { useQuery, useSubscription } from "@apollo/client"; +import React, { useEffect, useMemo, useRef, useContext } from "react"; +import { useQuery, useSubscription, useApolloClient, gql } from "@apollo/client"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { QUERY_JOBS_IN_PRODUCTION, SUBSCRIPTION_JOBS_IN_PRODUCTION, - SUBSCRIPTION_JOBS_IN_PRODUCTION_VIEW + SUBSCRIPTION_JOBS_IN_PRODUCTION_VIEW, + GET_JOB_BY_PK } from "../../graphql/jobs.queries"; import { QUERY_KANBAN_SETTINGS } from "../../graphql/user.queries"; import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors"; import ProductionBoardKanbanComponent from "./production-board-kanban.component"; +import { useSplitTreatments } from "@splitsoftware/splitio-react"; +import SocketContext from "../../contexts/SocketIO/socketContext.jsx"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -17,7 +20,17 @@ const mapStateToProps = createStructuredSelector({ }); function ProductionBoardKanbanContainer({ bodyshop, currentUser, subscriptionType = "direct" }) { - const fired = useRef(false); // useRef to keep track of whether the subscription fired + const fired = useRef(false); + const client = useApolloClient(); + const { socket } = useContext(SocketContext); // Get the socket from context + + const { + treatments: { Websocket_Production } + } = useSplitTreatments({ + attributes: {}, + names: ["Websocket_Production"], + splitKey: bodyshop && bodyshop.imexshopid + }); const combinedStatuses = useMemo( () => [ @@ -34,9 +47,12 @@ function ProductionBoardKanbanContainer({ bodyshop, currentUser, subscriptionTyp onError: (error) => console.error(`Error fetching jobs in production: ${error.message}`) }); + const subscriptionEnabled = Websocket_Production?.treatment === "on"; + const { data: updatedJobs } = useSubscription( subscriptionType === "view" ? SUBSCRIPTION_JOBS_IN_PRODUCTION_VIEW : SUBSCRIPTION_JOBS_IN_PRODUCTION, { + skip: !subscriptionEnabled, onError: (error) => console.error(`Error subscribing to jobs in production: ${error.message}`) } ); @@ -46,22 +62,67 @@ function ProductionBoardKanbanContainer({ bodyshop, currentUser, subscriptionTyp onError: (error) => console.error(`Error fetching Kanban settings: ${error.message}`) }); - // const currentReducerData = useSelector((state) => (state.trello.lanes ? state.trello : {})); - useEffect(() => { - if (!updatedJobs) { + if (subscriptionEnabled) { + if (!updatedJobs) { + return; + } + if (!fired.current) { + fired.current = true; + return; + } + refetch().catch((err) => console.error(`Error re-fetching jobs in production: ${err.message}`)); + } + }, [updatedJobs, refetch, subscriptionEnabled]); + + // Socket.IO implementation for users with Split treatment "off" + useEffect(() => { + if (subscriptionEnabled || !socket || !bodyshop || !bodyshop.id) { return; } - if (!fired.current) { - fired.current = true; - return; - } - refetch().catch((err) => console.error(`Error re-fetching jobs in production: ${err.message}`)); - }, [updatedJobs, refetch]); + + const handleJobChanged = async (jobChangedData) => { + const jobId = jobChangedData.jobId; + const existingJob = data?.jobs.find((job) => job.id === jobId); + + if (existingJob) { + try { + const { data: jobData } = await client.query({ + query: GET_JOB_BY_PK, + variables: { id: jobId }, + fetchPolicy: "network-only" + }); + + client.writeFragment({ + id: client.cache.identify({ __typename: "Job", id: jobId }), + fragment: gql` + fragment UpdatedJob on Job { + id + status + updatedAt + # ... include other fields you need to update + } + `, + data: jobData.job + }); + } catch (error) { + console.error(`Error fetching job ${jobId}: ${error.message}`); + } + } + }; + + // Listen for 'job-changed' events + socket.on("job-changed", handleJobChanged); + + // Clean up on unmount or when dependencies change + return () => { + socket.off("job-changed", handleJobChanged); + }; + }, [subscriptionEnabled, socket, bodyshop, data, client]); const filteredAssociationSettings = useMemo(() => { return associationSettings?.associations[0] || null; - }, [associationSettings]); + }, [associationSettings?.associations]); return (