Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@
"react-dom": "18.2.0",
"react-emojione": "5.0.1",
"react-final-form": "6.5.9",
"react-router": "5.3.4",
"react-router-dom": "5.3.4",
"react-router": "6.16.0",
"react-router-dom": "6.16.0",
"react-transition-group": "4.4.5",
"ts-loader": "9.4.4",
"typescript": "5.2.2"
Expand Down
64 changes: 22 additions & 42 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 27 additions & 28 deletions src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { useContext } from 'react';
import {
Redirect,
Navigate,
HashRouter as Router,
Route,
Switch,
Routes,
useLocation,
} from 'react-router-dom';

Expand All @@ -23,7 +23,7 @@ function RequireAuth({ children }) {
return isLoggedIn ? (
children
) : (
<Redirect to={{ pathname: '/login', state: { from: location } }} />
<Navigate to="/login" replace state={{ from: location }} />
);
}

Expand All @@ -34,31 +34,30 @@ export const App = () => {
<div className="flex flex-col pl-14 h-full">
<Loading />
<Sidebar />

<Switch>
<Route path="/" exact>
<RequireAuth>
<NotificationsRoute />
</RequireAuth>
</Route>
<Route path="/settings" exact>
<RequireAuth>
<SettingsRoute />
</RequireAuth>
</Route>
<Route path="/login">
<LoginRoute />
</Route>
<Route path="/login">
<LoginRoute />
</Route>
<Route path="/login-enterprise">
<LoginEnterpriseRoute />
</Route>
<Route path="/login-token">
<LoginWithToken />
</Route>
</Switch>
<Routes>
<Route
path="/"
element={
<RequireAuth>
<NotificationsRoute />
</RequireAuth>
}
/>
<Route
path="/settings"
element={
<RequireAuth>
<SettingsRoute />
</RequireAuth>
}
/>
<Route path="/login" element={<LoginRoute />} />
<Route
path="/login-enterprise"
element={<LoginEnterpriseRoute />}
/>
<Route path="/login-token" element={<LoginWithToken />} />
</Routes>
</div>
</Router>
</AppProvider>
Expand Down
12 changes: 8 additions & 4 deletions src/components/Sidebar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import { mockedAccountNotifications } from '../__mocks__/mockedData';
import { AppContext } from '../context/App';
import { Sidebar } from './Sidebar';

const mockNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: () => mockNavigate,
}));

