fix(frontend): no-device default, program role, presets, URL order, and Add-Line UX#618
Merged
fix(frontend): no-device default, program role, presets, URL order, and Add-Line UX#618
Conversation
…on, and auto-join race - Device default bug: first-time users (cleared localStorage) received "no-device" as audioinput, causing 500 errors on join. Add a useEffect in user-settings-form.tsx that resets the field to the real default device once enumeration completes; add a defense-in-depth guard in use-submit-form.tsx that falls back to userSettings.audioinput or "default" when the resolved value is falsy or "no-device". - Program feed UX: remove the role selector (Listener / Audio feed checkboxes) from the join form entirely. ProgramLineJoinCard is now the sole place for role selection, eliminating duplicate state and the associated correctness hazard for first-time users. - Program line auto-join bug: two fixes applied together: (1) calls-page.tsx used pendingProgramLines state in the auto-join effect, which could be stale at the time the effect ran — replaced with a ref (pendingProgramKeysRef) updated synchronously before setPendingProgramLines so the effect always reads the latest value. (2) use-submit-form.tsx unconditionally called initiateProductionCall even for program output lines — added a !selectedLine.programOutputLine guard so program lines are not auto-joined before the user picks a role. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…gn WebRTC modal - Add TVIcon next to program output lines in presets-list and manage-presets-list with isProgramOutput purple background - Refactor settings-modal.tsx to use the base Modal component, removing duplicated modal primitives from settings-modal-components.ts - Rewrite generate-whip-whep-url-modal.tsx: single username field, WHIP/WHEP copy buttons, title changed to "WebRTC" Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Add `presetOrder` field to `CallData` and a `sortedEntries()` helper in `use-call-list.ts` so CALLS_STATE_UPDATE and CALL_UPDATE messages always list calls in preset position order rather than insertion order. Build `callIndexMap` in `calls-page.tsx` using the same preset-order sort (keyed by productionId:lineId via `presetOrderMap`) so incoming companion actions (mute, volume, etc.) resolve to the correct call. Remove the duplicate `callIndexMap` effect from `connect-to-ws-button.tsx` that was overwriting the sorted map with insertion order on every state change. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
- Update browser URL when user connects/disconnects companion manually - Remove stale useMemo([], []) for companionUrl in use-calls-navigation so the URL-rebuild effect always uses the current companion param instead of the frozen mount-time value (which was stripping the param on every calls change) - Pass activeCompanionUrl (manual or from URL param) to ShareUrlModal so the "Include companion URL" checkbox works regardless of how the companion was connected Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…lines Lift isProgramUser state to JoinProduction so the role checkbox persists across re-renders. Add Listener / Audio feed checkboxes when a program output line is selected in the join form. Remove the old guard that blocked initiateProductionCall for program output lines so the role selection drives the behaviour instead. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Add optional :l (listener) and :p (audio-feed) role suffix to the lines URL param (e.g. ?lines=1:3:l,2:7:p). When a role is present the program line is auto-joined immediately without showing ProgramLineJoinCard. Lines without a role suffix are unaffected (backwards compatible). - call-url.ts: add role to CallRef; encode/decode third URL segment - api.ts: add isProgramUser to TPresetCall - calls-page.tsx: skip ProgramLineJoinCard for refs with role; auto-join with correct lineUsedForProgramOutput/isProgramUser values - save-preset-modal.tsx: pass isProgramUser per call when saving - presets-list.tsx: map preset calls to CallRef with role encoding on join and share so loaded presets auto-join with the correct role Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…taleness Pre-fetch production and production list in CallsPage so the "Add Line" form renders immediately without waiting for data to load. Default the line dropdown to the first unjoined line for the selected production. Fix useCallsNavigation to derive call order from the live URL instead of the frozen pendingCallRefs snapshot, preventing stale-order flashes when calls are added or removed. Guard attachInputAudioToPeerConnection and the RTC setup effect against closed peer connections. Propagate isProgramUser through TPresetCall in presets-list, manage-presets-list, create-production-page, use-local-presets, and use-presets so that the role (Listener / Audio feed) is preserved when editing presets. Add an inline role selector to ManagePresetCard for program output lines. Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
…connect timing - useCallsNavigation now reads companion param from window.location.search (live URL) instead of the stale React searchParams snapshot, preventing the companion param from being silently dropped when a calls-state effect fires immediately after handleCompanionUrlChange writes the new URL - handleCompanionUrlChange uses currentCallRefs (not pendingCallRefs) so the URL it writes is consistent with the already-joined calls - ConnectToWSButton stores the auto-connect URL in connectingUrlRef before the timer fires, fixing a race where the ref was unset during the delay - Fix TypeScript error in companion-preservation test: use unknown[] + cast instead of tuple destructuring on mock.calls (any[][]) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
"no-device"as audio input ID causing 500 errors. AuseEffectresets the field once device enumeration completes;use-submit-form.tsxguards against falsy/"no-device"values.isProgramUserstate lifted toJoinProduction.?companion=in the address bar; disconnecting removes it. Fixed staleuseMemo([], [])inuse-calls-navigationthat was stripping the param on everycallschange. Share modal receives the active companion URL in both URL-param and manual-connect cases.useCallsNavigationnow reads the companion param fromwindow.location.search(live URL) rather than the stale ReactsearchParamssnapshot, preventing the param from being dropped when a calls-state effect fires immediately afterhandleCompanionUrlChangewrites the new URL.handleCompanionUrlChangealso switched tocurrentCallRefs(notpendingCallRefs) for a consistent URL write.ConnectToWSButtonstores the auto-connect URL inconnectingUrlRefbefore the timer fires, fixing a race where the ref was unset during the delay.:l(listener) or:p(audio feed) in the?lines=URL param. When a role is present the line is auto-joined immediately — noProgramLineJoinCardshown. Lines without a role suffix are unaffected (fully backwards compatible). Pairs with backend PR feat(presets): add isProgramUser field to PresetCall schema intercom-manager#213 which addsisProgramUserto thePresetCallschema.ManagePresetCard, both for existing calls and when adding a new call.TPresetCalltype exported fromapi.tsand used consistently acrossuse-presets,use-local-presets,create-production-page, andmanage-presets-list.CallsPagepre-fetches the selected production and full production list eagerly, passing them as props throughJoinProduction→UserSettingsForm. The line dropdown appears instantly without a loading state.UserSettingsFormskips already-joined lines for the selected production and defaults to the first one the user has not yet joined.useCallsNavigationnow reads call order from the livewindow.location.searchinstead of the frozenpendingCallRefssnapshot, preventing stale-order flashes when calls are added or removed mid-session.production-lines.tsxsorts rendered cards by this samecallOrderMap.attachInputAudioToPeerConnectionand the RTC setup effect both bail early ifsignalingState === "closed", preventing errors when the connection is torn down during re-render.Test plan
npm test)npm run typecheck)npm run lint)"no-device"?companion=host:portappears and persists in address bar; disconnect removes it?companion=is still present in the URL after the calls-state effect fires:l/:psuffix → recipient auto-joins with correct role🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.6 [email protected]