chore(orbit): auto-switch to the link's server on paste / join

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Psychotoxical
2026-04-24 18:43:18 +02:00
parent f2e4c5b684
commit 6370b5fa3c
4 changed files with 48 additions and 16 deletions
+17 -4
View File
@@ -9,6 +9,7 @@ import {
readOrbitState, readOrbitState,
joinOrbitSession, joinOrbitSession,
} from '../utils/orbit'; } from '../utils/orbit';
import { switchActiveServer } from '../utils/switchActiveServer';
import { showToast } from '../utils/toast'; import { showToast } from '../utils/toast';
interface Props { interface Props {
@@ -44,13 +45,25 @@ export default function OrbitJoinModal({ onClose }: Props) {
const active = useAuthStore.getState().getActiveServer(); const active = useAuthStore.getState().getActiveServer();
const activeUrl = (active?.url ?? '').replace(/\/+$/, ''); const activeUrl = (active?.url ?? '').replace(/\/+$/, '');
const wantUrl = parsed.serverBase.replace(/\/+$/, ''); const wantUrl = parsed.serverBase.replace(/\/+$/, '');
if (activeUrl !== wantUrl) {
setError(t('orbit.toastSwitchServer', { url: wantUrl }));
return;
}
setBusy(true); setBusy(true);
try { try {
// Auto-switch to the link's server if the user has an account for it.
// switch itself tears down any lingering orbit session.
if (activeUrl !== wantUrl) {
const targetServer = useAuthStore.getState().servers
.find(s => s.url.replace(/\/+$/, '') === wantUrl);
if (!targetServer) {
setError(t('orbit.toastNoAccountForServer', { url: wantUrl }));
return;
}
const switched = await switchActiveServer(targetServer);
if (!switched) {
setError(t('orbit.toastSwitchFailed', { url: wantUrl }));
return;
}
}
const playlistId = await findSessionPlaylistId(parsed.sid); const playlistId = await findSessionPlaylistId(parsed.sid);
if (!playlistId) { setError(t('orbit.joinErrNotFound')); return; } if (!playlistId) { setError(t('orbit.joinErrNotFound')); return; }
const state = await readOrbitState(playlistId); const state = await readOrbitState(playlistId);
+27 -12
View File
@@ -13,6 +13,7 @@ import {
readOrbitState, readOrbitState,
OrbitJoinError, OrbitJoinError,
} from '../utils/orbit'; } from '../utils/orbit';
import { switchActiveServer } from '../utils/switchActiveServer';
import ConfirmModal from './ConfirmModal'; import ConfirmModal from './ConfirmModal';
const ORBIT_JOIN_ERROR_KEYS: Record<string, string> = { const ORBIT_JOIN_ERROR_KEYS: Record<string, string> = {
@@ -81,21 +82,35 @@ export default function PasteClipboardHandler() {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
if (!isLoggedIn) { showToast(t('orbit.toastLoginFirst'), 4000, 'info'); return; } if (!isLoggedIn) { showToast(t('orbit.toastLoginFirst'), 4000, 'info'); return; }
const active = useAuthStore.getState().getActiveServer();
const activeUrl = (active?.url ?? '').replace(/\/+$/, '');
const wantUrl = orbit.serverBase.replace(/\/+$/, '');
if (activeUrl !== wantUrl) {
showToast(t('orbit.toastSwitchServer', { url: wantUrl }), 5000, 'info');
return;
}
if (busy.current) return; if (busy.current) return;
// Preview the session state so the confirm dialog can show the host
// and session name. Failures (session vanished / ended / unreachable)
// surface the same error toasts the join would, without ever showing
// the confirm.
busy.current = true; busy.current = true;
(async () => { (async () => {
const active = useAuthStore.getState().getActiveServer();
const activeUrl = (active?.url ?? '').replace(/\/+$/, '');
const wantUrl = orbit.serverBase.replace(/\/+$/, '');
// Auto-switch to the link's target server if the user has an
// account registered for it. No account → clear error. switch
// itself tears down any lingering orbit session (see
// switchActiveServer) so the join below starts clean.
if (activeUrl !== wantUrl) {
const targetServer = useAuthStore.getState().servers
.find(s => s.url.replace(/\/+$/, '') === wantUrl);
if (!targetServer) {
showToast(t('orbit.toastNoAccountForServer', { url: wantUrl }), 5000, 'warning');
return;
}
const switched = await switchActiveServer(targetServer);
if (!switched) {
showToast(t('orbit.toastSwitchFailed', { url: wantUrl }), 5000, 'error');
return;
}
}
// Preview the session state so the confirm dialog can show the
// host and session name. Failures surface the same error toasts
// the join would, without ever showing the confirm.
const playlistId = await findSessionPlaylistId(orbit.sid); const playlistId = await findSessionPlaylistId(orbit.sid);
if (!playlistId) { handleJoinError('not-found'); return; } if (!playlistId) { handleJoinError('not-found'); return; }
const state = await readOrbitState(playlistId); const state = await readOrbitState(playlistId);
+2
View File
@@ -1546,6 +1546,8 @@ export const deTranslation = {
toastJoined: 'Session beigetreten', toastJoined: 'Session beigetreten',
toastLoginFirst: 'Erst anmelden, um einer Session beizutreten', toastLoginFirst: 'Erst anmelden, um einer Session beizutreten',
toastSwitchServer: 'Wechsle erst zu {{url}} und füge den Link dann erneut ein', toastSwitchServer: 'Wechsle erst zu {{url}} und füge den Link dann erneut ein',
toastNoAccountForServer: 'Du hast keinen Zugang zu {{url}}. Bitte den Host um einen Einladungslink.',
toastSwitchFailed: 'Wechsel zu {{url}} fehlgeschlagen',
toastJoinFail: 'Session konnte nicht beigetreten werden', toastJoinFail: 'Session konnte nicht beigetreten werden',
joinErrNotFound: 'Session nicht gefunden', joinErrNotFound: 'Session nicht gefunden',
joinErrEnded: 'Session wurde beendet', joinErrEnded: 'Session wurde beendet',
+2
View File
@@ -1549,6 +1549,8 @@ export const enTranslation = {
toastJoined: 'Joined session', toastJoined: 'Joined session',
toastLoginFirst: 'Log in before joining a session', toastLoginFirst: 'Log in before joining a session',
toastSwitchServer: 'Switch to {{url}} first, then paste again', toastSwitchServer: 'Switch to {{url}} first, then paste again',
toastNoAccountForServer: "You don't have access to {{url}}. Ask the host for an invite.",
toastSwitchFailed: "Couldn't switch to {{url}}",
toastJoinFail: "Couldn't join session", toastJoinFail: "Couldn't join session",
joinErrNotFound: 'Session not found', joinErrNotFound: 'Session not found',
joinErrEnded: 'Session has ended', joinErrEnded: 'Session has ended',