diff --git a/src/components/OrbitJoinModal.tsx b/src/components/OrbitJoinModal.tsx index b0aa08bf..eacb3f64 100644 --- a/src/components/OrbitJoinModal.tsx +++ b/src/components/OrbitJoinModal.tsx @@ -9,6 +9,7 @@ import { readOrbitState, joinOrbitSession, } from '../utils/orbit'; +import { switchActiveServer } from '../utils/switchActiveServer'; import { showToast } from '../utils/toast'; interface Props { @@ -44,13 +45,25 @@ export default function OrbitJoinModal({ onClose }: Props) { const active = useAuthStore.getState().getActiveServer(); const activeUrl = (active?.url ?? '').replace(/\/+$/, ''); const wantUrl = parsed.serverBase.replace(/\/+$/, ''); - if (activeUrl !== wantUrl) { - setError(t('orbit.toastSwitchServer', { url: wantUrl })); - return; - } setBusy(true); 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); if (!playlistId) { setError(t('orbit.joinErrNotFound')); return; } const state = await readOrbitState(playlistId); diff --git a/src/components/PasteClipboardHandler.tsx b/src/components/PasteClipboardHandler.tsx index 213241fd..c580f2ff 100644 --- a/src/components/PasteClipboardHandler.tsx +++ b/src/components/PasteClipboardHandler.tsx @@ -13,6 +13,7 @@ import { readOrbitState, OrbitJoinError, } from '../utils/orbit'; +import { switchActiveServer } from '../utils/switchActiveServer'; import ConfirmModal from './ConfirmModal'; const ORBIT_JOIN_ERROR_KEYS: Record = { @@ -81,21 +82,35 @@ export default function PasteClipboardHandler() { e.preventDefault(); e.stopPropagation(); 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; - - // 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; + (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); if (!playlistId) { handleJoinError('not-found'); return; } const state = await readOrbitState(playlistId); diff --git a/src/locales/de.ts b/src/locales/de.ts index 21253942..58b855f3 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -1546,6 +1546,8 @@ export const deTranslation = { toastJoined: 'Session beigetreten', toastLoginFirst: 'Erst anmelden, um einer Session beizutreten', 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', joinErrNotFound: 'Session nicht gefunden', joinErrEnded: 'Session wurde beendet', diff --git a/src/locales/en.ts b/src/locales/en.ts index 529318de..54fe3da5 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -1549,6 +1549,8 @@ export const enTranslation = { toastJoined: 'Joined session', toastLoginFirst: 'Log in before joining a session', 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", joinErrNotFound: 'Session not found', joinErrEnded: 'Session has ended',