diff --git a/src/app/components/options/options.component.ts b/src/app/components/options/options.component.ts
index c32a9b9..568be8f 100644
--- a/src/app/components/options/options.component.ts
+++ b/src/app/components/options/options.component.ts
@@ -42,7 +42,7 @@ export class OptionsComponent extends DisposableComponent implements OnInit {
 
     this.settings = settingsService.getExtensionSettings();
 
-    this.enableBrowserNotifications = !!this.settings.notifications.browser;
+    this.enableBrowserNotifications = this.settings.notifications.browser;
     this.enableSlackNotifications = !!this.settings.notifications.slack;
     this.slackSettings = this.settings.notifications.slack || new SlackSettings();
     this.bitbucketSettings = this.settings.bitbucket || new BitbucketSettings();
@@ -163,16 +163,7 @@ export class OptionsComponent extends DisposableComponent implements OnInit {
   }
 
   onBrowserNotificationTest() {
-    this.notificationService
-      .requestPermission()
-      .subscribe(permission => {
-        if (permission === 'granted') {
-          new Notification('test', {
-            icon: 'icon64.png',
-            body: 'hello'
-          });
-        }
-      });
+    this.notificationService.sendBrowserNotification('test', 'hello', 'https://www.mozilla.org')
   }
 }
 
diff --git a/src/app/other/notification.titles.ts b/src/app/other/notification.titles.ts
index a3cbc3a..8401ac2 100644
--- a/src/app/other/notification.titles.ts
+++ b/src/app/other/notification.titles.ts
@@ -37,7 +37,7 @@ export function GetSlackNotificationTitle(options: NotificationOptions): string
   return title;
 }
 
