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
111 changes: 111 additions & 0 deletions src/components/settings/AppearanceSettings.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { act, fireEvent, render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { mockAuth, mockSettings } from '../../__mocks__/state-mocks';
import { AppContext } from '../../context/App';
import { AppearanceSettings } from './AppearanceSettings';

describe('routes/components/AppearanceSettings.tsx', () => {
const updateSetting = jest.fn();

afterEach(() => {
jest.clearAllMocks();
});

it('should change the theme radio group', async () => {
await act(async () => {
render(
<AppContext.Provider
value={{
auth: mockAuth,
settings: mockSettings,
updateSetting,
}}
>
<MemoryRouter>
<AppearanceSettings />
</MemoryRouter>
</AppContext.Provider>,
);
});

fireEvent.click(screen.getByLabelText('Light'));

expect(updateSetting).toHaveBeenCalledTimes(1);
expect(updateSetting).toHaveBeenCalledWith('theme', 'LIGHT');
});

it('should toggle detailed notifications checkbox', async () => {
await act(async () => {
render(
<AppContext.Provider
value={{
auth: mockAuth,
settings: mockSettings,
updateSetting,
}}
>
<MemoryRouter>
<AppearanceSettings />
</MemoryRouter>
</AppContext.Provider>,
);
});

await screen.findByLabelText('Detailed notifications');

fireEvent.click(screen.getByLabelText('Detailed notifications'));

expect(updateSetting).toHaveBeenCalledTimes(1);
expect(updateSetting).toHaveBeenCalledWith('detailedNotifications', false);
});

it('should toggle metric pills checkbox', async () => {
await act(async () => {
render(
<AppContext.Provider
value={{
auth: mockAuth,
settings: mockSettings,
updateSetting,
}}
>
<MemoryRouter>
<AppearanceSettings />
</MemoryRouter>
</AppContext.Provider>,
);
});

await screen.findByLabelText('Show notification metric pills');

fireEvent.click(screen.getByLabelText('Show notification metric pills'));

expect(updateSetting).toHaveBeenCalledTimes(1);
expect(updateSetting).toHaveBeenCalledWith('showPills', false);
});

it('should toggle account hostname checkbox', async () => {
await act(async () => {
render(
<AppContext.Provider
value={{
auth: mockAuth,
settings: mockSettings,
updateSetting,
}}
>
<MemoryRouter>
<AppearanceSettings />
</MemoryRouter>
</AppContext.Provider>,
);
});

await screen.findByLabelText('Show account hostname');

fireEvent.click(screen.getByLabelText('Show account hostname'));

expect(updateSetting).toHaveBeenCalledTimes(1);
expect(updateSetting).toHaveBeenCalledWith('showAccountHostname', true);
});
});
111 changes: 111 additions & 0 deletions src/components/settings/AppearanceSettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import {
CheckIcon,
CommentIcon,
IssueClosedIcon,
MilestoneIcon,
TagIcon,
} from '@primer/octicons-react';
import { ipcRenderer } from 'electron';
import { type FC, useContext, useEffect } from 'react';
import { AppContext } from '../../context/App';
import { Size, Theme } from '../../types';
import { setTheme } from '../../utils/theme';
import { Checkbox } from '../fields/Checkbox';
import { RadioGroup } from '../fields/RadioGroup';

export const AppearanceSettings: FC = () => {
const { settings, updateSetting } = useContext(AppContext);

useEffect(() => {
ipcRenderer.on('gitify:update-theme', (_, updatedTheme: Theme) => {
if (settings.theme === Theme.SYSTEM) {
setTheme(updatedTheme);
}
});
}, [settings.theme]);

return (
<fieldset className="mb-3">
<legend id="appearance" className="mb-1 mt-2 font-semibold">
Appearance
</legend>
<RadioGroup
name="theme"
label="Theme:"
value={settings.theme}
options={[
{ label: 'System', value: Theme.SYSTEM },
{ label: 'Light', value: Theme.LIGHT },
{ label: 'Dark', value: Theme.DARK },
]}
onChange={(evt) => {
updateSetting('theme', evt.target.value);
}}
/>
<Checkbox
name="detailedNotifications"
label="Detailed notifications"
checked={settings.detailedNotifications}
onChange={(evt) =>
updateSetting('detailedNotifications', evt.target.checked)
}
tooltip={
<div>
<div className="pb-3">
Enrich notifications with author or last commenter profile
information, state and GitHub-like colors.
</div>
<div className="text-orange-600">
⚠️ Users with a large number of unread notifications <i>may</i>{' '}
experience rate limiting under certain circumstances. Disable this
setting if you experience this.
</div>
</div>
}
/>
<Checkbox
name="showPills"
label="Show notification metric pills"
checked={settings.showPills}
onChange={(evt) => updateSetting('showPills', evt.target.checked)}
tooltip={
<div>
<div>Show notification metric pills for:</div>
<div className="pl-6">
<ul className="list-disc">
<li>
<IssueClosedIcon size={Size.MEDIUM} className="pr-1" />
linked issues
</li>
<li>
<CheckIcon size={Size.MEDIUM} className="pr-1" /> pr reviews
</li>
<li>
<CommentIcon size={Size.MEDIUM} className="pr-1" />
comments
</li>

<li>
<TagIcon size={Size.MEDIUM} className="pr-1" />
labels
</li>
<li>
<MilestoneIcon size={Size.MEDIUM} className="pr-1" />
milestones
</li>
</ul>
</div>
</div>
}
/>
<Checkbox
name="showAccountHostname"
label="Show account hostname"
checked={settings.showAccountHostname}
onChange={(evt) =>
updateSetting('showAccountHostname', evt.target.checked)
}
/>
</fieldset>
);
};
Loading