import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { CommandLineIcon, ArrowPathIcon } from '@heroicons/react/24/outline'; import { KeyboardShortcut, KeyboardShortcutsConfig, ShortcutAction, SHORTCUT_LABELS, formatShortcutDisplay, validateShortcuts, getDefaultShortcuts, getDefaultConfig, shortcutToString, } from '../../../utils/keyboardShortcutsService'; interface KeyboardShortcutsTabProps { isActive: boolean; config: KeyboardShortcutsConfig | null | undefined; onChange: (config: KeyboardShortcutsConfig) => void; } const SHORTCUT_ACTIONS: ShortcutAction[] = [ 'inbox', 'task', 'project', 'note', 'area', 'tag', ]; const KeyboardShortcutsTab: React.FC = ({ isActive, config, onChange, }) => { const { t } = useTranslation(); const [editingAction, setEditingAction] = useState(null); const [isRecording, setIsRecording] = useState(false); const [tempShortcut, setTempShortcut] = useState(null); // Ensure we always have a valid config const activeConfig = config || getDefaultConfig(); const shortcuts = activeConfig.shortcuts || getDefaultShortcuts(); // Validation const validation = validateShortcuts(shortcuts); const handleEditClick = (action: ShortcutAction) => { const current = shortcuts.find(s => s.action === action); setEditingAction(action); setTempShortcut(current || null); setIsRecording(false); }; const handleCancelEdit = () => { setEditingAction(null); setTempShortcut(null); setIsRecording(false); }; const handleSaveEdit = () => { if (!editingAction || !tempShortcut) return; const newShortcuts = shortcuts.map(s => s.action === editingAction ? tempShortcut : s ); onChange({ ...activeConfig, shortcuts: newShortcuts, }); setEditingAction(null); setTempShortcut(null); setIsRecording(false); }; const handleStartRecording = () => { setIsRecording(true); }; // Handle keyboard recording useEffect(() => { if (!isRecording || !editingAction) return; const handleKeyDown = (event: KeyboardEvent) => { event.preventDefault(); event.stopPropagation(); // Ignore if only modifier keys are pressed const key = event.key.toLowerCase(); if (['control', 'alt', 'shift', 'meta'].includes(key)) { return; } // Require at least one modifier if (!event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) { return; } const newShortcut: KeyboardShortcut = { action: editingAction, key: key.length === 1 ? key : key, modifiers: { ctrl: event.ctrlKey, alt: event.altKey, shift: event.shiftKey, meta: event.metaKey, }, }; setTempShortcut(newShortcut); setIsRecording(false); }; document.addEventListener('keydown', handleKeyDown, true); return () => { document.removeEventListener('keydown', handleKeyDown, true); }; }, [isRecording, editingAction]); const handleResetToDefaults = () => { onChange(getDefaultConfig()); }; const handleToggleEnabled = () => { onChange({ ...activeConfig, enabled: !activeConfig.enabled, }); }; const getShortcutForAction = (action: ShortcutAction): KeyboardShortcut | undefined => { return shortcuts.find(s => s.action === action); }; // Check if a shortcut would create a duplicate const wouldCreateDuplicate = (newShortcut: KeyboardShortcut): string | null => { const newKey = shortcutToString(newShortcut); for (const existing of shortcuts) { if (existing.action !== newShortcut.action && shortcutToString(existing) === newKey) { return existing.action; } } return null; }; if (!isActive) return null; return (

{t('profile.keyboardShortcuts', 'Keyboard Shortcuts')}

{/* Enable/Disable Toggle */}

{t( 'profile.shortcuts.enableDescription', 'Turn keyboard shortcuts on or off globally.' )}

{/* Validation Warnings */} {!validation.valid && (

{t('profile.shortcuts.duplicateWarning', 'Duplicate shortcuts detected:')}

    {validation.duplicates.map((dup, idx) => (
  • {dup}
  • ))}
)} {/* Shortcuts List */}
{SHORTCUT_ACTIONS.map((action) => { const shortcut = getShortcutForAction(action); const isEditing = editingAction === action; const label = SHORTCUT_LABELS[action]; return (
{t(label.labelKey, label.defaultLabel)}
{isEditing ? (
{isRecording ? (
{t('profile.shortcuts.pressKeys', 'Press keys...')}
) : tempShortcut ? (
{formatShortcutDisplay(tempShortcut)} {wouldCreateDuplicate(tempShortcut) && ( {t('profile.shortcuts.duplicateWith', 'Conflicts with {{action}}', { action: wouldCreateDuplicate(tempShortcut), })} )}
) : null}
) : (
{shortcut && ( {formatShortcutDisplay(shortcut)} )}
)}
); })}
{/* Reset to Defaults */}
{/* Info Box */}

{t( 'profile.shortcuts.info', 'Keyboard shortcuts help you navigate quickly. Changes are saved when you click "Save Changes" at the bottom of the page. Shortcuts are disabled when typing in text fields.' )}

); }; export default KeyboardShortcutsTab;