diff --git a/SAS/TMSS/frontend/tmss_webapp/package-lock.json b/SAS/TMSS/frontend/tmss_webapp/package-lock.json
index 9b5bad26eaeabec4390b8fc073efd424b097ae0f..50cb006c1af9b9ea004908086540e01fbdb0b02a 100644
--- a/SAS/TMSS/frontend/tmss_webapp/package-lock.json
+++ b/SAS/TMSS/frontend/tmss_webapp/package-lock.json
@@ -69,6 +69,7 @@
         "react-tooltip": "^4.5.1",
         "react-transition-group": "^2.5.1",
         "react-websocket": "^2.1.0",
+        "react-use-websocket": "^3.0.0",
         "reactstrap": "^9.2.0",
         "redux": "^4.2.1",
         "replace-in-file": "^7.0.1",
diff --git a/SAS/TMSS/frontend/tmss_webapp/package.json b/SAS/TMSS/frontend/tmss_webapp/package.json
index 58c6cd1027acc86472966de92cb96b92bb850ffe..04f4f9578ee3b6f8e0209e146d6e823b3ab5ac0c 100644
--- a/SAS/TMSS/frontend/tmss_webapp/package.json
+++ b/SAS/TMSS/frontend/tmss_webapp/package.json
@@ -62,6 +62,7 @@
     "react-tooltip": "^4.5.1",
     "react-transition-group": "^2.5.1",
     "react-websocket": "^2.1.0",
+    "react-use-websocket": "^3.0.0",
     "reactstrap": "^9.2.0",
     "redux": "^4.2.1",
     "replace-in-file": "^7.0.1",
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/WeekView.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/WeekView.js
index 5564120a48b210f538eba4710beaf719d422b380..eba8b8a422a961cf78be432ae23c75b400b1751d 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/WeekView.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/WeekView.js
@@ -46,9 +46,14 @@ import {
     fetchSchedulerStatuses,
     fetchSunTimings, fetchSUSummaryInformation,
     fetchTimelineData,
-    fetchUserPermissions
+    fetchUserPermissions,
 } from "./data/week.view.data";
 
+import useWebSocket from 'react-use-websocket';
+import _ from 'lodash';
+import ScheduleService from "../../services/schedule.service";
+import ReservationService from "../../services/reservation.service";
+
 function getTimelineHeaders(headerSettings) {
     return <TimelineHeaders className="sticky">
         <SidebarHeader>
@@ -243,6 +248,169 @@ export default function WeekView() {
         }
     }, [summaryItem]);
 
