Skip to content

Commit 9e08708

Browse files
committed
refactor(renderer): relocate shortcut-registration store into stores
Move the transient global-shortcut registration Zustand store out of the hooks layer into the stores layer, matching the documented state-ownership rule for session client state. - Add stores/useShortcutRegistrationStore.ts and mirror its ShortcutRegistrationStore type in stores/types.ts - Export it from the stores barrel - Trim hooks/useShortcutRegistration.ts to the effect hook, importing the store from the stores layer - Repoint the seven consumers (GlobalEffects, SystemSettings, and the test setup/helpers) to the barrel No behavior change: registration, revert-on-failure, and the surfaced error are identical.
1 parent bd0e08d commit 9e08708

11 files changed

Lines changed: 78 additions & 54 deletions

‎src/renderer/__helpers__/test-utils.tsx‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@ import { type InitialEntry, MemoryRouter } from 'react-router-dom';
44

55
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
66

7-
import { useShortcutRegistrationStore } from '../hooks/useShortcutRegistration';
8-
import { type FiltersStore, useAccountsStore, useFiltersStore, useSettingsStore } from '../stores';
7+
import {
8+
type FiltersStore,
9+
useAccountsStore,
10+
useFiltersStore,
11+
useSettingsStore,
12+
useShortcutRegistrationStore,
13+
} from '../stores';
914

1015
import type { Account, SettingsState } from '../types';
1116

‎src/renderer/__helpers__/visual.setup.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ beforeEach(async () => {
162162
const { resetHookMocks } = await import('./hook-mocks');
163163
resetHookMocks();
164164

165-
const { useShortcutRegistrationStore } = await import('../hooks/useShortcutRegistration');
165+
const { useShortcutRegistrationStore } = await import('../stores');
166166
useShortcutRegistrationStore.getState().reset();
167167
});
168168

‎src/renderer/__helpers__/vitest.setup.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ beforeEach(async () => {
153153
const { resetHookMocks } = await import('./hook-mocks');
154154
resetHookMocks();
155155

156-
const { useShortcutRegistrationStore } = await import('../hooks/useShortcutRegistration');
156+
const { useShortcutRegistrationStore } = await import('../stores');
157157
useShortcutRegistrationStore.getState().reset();
158158
});
159159

‎src/renderer/components/GlobalEffects.test.tsx‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import { act } from '@testing-library/react';
33
import { renderWithProviders } from '../__helpers__/test-utils';
44
import { mockGitHubCloudAccount } from '../__mocks__/account-mocks';
55

6-
import { useShortcutRegistrationStore } from '../hooks/useShortcutRegistration';
7-
import { useAccountsStore, useSettingsStore } from '../stores';
6+
import { useAccountsStore, useSettingsStore, useShortcutRegistrationStore } from '../stores';
87

98
import { Theme } from '../types';
109

‎src/renderer/components/GlobalEffects.tsx‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import { useNotificationsHost } from '../hooks/notifications/useNotificationsHos
66
import { useAccounts } from '../hooks/useAccounts';
77
import { useAppearance } from '../hooks/useAppearance';
88
import { useOnlineStatus } from '../hooks/useOnlineStatus';
9+
import { useShortcutRegistration } from '../hooks/useShortcutRegistration';
910
import {
10-
useShortcutRegistration,
11+
useAccountsStore,
12+
useFiltersStore,
13+
useSettingsStore,
1114
useShortcutRegistrationStore,
12-
} from '../hooks/useShortcutRegistration';
13-
import { useAccountsStore, useFiltersStore, useSettingsStore } from '../stores';
15+
} from '../stores';
1416

1517
import { setTrayIconColorAndTitle } from '../utils/system/tray';
1618

‎src/renderer/components/settings/SystemSettings.tsx‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ import { Banner, Button, ButtonGroup, IconButton, Stack, Text } from '@primer/re
55

66
import { APPLICATION } from '../../../shared/constants';
77

8-
import { useShortcutRegistrationStore } from '../../hooks/useShortcutRegistration';
9-
import { DEFAULT_SETTINGS_STATE, useSettingsStore } from '../../stores';
8+
import {
9+
DEFAULT_SETTINGS_STATE,
10+
useSettingsStore,
11+
useShortcutRegistrationStore,
12+
} from '../../stores';
1013

1114
import { Checkbox } from '../fields/Checkbox';
1215
import { RadioGroup } from '../fields/RadioGroup';

‎src/renderer/hooks/useShortcutRegistration.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { renderHook, waitFor } from '@testing-library/react';
22

