Repository: gitify-app/gitify
Pull request #1303 (2024-06-21 02:39:07)

refactor: notification footer component


Patch:
diff --git a/src/components/NotificationRow.tsx b/src/components/NotificationRow.tsx
index 50ea7012..bfcead59 100644
--- a/src/components/NotificationRow.tsx
+++ b/src/components/NotificationRow.tsx
@@ -1,9 +1,4 @@
-import {
-  BellSlashIcon,
-  CheckIcon,
-  FeedPersonIcon,
-  ReadIcon,
-} from '@primer/octicons-react';
+import { BellSlashIcon, CheckIcon, ReadIcon } from '@primer/octicons-react';
 import {
   type FC,
   type MouseEvent,
@@ -12,24 +7,19 @@ import {
   useState,
 } from 'react';
 import { AppContext } from '../context/App';
-import { IconColor, Opacity, Size } from '../types';
+import { Opacity, Size } from '../types';
 import type { Notification } from '../typesGitHub';
 import { cn } from '../utils/cn';
-import {
-  formatForDisplay,
-  formatNotificationUpdatedAt,
-} from '../utils/helpers';
+import { formatForDisplay } from '../utils/helpers';
 import {
   getNotificationTypeIcon,
   getNotificationTypeIconColor,
 } from '../utils/icons';
-import { openNotification, openUserProfile } from '../utils/links';
-import { formatReason } from '../utils/reason';
+import { openNotification } from '../utils/links';
 import { HoverGroup } from './HoverGroup';
 import { InteractionButton } from './buttons/InteractionButton';
-import { AvatarIcon } from './icons/AvatarIcon';
+import { NotificationFooter } from './notification/NotificationFooter';
 import { NotificationHeader } from './notification/NotificationHeader';
-import { Pills } from './notification/Pills';
 
 interface INotificationRow {
   notification: Notification;
@@ -73,16 +63,10 @@ export const NotificationRow: FC<INotificationRow> = ({
     unsubscribeNotification(notification);
   };
 
-  const reason = formatReason(notification.reason);
   const NotificationIcon = getNotificationTypeIcon(notification.subject);
   const iconColor = getNotificationTypeIconColor(notification.subject);
 
-  const updatedAt = formatNotificationUpdatedAt(notification);
-  const updatedLabel = notification.subject.user
-    ? `${notification.subject.user.login} updated ${updatedAt}`
-    : `Updated ${updatedAt}`;
-
-  const notificationTitle = formatForDisplay([
+  const notificationType = formatForDisplay([
     notification.subject.state,
     notification.subject.type,
   ]);
@@ -101,7 +85,7 @@ export const NotificationRow: FC<INotificationRow> = ({
     >
       <div
         className={cn('mr-3 flex items-center justify-center', iconColor)}
-        title={notificationTitle}
+        title={notificationType}
       >
         <NotificationIcon
           size={groupByDate ? Size.XLARGE : Size.MEDIUM}
@@ -123,39 +107,7 @@ export const NotificationRow: FC<INotificationRow> = ({
           {notification.subject.title}
         </div>
 
-        <div
-          className={cn(
-            'flex flex-wrap items-center gap-1 text-xs capitalize',
-            Opacity.MEDIUM,
-          )}
-        >
-          {notification.subject.user ? (
-            <button
-              type="button"
-              title="View User Profile"
-              onClick={(event: MouseEvent<HTMLElement>) => {
-                // Don't trigger onClick of parent element.
-                event.stopPropagation();
-                openUserProfile(notification.subject.user);
-              }}
-              className="flex-shrink-0"
-            >
-              <AvatarIcon
-                title={notification.subject.user.login}
-                url={notification.subject.user.avatar_url}
-                size={Size.XSMALL}
-                defaultIcon={FeedPersonIcon}
-              />
-            </button>
-          ) : (
-            <div>
-              <FeedPersonIcon size={Size.MEDIUM} className={IconColor.GRAY} />
-            </div>
-          )}
-          <div title={reason.description}>{reason.title}</div>
-          <div title={updatedLabel}>{updatedAt}</div>
-          <Pills notification={notification} />
-        </div>
+        <NotificationFooter notification={notification} />
       </div>
 
       <HoverGroup>
diff --git a/src/components/notification/NotificationFooter.tsx b/src/components/notification/NotificationFooter.tsx
new file mode 100644
index 00000000..fa883512
--- /dev/null
+++ b/src/components/notification/NotificationFooter.tsx
@@ -0,0 +1,61 @@
+import { FeedPersonIcon } from '@primer/octicons-react';
+import type { FC, MouseEvent } from 'react';
+import { IconColor, Opacity, Size } from '../../types';
+import type { Notification } from '../../typesGitHub';
+import { cn } from '../../utils/cn';
+import { formatNotificationUpdatedAt } from '../../utils/helpers';
+import { openUserProfile } from '../../utils/links';
+import { formatReason } from '../../utils/reason';
+import { AvatarIcon } from '../icons/AvatarIcon';
+import { Pills } from './Pills';
+
+interface INotificationFooter {
+  notification: Notification;
+}
+
+export const NotificationFooter: FC<INotificationFooter> = ({
+  notification,
+}: INotificationFooter) => {
+  const reason = formatReason(notification.reason);
+
+  const updatedAt = formatNotificationUpdatedAt(notification);
+  const updatedLabel = notification.subject.user
+    ? `${notification.subject.user.login} updated ${updatedAt}`
+    : `Updated ${updatedAt}`;
+
+  return (
+    <div
+      className={cn(
+        'flex flex-wrap items-center gap-1 text-xs capitalize',
+        Opacity.MEDIUM,
+      )}
+    >
+      {notification.subject.user ? (
+        <button
+          type="button"
+          title="View User Profile"
+          onClick={(event: MouseEvent<HTMLElement>) => {
+            // Don't trigger onClick of parent element.
+            event.stopPropagation();
+            openUserProfile(notification.subject.user);
+          }}
+          className="flex-shrink-0"
+        >
+          <AvatarIcon
+            title={notification.subject.user.login}
+            url={notification.subject.user.avatar_url}
+            size={Size.XSMALL}
+            defaultIcon={FeedPersonIcon}
+          />
+        </button>
+      ) : (
+        <div>
+          <FeedPersonIcon size={Size.MEDIUM} className={IconColor.GRAY} />
+        </div>
+      )}
+      <div title={reason.description}>{reason.title}</div>
+      <div title={updatedLabel}>{updatedAt}</div>
+      <Pills notification={notification} />
+    </div>
+  );
+};


Test patch:
diff --git a/src/components/NotificationRow.test.tsx b/src/components/NotificationRow.test.tsx
index 442393f4..bb781f14 100644
--- a/src/components/NotificationRow.test.tsx
+++ b/src/components/NotificationRow.test.tsx
@@ -61,48 +61,6 @@ describe('components/NotificationRow.tsx', () => {
     expect(tree).toMatchSnapshot();
   });
 
-  it('should render itself & its children when last_read_at is null', async () => {
-    jest
-      .spyOn(global.Date, 'now')
-      .mockImplementation(() => new Date('2024').valueOf());
-
-    const mockNotification = mockSingleNotification;
-    mockNotification.last_read_at = null;
-
-    const props = {
-      notification: mockNotification,
-      account: mockGitHubCloudAccount,
-    };
-
-    const tree = render(
-      <AppContext.Provider value={{ settings: mockSettings }}>
-        <NotificationRow {...props} />
-      </AppContext.Provider>,
-    );
-    expect(tree).toMatchSnapshot();
-  });
-
-  it('should render itself & its children without avatar', async () => {
-    jest
-      .spyOn(global.Date, 'now')
-      .mockImplementation(() => new Date('2024').valueOf());
-
-    const mockNotification = mockSingleNotification;
-    mockNotification.subject.user = null;
-
-    const props = {
-      notification: mockNotification,
-      account: mockGitHubCloudAccount,
-    };
-
-    const tree = render(
-      <AppContext.Provider value={{ settings: mockSettings }}>
-        <NotificationRow {...props} />
-      </AppContext.Provider>,
-    );
-    expect(tree).toMatchSnapshot();
-  });
-
   describe('notification interactions', () => {
     it('should open a notification in the browser - click', () => {
       const removeNotificationFromState = jest.fn();
diff --git a/src/components/__snapshots__/NotificationRow.test.tsx.snap b/src/components/__snapshots__/NotificationRow.test.tsx.snap
index 2d9fb373..30e7c1cd 100644
--- a/src/components/__snapshots__/NotificationRow.test.tsx.snap
+++ b/src/components/__snapshots__/NotificationRow.test.tsx.snap
@@ -875,855 +875,3 @@ exports[`components/NotificationRow.tsx should render itself & its children - gr
   "unmount": [Function],
 }
 `;
-
-exports[`components/NotificationRow.tsx should render itself & its children when last_read_at is null 1`] = `
-{
-  "asFragment": [Function],
-  "baseElement": <body>
-    <div>
-      <div
-        class="group flex border-b border-gray-100 bg-white px-3 py-2 hover:bg-gray-100 dark:border-gray-darker dark:bg-gray-dark dark:text-white dark:hover:bg-gray-darker"
-        id="138661096"
-      >
-        <div
-          class="mr-3 flex items-center justify-center text-green-500"
-          title="Open Issue"
-        >
-          <svg
-            aria-label="Issue"
-            class="octicon octicon-issue-opened"
-            fill="currentColor"
-            focusable="false"
-            height="16"
-            role="img"
-            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-            viewBox="0 0 16 16"
-            width="16"
-          >
-            <path
-              d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"
-            />
-            <path
-              d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"
-            />
-          </svg>
-        </div>
-        <div
-          class="flex-1 overflow-hidden overflow-ellipsis whitespace-nowrap cursor-pointer"
-        >
-          <div
-            class="mb-1 truncate text-sm"
-            role="main"
-            title="I am a robot and this is a test!"
-          >
-            I am a robot and this is a test!
-          </div>
-          <div
-            class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
-          >
-            <button
-              class="flex-shrink-0"
-              title="View User Profile"
-              type="button"
-            >
-              <img
-                alt="gitify-app's avatar"
-                class="rounded-full object-cover size-4"
-                src="https://avatars.githubusercontent.com/u/133795385?s=200&v=4"
-              />
-            </button>
-            <div
-              title="You're watching the repository."
-            >
-              Updated
-            </div>
-            <div
-              title="gitify-app updated 7 years ago"
-            >
-              7 years ago
-            </div>
-            <div
-              class="flex"
-            >
-              <button
-                class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
-                title="octocat approved these changes"
-                type="button"
-              >
-                <svg
-                  aria-label="octocat approved these changes"
-                  class="text-green-500"
-                  fill="currentColor"
-                  focusable="false"
-                  height="12"
-                  role="img"
-                  style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-                  viewBox="0 0 16 16"
-                  width="12"
-                >
-                  <path
-                    d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
-                  />
-                </svg>
-                1
-              </button>
-              <button
-                class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
-                title="gitify-app requested changes"
-                type="button"
-              >
-                <svg
-                  aria-label="gitify-app requested changes"
-                  class="text-red-500"
-                  fill="currentColor"
-                  focusable="false"
-                  height="12"
-                  role="img"
-                  style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-                  viewBox="0 0 16 16"
-                  width="12"
-                >
-                  <path
-                    d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
-                  />
-                </svg>
-                1
-              </button>
-            </div>
-          </div>
-        </div>
-        <div
-          class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
-        >
-          <button
-            class="h-full hover:text-green-500 focus:outline-none"
-            title="Mark as Done"
-            type="button"
-          >
-            <svg
-              aria-label="Mark as Done"
-              class="octicon octicon-check"
-              fill="currentColor"
-              focusable="false"
-              height="16"
-              role="img"
-              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-              viewBox="0 0 16 16"
-              width="16"
-            >
-              <path
-                d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
-              />
-            </svg>
-          </button>
-          <button
-            class="h-full hover:text-green-500 focus:outline-none"
-            title="Mark as Read"
-            type="button"
-          >
-            <svg
-              aria-label="Mark as Read"
-              class="octicon octicon-read"
-              fill="currentColor"
-              focusable="false"
-              height="14"
-              role="img"
-              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-              viewBox="0 0 16 16"
-              width="14"
-            >
-              <path
-                d="M7.115.65a1.752 1.752 0 0 1 1.77 0l6.25 3.663c.536.314.865.889.865 1.51v6.427A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25V5.823c0-.621.33-1.196.865-1.51Zm1.011 1.293a.252.252 0 0 0-.252 0l-5.72 3.353L6.468 7.76a2.748 2.748 0 0 1 3.066 0l4.312-2.464-5.719-3.353ZM13.15 12.5 8.772 9.06a1.25 1.25 0 0 0-1.544 0L2.85 12.5Zm1.35-5.85-3.687 2.106 3.687 2.897ZM5.187 8.756 1.5 6.65v5.003Z"
-              />
-            </svg>
-          </button>
-          <button
-            class="h-full hover:text-green-500 focus:outline-none"
-            title="Unsubscribe from Thread"
-            type="button"
-          >
-            <svg
-              aria-label="Unsubscribe from Thread"
-              class="octicon octicon-bell-slash"
-              fill="currentColor"
-              focusable="false"
-              height="14"
-              role="img"
-              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-              viewBox="0 0 16 16"
-              width="14"
-            >
-              <path
-                d="m4.182 4.31.016.011 10.104 7.316.013.01 1.375.996a.75.75 0 1 1-.88 1.214L13.626 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947V5.305L.31 3.357a.75.75 0 1 1 .88-1.214Zm7.373 7.19L4.5 6.391v1.556c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01c0 .005.002.009.005.012l.006.004.007.001ZM8 1.5c-.997 0-1.895.416-2.534 1.086A.75.75 0 1 1 4.38 1.55 5 5 0 0 1 13 5v2.373a.75.75 0 0 1-1.5 0V5A3.5 3.5 0 0 0 8 1.5ZM8 16a2 2 0 0 1-1.985-1.75c-.017-.137.097-.25.235-.25h3.5c.138 0 .252.113.235.25A2 2 0 0 1 8 16Z"
-              />
-            </svg>
-          </button>
-        </div>
-      </div>
-    </div>
-  </body>,
-  "container": <div>
-    <div
-      class="group flex border-b border-gray-100 bg-white px-3 py-2 hover:bg-gray-100 dark:border-gray-darker dark:bg-gray-dark dark:text-white dark:hover:bg-gray-darker"
-      id="138661096"
-    >
-      <div
-        class="mr-3 flex items-center justify-center text-green-500"
-        title="Open Issue"
-      >
-        <svg
-          aria-label="Issue"
-          class="octicon octicon-issue-opened"
-          fill="currentColor"
-          focusable="false"
-          height="16"
-          role="img"
-          style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-          viewBox="0 0 16 16"
-          width="16"
-        >
-          <path
-            d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"
-          />
-          <path
-            d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"
-          />
-        </svg>
-      </div>
-      <div
-        class="flex-1 overflow-hidden overflow-ellipsis whitespace-nowrap cursor-pointer"
-      >
-        <div
-          class="mb-1 truncate text-sm"
-          role="main"
-          title="I am a robot and this is a test!"
-        >
-          I am a robot and this is a test!
-        </div>
-        <div
-          class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
-        >
-          <button
-            class="flex-shrink-0"
-            title="View User Profile"
-            type="button"
-          >
-            <img
-              alt="gitify-app's avatar"
-              class="rounded-full object-cover size-4"
-              src="https://avatars.githubusercontent.com/u/133795385?s=200&v=4"
-            />
-          </button>
-          <div
-            title="You're watching the repository."
-          >
-            Updated
-          </div>
-          <div
-            title="gitify-app updated 7 years ago"
-          >
-            7 years ago
-          </div>
-          <div
-            class="flex"
-          >
-            <button
-              class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
-              title="octocat approved these changes"
-              type="button"
-            >
-              <svg
-                aria-label="octocat approved these changes"
-                class="text-green-500"
-                fill="currentColor"
-                focusable="false"
-                height="12"
-                role="img"
-                style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-                viewBox="0 0 16 16"
-                width="12"
-              >
-                <path
-                  d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
-                />
-              </svg>
-              1
-            </button>
-            <button
-              class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
-              title="gitify-app requested changes"
-              type="button"
-            >
-              <svg
-                aria-label="gitify-app requested changes"
-                class="text-red-500"
-                fill="currentColor"
-                focusable="false"
-                height="12"
-                role="img"
-                style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-                viewBox="0 0 16 16"
-                width="12"
-              >
-                <path
-                  d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
-                />
-              </svg>
-              1
-            </button>
-          </div>
-        </div>
-      </div>
-      <div
-        class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
-      >
-        <button
-          class="h-full hover:text-green-500 focus:outline-none"
-          title="Mark as Done"
-          type="button"
-        >
-          <svg
-            aria-label="Mark as Done"
-            class="octicon octicon-check"
-            fill="currentColor"
-            focusable="false"
-            height="16"
-            role="img"
-            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-            viewBox="0 0 16 16"
-            width="16"
-          >
-            <path
-              d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
-            />
-          </svg>
-        </button>
-        <button
-          class="h-full hover:text-green-500 focus:outline-none"
-          title="Mark as Read"
-          type="button"
-        >
-          <svg
-            aria-label="Mark as Read"
-            class="octicon octicon-read"
-            fill="currentColor"
-            focusable="false"
-            height="14"
-            role="img"
-            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-            viewBox="0 0 16 16"
-            width="14"
-          >
-            <path
-              d="M7.115.65a1.752 1.752 0 0 1 1.77 0l6.25 3.663c.536.314.865.889.865 1.51v6.427A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25V5.823c0-.621.33-1.196.865-1.51Zm1.011 1.293a.252.252 0 0 0-.252 0l-5.72 3.353L6.468 7.76a2.748 2.748 0 0 1 3.066 0l4.312-2.464-5.719-3.353ZM13.15 12.5 8.772 9.06a1.25 1.25 0 0 0-1.544 0L2.85 12.5Zm1.35-5.85-3.687 2.106 3.687 2.897ZM5.187 8.756 1.5 6.65v5.003Z"
-            />
-          </svg>
-        </button>
-        <button
-          class="h-full hover:text-green-500 focus:outline-none"
-          title="Unsubscribe from Thread"
-          type="button"
-        >
-          <svg
-            aria-label="Unsubscribe from Thread"
-            class="octicon octicon-bell-slash"
-            fill="currentColor"
-            focusable="false"
-            height="14"
-            role="img"
-            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-            viewBox="0 0 16 16"
-            width="14"
-          >
-            <path
-              d="m4.182 4.31.016.011 10.104 7.316.013.01 1.375.996a.75.75 0 1 1-.88 1.214L13.626 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947V5.305L.31 3.357a.75.75 0 1 1 .88-1.214Zm7.373 7.19L4.5 6.391v1.556c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01c0 .005.002.009.005.012l.006.004.007.001ZM8 1.5c-.997 0-1.895.416-2.534 1.086A.75.75 0 1 1 4.38 1.55 5 5 0 0 1 13 5v2.373a.75.75 0 0 1-1.5 0V5A3.5 3.5 0 0 0 8 1.5ZM8 16a2 2 0 0 1-1.985-1.75c-.017-.137.097-.25.235-.25h3.5c.138 0 .252.113.235.25A2 2 0 0 1 8 16Z"
-            />
-          </svg>
-        </button>
-      </div>
-    </div>
-  </div>,
-  "debug": [Function],
-  "findAllByAltText": [Function],
-  "findAllByDisplayValue": [Function],
-  "findAllByLabelText": [Function],
-  "findAllByPlaceholderText": [Function],
-  "findAllByRole": [Function],
-  "findAllByTestId": [Function],
-  "findAllByText": [Function],
-  "findAllByTitle": [Function],
-  "findByAltText": [Function],
-  "findByDisplayValue": [Function],
-  "findByLabelText": [Function],
-  "findByPlaceholderText": [Function],
-  "findByRole": [Function],
-  "findByTestId": [Function],
-  "findByText": [Function],
-  "findByTitle": [Function],
-  "getAllByAltText": [Function],
-  "getAllByDisplayValue": [Function],
-  "getAllByLabelText": [Function],
-  "getAllByPlaceholderText": [Function],
-  "getAllByRole": [Function],
-  "getAllByTestId": [Function],
-  "getAllByText": [Function],
-  "getAllByTitle": [Function],
-  "getByAltText": [Function],
-  "getByDisplayValue": [Function],
-  "getByLabelText": [Function],
-  "getByPlaceholderText": [Function],
-  "getByRole": [Function],
-  "getByTestId": [Function],
-  "getByText": [Function],
-  "getByTitle": [Function],
-  "queryAllByAltText": [Function],
-  "queryAllByDisplayValue": [Function],
-  "queryAllByLabelText": [Function],
-  "queryAllByPlaceholderText": [Function],
-  "queryAllByRole": [Function],
-  "queryAllByTestId": [Function],
-  "queryAllByText": [Function],
-  "queryAllByTitle": [Function],
-  "queryByAltText": [Function],
-  "queryByDisplayValue": [Function],
-  "queryByLabelText": [Function],
-  "queryByPlaceholderText": [Function],
-  "queryByRole": [Function],
-  "queryByTestId": [Function],
-  "queryByText": [Function],
-  "queryByTitle": [Function],
-  "rerender": [Function],
-  "unmount": [Function],
-}
-`;
-
-exports[`components/NotificationRow.tsx should render itself & its children without avatar 1`] = `
-{
-  "asFragment": [Function],
-  "baseElement": <body>
-    <div>
-      <div
-        class="group flex border-b border-gray-100 bg-white px-3 py-2 hover:bg-gray-100 dark:border-gray-darker dark:bg-gray-dark dark:text-white dark:hover:bg-gray-darker"
-        id="138661096"
-      >
-        <div
-          class="mr-3 flex items-center justify-center text-green-500"
-          title="Open Issue"
-        >
-          <svg
-            aria-label="Issue"
-            class="octicon octicon-issue-opened"
-            fill="currentColor"
-            focusable="false"
-            height="16"
-            role="img"
-            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-            viewBox="0 0 16 16"
-            width="16"
-          >
-            <path
-              d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"
-            />
-            <path
-              d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"
-            />
-          </svg>
-        </div>
-        <div
-          class="flex-1 overflow-hidden overflow-ellipsis whitespace-nowrap cursor-pointer"
-        >
-          <div
-            class="mb-1 truncate text-sm"
-            role="main"
-            title="I am a robot and this is a test!"
-          >
-            I am a robot and this is a test!
-          </div>
-          <div
-            class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
-          >
-            <div>
-              <svg
-                aria-hidden="true"
-                class="text-gray-500 dark:text-gray-300"
-                fill="currentColor"
-                focusable="false"
-                height="16"
-                style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-                viewBox="0 0 16 16"
-                width="16"
-              >
-                <path
-                  d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm.847-8.145a2.502 2.502 0 1 0-1.694 0C5.471 8.261 4 9.775 4 11c0 .395.145.995 1 .995h6c.855 0 1-.6 1-.995 0-1.224-1.47-2.74-3.153-3.145Z"
-                />
-              </svg>
-            </div>
-            <div
-              title="You're watching the repository."
-            >
-              Updated
-            </div>
-            <div
-              title="Updated 7 years ago"
-            >
-              7 years ago
-            </div>
-            <div
-              class="flex"
-            >
-              <button
-                class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
-                title="octocat approved these changes"
-                type="button"
-              >
-                <svg
-                  aria-label="octocat approved these changes"
-                  class="text-green-500"
-                  fill="currentColor"
-                  focusable="false"
-                  height="12"
-                  role="img"
-                  style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-                  viewBox="0 0 16 16"
-                  width="12"
-                >
-                  <path
-                    d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
-                  />
-                </svg>
-                1
-              </button>
-              <button
-                class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
-                title="gitify-app requested changes"
-                type="button"
-              >
-                <svg
-                  aria-label="gitify-app requested changes"
-                  class="text-red-500"
-                  fill="currentColor"
-                  focusable="false"
-                  height="12"
-                  role="img"
-                  style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-                  viewBox="0 0 16 16"
-                  width="12"
-                >
-                  <path
-                    d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
-                  />
-                </svg>
-                1
-              </button>
-            </div>
-          </div>
-        </div>
-        <div
-          class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
-        >
-          <button
-            class="h-full hover:text-green-500 focus:outline-none"
-            title="Mark as Done"
-            type="button"
-          >
-            <svg
-              aria-label="Mark as Done"
-              class="octicon octicon-check"
-              fill="currentColor"
-              focusable="false"
-              height="16"
-              role="img"
-              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-              viewBox="0 0 16 16"
-              width="16"
-            >
-              <path
-                d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
-              />
-            </svg>
-          </button>
-          <button
-            class="h-full hover:text-green-500 focus:outline-none"
-            title="Mark as Read"
-            type="button"
-          >
-            <svg
-              aria-label="Mark as Read"
-              class="octicon octicon-read"
-              fill="currentColor"
-              focusable="false"
-              height="14"
-              role="img"
-              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-              viewBox="0 0 16 16"
-              width="14"
-            >
-              <path
-                d="M7.115.65a1.752 1.752 0 0 1 1.77 0l6.25 3.663c.536.314.865.889.865 1.51v6.427A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25V5.823c0-.621.33-1.196.865-1.51Zm1.011 1.293a.252.252 0 0 0-.252 0l-5.72 3.353L6.468 7.76a2.748 2.748 0 0 1 3.066 0l4.312-2.464-5.719-3.353ZM13.15 12.5 8.772 9.06a1.25 1.25 0 0 0-1.544 0L2.85 12.5Zm1.35-5.85-3.687 2.106 3.687 2.897ZM5.187 8.756 1.5 6.65v5.003Z"
-              />
-            </svg>
-          </button>
-          <button
-            class="h-full hover:text-green-500 focus:outline-none"
-            title="Unsubscribe from Thread"
-            type="button"
-          >
-            <svg
-              aria-label="Unsubscribe from Thread"
-              class="octicon octicon-bell-slash"
-              fill="currentColor"
-              focusable="false"
-              height="14"
-              role="img"
-              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-              viewBox="0 0 16 16"
-              width="14"
-            >
-              <path
-                d="m4.182 4.31.016.011 10.104 7.316.013.01 1.375.996a.75.75 0 1 1-.88 1.214L13.626 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947V5.305L.31 3.357a.75.75 0 1 1 .88-1.214Zm7.373 7.19L4.5 6.391v1.556c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01c0 .005.002.009.005.012l.006.004.007.001ZM8 1.5c-.997 0-1.895.416-2.534 1.086A.75.75 0 1 1 4.38 1.55 5 5 0 0 1 13 5v2.373a.75.75 0 0 1-1.5 0V5A3.5 3.5 0 0 0 8 1.5ZM8 16a2 2 0 0 1-1.985-1.75c-.017-.137.097-.25.235-.25h3.5c.138 0 .252.113.235.25A2 2 0 0 1 8 16Z"
-              />
-            </svg>
-          </button>
-        </div>
-      </div>
-    </div>
-  </body>,
-  "container": <div>
-    <div
-      class="group flex border-b border-gray-100 bg-white px-3 py-2 hover:bg-gray-100 dark:border-gray-darker dark:bg-gray-dark dark:text-white dark:hover:bg-gray-darker"
-      id="138661096"
-    >
-      <div
-        class="mr-3 flex items-center justify-center text-green-500"
-        title="Open Issue"
-      >
-        <svg
-          aria-label="Issue"
-          class="octicon octicon-issue-opened"
-          fill="currentColor"
-          focusable="false"
-          height="16"
-          role="img"
-          style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-          viewBox="0 0 16 16"
-          width="16"
-        >
-          <path
-            d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"
-          />
-          <path
-            d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"
-          />
-        </svg>
-      </div>
-      <div
-        class="flex-1 overflow-hidden overflow-ellipsis whitespace-nowrap cursor-pointer"
-      >
-        <div
-          class="mb-1 truncate text-sm"
-          role="main"
-          title="I am a robot and this is a test!"
-        >
-          I am a robot and this is a test!
-        </div>
-        <div
-          class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
-        >
-          <div>
-            <svg
-              aria-hidden="true"
-              class="text-gray-500 dark:text-gray-300"
-              fill="currentColor"
-              focusable="false"
-              height="16"
-              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-              viewBox="0 0 16 16"
-              width="16"
-            >
-              <path
-                d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm.847-8.145a2.502 2.502 0 1 0-1.694 0C5.471 8.261 4 9.775 4 11c0 .395.145.995 1 .995h6c.855 0 1-.6 1-.995 0-1.224-1.47-2.74-3.153-3.145Z"
-              />
-            </svg>
-          </div>
-          <div
-            title="You're watching the repository."
-          >
-            Updated
-          </div>
-          <div
-            title="Updated 7 years ago"
-          >
-            7 years ago
-          </div>
-          <div
-            class="flex"
-          >
-            <button
-              class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
-              title="octocat approved these changes"
-              type="button"
-            >
-              <svg
-                aria-label="octocat approved these changes"
-                class="text-green-500"
-                fill="currentColor"
-                focusable="false"
-                height="12"
-                role="img"
-                style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-                viewBox="0 0 16 16"
-                width="12"
-              >
-                <path
-                  d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
-                />
-              </svg>
-              1
-            </button>
-            <button
-              class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
-              title="gitify-app requested changes"
-              type="button"
-            >
-              <svg
-                aria-label="gitify-app requested changes"
-                class="text-red-500"
-                fill="currentColor"
-                focusable="false"
-                height="12"
-                role="img"
-                style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-                viewBox="0 0 16 16"
-                width="12"
-              >
-                <path
-                  d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
-                />
-              </svg>
-              1
-            </button>
-          </div>
-        </div>
-      </div>
-      <div
-        class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
-      >
-        <button
-          class="h-full hover:text-green-500 focus:outline-none"
-          title="Mark as Done"
-          type="button"
-        >
-          <svg
-            aria-label="Mark as Done"
-            class="octicon octicon-check"
-            fill="currentColor"
-            focusable="false"
-            height="16"
-            role="img"
-            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-            viewBox="0 0 16 16"
-            width="16"
-          >
-            <path
-              d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
-            />
-          </svg>
-        </button>
-        <button
-          class="h-full hover:text-green-500 focus:outline-none"
-          title="Mark as Read"
-          type="button"
-        >
-          <svg
-            aria-label="Mark as Read"
-            class="octicon octicon-read"
-            fill="currentColor"
-            focusable="false"
-            height="14"
-            role="img"
-            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-            viewBox="0 0 16 16"
-            width="14"
-          >
-            <path
-              d="M7.115.65a1.752 1.752 0 0 1 1.77 0l6.25 3.663c.536.314.865.889.865 1.51v6.427A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25V5.823c0-.621.33-1.196.865-1.51Zm1.011 1.293a.252.252 0 0 0-.252 0l-5.72 3.353L6.468 7.76a2.748 2.748 0 0 1 3.066 0l4.312-2.464-5.719-3.353ZM13.15 12.5 8.772 9.06a1.25 1.25 0 0 0-1.544 0L2.85 12.5Zm1.35-5.85-3.687 2.106 3.687 2.897ZM5.187 8.756 1.5 6.65v5.003Z"
-            />
-          </svg>
-        </button>
-        <button
-          class="h-full hover:text-green-500 focus:outline-none"
-          title="Unsubscribe from Thread"
-          type="button"
-        >
-          <svg
-            aria-label="Unsubscribe from Thread"
-            class="octicon octicon-bell-slash"
-            fill="currentColor"
-            focusable="false"
-            height="14"
-            role="img"
-            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-            viewBox="0 0 16 16"
-            width="14"
-          >
-            <path
-              d="m4.182 4.31.016.011 10.104 7.316.013.01 1.375.996a.75.75 0 1 1-.88 1.214L13.626 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947V5.305L.31 3.357a.75.75 0 1 1 .88-1.214Zm7.373 7.19L4.5 6.391v1.556c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01c0 .005.002.009.005.012l.006.004.007.001ZM8 1.5c-.997 0-1.895.416-2.534 1.086A.75.75 0 1 1 4.38 1.55 5 5 0 0 1 13 5v2.373a.75.75 0 0 1-1.5 0V5A3.5 3.5 0 0 0 8 1.5ZM8 16a2 2 0 0 1-1.985-1.75c-.017-.137.097-.25.235-.25h3.5c.138 0 .252.113.235.25A2 2 0 0 1 8 16Z"
-            />
-          </svg>
-        </button>
-      </div>
-    </div>
-  </div>,
-  "debug": [Function],
-  "findAllByAltText": [Function],
-  "findAllByDisplayValue": [Function],
-  "findAllByLabelText": [Function],
-  "findAllByPlaceholderText": [Function],
-  "findAllByRole": [Function],
-  "findAllByTestId": [Function],
-  "findAllByText": [Function],
-  "findAllByTitle": [Function],
-  "findByAltText": [Function],
-  "findByDisplayValue": [Function],
-  "findByLabelText": [Function],
-  "findByPlaceholderText": [Function],
-  "findByRole": [Function],
-  "findByTestId": [Function],
-  "findByText": [Function],
-  "findByTitle": [Function],
-  "getAllByAltText": [Function],
-  "getAllByDisplayValue": [Function],
-  "getAllByLabelText": [Function],
-  "getAllByPlaceholderText": [Function],
-  "getAllByRole": [Function],
-  "getAllByTestId": [Function],
-  "getAllByText": [Function],
-  "getAllByTitle": [Function],
-  "getByAltText": [Function],
-  "getByDisplayValue": [Function],
-  "getByLabelText": [Function],
-  "getByPlaceholderText": [Function],
-  "getByRole": [Function],
-  "getByTestId": [Function],
-  "getByText": [Function],
-  "getByTitle": [Function],
-  "queryAllByAltText": [Function],
-  "queryAllByDisplayValue": [Function],
-  "queryAllByLabelText": [Function],
-  "queryAllByPlaceholderText": [Function],
-  "queryAllByRole": [Function],
-  "queryAllByTestId": [Function],
-  "queryAllByText": [Function],
-  "queryAllByTitle": [Function],
-  "queryByAltText": [Function],
-  "queryByDisplayValue": [Function],
-  "queryByLabelText": [Function],
-  "queryByPlaceholderText": [Function],
-  "queryByRole": [Function],
-  "queryByTestId": [Function],
-  "queryByText": [Function],
-  "queryByTitle": [Function],
-  "rerender": [Function],
-  "unmount": [Function],
-}
-`;
diff --git a/src/components/notification/NotificationFooter.test.tsx b/src/components/notification/NotificationFooter.test.tsx
new file mode 100644
index 00000000..200b919b
--- /dev/null
+++ b/src/components/notification/NotificationFooter.test.tsx
@@ -0,0 +1,119 @@
+import { fireEvent, render, screen } from '@testing-library/react';
+import {
+  mockGitHubCloudAccount,
+  mockSettings,
+} from '../../__mocks__/state-mocks';
+import { AppContext } from '../../context/App';
+import { GroupBy, type Link } from '../../types';
+import type { UserType } from '../../typesGitHub';
+import { mockSingleNotification } from '../../utils/api/__mocks__/response-mocks';
+import * as comms from '../../utils/comms';
+import * as links from '../../utils/links';
+import { NotificationFooter } from './NotificationFooter';
+
+describe('components/notification/NotificationFooter.tsx', () => {
+  beforeEach(() => {
+    jest.spyOn(links, 'openNotification');
+  });
+
+  afterEach(() => {
+    jest.clearAllMocks();
+  });
+
+  it('should render itself & its children', async () => {
+    jest
+      .spyOn(global.Date, 'now')
+      .mockImplementation(() => new Date('2024').valueOf());
+
+    const props = {
+      notification: mockSingleNotification,
+    };
+
+    const tree = render(
+      <AppContext.Provider
+        value={{ settings: { ...mockSettings, groupBy: GroupBy.DATE } }}
+      >
+        <NotificationFooter {...props} />
+      </AppContext.Provider>,
+    );
+    expect(tree).toMatchSnapshot();
+  });
+
+  it('should render itself & its children when last_read_at is null', async () => {
+    jest
+      .spyOn(global.Date, 'now')
+      .mockImplementation(() => new Date('2024').valueOf());
+
+    const mockNotification = mockSingleNotification;
+    mockNotification.last_read_at = null;
+
+    const props = {
+      notification: mockNotification,
+    };
+
+    const tree = render(
+      <AppContext.Provider value={{ settings: mockSettings }}>
+        <NotificationFooter {...props} />
+      </AppContext.Provider>,
+    );
+    expect(tree).toMatchSnapshot();
+  });
+
+  it('should render itself & its children without avatar', async () => {
+    jest
+      .spyOn(global.Date, 'now')
+      .mockImplementation(() => new Date('2024').valueOf());
+
+    const mockNotification = mockSingleNotification;
+    mockNotification.subject.user = null;
+
+    const props = {
+      notification: mockNotification,
+    };
+
+    const tree = render(
+      <AppContext.Provider value={{ settings: mockSettings }}>
+        <NotificationFooter {...props} />
+      </AppContext.Provider>,
+    );
+    expect(tree).toMatchSnapshot();
+  });
+
+  it('should open notification user profile', () => {
+    const openExternalLinkMock = jest.spyOn(comms, 'openExternalLink');
+
+    const props = {
+      notification: {
+        ...mockSingleNotification,
+        subject: {
+          ...mockSingleNotification.subject,
+          user: {
+            login: 'some-user',
+            html_url: 'https://github.com/some-user' as Link,
+            avatar_url:
+              'https://avatars.githubusercontent.com/u/123456789?v=4' as Link,
+            type: 'User' as UserType,
+          },
+          reviews: null,
+        },
+      },
+      account: mockGitHubCloudAccount,
+    };
+
+    render(
+      <AppContext.Provider
+        value={{
+          settings: { ...mockSettings },
+        }}
+      >
+        <NotificationFooter {...props} />
+      </AppContext.Provider>,
+    );
+
+    fireEvent.click(screen.getByTitle('View User Profile'));
+    expect(openExternalLinkMock).toHaveBeenCalledTimes(1);
+    expect(openExternalLinkMock).toHaveBeenCalledWith(
+      props.notification.subject.user.html_url,
+    );
+  });
+});
diff --git a/src/components/notification/__snapshots__/NotificationFooter.test.tsx.snap b/src/components/notification/__snapshots__/NotificationFooter.test.tsx.snap
new file mode 100644
index 00000000..5d59c1f5
--- /dev/null
+++ b/src/components/notification/__snapshots__/NotificationFooter.test.tsx.snap
@@ -0,0 +1,638 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`components/notification/NotificationFooter.tsx should render itself & its children 1`] = `
+{
+  "asFragment": [Function],
+  "baseElement": <body>
+    <div>
+      <div
+        class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
+      >
+        <button
+          class="flex-shrink-0"
+          title="View User Profile"
+          type="button"
+        >
+          <img
+            alt="gitify-app's avatar"
+            class="rounded-full object-cover size-4"
+            src="https://avatars.githubusercontent.com/u/133795385?s=200&v=4"
+          />
+        </button>
+        <div
+          title="You're watching the repository."
+        >
+          Updated
+        </div>
+        <div
+          title="gitify-app updated 7 years ago"
+        >
+          7 years ago
+        </div>
+        <div
+          class="flex"
+        >
+          <button
+            class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+            title="octocat approved these changes"
+            type="button"
+          >
+            <svg
+              aria-label="octocat approved these changes"
+              class="text-green-500"
+              fill="currentColor"
+              focusable="false"
+              height="12"
+              role="img"
+              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+              viewBox="0 0 16 16"
+              width="12"
+            >
+              <path
+                d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+              />
+            </svg>
+            1
+          </button>
+          <button
+            class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+            title="gitify-app requested changes"
+            type="button"
+          >
+            <svg
+              aria-label="gitify-app requested changes"
+              class="text-red-500"
+              fill="currentColor"
+              focusable="false"
+              height="12"
+              role="img"
+              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+              viewBox="0 0 16 16"
+              width="12"
+            >
+              <path
+                d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
+              />
+            </svg>
+            1
+          </button>
+        </div>
+      </div>
+    </div>
+  </body>,
+  "container": <div>
+    <div
+      class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
+    >
+      <button
+        class="flex-shrink-0"
+        title="View User Profile"
+        type="button"
+      >
+        <img
+          alt="gitify-app's avatar"
+          class="rounded-full object-cover size-4"
+          src="https://avatars.githubusercontent.com/u/133795385?s=200&v=4"
+        />
+      </button>
+      <div
+        title="You're watching the repository."
+      >
+        Updated
+      </div>
+      <div
+        title="gitify-app updated 7 years ago"
+      >
+        7 years ago
+      </div>
+      <div
+        class="flex"
+      >
+        <button
+          class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+          title="octocat approved these changes"
+          type="button"
+        >
+          <svg
+            aria-label="octocat approved these changes"
+            class="text-green-500"
+            fill="currentColor"
+            focusable="false"
+            height="12"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="12"
+          >
+            <path
+              d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+            />
+          </svg>
+          1
+        </button>
+        <button
+          class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+          title="gitify-app requested changes"
+          type="button"
+        >
+          <svg
+            aria-label="gitify-app requested changes"
+            class="text-red-500"
+            fill="currentColor"
+            focusable="false"
+            height="12"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="12"
+          >
+            <path
+              d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
+            />
+          </svg>
+          1
+        </button>
+      </div>
+    </div>
+  </div>,
+  "debug": [Function],
+  "findAllByAltText": [Function],
+  "findAllByDisplayValue": [Function],
+  "findAllByLabelText": [Function],
+  "findAllByPlaceholderText": [Function],
+  "findAllByRole": [Function],
+  "findAllByTestId": [Function],
+  "findAllByText": [Function],
+  "findAllByTitle": [Function],
+  "findByAltText": [Function],
+  "findByDisplayValue": [Function],
+  "findByLabelText": [Function],
+  "findByPlaceholderText": [Function],
+  "findByRole": [Function],
+  "findByTestId": [Function],
+  "findByText": [Function],
+  "findByTitle": [Function],
+  "getAllByAltText": [Function],
+  "getAllByDisplayValue": [Function],
+  "getAllByLabelText": [Function],
+  "getAllByPlaceholderText": [Function],
+  "getAllByRole": [Function],
+  "getAllByTestId": [Function],
+  "getAllByText": [Function],
+  "getAllByTitle": [Function],
+  "getByAltText": [Function],
+  "getByDisplayValue": [Function],
+  "getByLabelText": [Function],
+  "getByPlaceholderText": [Function],
+  "getByRole": [Function],
+  "getByTestId": [Function],
+  "getByText": [Function],
+  "getByTitle": [Function],
+  "queryAllByAltText": [Function],
+  "queryAllByDisplayValue": [Function],
+  "queryAllByLabelText": [Function],
+  "queryAllByPlaceholderText": [Function],
+  "queryAllByRole": [Function],
+  "queryAllByTestId": [Function],
+  "queryAllByText": [Function],
+  "queryAllByTitle": [Function],
+  "queryByAltText": [Function],
+  "queryByDisplayValue": [Function],
+  "queryByLabelText": [Function],
+  "queryByPlaceholderText": [Function],
+  "queryByRole": [Function],
+  "queryByTestId": [Function],
+  "queryByText": [Function],
+  "queryByTitle": [Function],
+  "rerender": [Function],
+  "unmount": [Function],
+}
+`;
+
+exports[`components/notification/NotificationFooter.tsx should render itself & its children when last_read_at is null 1`] = `
+{
+  "asFragment": [Function],
+  "baseElement": <body>
+    <div>
+      <div
+        class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
+      >
+        <button
+          class="flex-shrink-0"
+          title="View User Profile"
+          type="button"
+        >
+          <img
+            alt="gitify-app's avatar"
+            class="rounded-full object-cover size-4"
+            src="https://avatars.githubusercontent.com/u/133795385?s=200&v=4"
+          />
+        </button>
+        <div
+          title="You're watching the repository."
+        >
+          Updated
+        </div>
+        <div
+          title="gitify-app updated 7 years ago"
+        >
+          7 years ago
+        </div>
+        <div
+          class="flex"
+        >
+          <button
+            class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+            title="octocat approved these changes"
+            type="button"
+          >
+            <svg
+              aria-label="octocat approved these changes"
+              class="text-green-500"
+              fill="currentColor"
+              focusable="false"
+              height="12"
+              role="img"
+              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+              viewBox="0 0 16 16"
+              width="12"
+            >
+              <path
+                d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+              />
+            </svg>
+            1
+          </button>
+          <button
+            class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+            title="gitify-app requested changes"
+            type="button"
+          >
+            <svg
+              aria-label="gitify-app requested changes"
+              class="text-red-500"
+              fill="currentColor"
+              focusable="false"
+              height="12"
+              role="img"
+              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+              viewBox="0 0 16 16"
+              width="12"
+            >
+              <path
+                d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
+              />
+            </svg>
+            1
+          </button>
+        </div>
+      </div>
+    </div>
+  </body>,
+  "container": <div>
+    <div
+      class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
+    >
+      <button
+        class="flex-shrink-0"
+        title="View User Profile"
+        type="button"
+      >
+        <img
+          alt="gitify-app's avatar"
+          class="rounded-full object-cover size-4"
+          src="https://avatars.githubusercontent.com/u/133795385?s=200&v=4"
+        />
+      </button>
+      <div
+        title="You're watching the repository."
+      >
+        Updated
+      </div>
+      <div
+        title="gitify-app updated 7 years ago"
+      >
+        7 years ago
+      </div>
+      <div
+        class="flex"
+      >
+        <button
+          class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+          title="octocat approved these changes"
+          type="button"
+        >
+          <svg
+            aria-label="octocat approved these changes"
+            class="text-green-500"
+            fill="currentColor"
+            focusable="false"
+            height="12"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="12"
+          >
+            <path
+              d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+            />
+          </svg>
+          1
+        </button>
+        <button
+          class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+          title="gitify-app requested changes"
+          type="button"
+        >
+          <svg
+            aria-label="gitify-app requested changes"
+            class="text-red-500"
+            fill="currentColor"
+            focusable="false"
+            height="12"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="12"
+          >
+            <path
+              d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
+            />
+          </svg>
+          1
+        </button>
+      </div>
+    </div>
+  </div>,
+  "debug": [Function],
+  "findAllByAltText": [Function],
+  "findAllByDisplayValue": [Function],
+  "findAllByLabelText": [Function],
+  "findAllByPlaceholderText": [Function],
+  "findAllByRole": [Function],
+  "findAllByTestId": [Function],
+  "findAllByText": [Function],
+  "findAllByTitle": [Function],
+  "findByAltText": [Function],
+  "findByDisplayValue": [Function],
+  "findByLabelText": [Function],
+  "findByPlaceholderText": [Function],
+  "findByRole": [Function],
+  "findByTestId": [Function],
+  "findByText": [Function],
+  "findByTitle": [Function],
+  "getAllByAltText": [Function],
+  "getAllByDisplayValue": [Function],
+  "getAllByLabelText": [Function],
+  "getAllByPlaceholderText": [Function],
+  "getAllByRole": [Function],
+  "getAllByTestId": [Function],
+  "getAllByText": [Function],
+  "getAllByTitle": [Function],
+  "getByAltText": [Function],
+  "getByDisplayValue": [Function],
+  "getByLabelText": [Function],
+  "getByPlaceholderText": [Function],
+  "getByRole": [Function],
+  "getByTestId": [Function],
+  "getByText": [Function],
+  "getByTitle": [Function],
+  "queryAllByAltText": [Function],
+  "queryAllByDisplayValue": [Function],
+  "queryAllByLabelText": [Function],
+  "queryAllByPlaceholderText": [Function],
+  "queryAllByRole": [Function],
+  "queryAllByTestId": [Function],
+  "queryAllByText": [Function],
+  "queryAllByTitle": [Function],
+  "queryByAltText": [Function],
+  "queryByDisplayValue": [Function],
+  "queryByLabelText": [Function],
+  "queryByPlaceholderText": [Function],
+  "queryByRole": [Function],
+  "queryByTestId": [Function],
+  "queryByText": [Function],
+  "queryByTitle": [Function],
+  "rerender": [Function],
+  "unmount": [Function],
+}
+`;
+
+exports[`components/notification/NotificationFooter.tsx should render itself & its children without avatar 1`] = `
+{
+  "asFragment": [Function],
+  "baseElement": <body>
+    <div>
+      <div
+        class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
+      >
+        <div>
+          <svg
+            aria-hidden="true"
+            class="text-gray-500 dark:text-gray-300"
+            fill="currentColor"
+            focusable="false"
+            height="16"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="16"
+          >
+            <path
+              d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm.847-8.145a2.502 2.502 0 1 0-1.694 0C5.471 8.261 4 9.775 4 11c0 .395.145.995 1 .995h6c.855 0 1-.6 1-.995 0-1.224-1.47-2.74-3.153-3.145Z"
+            />
+          </svg>
+        </div>
+        <div
+          title="You're watching the repository."
+        >
+          Updated
+        </div>
+        <div
+          title="Updated 7 years ago"
+        >
+          7 years ago
+        </div>
+        <div
+          class="flex"
+        >
+          <button
+            class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+            title="octocat approved these changes"
+            type="button"
+          >
+            <svg
+              aria-label="octocat approved these changes"
+              class="text-green-500"
+              fill="currentColor"
+              focusable="false"
+              height="12"
+              role="img"
+              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+              viewBox="0 0 16 16"
+              width="12"
+            >
+              <path
+                d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+              />
+            </svg>
+            1
+          </button>
+          <button
+            class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+            title="gitify-app requested changes"
+            type="button"
+          >
+            <svg
+              aria-label="gitify-app requested changes"
+              class="text-red-500"
+              fill="currentColor"
+              focusable="false"
+              height="12"
+              role="img"
+              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+              viewBox="0 0 16 16"
+              width="12"
+            >
+              <path
+                d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
+              />
+            </svg>
+            1
+          </button>
+        </div>
+      </div>
+    </div>
+  </body>,
+  "container": <div>
+    <div
+      class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
+    >
+      <div>
+        <svg
+          aria-hidden="true"
+          class="text-gray-500 dark:text-gray-300"
+          fill="currentColor"
+          focusable="false"
+          height="16"
+          style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+          viewBox="0 0 16 16"
+          width="16"
+        >
+          <path
+            d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm.847-8.145a2.502 2.502 0 1 0-1.694 0C5.471 8.261 4 9.775 4 11c0 .395.145.995 1 .995h6c.855 0 1-.6 1-.995 0-1.224-1.47-2.74-3.153-3.145Z"
+          />
+        </svg>
+      </div>
+      <div
+        title="You're watching the repository."
+      >
+        Updated
+      </div>
+      <div
+        title="Updated 7 years ago"
+      >
+        7 years ago
+      </div>
+      <div
+        class="flex"
+      >
+        <button
+          class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+          title="octocat approved these changes"
+          type="button"
+        >
+          <svg
+            aria-label="octocat approved these changes"
+            class="text-green-500"
+            fill="currentColor"
+            focusable="false"
+            height="12"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="12"
+          >
+            <path
+              d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+            />
+          </svg>
+          1
+        </button>
+        <button
+          class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+          title="gitify-app requested changes"
+          type="button"
+        >
+          <svg
+            aria-label="gitify-app requested changes"
+            class="text-red-500"
+            fill="currentColor"
+            focusable="false"
+            height="12"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="12"
+          >
+            <path
+              d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
+            />
+          </svg>
+          1
+        </button>
+      </div>
+    </div>
+  </div>,
+  "debug": [Function],
+  "findAllByAltText": [Function],
+  "findAllByDisplayValue": [Function],
+  "findAllByLabelText": [Function],
+  "findAllByPlaceholderText": [Function],
+  "findAllByRole": [Function],
+  "findAllByTestId": [Function],
+  "findAllByText": [Function],
+  "findAllByTitle": [Function],
+  "findByAltText": [Function],
+  "findByDisplayValue": [Function],
+  "findByLabelText": [Function],
+  "findByPlaceholderText": [Function],
+  "findByRole": [Function],
+  "findByTestId": [Function],
+  "findByText": [Function],
+  "findByTitle": [Function],
+  "getAllByAltText": [Function],
+  "getAllByDisplayValue": [Function],
+  "getAllByLabelText": [Function],
+  "getAllByPlaceholderText": [Function],
+  "getAllByRole": [Function],
+  "getAllByTestId": [Function],
+  "getAllByText": [Function],
+  "getAllByTitle": [Function],
+  "getByAltText": [Function],
+  "getByDisplayValue": [Function],
+  "getByLabelText": [Function],
+  "getByPlaceholderText": [Function],
+  "getByRole": [Function],
+  "getByTestId": [Function],
+  "getByText": [Function],
+  "getByTitle": [Function],
+  "queryAllByAltText": [Function],
+  "queryAllByDisplayValue": [Function],
+  "queryAllByLabelText": [Function],
+  "queryAllByPlaceholderText": [Function],
+  "queryAllByRole": [Function],
+  "queryAllByTestId": [Function],
+  "queryAllByText": [Function],
+  "queryAllByTitle": [Function],
+  "queryByAltText": [Function],
+  "queryByDisplayValue": [Function],
+  "queryByLabelText": [Function],
+  "queryByPlaceholderText": [Function],
+  "queryByRole": [Function],
+  "queryByTestId": [Function],
+  "queryByText": [Function],
+  "queryByTitle": [Function],
+  "rerender": [Function],
+  "unmount": [Function],
+}
+`;