+    // websocket handling
+
+    /**
+     * Function to call wnen websocket is connected
+     */
+    function onConnect() {
+        try{
+            console.log("WS Opened");
+            const userDets = localStorage.getItem("user");
+            if (userDets) {
+                sendMessage(JSON.stringify({"token": JSON.parse(userDets).websocket_token}));
+                console.log("Auth token submitted");
+            }
+        }catch (err) {
+            console.log('err',err)
+        }
+    }
+
+    /**
+     * Function to call when websocket is disconnected
+     */
+    function onDisconnect() {
+        console.log("WS Closed")
+    }
+
+    /**
+     * Handles the message received through websocket
+     * @param {String} data - String of JSON data
+     */
+    function handleData(event) {
+        const jsonData = JSON.parse(event?.data) || {};
+        console.log('received websocket data:', jsonData)
+        switch (jsonData.object_type) {
+            case 'scheduling_unit_blueprint': {
+                switch (jsonData.action) {
+                    case 'delete': {
+                        console.log('ws delete SU');
+                        const schedulingUnits = data.schedulingUnits
+                        _.remove(schedulingUnits, function (su) { return su.id === jsonData.object_details.id});
+                        setData(prevData => ({
+                            ...prevData,
+                            schedulingUnits: schedulingUnits
+                        }))
+                        if (summaryItem?.id === jsonData.object_details.id) {
+                            setSummaryItem({});
+                        }
+                        break;
+                    }
+                    case 'update': {
+                        console.log("ws update SU");
+                        setData(prevData => ({
+                            ...prevData,
+                            schedulingUnits: prevData.schedulingUnits.map(
+                                unit => unit.id === jsonData.object_details.id? {...unit, ...jsonData.object_details}: unit
+                            )
+                        }));
+                        if (summaryItem?.id === jsonData.object_details.id) {
+                            // Note: we could also update details directly so we don't need to fetch again.
+                            // However, we would have to send full deltas via websocket instead of the subset that is
+                            // relevant for the timeline (like id, timestamps, and status).
+                            // e.g.
+                            //
+                            // setSummarySettings(prevState => ({
+                            //    ...prevState,
+                            //    schedulingUnitItem: {...prevState.schedulingUnitItem, ...jsonData.object_details}
+                            // }));
+                            //
+                            // Instead, trigger a full refresh of the details panel:
+                            setSummaryItem({id: jsonData.object_details.id, type: "SCHEDULE"});
+                        }
+                        break;
+                    }
+                    case 'create': {
+                        console.log("ws create SU");
+                        // the ws message only contains a subset of the details we need, so fetch the full set
+                        return async (dispatch) => {    // todo: async here problematic?
+                            const response = await ScheduleService.getTimelineSlimBlueprints(undefined, undefined, jsonData.object_details.id);   // todo: check time
+                            console.log('response:', response);
+                            setData(prevData => ({
+                                ...prevData,
+                                schedulingUnits: prevData.schedulingUnits.concat(response.results)
+                            }));
+                        };
+                        break;
+                    }
+                    default: { break; }
+                }
+                break;
+            }
+            case 'reservation': {
+                switch (jsonData.action) {
+                    case 'delete': {
+                        console.log('ws delete reservation');
+                        const reservations = data.reservations
+                        _.remove(reservations, function (res) { return res.id === jsonData.object_details.id});
+                        setData(prevData => ({
+                            ...prevData,
+                            reservations: reservations
+                        }))
+                        if (summaryItem?.id === jsonData.object_details.id) {
+                            setSummaryItem({});
+                        }
+                        break;
+                    }
+                    case 'update': {
+                        console.log("ws update reservation");
+                        setData(prevData => ({
+                            ...prevData,
+                            reservations: prevData.reservations.map(
+                                res => res.id === jsonData.object_details.id? {...res, ...jsonData.object_details}: res
+                            ),
+                        }));
+                        if (summaryItem?.id === jsonData.object_details.id) {
+                            // Note: this triggers a full fetch again to get all details (see SU above).
+                            setSummaryItem({id: jsonData.object_details.id, type: "RESERVATION"});
+                        }
+                        break;
+                    }
+                    case 'create': {
+                        console.log("ws create reservation");
+                        const shouldFetchReservations = getStore(UIConstants.STORE_KEY_TIMELINE).reservationsToggle;
+                        if (shouldFetchReservations) {
+                            // the ws message only contains a subset of the details we need, so fetch the full set
+                            return async (dispatch) => {    // todo: async here problematic?
+                                const response = await ReservationService.getTimelineReservations(undefined, undefined, jsonData.object_details.id);  // todo: check time
+                                console.log('response:', response);
+                                setData(prevData => ({
+                                    ...prevData,
+                                    reservations: prevData.reservations.concat(response.results)
+                                }));
+                            };
+                        }
+                        break;
+                    }
+                    default: { break; }
+                }
+                break;
+            }
+            default: { break; }
+        }
+    }
+
+    // debug logging whenever the SU and reservation data gets updated
+    useEffect(() => {
+        console.log('data update:', data);
+    }, [data])
+
+    // websocket hook that opens and allows interaction via the wss connection
+    const {
+      sendMessage,
+      sendJsonMessage,
+      lastMessage,
+      lastJsonMessage,
+      readyState,
+      getWebSocket,
+    } = useWebSocket(process.env.REACT_APP_WEBSOCKET_URL, {
+      onOpen: () => onConnect(),
+      onClose: () => onDisconnect(),
+      onMessage: (event) => handleData(event),
+      onError: (event) => { console.error(event); },
+      shouldReconnect: (closeEvent) => true,
+    });
+
     return <div>
         <div className={(isLoading ? "" : "hide-element")}>
             <ProgressBar className={isLoading ? "" : "hide-element"} mode="indeterminate"