Add account type

This commit is contained in:
2025-04-14 23:25:45 +02:00
parent 342af2c443
commit 5a51dee8b0
16 changed files with 176 additions and 6 deletions

View File

@ -11,6 +11,7 @@
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@fontsource/roboto": "^5.2.5",
"@jsonjoy.com/base64": "^1.1.2",
"@mdi/js": "^7.4.47",
"@mdi/react": "^1.6.1",
"@mui/icons-material": "^7.0.1",
@ -1321,6 +1322,22 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@jsonjoy.com/base64": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz",
"integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==",
"license": "Apache-2.0",
"engines": {
"node": ">=10.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/streamich"
},
"peerDependencies": {
"tslib": "2"
}
},
"node_modules/@mdi/js": {
"version": "7.4.47",
"resolved": "https://registry.npmjs.org/@mdi/js/-/js-7.4.47.tgz",
@ -4238,6 +4255,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD",
"peer": true
},
"node_modules/turbo-stream": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",

View File

@ -13,6 +13,7 @@
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@fontsource/roboto": "^5.2.5",
"@jsonjoy.com/base64": "^1.1.2",
"@mdi/js": "^7.4.47",
"@mdi/react": "^1.6.1",
"@mui/icons-material": "^7.0.1",

View File

@ -1,4 +1,5 @@
import { APIClient } from "./ApiClient";
import { ServerApi } from "./ServerApi";
export interface Account {
id: number;
@ -6,6 +7,7 @@ export interface Account {
user_id: number;
time_create: number;
time_update: number;
type: string;
default_account: boolean;
}
@ -66,6 +68,7 @@ export class AccountApi {
method: "POST",
jsonData: {
name,
type: ServerApi.Config.accounts_types[0].code,
},
});
}
@ -79,6 +82,7 @@ export class AccountApi {
method: "PUT",
jsonData: {
name: account.name,
type: account.type,
},
});
}

View File

@ -3,9 +3,16 @@ import { APIClient } from "./ApiClient";
export interface ServerConfig {
auth_disabled: boolean;
oidc_provider_name: string;
accounts_types: AccountType[];
constraints: ServerConstraints;
}
export interface AccountType {
label: string;
code: string;
icon: string;
}
export interface ServerConstraints {
token_name: LenConstraint;
token_ip_net: LenConstraint;

View File

@ -10,6 +10,8 @@ import { MoneyMgrWebRouteContainer } from "../widgets/MoneyMgrWebRouteContainer"
import { TimeWidget } from "../widgets/TimeWidget";
import DeleteIcon from "@mui/icons-material/DeleteOutlined";
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
import { AccountWidget } from "../widgets/AccountWidget";
import { ServerApi } from "../api/ServerApi";
export function AccountsRoute(): React.ReactElement {
const alert = useAlert();
@ -88,6 +90,35 @@ export function AccountsRoute(): React.ReactElement {
const columns: GridColDef<(typeof list)[number]>[] = [
{ field: "id", headerName: "ID", flex: 1 },
{
field: "type",
headerName: "Type",
flex: 2,
editable: true,
type: "singleSelect",
valueOptions: ServerApi.Config.accounts_types.map((v) => {
return { label: v.label, value: v.code };
}),
renderCell(params) {
return (
<span
style={{
display: "flex",
flexDirection: "row",
justifyContent: "start",
alignItems: "center",
}}
>
<AccountWidget account={params.row} />
{
ServerApi.Config.accounts_types.find(
(t) => t.code === params.row.type
)!.label
}
</span>
);
},
},
{ field: "name", headerName: "Name", flex: 6, editable: true },
{
field: "time_create",
@ -159,7 +190,10 @@ export function AccountsRoute(): React.ReactElement {
return setDefaultAccount(updated);
}
if (updated.name !== original.name) {
if (
updated.name !== original.name ||
updated.type !== original.type
) {
return updateAccount(updated);
}

View File

@ -0,0 +1,25 @@
import { Account } from "../api/AccountApi";
import { ServerApi } from "../api/ServerApi";
import { useDarkTheme } from "../hooks/context_providers/DarkThemeProvider";
import { toBase64 } from "@jsonjoy.com/base64";
export function AccountWidget(p: { account: Account }): React.ReactElement {
const darkTheme = useDarkTheme();
return (
<img
style={{
height: "1.5em",
width: "1.5em",
backgroundColor: darkTheme.enabled ? "white" : "black",
mask: `url(\"data:image/svg+xml;base64,${toBase64(
new TextEncoder().encode(
ServerApi.Config.accounts_types.find(
(t) => t.code === p.account.type
)!.icon
)
)}\")`,
}}
/>
);
}

View File

@ -1,4 +1,4 @@
import { mdiAccount, mdiApi, mdiCashMultiple, mdiHome } from "@mdi/js";
import { mdiApi, mdiCashMultiple, mdiHome } from "@mdi/js";
import Icon from "@mdi/react";
import {
Divider,
@ -8,8 +8,10 @@ import {
ListItemText,
Typography,
} from "@mui/material";
import React from "react";
import { useLocation } from "react-router-dom";
import { useAccounts } from "../hooks/AccountsListProvider";
import { AccountWidget } from "./AccountWidget";
import { RouterLink } from "./RouterLink";
export function MoneyNavList(): React.ReactElement {
@ -59,7 +61,7 @@ export function MoneyNavList(): React.ReactElement {
<NavLink
label={a.name}
uri={`/account/${a.id}`}
icon={<Icon path={mdiAccount} size={1} />}
icon={<AccountWidget account={a} />}
/>
))}
</List>