From ad4c0d288544bb619d079708bdd549972e4f952f Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Mon, 7 Apr 2025 22:12:26 +0200 Subject: [PATCH] Add accounts list as a provider --- moneymgr_web/src/api/AccountApi.ts | 41 +++++++++++ .../src/hooks/AccountsListProvider.tsx | 68 +++++++++++++++++++ moneymgr_web/src/routes/HomeRoute.tsx | 4 ++ .../src/widgets/BaseAuthenticatedPage.tsx | 63 +++++++++-------- 4 files changed, 146 insertions(+), 30 deletions(-) create mode 100644 moneymgr_web/src/api/AccountApi.ts create mode 100644 moneymgr_web/src/hooks/AccountsListProvider.tsx diff --git a/moneymgr_web/src/api/AccountApi.ts b/moneymgr_web/src/api/AccountApi.ts new file mode 100644 index 0000000..e5501e3 --- /dev/null +++ b/moneymgr_web/src/api/AccountApi.ts @@ -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 { + const array = ( + await APIClient.exec({ + uri: "/accounts", + method: "GET", + }) + ).data; + + return new AccountsList(array); + } +} diff --git a/moneymgr_web/src/hooks/AccountsListProvider.tsx b/moneymgr_web/src/hooks/AccountsListProvider.tsx new file mode 100644 index 0000000..a01d15a --- /dev/null +++ b/moneymgr_web/src/hooks/AccountsListProvider.tsx @@ -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(null); + +export function AccountsListProvider( + p: React.PropsWithChildren +): React.ReactElement { + const [list, setList] = React.useState(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((res) => { + loadPromise.current = () => { + res(); + }; + }); + }; + + return ( + { + if (loadPromise.current != null) { + loadPromise.current(); + loadPromise.current = null; + } + + return ( + + {p.children} + + ); + }} + /> + ); +} + +export function useAccounts(): AccountContext { + return React.use(AccountContextK)!; +} diff --git a/moneymgr_web/src/routes/HomeRoute.tsx b/moneymgr_web/src/routes/HomeRoute.tsx index 6207f28..f80d791 100644 --- a/moneymgr_web/src/routes/HomeRoute.tsx +++ b/moneymgr_web/src/routes/HomeRoute.tsx @@ -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; } diff --git a/moneymgr_web/src/widgets/BaseAuthenticatedPage.tsx b/moneymgr_web/src/widgets/BaseAuthenticatedPage.tsx index 9505fbd..c03564c 100644 --- a/moneymgr_web/src/widgets/BaseAuthenticatedPage.tsx +++ b/moneymgr_web/src/widgets/BaseAuthenticatedPage.tsx @@ -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, }} > - - 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], - }} - > - - + + 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], }} > - -
+ + - -
+ +
+ +
+
- + )} />