describe('components/Sidebar.tsx', () => {
const fetchNotifications = jest.fn();
const history = createMemoryHistory();
Expand Down Expand Up @@ -73,17 +79,15 @@ describe('components/Sidebar.tsx', () => {
});

it('go to the settings route', () => {
const pushMock = jest.spyOn(history, 'push');

const { getByLabelText } = render(
<AppContext.Provider value={{ isLoggedIn: true, notifications: [] }}>
<Router history={history}>
<Router location={history.location} navigator={history}>
<Sidebar />
</Router>
</AppContext.Provider>,
);
fireEvent.click(getByLabelText('Settings'));
expect(pushMock).toHaveBeenCalledTimes(1);
expect(mockNavigate).toHaveBeenNthCalledWith(1, '/settings');
});

it('opens github in the notifications page', () => {
Expand Down
10 changes: 5 additions & 5 deletions src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BellIcon } from '@primer/octicons-react';
import { ipcRenderer, shell } from 'electron';
import React, { useCallback, useContext, useMemo } from 'react';
import { useHistory, useLocation } from 'react-router-dom';
import { useNavigate, useLocation } from 'react-router-dom';

import { Logo } from '../components/Logo';
import { AppContext } from '../context/App';
Expand All @@ -11,7 +11,7 @@ import { IconRefresh } from '../icons/Refresh';
import { Constants } from '../utils/constants';

export const Sidebar: React.FC = () => {
const history = useHistory();
const navigate = useNavigate();
const location = useLocation();

const { isLoggedIn } = useContext(AppContext);
Expand Down Expand Up @@ -66,7 +66,7 @@ export const Sidebar: React.FC = () => {
<button
className={footerButtonClasses}
onClick={() => {
history.replace('/');
navigate('/', { replace: true });
fetchNotifications();
}}
aria-label="Refresh Notifications"
Expand All @@ -78,9 +78,9 @@ export const Sidebar: React.FC = () => {
className={footerButtonClasses}
onClick={() => {
if (location.pathname.startsWith('/settings')) {
history.replace('/');
navigate('/', { replace: true });
} else {
history.push('/settings');
navigate('/settings');
}
}}
aria-label="Settings"
Expand Down
24 changes: 13 additions & 11 deletions src/routes/Login.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ const { ipcRenderer } = require('electron');
import { AppContext } from '../context/App';
import { LoginRoute } from './Login';

const mockNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: () => mockNavigate,
}));

describe('routes/Login.tsx', () => {
const history = createMemoryHistory();
const pushMock = jest.spyOn(history, 'push');
const replaceMock = jest.spyOn(history, 'replace');

beforeEach(function () {
pushMock.mockReset();

beforeEach(() => {
mockNavigate.mockReset();
jest.spyOn(ipcRenderer, 'send');
});

Expand All @@ -34,35 +37,34 @@ describe('routes/Login.tsx', () => {
it('should redirect to notifications once logged in', () => {
const { rerender } = render(
<AppContext.Provider value={{ isLoggedIn: false }}>
<Router history={history}>
<Router location={history.location} navigator={history}>
<LoginRoute />
</Router>
</AppContext.Provider>,
);

rerender(
<AppContext.Provider value={{ isLoggedIn: true }}>
<Router history={history}>
<Router location={history.location} navigator={history}>
<LoginRoute />
</Router>
</AppContext.Provider>,
);

expect(ipcRenderer.send).toHaveBeenCalledTimes(1);
expect(ipcRenderer.send).toHaveBeenCalledWith('reopen-window');
expect(replaceMock).toHaveBeenCalledTimes(1);
expect(mockNavigate).toHaveBeenNthCalledWith(1, '/', { replace: true });
});

it('should navigate to login with github enterprise', () => {
const { getByLabelText } = render(
<Router history={history}>
<Router location={history.location} navigator={history}>
<LoginRoute />
</Router>,
);

fireEvent.click(getByLabelText('Login with GitHub Enterprise'));

expect(pushMock).toHaveBeenCalledTimes(1);
expect(pushMock).toHaveBeenCalledWith('/login-enterprise');
expect(mockNavigate).toHaveBeenNthCalledWith(1, '/login-enterprise');
});
});
10 changes: 5 additions & 5 deletions src/routes/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
const { ipcRenderer } = require('electron');

import React, { useCallback, useContext, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';

import { AppContext } from '../context/App';
import { Logo } from '../components/Logo';

export const LoginRoute: React.FC = () => {
const history = useHistory();
const navigate = useNavigate();
const { isLoggedIn, login } = useContext(AppContext);

useEffect(() => {
if (isLoggedIn) {
ipcRenderer.send('reopen-window');
history.replace('/');
navigate('/', { replace: true });
}
}, [isLoggedIn]);

Expand Down Expand Up @@ -46,15 +46,15 @@ export const LoginRoute: React.FC = () => {

<button
className={loginButtonClass}
onClick={() => history.push('/login-enterprise')}
onClick={() => navigate('/login-enterprise')}
aria-label="Login with GitHub Enterprise"
>
Login to GitHub Enterprise
</button>

<button
className="bg-none hover:text-gray-800 dark:text-gray-100 dark:hover:text-gray-300 mt-4 focus:outline-none"
onClick={() => history.push('/login-token')}
onClick={() => navigate('/login-token')}
aria-label="Login with Personal Token"
>
<small>or login with a personal token</small>
Expand Down
Loading