-export function GetWindowsNotificationBody(action: PullRequestActivityAction) {
+export function GetWindowsNotificationBody(action: PullRequestActivityAction): string {
   let body;
   switch (action) {
     case PullRequestActivityAction.Commented:
@@ -64,6 +64,9 @@ export function GetWindowsNotificationBody(action: PullRequestActivityAction) {
     case PullRequestActivityAction.Conflicted:
       body = 'pull request got code conflicts';
       break;
+    default:
+      body = `an action taken over pull request: ${action}`;
+      break;
   }
 
   return body;
diff --git a/src/app/other/slack-notification.builder.ts b/src/app/other/slack-notification.builder.ts
new file mode 100644
index 0000000..093b223
--- /dev/null
+++ b/src/app/other/slack-notification.builder.ts
@@ -0,0 +1,111 @@
+import {NotificationOptions, PullRequestIssue} from '../models/models';
+import {GetSlackNotificationTitle} from './notification.titles';
+import {SlackMessageOptions} from '../services/slackClient';
+import {PullRequestActivityAction} from '../models/enums';
+
+export class SlackNotificationBuilder {
+  private readonly message: SlackMessageOptions;
+
+  constructor(private memberId: string, private options: NotificationOptions, private issues: PullRequestIssue[]) {
+    let title = GetSlackNotificationTitle(this.options);
+
+    this.message = {
+      channel: this.memberId,
+      text: title,
+      blocks: []
+    };
+
+    // add title with PR link
+    // todo: use link to the comment for Commented action
+    this.message.blocks?.push({
+      'type': 'section',
+      'text': {
+        'type': 'mrkdwn',
+        'text': `${title}: *<${options.pullRequest.links.self[0].href}|${options.pullRequest.title}>*`
+      }
+    });
+  }
+
+  private addComment() {
+    if (this.options.action == PullRequestActivityAction.Commented) {
+      this.message.blocks?.push({
+        'type': 'section',
+        'text': {
+          'type': 'mrkdwn',
+          'text': `_${this.options.comment?.text}_`
+        }
+      });
+    }
+
+    return this;
+  }
+
+  private addDescription() {
+    let descriptionMaxLength = 50;
+    if (this.options.pullRequest.description?.length) {
+      let prDescription: string;
+      if (this.options.action === PullRequestActivityAction.Opened) {
+        // use longer description for just created PR
+        descriptionMaxLength = 200;
+      }
+
+      // todo: fix description
+      let spaceIndex = this.options.pullRequest.description.indexOf(' ', descriptionMaxLength);
+      prDescription = this.options.pullRequest.description.length > descriptionMaxLength && spaceIndex > descriptionMaxLength
+        ? (this.options.pullRequest.description.substr(0, spaceIndex + 1)) + '...'
+        : this.options.pullRequest.description;
+
+      this.message.blocks?.push({
+        'type': 'section',
+        'text': {
+          'type': 'mrkdwn',
+          'text': `*Description:*\n${prDescription}\n`
+        }
+      });
+    }
+    return this;
+  }
+
+  private addIssues() {
+    if (this.issues.length) {
+      this.message.blocks?.push({
+        'type': 'section',
+        'text': {
+          'type': 'mrkdwn',
+          'text': `*Issues:* ${this.issues.map(i => `<${i.url}|${i.key}>`).join(', ')}`
+        }
+      });
+    }
+    return this;
+  }
+
+  private addContext() {
+    const data = this.options.pullRequest;
+    this.message.blocks?.push({
+      'type': 'context',
+      'elements': [
+        {
+          'text':
+            `*PR created by <${data.author.user.links?.self[0].href}|${data.author.user.displayName}>` +
+            ` at ${new Date(data.createdDate).toDateString()}*` +
+            ` | <${data.fromRef.repository.links?.self[0].href}|${data.fromRef.repository.name}>` +
+            ` \`${data.toRef.displayId}\`` +
+            `${data.properties.commentCount ? (` :memo:${data.properties.commentCount}`) : ''}`,
+          'type': 'mrkdwn'
+        }
+      ]
+    });
+    return this;
+  }
+
+  public build(): SlackMessageOptions {
+    this
+      .addComment()
+      // .addDescription()
+      .addIssues()
+      .addContext();
+
+    this.message.blocks?.push({'type': 'divider'});
+    return this.message;
+  }
+}
diff --git a/src/app/services/notification.service.ts b/src/app/services/notification.service.ts
index 597c602..da948ab 100644
--- a/src/app/services/notification.service.ts
+++ b/src/app/services/notification.service.ts
@@ -1,16 +1,15 @@
 import {Injectable} from '@angular/core';
 import {DataService} from './data.service';
-import {SlackClient, SlackMessageOptions} from './slackClient';
+import {SlackClient} from './slackClient';
 import {catchError} from 'rxjs/operators';
 import {from, Observable, of, throwError} from 'rxjs';
-import {NotificationOptions, PullRequestIssue} from '../models/models';
+import {NotificationOptions} from '../models/models';
 import {BitbucketService} from './bitbucket.service';
-import {PullRequestActivityAction} from '../models/enums';
-import {GetSlackNotificationTitle, GetWindowsNotificationBody} from '../other/notification.titles';
+import {GetWindowsNotificationBody} from '../other/notification.titles';
+import {SlackNotificationBuilder} from '../other/slack-notification.builder';
 
 @Injectable()
 export class NotificationService {
-
   constructor(private dataService: DataService, private bitbucketService: BitbucketService) {
   }
 
@@ -22,8 +21,28 @@ export class NotificationService {
     return of(Notification.permission);
   }
 
-  sendNotification(options: NotificationOptions) {
+  sendBrowserNotification(title: string, body: string, clickUrl?: string) {
+    this
+      .requestPermission()
+      .subscribe((permission: NotificationPermission) => {
+        if (permission === 'granted') {
+          let notification = new Notification(title, {
+            icon: 'icon64.png',
+            body: body
+          });
+
+          if (clickUrl) {
+            notification.onclick = (event) => {
+              // prevent the browser from focusing the Notification's tab
+              event.preventDefault();
+              window.open(clickUrl, '_blank');
+            };
+          }
+        }
+      });
+  }
 
+  sendNotification(options: NotificationOptions) {
     // skip notification if it is snoozed for this PR
     let snoozeSettings = this.dataService.getNotificationSnoozeSettings();
     if (snoozeSettings.includes(options.pullRequest.id)) {
@@ -31,19 +50,9 @@ export class NotificationService {
     }
 
     let extensionSettings = this.dataService.getExtensionSettings();
-
     if (extensionSettings.notifications.browser) {
-      this.requestPermission()
-        .subscribe(permission => {
-          if (permission === 'granted') {
-            let body = GetWindowsNotificationBody(options.action);
-
-            new Notification(options.pullRequest.title, {
-              icon: 'favicon.ico',
-              body: body
-            });
-          }
-        });
+      let body = GetWindowsNotificationBody(options.action);
+      this.sendBrowserNotification(options.pullRequest.title, body, options.pullRequest.links.self[0].href);
     }
 
     // check if slack is enabled
@@ -57,7 +66,7 @@ export class NotificationService {
         .getPullRequestIssues(pr.fromRef.repository.project.key, pr.fromRef.repository.slug, pr.id)
         .pipe(catchError(() => of([])))
         .subscribe(issues => {
-          let messageOptions = NotificationService.buildPullRequestSlackMessage(slackSettings.memberId, options, issues);
+          let messageOptions = new SlackNotificationBuilder(slackSettings.memberId, options, issues).build();
 
           slackClient
             .postMessage(messageOptions)
@@ -93,88 +102,4 @@ export class NotificationService {
       chrome.browserAction.setTitle({title: options.title});
     }
   }
-
-  public static buildPullRequestSlackMessage(memberId: string, options: NotificationOptions, issues: PullRequestIssue[]): SlackMessageOptions {
-    let title = GetSlackNotificationTitle(options);
-    let data = options.pullRequest;
-
-    let message: SlackMessageOptions = {
-      channel: memberId,
-      text: title,
-      blocks: []
-    };
-
-    // add title with PR link
-    // todo: use link to the comment for Commented action
-    message.blocks?.push({
-      'type': 'section',
-      'text': {
-        'type': 'mrkdwn',
-        'text': `${title}: *<${data.links.self[0].href}|${data.title}>*`
-      }
-    });
-
-    // add comment
-    if (options.action == PullRequestActivityAction.Commented) {
-      message.blocks?.push({
-        'type': 'section',
-        'text': {
-          'type': 'mrkdwn',
-          'text': `_${options.comment?.text}_`
-        }
-      });
-    }
-
-    // add description
-    let descriptionMaxLength = 50;
-    if (data.description?.length) {
-      let prDescription: string;
-      if (options.action === PullRequestActivityAction.Opened) {
-        // use longer description for just created PR
-        descriptionMaxLength = 200;
-      }
-      let spaceIndex = data.description.indexOf(' ', descriptionMaxLength);
-      prDescription = data.description.length > descriptionMaxLength && spaceIndex > descriptionMaxLength
-        ? (data.description.substr(0, spaceIndex + 1)) + '...'
-        : data.description;
-
-      message.blocks?.push({
-        'type': 'section',
-        'text': {
-          'type': 'mrkdwn',
-          'text': `*Description:*\n${prDescription}\n`
-        }
-      });
-    }
-
-    // add issues
-    if (issues.length) {
-      message.blocks?.push({
-        'type': 'section',
-        'text': {
-          'type': 'mrkdwn',
-          'text': `*Issues:* ${issues.map(i => `<${i.url}|${i.key}>`).join(', ')}`
-        }
-      });
-    }
-
-    // add context
-    message.blocks?.push({
-      'type': 'context',
-      'elements': [
-        {
-          'text':
-            `*PR created by <${data.author.user.links?.self[0].href}|${data.author.user.displayName}>` +
-            ` at ${new Date(data.createdDate).toDateString()}*` +
-            ` | <${data.fromRef.repository.links?.self[0].href}|${data.fromRef.repository.name}>` +
-            ` \`${data.toRef.displayId}\`` +
-            `${data.properties.commentCount ? (` :memo:${data.properties.commentCount}`) : ''}`,
-          'type': 'mrkdwn'
-        }
-      ]
-    });
-
-    message.blocks?.push({'type': 'divider'});
-    return message;
-  }
 }