diff --git a/src/assets/locales/en.json b/src/assets/locales/en.json index b762fe3a..122c8975 100644 --- a/src/assets/locales/en.json +++ b/src/assets/locales/en.json @@ -992,9 +992,14 @@ "loadingUserError": { "logout": "Logout", "reset": "Reset custom server", + "disconnect": "Disconnect from backend", "text": "Failed to load your profile", "reload": "Reload", - "textWithReset": "Failed to load your profile from your custom server, want to reset back to the default server?" + "textWithReset": "Failed to load your profile from your custom server, want to reset back to the default server?", + "disconnectTitle": "Disconnect from backend?", + "disconnectMessage": "Disconnect from the account server, maintaining the most recent local data. Changes and watched content will not sync until you're signed in again.", + "disconnectConfirm": "Confirm", + "disconectCancel": "Cancel" }, "migration": { "failed": "Failed to migrate your data. 😿", diff --git a/src/hooks/auth/useAuth.ts b/src/hooks/auth/useAuth.ts index 77c2fb86..32150c38 100644 --- a/src/hooks/auth/useAuth.ts +++ b/src/hooks/auth/useAuth.ts @@ -102,6 +102,21 @@ export function useAuth() { await userDataLogout(); }, [userDataLogout, backendUrl, currentAccount]); + const disconnectFromBackend = useCallback(async () => { + if (!currentAccount || !backendUrl) return; + try { + await removeSession( + backendUrl, + currentAccount.token, + currentAccount.sessionId, + ); + } catch { + // we dont care about failing to delete session + } + // Only remove the account, keep all local data + useAuthStore.getState().removeAccount(); + }, [backendUrl, currentAccount]); + const register = useCallback( async (registerData: RegistrationData) => { if (!backendUrl) return; @@ -215,6 +230,7 @@ export function useAuth() { profile, login, logout, + disconnectFromBackend, register, restore, importData, diff --git a/src/index.tsx b/src/index.tsx index e524488a..26bdf087 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -4,7 +4,7 @@ import "./stores/__old/imports"; import "@/setup/ga"; import "@/assets/css/index.css"; -import { StrictMode, Suspense, useCallback } from "react"; +import { StrictMode, Suspense, useCallback, useState } from "react"; import type { ReactNode } from "react"; import { createRoot } from "react-dom/client"; import { HelmetProvider } from "react-helmet-async"; @@ -62,15 +62,19 @@ function ErrorScreen(props: { showResetButton?: boolean; showLogoutButton?: boolean; showReloadButton?: boolean; + showDisconnectButton?: boolean; }) { const { t } = useTranslation(); - const { logout } = useAuth(); + const { logout, disconnectFromBackend } = useAuth(); const setBackendUrl = useAuthStore((s) => s.setBackendUrl); + const [showDisconnectConfirm, setShowDisconnectConfirm] = useState(false); + const resetBackend = useCallback(() => { setBackendUrl(null); // eslint-disable-next-line no-restricted-globals location.reload(); }, [setBackendUrl]); + const logoutFromBackend = useCallback(() => { logout().then(() => { // eslint-disable-next-line no-restricted-globals @@ -78,6 +82,13 @@ function ErrorScreen(props: { }); }, [logout]); + const handleDisconnectConfirm = useCallback(() => { + disconnectFromBackend().then(() => { + // eslint-disable-next-line no-restricted-globals + location.reload(); + }); + }, [disconnectFromBackend]); + return ( ) : null} + {props.showDisconnectButton ? ( + + setShowDisconnectConfirm(true)} + > + {t("screens.loadingUserError.disconnect")} + + + ) : null} {props.showReloadButton ? ( window.location.reload()}> @@ -106,6 +127,31 @@ function ErrorScreen(props: { ) : null} + + {/* Disconnect Confirmation Modal */} + {showDisconnectConfirm && ( + + + + {t("screens.loadingUserError.disconnectTitle")} + + + {t("screens.loadingUserError.disconnectMessage")} + + + setShowDisconnectConfirm(false)} + > + {t("screens.loadingUserError.disconectCancel")} + + + {t("screens.loadingUserError.disconnectConfirm")} + + + + + )} ); } @@ -115,6 +161,7 @@ function AuthWrapper() { const backendUrl = conf().BACKEND_URL; const userBackendUrl = useBackendUrl(); const { t } = useTranslation(); + const isLoggedIn = !!useAuthStore((s) => s.account); const isCustomUrl = backendUrl !== userBackendUrl; @@ -124,6 +171,7 @@ function AuthWrapper() { {t(
+ {t("screens.loadingUserError.disconnectMessage")} +