diff --git a/frontend/src/ts/auth.tsx b/frontend/src/ts/auth.tsx index c45eb24210b2..9baf70b90c2b 100644 --- a/frontend/src/ts/auth.tsx +++ b/frontend/src/ts/auth.tsx @@ -37,6 +37,7 @@ import { } from "./firebase"; import { createSignalWithSetters } from "./hooks/createSignalWithSetters"; import { createEffectOn } from "./hooks/effects"; +import { lastAuthenticationState } from "./legacy-states/last-authentication"; import * as Sentry from "./sentry"; import { getUserId, isAuthenticated, setUserId } from "./states/core"; import { hideLoaderBar, showLoaderBar } from "./states/loader-bar"; @@ -229,6 +230,15 @@ export async function onAuthStateChanged( } else { setUserId(null); DB.setSnapshot(undefined); + + const lastState = lastAuthenticationState.get(); + if (lastState.isLoggedIn && Date.now() - lastState.timestamp > 5_000) { + showNoticeNotification("You got logged out."); + lastAuthenticationState.set({ + isLoggedIn: false, + timestamp: Date.now(), + }); + } } } diff --git a/frontend/src/ts/firebase.ts b/frontend/src/ts/firebase.ts index 55462c8bc268..bfda45a5db86 100644 --- a/frontend/src/ts/firebase.ts +++ b/frontend/src/ts/firebase.ts @@ -34,6 +34,7 @@ import { tryCatch } from "@monkeytype/util/trycatch"; import { googleSignUpEvent } from "./events/google-sign-up"; import { addBanner } from "./states/banners"; import { setUserId, setUserVerified } from "./states/core"; +import { lastAuthenticationState } from "./legacy-states/last-authentication"; let app: FirebaseApp | undefined; let Auth: AuthType | undefined; @@ -110,6 +111,10 @@ export function isAuthAvailable(): boolean { export async function signOut(): Promise { console.log("auth signout"); await Auth?.signOut(); + lastAuthenticationState.set({ + isLoggedIn: false, + timestamp: Date.now(), + }); } export async function signInWithEmailAndPassword( @@ -130,7 +135,6 @@ export async function signInWithEmailAndPassword( "Failed to sign in with email and password", ); } - return result; } @@ -146,6 +150,10 @@ export function setUserState( } else { setUserId(options.uid); setUserVerified(options.emailVerified); + lastAuthenticationState.set({ + isLoggedIn: true, + timestamp: Date.now(), + }); } } diff --git a/frontend/src/ts/legacy-states/last-authentication.ts b/frontend/src/ts/legacy-states/last-authentication.ts new file mode 100644 index 000000000000..63f18f2241ba --- /dev/null +++ b/frontend/src/ts/legacy-states/last-authentication.ts @@ -0,0 +1,16 @@ +import { z } from "zod"; +import { LocalStorageWithSchema } from "../utils/local-storage-with-schema"; + +const LastAuthenticationStateSchema = z.object({ + isLoggedIn: z.boolean(), + timestamp: z.number().safe().nonnegative(), +}); +export type LastAuthenticationState = z.infer< + typeof LastAuthenticationStateSchema +>; + +export const lastAuthenticationState = new LocalStorageWithSchema({ + key: "lastAuthenticationState", + schema: LastAuthenticationStateSchema, + fallback: { isLoggedIn: false, timestamp: Date.now() }, +});