Repository: gitify-app/gitify
Pull request #1008 (2024-04-15 18:40:00)

feat: add tooltip for show participating setting
![Screenshot 2024-04-15 at 2 37 42 PM](https://github.com/gitify-app/gitify/assets/386277/d1bf5fa1-8493-498a-9b7a-bb15ad7e101d)



Patch:
diff --git a/src/components/fields/Checkbox.tsx b/src/components/fields/Checkbox.tsx
index e420d5ed..554699fd 100644
--- a/src/components/fields/Checkbox.tsx
+++ b/src/components/fields/Checkbox.tsx
@@ -35,7 +35,9 @@ export const Checkbox: FC<ICheckbox> = (props: ICheckbox) => {
             }
           >
             {props.label}
-            {props.tooltip && <Tooltip tooltip={props.tooltip} />}
+            {props.tooltip && (
+              <Tooltip name={`tooltip-${props.name}`} tooltip={props.tooltip} />
+            )}
           </label>
         </div>
       </div>
diff --git a/src/components/fields/Tooltip.tsx b/src/components/fields/Tooltip.tsx
index 3a9232fa..fdf89223 100644
--- a/src/components/fields/Tooltip.tsx
+++ b/src/components/fields/Tooltip.tsx
@@ -2,6 +2,7 @@ import { QuestionIcon } from '@primer/octicons-react';
 import { type FC, type ReactNode, useState } from 'react';
 
 export interface ITooltip {
+  name: string;
   tooltip: ReactNode | string;
 }
 
@@ -10,7 +11,8 @@ export const Tooltip: FC<ITooltip> = (props: ITooltip) => {
 
   return (
     <span
-      title="tooltip"
+      id={props.name}
+      aria-label={props.name}
       className="relative"
       onMouseEnter={() => setShowTooltip(true)}
       onMouseLeave={() => setShowTooltip(false)}
diff --git a/src/routes/Settings.tsx b/src/routes/Settings.tsx
index 9928b607..7c6ab6c7 100644
--- a/src/routes/Settings.tsx
+++ b/src/routes/Settings.tsx
@@ -8,6 +8,7 @@ import { ipcRenderer } from 'electron';
 
 import {
   type FC,
+  type MouseEvent,
   useCallback,
   useContext,
   useEffect,
@@ -44,6 +45,15 @@ export const SettingsRoute: FC = () => {
     );
   }, []);
 
+  const openGitHubParticipatingDocs = (event: MouseEvent<HTMLElement>) => {
+    // Don't trigger onClick of parent element.
+    event.stopPropagation();
+
+    openExternalLink(
+      'https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications#about-participating-and-watching-notifications',
+    );
+  };
+
   useEffect(() => {
     ipcRenderer.invoke('get-platform').then((result: string) => {
       setIsLinux(result === 'linux');
@@ -177,6 +187,22 @@ export const SettingsRoute: FC = () => {
             onChange={(evt) =>
               updateSetting('participating', evt.target.checked)
             }
+            tooltip={
+              <div>
+                <div className="pb-3">
+                  See{' '}
+                  <button
+                    type="button"
+                    className="text-blue-500"
+                    title="Open GitHub documentation for participating and watching notifications"
+                    onClick={openGitHubParticipatingDocs}
+                  >
+                    official docs
+                  </button>{' '}
+                  for more details.
+                </div>
+              </div>
+            }
           />
           <Checkbox
             name="showBots"


Test patch:
diff --git a/src/components/fields/Tooltip.test.tsx b/src/components/fields/Tooltip.test.tsx
index 863847ee..e0eaa960 100644
--- a/src/components/fields/Tooltip.test.tsx
+++ b/src/components/fields/Tooltip.test.tsx
@@ -6,6 +6,7 @@ import { type ITooltip, Tooltip } from './Tooltip';
 
 describe('components/fields/Tooltip.tsx', () => {
   const props: ITooltip = {
+    name: 'tooltip',
     tooltip: 'This is some tooltip text',
   };
 
@@ -17,7 +18,7 @@ describe('components/fields/Tooltip.tsx', () => {
   it('should display on mouse enter / leave', () => {
     render(<Tooltip {...props} />);
 
-    const tooltipElement = screen.getByTitle('tooltip');
+    const tooltipElement = screen.getByLabelText('tooltip');
 
     fireEvent.mouseEnter(tooltipElement);
     expect(tooltipElement).toMatchSnapshot();
diff --git a/src/components/fields/__snapshots__/Tooltip.test.tsx.snap b/src/components/fields/__snapshots__/Tooltip.test.tsx.snap
index c2ed6592..e4586a87 100644
--- a/src/components/fields/__snapshots__/Tooltip.test.tsx.snap
+++ b/src/components/fields/__snapshots__/Tooltip.test.tsx.snap
@@ -2,8 +2,9 @@
 
 exports[`components/fields/Tooltip.tsx should display on mouse enter / leave 1`] = `
 <span
+  aria-label="tooltip"
   class="relative"
-  title="tooltip"
+  id="tooltip"
 >
   <svg
     aria-hidden="true"
@@ -33,8 +34,9 @@ exports[`components/fields/Tooltip.tsx should display on mouse enter / leave 1`]
 
 exports[`components/fields/Tooltip.tsx should display on mouse enter / leave 2`] = `
 <span
+  aria-label="tooltip"
   class="relative"
-  title="tooltip"
+  id="tooltip"
 >
   <svg
     aria-hidden="true"
@@ -55,10 +57,11 @@ exports[`components/fields/Tooltip.tsx should display on mouse enter / leave 2`]
 
 exports[`components/fields/Tooltip.tsx should render 1`] = `
 <span
+  aria-label="tooltip"
   className="relative"
+  id="tooltip"
   onMouseEnter={[Function]}
   onMouseLeave={[Function]}
-  title="tooltip"
 >
   <svg
     aria-hidden="true"
diff --git a/src/routes/Settings.test.tsx b/src/routes/Settings.test.tsx
index a5155f5d..60107a2d 100644
--- a/src/routes/Settings.test.tsx
+++ b/src/routes/Settings.test.tsx
@@ -119,6 +119,41 @@ describe('routes/Settings.tsx', () => {
     expect(updateSetting).toHaveBeenCalledWith('participating', false);
   });
 
+  it('should open official docs for showOnlyParticipating tooltip', async () => {
+    await act(async () => {
+      render(
+        <AppContext.Provider
+          value={{
+            settings: mockSettings,
+            accounts: mockAccounts,
+            updateSetting,
+          }}
+        >
+          <MemoryRouter>
+            <SettingsRoute />
+          </MemoryRouter>
+        </AppContext.Provider>,
+      );
+    });
+
+    const tooltipElement = screen.getByLabelText(
+      'tooltip-showOnlyParticipating',
+    );
+
+    fireEvent.mouseEnter(tooltipElement);
+
+    fireEvent.click(
+      screen.getByTitle(
+        'Open GitHub documentation for participating and watching notifications',
+      ),
+    );
+
+    expect(shell.openExternal).toHaveBeenCalledTimes(1);
+    expect(shell.openExternal).toHaveBeenCalledWith(
+      'https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications#about-participating-and-watching-notifications',
+    );
+  });
+
   it('should not be able to toggle the showBots checkbox when detailedNotifications is disabled', async () => {
     await act(async () => {
       render(
diff --git a/src/routes/__snapshots__/Settings.test.tsx.snap b/src/routes/__snapshots__/Settings.test.tsx.snap
index 0dbaa19e..0e599972 100644
--- a/src/routes/__snapshots__/Settings.test.tsx.snap
+++ b/src/routes/__snapshots__/Settings.test.tsx.snap
@@ -23,8 +23,9 @@ exports[`routes/Settings.tsx should be able to toggle the showBots checkbox when
     >
       Show notifications from Bot accounts
       <span
+        aria-label="tooltip-showBots"
         class="relative"
-        title="tooltip"
+        id="tooltip-showBots"
       >
         <svg
           aria-hidden="true"
@@ -70,8 +71,9 @@ exports[`routes/Settings.tsx should not be able to enable detailed notifications
     >
       Detailed notifications (requires repo scope)
       <span
+        aria-label="tooltip-detailedNotifications"
         class="relative"
-        title="tooltip"
+        id="tooltip-detailedNotifications"
       >
         <svg
           aria-hidden="true"
@@ -118,8 +120,9 @@ exports[`routes/Settings.tsx should not be able to toggle the showBots checkbox
     >
       Show notifications from Bot accounts
       <span
+        aria-label="tooltip-showBots"
         class="relative"
-        title="tooltip"
+        id="tooltip-showBots"
       >
         <svg
           aria-hidden="true"
@@ -289,8 +292,9 @@ exports[`routes/Settings.tsx should render itself & its children 1`] = `
             >
               Detailed notifications
               <span
+                aria-label="tooltip-detailedNotifications"
                 class="relative"
-                title="tooltip"
+                id="tooltip-detailedNotifications"
               >
                 <svg
                   aria-hidden="true"
@@ -371,6 +375,26 @@ exports[`routes/Settings.tsx should render itself & its children 1`] = `
               for="showOnlyParticipating"
             >
               Show only participating
+              <span
+                aria-label="tooltip-showOnlyParticipating"
+                class="relative"
+                id="tooltip-showOnlyParticipating"
+              >
+                <svg
+                  aria-hidden="true"
+                  class="text-blue-500 ml-1"
+                  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="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.92 6.085h.001a.749.749 0 1 1-1.342-.67c.169-.339.436-.701.849-.977C6.845 4.16 7.369 4 8 4a2.756 2.756 0 0 1 1.637.525c.503.377.863.965.863 1.725 0 .448-.115.83-.329 1.15-.205.307-.47.513-.692.662-.109.072-.22.138-.313.195l-.006.004a6.24 6.24 0 0 0-.26.16.952.952 0 0 0-.276.245.75.75 0 0 1-1.248-.832c.184-.264.42-.489.692-.661.103-.067.207-.132.313-.195l.007-.004c.1-.061.182-.11.258-.161a.969.969 0 0 0 .277-.245C8.96 6.514 9 6.427 9 6.25a.612.612 0 0 0-.262-.525A1.27 1.27 0 0 0 8 5.5c-.369 0-.595.09-.74.187a1.01 1.01 0 0 0-.34.398ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"
+                  />
+                </svg>
+              </span>
             </label>
           </div>
         </div>
@@ -402,8 +426,9 @@ exports[`routes/Settings.tsx should render itself & its children 1`] = `
             >
               Show notifications from Bot accounts
               <span
+                aria-label="tooltip-showBots"
                 class="relative"
-                title="tooltip"
+                id="tooltip-showBots"
               >
                 <svg
                   aria-hidden="true"