Files
hspguard/web/src/store/auth.ts

158 lines
3.6 KiB
TypeScript

import {
deleteAccount,
getAllAccounts,
updateAccountInfo,
type LocalAccount,
} from "@/repository/account";
import type { UserProfile } from "@/types";
import { create } from "zustand";
import { useDbStore } from "./db";
import { fetchProfileApi } from "@/api/profile";
export interface IAuthState {
profile: UserProfile | null;
authenticating: boolean;
activeAccount: LocalAccount | null;
loadingAccounts: boolean;
accounts: LocalAccount[];
signInRequired: boolean;
hasAuthenticated: boolean;
hasLoadedAccounts: boolean;
loadAccounts: () => Promise<void>;
updateActiveAccount: (account: LocalAccount) => Promise<void>;
deleteActiveAccount: () => Promise<void>;
authenticate: () => Promise<void>;
requireSignIn: () => void;
signOut: () => void;
}
const getActiveAccountId = (): string | null => {
const accountId = localStorage.getItem("guard-selected");
return accountId;
};
const saveActiveAccountId = (accountId: string): void => {
localStorage.setItem("guard-selected", accountId);
};
const resetActiveAccount = (): void => {
localStorage.removeItem("guard-selected");
};
// TODO: maybe add deleteActiveAccount
export const useAuth = create<IAuthState>((set, get) => ({
profile: null,
authenticating: false,
activeAccount: null,
accounts: [],
loadingAccounts: false,
signInRequired: false,
hasAuthenticated: false,
hasLoadedAccounts: false,
updateActiveAccount: async (account) => {
set({ activeAccount: account });
saveActiveAccountId(account.accountId);
set({ signInRequired: false });
},
loadAccounts: async () => {
set({ loadingAccounts: true });
const db = useDbStore.getState().db;
if (!db) return;
const accounts = await getAllAccounts(db);
console.log("loaded accounts:", accounts);
if (!accounts || accounts.length === 0) {
set({ signInRequired: true });
}
const active = getActiveAccountId();
if (!active) {
set({ signInRequired: true });
} else {
const account = accounts.find((acc) => acc.accountId === active);
if (!account) {
resetActiveAccount();
set({ signInRequired: true });
} else {
set({ activeAccount: account });
}
}
set({
accounts,
loadingAccounts: false,
hasLoadedAccounts: true,
});
},
deleteActiveAccount: async () => {
resetActiveAccount();
set({ activeAccount: null });
get().loadAccounts();
},
authenticate: async () => {
const { authenticating } = get();
if (authenticating) return;
set({ authenticating: true });
try {
const response = await fetchProfileApi();
console.log("authenticate response:", response);
try {
// update local account information
const db = useDbStore.getState().db;
if (db) {
await updateAccountInfo(db, {
accountId: response.id,
label: response.full_name,
...(response.profile_picture
? { profilePicture: response.profile_picture }
: {}),
});
}
} finally {
set({ profile: response });
}
} catch (err) {
// TODO: set error
console.log(err);
} finally {
set({ authenticating: false, hasAuthenticated: true });
}
},
requireSignIn: () => set({ signInRequired: true }),
signOut: async () => {
resetActiveAccount();
const db = useDbStore.getState().db;
const activeAccount = get().activeAccount;
if (db && activeAccount) {
await deleteAccount(db, activeAccount.accountId);
}
await get().loadAccounts();
set({ activeAccount: null, signInRequired: true });
},
}));