3-
import { DEFAULT_SETTINGS_STATE, useSettingsStore } from '../stores';
3+
import { DEFAULT_SETTINGS_STATE, useSettingsStore, useShortcutRegistrationStore } from '../stores';
44

55
import type { KeyboardAcceleratorShortcut } from '../types';
66

7-
import { useShortcutRegistration, useShortcutRegistrationStore } from './useShortcutRegistration';
7+
import { useShortcutRegistration } from './useShortcutRegistration';
88

99
describe('renderer/hooks/useShortcutRegistration.ts', () => {
1010
it('registers the configured shortcut and records it as last applied', async () => {

‎src/renderer/hooks/useShortcutRegistration.ts‎

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,9 @@
11
import { useEffect } from 'react';
22

3-
import { create } from 'zustand';
4-
5-
import { DEFAULT_SETTINGS_STATE, useSettingsStore } from '../stores';
6-
7-
import type { KeyboardAcceleratorShortcut } from '../types';
3+
import { useSettingsStore, useShortcutRegistrationStore } from '../stores';
84

95
import { applyKeyboardShortcut } from '../utils/system/comms';
106

11-
interface ShortcutRegistrationStore {
12-
/**
13-
* User-facing error when the configured global shortcut could not be
14-
* registered (e.g. already in use by another application).
15-
*/
16-
shortcutRegistrationError: string | null;
17-
18-
/**
19-
* The last accelerator that registered successfully; used to revert the
20-
* setting when a newly chosen accelerator fails to register.
21-
*/
22-
lastAppliedShortcut: KeyboardAcceleratorShortcut;
23-
24-
setShortcutRegistrationError: (error: string | null) => void;
25-
setLastAppliedShortcut: (accelerator: KeyboardAcceleratorShortcut) => void;
26-
clearShortcutRegistrationError: () => void;
27-
reset: () => void;
28-
}
29-
30-
/**
31-
* Transient (non-persisted) state for global keyboard shortcut registration.
32-
*/
33-
export const useShortcutRegistrationStore = create<ShortcutRegistrationStore>()((set) => ({
34-
shortcutRegistrationError: null,
35-
lastAppliedShortcut: DEFAULT_SETTINGS_STATE.openGitifyShortcut,
36-
37-
setShortcutRegistrationError: (error) => set({ shortcutRegistrationError: error }),
38-
setLastAppliedShortcut: (accelerator) => set({ lastAppliedShortcut: accelerator }),
39-
clearShortcutRegistrationError: () => set({ shortcutRegistrationError: null }),
40-
reset: () =>
41-
set({
42-
shortcutRegistrationError: null,
43-
lastAppliedShortcut: DEFAULT_SETTINGS_STATE.openGitifyShortcut,
44-
}),
45-
}));
46-
477
/**
488
* Registers the global open/close shortcut whenever the setting changes,
499
* reverting to the last working accelerator when registration fails.

‎src/renderer/stores/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ export {
88
getNotificationFailureKey,
99
} from './useNotificationActionFailuresStore';
1010
export { default as useSettingsStore } from './useSettingsStore';
11+
export { default as useShortcutRegistrationStore } from './useShortcutRegistrationStore';

‎src/renderer/stores/types.ts‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {
55
Forge,
66
GitifyError,
77
Hostname,
8+
KeyboardAcceleratorShortcut,
89
ReasonFilterValue,
910
ReviewRequestTypeFilterValue,
1011
SearchToken,
@@ -273,3 +274,29 @@ export interface NotificationActionFailuresActions {
273274
*/
274275
export type NotificationActionFailuresStore = NotificationActionFailuresState &
275276
NotificationActionFailuresActions;
277+
278+
// ============================================================================
279+
// Shortcut Registration Store Types
280+
// ============================================================================
281+
282+
/**
283+
* Transient (non-persisted) state for global keyboard shortcut registration.
284+
*/
285+
export interface ShortcutRegistrationStore {
286+
/**
287+
* User-facing error when the configured global shortcut could not be
288+
* registered (e.g. already in use by another application).
289+
*/
290+
shortcutRegistrationError: string | null;
291+
292+
/**
293+
* The last accelerator that registered successfully; used to revert the
294+
* setting when a newly chosen accelerator fails to register.
295+
*/
296+
lastAppliedShortcut: KeyboardAcceleratorShortcut;
297+
298+
setShortcutRegistrationError: (error: string | null) => void;
299+
setLastAppliedShortcut: (accelerator: KeyboardAcceleratorShortcut) => void;
300+
clearShortcutRegistrationError: () => void;
301+
reset: () => void;
302+
}

0 commit comments

Comments
 (0)