Add accounts list as a provider
This commit is contained in:
		
							
								
								
									
										41
									
								
								moneymgr_web/src/api/AccountApi.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								moneymgr_web/src/api/AccountApi.ts
									
									
									
									
									
										Normal 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);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								moneymgr_web/src/hooks/AccountsListProvider.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								moneymgr_web/src/hooks/AccountsListProvider.tsx
									
									
									
									
									
										Normal 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)!;
 | 
			
		||||
}
 | 
			
		||||
@@ -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</>;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
      )}
 | 
			
		||||
    />
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user