Add accounts list as a provider

This commit is contained in:
Pierre HUBERT 2025-04-07 22:12:26 +02:00
parent 90bb4db806
commit ad4c0d2885
4 changed files with 146 additions and 30 deletions

View File

@ -0,0 +1,41 @@
import { APIClient } from "./ApiClient";
export interface Account {
id: number;
name: string;
user_id: number;
time_create: number;
time_update: number;
default_account: boolean;
}
export class AccountsList {
list: Account[];
constructor(list: Account[]) {
this.list = list;
}
/**
* Get a single account by its id
*/
get(id: number): Account | null {
return this.list.find((a) => a.id === id) ?? null;
}
}
export class AccountApi {
/**
* Get the current list of accounts of the user
*/
static async GetList(): Promise<AccountsList> {
const array = (
await APIClient.exec({
uri: "/accounts",
method: "GET",
})
).data;
return new AccountsList(array);
}
}

View File

@ -0,0 +1,68 @@
import React from "react";
import { Account, AccountApi, AccountsList } from "../api/AccountApi";
import { AsyncWidget } from "../widgets/AsyncWidget";
interface AccountContext {
list: AccountsList;
reload: () => void;
get(id: number): Account | null;
}
const AccountContextK = React.createContext<AccountContext | null>(null);
export function AccountsListProvider(
p: React.PropsWithChildren
): React.ReactElement {
const [list, setList] = React.useState<AccountsList | null>(null);
const loadKey = React.useRef(1);
const loadPromise = React.useRef<(() => void) | null>(null);
const load = async () => {
setList(await AccountApi.GetList());
};
const onReload = async () => {
loadKey.current += 1;
setList(null);
return new Promise<void>((res) => {
loadPromise.current = () => {
res();
};
});
};
return (
<AsyncWidget
loadKey={loadKey.current}
load={load}
errMsg="Failed to load the list of accounts!"
build={() => {
if (loadPromise.current != null) {
loadPromise.current();
loadPromise.current = null;
}
return (
<AccountContextK
value={{
list: list!,
get(id) {
return list!.get(id);
},
reload: onReload,
}}
>
{p.children}
</AccountContextK>
);
}}
/>
);
}
export function useAccounts(): AccountContext {
return React.use(AccountContextK)!;
}

View File

@ -1,3 +1,7 @@
import { useAccounts } from "../hooks/AccountsListProvider";
export function HomeRoute(): React.ReactElement {
const accounts = useAccounts();
console.log(accounts.list.list);
return <>home authenticated todo</>;
}

View File

@ -3,9 +3,10 @@ import * as React from "react";
import { Outlet, useNavigate } from "react-router-dom";
import { useAuth } from "../App";
import { AuthApi, AuthInfo } from "../api/AuthApi";
import { AccountsListProvider } from "../hooks/AccountsListProvider";
import { AsyncWidget } from "./AsyncWidget";
import { MoneyWebAppBar } from "./MoneyWebAppBar";
import { MoneyNavList } from "./MoneyNavList";
import { MoneyWebAppBar } from "./MoneyWebAppBar";
interface AuthInfoContext {
info: AuthInfo;
@ -46,44 +47,46 @@ export function BaseAuthenticatedPage(): React.ReactElement {
reloadAuthInfo: load,
}}
>
<Box
component="div"
sx={{
minHeight: "100vh",
display: "flex",
flexDirection: "column",
backgroundColor: (theme) =>
theme.palette.mode === "light"
? theme.palette.grey[100]
: theme.palette.grey[900],
color: (theme) =>
theme.palette.mode === "light"
? theme.palette.grey[900]
: theme.palette.grey[100],
}}
>
<MoneyWebAppBar onSignOut={signOut} />
<AccountsListProvider>
<Box
component="div"
sx={{
minHeight: "100vh",
display: "flex",
flex: "2",
flexDirection: "column",
backgroundColor: (theme) =>
theme.palette.mode === "light"
? theme.palette.grey[100]
: theme.palette.grey[900],
color: (theme) =>
theme.palette.mode === "light"
? theme.palette.grey[900]
: theme.palette.grey[100],
}}
>
<MoneyNavList />
<div
style={{
flexGrow: 1,
flexShrink: 0,
flexBasis: 0,
minWidth: 0,
<MoneyWebAppBar onSignOut={signOut} />
<Box
sx={{
display: "flex",
flex: "2",
}}
>
<Outlet />
</div>
<MoneyNavList />
<div
style={{
flexGrow: 1,
flexShrink: 0,
flexBasis: 0,
minWidth: 0,
display: "flex",
}}
>
<Outlet />
</div>
</Box>
</Box>
</Box>
</AccountsListProvider>
</AuthInfoContextK>
)}
/>