diff options
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/group-page.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/group-page.js | 25 |
1 files changed, 24 insertions, 1 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/group-page.js b/packages/meshbay-hub/src/meshbay_hub/static/group-page.js index 6b9c82a..7d13260 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/group-page.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/group-page.js @@ -96,6 +96,30 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs, // every registered app when a node predates the setting (or hasn't answered // yet), so nothing disappears for an existing group. const [enabledApps, setEnabledApps] = useState(null); + // Declared here rather than beside the render, because the effect below + // depends on it and a `const` further down would be in its temporal dead + // zone — the hook-ordering trap this codebase has already paid for. + const apps = visibleApps(enabledApps); + + // The landing tab is chosen before the node has said which applications this + // group has, and a preference is a preference — not a promise that the app + // exists here. Two ways to land on a tab that renders nothing at all, with no + // tab shown active and no way to tell what went wrong: the group has Chat + // disabled while 'chat' is the default, or the reader's preferred app is one + // this group does not run. The first app the group *does* offer is the + // answer to both. + // + // Also covers an operator disabling the app someone is currently looking at: + // `enabledApps` changes live over `apps_enabled`, and being moved to a + // working tab beats being left staring at an empty panel. + // + // Settings is exempt: it is not an application, it is never in `apps`, and + // the create-group wizard lands on it deliberately. + useEffect(() => { + if (tab === 'settings') return; + if (!apps.length || apps.some(a => a.key === tab)) return; + setTab(apps[0].key); + }, [enabledApps, tab]); // Reconcile interval / debounce currently in effect on the node — shown // to the operator in Settings, not enforced from here (indexer.py owns // that). Null until the handshake ack arrives. @@ -532,7 +556,6 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs, setPreviewEntry(entry); }, [entries, onPlayQueue, onStopMusic]); - const apps = visibleApps(enabledApps); const commonProps = { groupId, transportRef, gekRef, status, username, entries, nodeDirs, nodeRoots, setEntries, setNodeDirs, setNodeRoots, applyIndex, |