Add an archive hotkey to the support inbox
React · React · advanced · modification
Adds keyboard archiving to the support inbox. A new reusable useHotkey hook binds a window keydown listener for the lifetime of the component, with the usual guards (modifier keys, editable elements) and cleanup on unmount. The inbox wires it up with one line: useHotkey('e', archiveSelected), reusing the exact same archive routine as the toolbar button. Tested by selecting a message and pressing e — the row archives and selection moves on, same as clicking Archive.
The support console of a helpdesk app. Agents triage dozens of messages per session, selecting rows by mouse and archiving with the keyboard. onArchive posts the archive to the API; the parent owns that call.
Requirements
- The support inbox lists messages; clicking a row selects it, and the toolbar Archive button archives the selected message (existing behavior, unchanged).
- This PR adds a keyboard shortcut through a new reusable `useHotkey(key, handler)` hook: pressing `e` archives whichever message is selected at the moment of the keypress — exactly what the toolbar button would do at that moment.
- Archiving removes the row from the list, moves the selection to the next row (the previous row if the last one was archived, cleared if the list is now empty), and calls `onArchive(id)` exactly once per archived message.
- `useHotkey` binds a window keydown listener while the component is mounted and unbinds it on unmount; it must ignore chorded presses (Ctrl, Meta, or Alt held — a shifted letter already produces a different `event.key`) and presses while focus is in an editable element (input, textarea, select, or contenteditable content). The handler it invokes must always be the latest handler passed from the component's most recent render.
Files touched
- src/hooks/useHotkey.js
- src/components/InboxList.jsx
--- src/hooks/useHotkey.js
+import { useEffect } from 'react';
+
+/**
+ * Bind a single-key hotkey for the lifetime of the component.
+ * Ignores chorded presses or presses while focus is in an editable
+ * element, and unbinds on unmount.
+ */
+export function useHotkey(key, handler) {
+ useEffect(() => {
+ function onKeyDown(event) {
+ if (event.key !== key || event.metaKey || event.ctrlKey || event.altKey) {
+ return;
+ }
+ const target = event.target;
+ if (target instanceof Element && (target.closest('input, textarea, select') || target.isContentEditable)) {
+ return;
+ }
+ event.preventDefault();
+ handler();
+ }
+ window.addEventListener('keydown', onKeyDown);
+ return () => window.removeEventListener('keydown', onKeyDown);
+ }, [key]);
+}
+
--- src/components/InboxList.jsx
import { useState } from 'react';
+import { useHotkey } from '../hooks/useHotkey';