Skip to content

Commit b4b622f

Browse files
authored
refactor: create Header component (#1240)
* refactor: create `Header` component * chore: switch to `mt-2`
1 parent 3cd3a4e commit b4b622f

File tree

9 files changed

+204
-100
lines changed

9 files changed

+204
-100
lines changed

src/components/Header.test.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { fireEvent, render, screen } from '@testing-library/react';
2+
import { Header } from './Header';
3+
4+
const mockNavigate = jest.fn();
5+
jest.mock('react-router-dom', () => ({
6+
...jest.requireActual('react-router-dom'),
7+
useNavigate: () => mockNavigate,
8+
}));
9+
10+
describe('components/Header.tsx', () => {
11+
it('should render itself & its children', () => {
12+
const tree = render(<Header>Test Header</Header>);
13+
14+
expect(tree).toMatchSnapshot();
15+
});
16+
17+
it('should navigate back', () => {
18+
render(<Header>Test Header</Header>);
19+
20+
fireEvent.click(screen.getByLabelText('Go Back'));
21+
expect(mockNavigate).toHaveBeenNthCalledWith(1, -1);
22+
23+
expect(mockNavigate).toHaveBeenCalledTimes(1);
24+
expect(mockNavigate).toHaveBeenCalledWith(-1);
25+
});
26+
});

src/components/Header.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { ArrowLeftIcon } from '@primer/octicons-react';
2+
import type { ReactNode } from 'react';
3+
import { useNavigate } from 'react-router-dom';
4+
5+
interface IHeader {
6+
children: ReactNode;
7+
}
8+
9+
export const Header = ({ children }: IHeader) => {
10+
const navigate = useNavigate();
11+
return (
12+
<div className="mx-8 mt-2 flex items-center justify-between py-2">
13+
<button
14+
type="button"
15+
className="focus:outline-none"
16+
title="Go Back"
17+
onClick={() => navigate(-1)}
18+
>
19+
<ArrowLeftIcon
20+
size={20}
21+
className="hover:text-gray-400"
22+
aria-label="Go Back"
23+
/>
24+
</button>
25+
26+
<h3 className="text-lg font-semibold">{children}</h3>
27+
</div>
28+
);
29+
};

src/components/__snapshots__/Header.test.tsx.snap

Lines changed: 124 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/routes/Accounts.tsx

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
ArrowLeftIcon,
32
KeyIcon,
43
PersonIcon,
54
PlusIcon,
@@ -8,11 +7,10 @@ import {
87

98
import { type FC, useCallback, useContext } from 'react';
109
import { useNavigate } from 'react-router-dom';
11-
12-
import { AppContext } from '../context/App';
13-
10+
import { Header } from '../components/Header';
1411
import { AuthMethodIcon } from '../components/icons/AuthMethodIcon';
1512
import { PlatformIcon } from '../components/icons/PlatformIcon';
13+
import { AppContext } from '../context/App';
1614
import { BUTTON_CLASS_NAME } from '../styles/gitify';
1715
import type { Account } from '../types';
1816
import { getAccountUUID } from '../utils/auth/utils';
@@ -47,23 +45,7 @@ export const AccountsRoute: FC = () => {
4745

4846
return (
4947
<div className="flex h-screen flex-col" data-testid="accounts">
50-
<div className="mx-8 mt-2 flex items-center justify-between py-2">
51-
<button
52-
type="button"
53-
className="focus:outline-none"
54-
title="Go Back"
55-
onClick={() => navigate(-1)}
56-
>
57-
<ArrowLeftIcon
58-
size={20}
59-
className="hover:text-gray-400"
60-
aria-label="Go Back"
61-
/>
62-
</button>
63-
64-
<h3 className="text-lg font-semibold">Accounts</h3>
65-
</div>
66-
48+
<Header>Accounts</Header>
6749
<div className="flex-grow overflow-x-auto px-8">
6850
<div className="mt-4 flex flex-col text-sm">
6951
{auth.accounts.map((account) => (

src/routes/LoginWithOAuthApp.tsx

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
import {
2-
ArrowLeftIcon,
3-
BookIcon,
4-
PersonIcon,
5-
SignInIcon,
6-
} from '@primer/octicons-react';
1+
import { BookIcon, PersonIcon, SignInIcon } from '@primer/octicons-react';
72
import { type FC, useCallback, useContext } from 'react';
83
import { Form, type FormRenderProps } from 'react-final-form';
9-
import { useNavigate } from 'react-router-dom';
4+
import { Header } from '../components/Header';
105
import { Button } from '../components/fields/Button';
116
import { FieldInput } from '../components/fields/FieldInput';
127
import { AppContext } from '../context/App';
@@ -58,7 +53,6 @@ export const validate = (values: IValues): IFormErrors => {
5853

5954
export const LoginWithOAuthApp: FC = () => {
6055
const { loginWithOAuthApp } = useContext(AppContext);
61-
const navigate = useNavigate();
6256

6357
const renderForm = (formProps: FormRenderProps) => {
6458
const { handleSubmit, submitting, pristine, values } = formProps;
@@ -130,26 +124,10 @@ export const LoginWithOAuthApp: FC = () => {
130124

131125
return (
132126
<div>
133-
<div className="mx-8 mt-4 flex items-center justify-between py-2">
134-
<button
135-
type="button"
136-
className="focus:outline-none"
137-
title="Go Back"
138-
onClick={() => navigate(-1)}
139-
>
140-
<ArrowLeftIcon
141-
size={20}
142-
className="hover:text-gray-400"
143-
aria-label="Go Back"
144-
/>
145-
</button>
146-
147-
<h3 className="justify-center text-lg font-semibold">
148-
<PersonIcon size={20} className="mr-2" />
149-
Login with OAuth App
150-
</h3>
151-
</div>
152-
127+
<Header>
128+
<PersonIcon size={20} className="mr-2" />
129+
Login with OAuth App
130+
</Header>
153131
<div className="px-8">
154132
<Form
155133
initialValues={{

src/routes/LoginWithPersonalAccessToken.tsx

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1-
import {
2-
ArrowLeftIcon,
3-
BookIcon,
4-
KeyIcon,
5-
SignInIcon,
6-
} from '@primer/octicons-react';
1+
import { BookIcon, KeyIcon, SignInIcon } from '@primer/octicons-react';
72
import { type FC, useCallback, useContext, useState } from 'react';
83
import { Form, type FormRenderProps } from 'react-final-form';
94
import { useNavigate } from 'react-router-dom';
5+
import { Header } from '../components/Header';
106
import { Button } from '../components/fields/Button';
117
import { FieldInput } from '../components/fields/FieldInput';
128
import { AppContext } from '../context/App';
@@ -138,25 +134,10 @@ export const LoginWithPersonalAccessToken: FC = () => {
138134

139135
return (
140136
<div>
141-
<div className="mx-8 mt-4 flex items-center justify-between py-2">
142-
<button
143-
type="button"
144-
className="focus:outline-none"
145-
title="Go Back"
146-
onClick={() => navigate(-1)}
147-
>
148-
<ArrowLeftIcon
149-
size={20}
150-
className="hover:text-gray-400"
151-
aria-label="Go Back"
152-
/>
153-
</button>
154-
155-
<h3 className="justify-center text-lg font-semibold">
156-
<KeyIcon size={18} className="mr-2" />
157-
Login with Personal Access Token
158-
</h3>
159-
</div>
137+
<Header>
138+
<KeyIcon size={18} className="mr-2" />
139+
Login with Personal Access Token
140+
</Header>
160141

161142
<div className="px-8">
162143
<Form

src/routes/Settings.tsx

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
ArrowLeftIcon,
32
CheckIcon,
43
CommentIcon,
54
IssueClosedIcon,
@@ -17,6 +16,7 @@ import {
1716
useState,
1817
} from 'react';
1918
import { useNavigate } from 'react-router-dom';
19+
import { Header } from '../components/Header';
2020
import { Checkbox } from '../components/fields/Checkbox';
2121
import { RadioGroup } from '../components/fields/RadioGroup';
2222
import { AppContext } from '../context/App';
@@ -55,23 +55,7 @@ export const SettingsRoute: FC = () => {
5555

5656
return (
5757
<div className="flex h-screen flex-col" data-testid="settings">
58-
<div className="mx-8 mt-2 flex items-center justify-between py-2">
59-
<button
60-
type="button"
61-
className="focus:outline-none"
62-
title="Go Back"
63-
onClick={() => navigate(-1)}
64-
>
65-
<ArrowLeftIcon
66-
size={20}
67-
className="hover:text-gray-400"
68-
aria-label="Go Back"
69-
/>
70-
</button>
71-
72-
<h3 className="text-lg font-semibold">Settings</h3>
73-
</div>
74-
58+
<Header>Settings</Header>
7559
<div className="flex-grow overflow-x-auto px-8">
7660
<fieldset className="mb-3">
7761
<legend id="appearance" className="mb-1 mt-2 font-semibold">

0 commit comments

Comments
 (0)