Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions src/nonview/core/AccountContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import React, {
} from "react";
import { useAuth } from "./AuthContext";
import { APIClient, APIError, defaultBaseURL } from "../api/client";
import { clearAccount } from "../cache/db";
import {
type AccountSession,
type LinkedAccount,
Expand All @@ -17,6 +18,7 @@ import {
getAccounts,
getSession,
getSessions,
removeAccountFromStorage,
removeSession,
saveAccount,
saveSession,
Expand Down Expand Up @@ -186,13 +188,43 @@ export const AccountProvider: React.FC<AccountProviderProps> = ({ children }) =>
[authContext],
);

const removeAccount = useCallback(async (_id: string): Promise<void> => {
throw new Error("removeAccount is not implemented yet — see Parent Issue 5");
}, []);
const removeAccount = useCallback(
async (id: string): Promise<void> => {
const account = getAccount(id);
if (!account) return;

const session = getSession(id);
if (session) {
await authContext.logout(session);
}
removeSession(id);
await clearAccount(account.id);
removeAccountFromStorage(id);

const remaining = getAccounts();
setAccounts(remaining);
setSessions(getSessions());

if (activeAccountId === id) {
if (remaining.length > 0) {
switchAccount(remaining[0].id);
} else {
sessionStorage.removeItem(STORAGE_ACTIVE_ACCOUNT);
setActiveAccountId(null);
}
}
},
[authContext, activeAccountId, switchAccount],
);

const logoutAll = useCallback(async (): Promise<void> => {
throw new Error("logoutAll is not implemented yet — see Parent Issue 5");
}, []);
const allSessions = getSessions();
await Promise.all(allSessions.map((s) => authContext.logout(s)));
allSessions.forEach((s) => removeSession(s.accountId));
setSessions(getSessions());
sessionStorage.removeItem(STORAGE_ACTIVE_ACCOUNT);
setActiveAccountId(null);
}, [authContext]);

const value: AccountContextValue = {
accounts,
Expand Down
10 changes: 1 addition & 9 deletions src/nonview/core/accountStorage.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
// Multi-account storage layer. Replaces the single-profile model (see
// AuthContext.tsx's MailProfile) with a list of linked accounts and a
// separate list of their sessions — accounts and sessions have different
// lifecycles (a 401 invalidates a session, not the linked account).
//
// Nothing consumes this module yet; it's additive groundwork for the
// upcoming AccountContext.

import type { LoginRequest } from "../api/types";

export interface LinkedAccount {
Expand Down Expand Up @@ -109,7 +101,7 @@ export function updateAccount(
return updated;
}

export function removeAccount(id: string): void {
export function removeAccountFromStorage(id: string): void {
writeList(
STORAGE_ACCOUNTS,
getAccounts().filter((a) => a.id !== id),
Expand Down
Loading