diff --git a/web/app/static/js/nopaque/main.js b/web/app/static/js/nopaque/main.js
index 6435186f26e0ac2da4e6629e00470987f077d5b7..4a91bd3116b03400fca328174d8c72f73a209d0d 100644
--- a/web/app/static/js/nopaque/main.js
+++ b/web/app/static/js/nopaque/main.js
@@ -3,6 +3,20 @@ class AppClient {
     this.socket = io({transports: ['websocket']});
     this.users = {};
     this.users.self = this.loadUser(currentUserId);
+    this.users.self.eventListeners.job.addEventListener((eventType, payload) => this.jobEventHandler(eventType, payload));
+  }
+
+  jobEventHandler(eventType, payload) {
+    switch (eventType) {
+      case 'init':
+        break;
+      case 'patch':
+        this.jobPatch(payload);
+        break;
+      default:
+        console.error(`[AppClient.jobEventHandler] Unknown event type: ${eventType}`);
+        break;
+    }
   }
 
   loadUser(userId) {
@@ -14,8 +28,17 @@ class AppClient {
     this.socket.emit('start_user_session', userId);
     return user;
   }
-}
 
+  jobPatch(patch) {
+    if (this.users.self.data.settings.job_status_site_notifications === 'none') {return;}
+    let jobStatusPatches = patch.filter(operation => operation.op === 'replace' && /^\/jobs\/(\d+)\/status$/.test(operation.path));
+    for (let operation of jobStatusPatches) {
+      let [match, jobId] = operation.path.match(/^\/jobs\/(\d+)\/status$/);
+      if (this.users.self.data.settings.job_status_site_notifications === "end" && !['complete', 'failed'].includes(operation.value)) {continue;}
+      nopaque.flash(`[<a href="/jobs/${jobId}">${this.users.self.data.jobs[jobId].title}</a>] New status: ${operation.value}`, 'job');
+    }
+  }
+}
 
 class User {
   constructor() {
@@ -40,8 +63,6 @@ class User {
   }
 
   init(data) {
-    console.log('### User.init ###');
-    console.log(data);
     this.data = data;
 
     for (let [corpusId, eventListeners] of Object.entries(this.eventListeners.corpus)) {
@@ -76,8 +97,6 @@ class User {
   }
 
   patch(patch) {
-    console.log('### User.patch ###');
-    console.log(patch);
     this.data = jsonpatch.apply_patch(this.data, patch);
 
     let corporaPatch = patch.filter(operation => operation.path.startsWith("/corpora"));
@@ -121,16 +140,6 @@ class User {
         }
       }
     }
-
-    for (let operation of jobsPatch) {
-      if (operation.op !== 'replace') {continue;}
-      // Matches the only path that should be handled here: /jobs/{jobId}/status
-      if (/^\/jobs\/(\d+)\/status$/.test(operation.path)) {
-        let [match, jobId] = operation.path.match(/^\/jobs\/(\d+)\/status$/);
-        if (this.data.settings.job_status_site_notifications === "end" && !['complete', 'failed'].includes(operation.value)) {continue;}
-        nopaque.flash(`[<a href="/jobs/${jobId}">${this.data.jobs[jobId].title}</a>] New status: ${operation.value}`, 'job');
-      }
-    }
   }
 }