diff --git a/src/client/components/SettingsModal/Shortcut.tsx b/src/client/components/SettingsModal/Shortcut.tsx index f2245fc3..9016fb47 100644 --- a/src/client/components/SettingsModal/Shortcut.tsx +++ b/src/client/components/SettingsModal/Shortcut.tsx @@ -1,16 +1,157 @@ -import React from 'react' +import React, { useEffect } from 'react' +import { useDispatch } from 'react-redux' +import { v4 as uuid } from 'uuid' +import { RefreshCw } from 'react-feather' + +import { updateShortcut } from '@/slices/settings' +import { ShortcutItem } from '@/types' export interface ShortcutProps { action: string - letter: string + shortcut: string + id: number + originalKey: string + shortcuts: ShortcutItem[] } -export const Shortcut: React.FC = ({ action, letter }) => { +export const Shortcut: React.FC = ({ + action, + shortcut, + id, + originalKey, + shortcuts, +}) => { + const [newShortcut, setNewShortcut] = React.useState('') + const [currentShortcut, setCurrentShortcut] = React.useState(shortcut) + const [editShortcut, setEditShortcut] = React.useState(false) + + // =========================================================================== + // Dispatch + // =========================================================================== + + const dispatch = useDispatch() + + const _updateShortcut = (newShortcut: string) => + dispatch( + updateShortcut({ + action, + key: shortcut, + newShortcut: newShortcut, + id: id, + originalKey: originalKey, + }) + ) + + const _resetShortcut = () => + dispatch( + updateShortcut({ + action, + key: shortcut, + newShortcut: originalKey, + id: id, + originalKey: originalKey, + }) + ) + + // =========================================================================== + // Hooks + // =========================================================================== + + useEffect(() => { + if (newShortcut !== '') { + _updateShortcut(newShortcut) + setCurrentShortcut(newShortcut) + } + if (!editShortcut) { + return document.removeEventListener('keydown', handleKeyDown) + } + + return () => document.removeEventListener('keydown', handleKeyDown) + }, [editShortcut]) + + useEffect(() => { + const shortcutItem = shortcuts.find((item) => item.id === id) + if (shortcutItem) { + setCurrentShortcut(shortcutItem.key) + } + }, [shortcuts]) + + function handleKeyDown(e): void { + e.preventDefault() // Prevent default browser behavior for the shortcut key + + const key = e.key.replace('Control', 'ctrl') + if (key === 'Backspace') { + return setNewShortcut((prevShortcut) => prevShortcut.split('+').slice(0, -1).join('+')) + } + + if (key === 'Enter') { + if (newShortcut === '') { + setEditShortcut(false) + + return setNewShortcut(shortcut) + } + setCurrentShortcut(newShortcut) + setEditShortcut(false) + + return document.removeEventListener('keydown', handleKeyDown) + } + setNewShortcut((prevShortcut) => { + if (prevShortcut.split('+').length < 3) { + return prevShortcut === '' ? key : `${prevShortcut}+${key}` + } + + return prevShortcut + }) + } + return (
{action}
-
- CTRL + ALT + {letter} +
setEditShortcut(!editShortcut)}> + {!editShortcut ? ( +
+ {currentShortcut.split('+').map((key, index) => { + return ( + + {key.toUpperCase()} + {index !== currentShortcut.split('+').length - 1 && + } + + ) + })} +
+ ) : ( +
+ + {}} + value={newShortcut.split('+').join(' + ')} + className="shortcut-edit-input" + onBlur={() => { + if (editShortcut) { + setNewShortcut('') + setCurrentShortcut(shortcut) + setEditShortcut(false) + + return document.removeEventListener('keydown', handleKeyDown) + } + }} + onFocus={() => { + setNewShortcut('') + document.addEventListener('keydown', handleKeyDown) + }} + /> + +
+ )} + +
) diff --git a/src/client/components/Tabs/Tab.tsx b/src/client/components/Tabs/Tab.tsx index 02e081a1..6b2c4bdb 100644 --- a/src/client/components/Tabs/Tab.tsx +++ b/src/client/components/Tabs/Tab.tsx @@ -4,15 +4,22 @@ import { Icon } from 'react-feather' export interface TabProps { label: string activeTab: string + testId?: string onClick: (label: string) => void icon: Icon } -export const Tab: React.FC = ({ activeTab, label, icon: IconCmp, onClick }) => { +export const Tab: React.FC = ({ activeTab, label, testId, icon: IconCmp, onClick }) => { const className = activeTab === label ? 'tab active' : 'tab' return ( -
onClick(label)}> +
onClick(label)} + >
) diff --git a/src/client/components/Tabs/TabPanel.tsx b/src/client/components/Tabs/TabPanel.tsx index f4e0aeb5..3c61f3b6 100644 --- a/src/client/components/Tabs/TabPanel.tsx +++ b/src/client/components/Tabs/TabPanel.tsx @@ -4,6 +4,7 @@ import { Icon } from 'react-feather' export interface TabPanelProps { label: string icon: Icon + testId?: string children: JSX.Element[] | JSX.Element } diff --git a/src/client/components/Tabs/Tabs.tsx b/src/client/components/Tabs/Tabs.tsx index dd1e1fb9..57c1bf53 100644 --- a/src/client/components/Tabs/Tabs.tsx +++ b/src/client/components/Tabs/Tabs.tsx @@ -13,7 +13,7 @@ export const Tabs: React.FC = ({ children }) => {