Create and delete tokens from web ui
This commit is contained in:
22
moneymgr_web/src/widgets/CopyTextChip.tsx
Normal file
22
moneymgr_web/src/widgets/CopyTextChip.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { Chip, Tooltip } from "@mui/material";
|
||||
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
|
||||
|
||||
export function CopyTextChip(p: { text: string }): React.ReactElement {
|
||||
const snackbar = useSnackbar();
|
||||
|
||||
const copyTextToClipboard = () => {
|
||||
navigator.clipboard.writeText(p.text);
|
||||
snackbar(`'${p.text}' was copied to clipboard.`);
|
||||
};
|
||||
|
||||
return (
|
||||
<Tooltip title="Copy to clipboard">
|
||||
<Chip
|
||||
label={p.text}
|
||||
variant="outlined"
|
||||
style={{ margin: "5px" }}
|
||||
onClick={copyTextToClipboard}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
34
moneymgr_web/src/widgets/MoneyMgrWebRouteContainer.tsx
Normal file
34
moneymgr_web/src/widgets/MoneyMgrWebRouteContainer.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import { Typography } from "@mui/material";
|
||||
import React, { PropsWithChildren } from "react";
|
||||
|
||||
export function MoneyMgrWebRouteContainer(
|
||||
p: {
|
||||
label: string;
|
||||
actions?: React.ReactElement;
|
||||
} & PropsWithChildren
|
||||
): React.ReactElement {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
margin: "50px",
|
||||
flex: "1",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: "20px",
|
||||
}}
|
||||
>
|
||||
<Typography variant="h4">{p.label}</Typography>
|
||||
{p.actions ?? <></>}
|
||||
</div>
|
||||
|
||||
{p.children}
|
||||
</div>
|
||||
);
|
||||
}
|
75
moneymgr_web/src/widgets/TimeWidget.tsx
Normal file
75
moneymgr_web/src/widgets/TimeWidget.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import { Tooltip } from "@mui/material";
|
||||
import date from "date-and-time";
|
||||
import { time } from "../utils/DateUtils";
|
||||
|
||||
export function formatDate(time: number): string {
|
||||
const t = new Date();
|
||||
t.setTime(1000 * time);
|
||||
return date.format(t, "DD/MM/YYYY HH:mm:ss");
|
||||
}
|
||||
|
||||
export function timeDiff(a: number, b: number): string {
|
||||
let diff = b - a;
|
||||
|
||||
if (diff === 0) return "now";
|
||||
if (diff === 1) return "1 second";
|
||||
|
||||
if (diff < 60) {
|
||||
return `${diff} seconds`;
|
||||
}
|
||||
|
||||
diff = Math.floor(diff / 60);
|
||||
|
||||
if (diff === 1) return "1 minute";
|
||||
if (diff < 60) {
|
||||
return `${diff} minutes`;
|
||||
}
|
||||
|
||||
diff = Math.floor(diff / 60);
|
||||
|
||||
if (diff === 1) return "1 hour";
|
||||
if (diff < 24) {
|
||||
return `${diff} hours`;
|
||||
}
|
||||
|
||||
const diffDays = Math.floor(diff / 24);
|
||||
|
||||
if (diffDays === 1) return "1 day";
|
||||
if (diffDays < 31) {
|
||||
return `${diffDays} days`;
|
||||
}
|
||||
|
||||
diff = Math.floor(diffDays / 31);
|
||||
|
||||
if (diff < 12) {
|
||||
return `${diff} month`;
|
||||
}
|
||||
|
||||
const diffYears = Math.floor(diffDays / 365);
|
||||
|
||||
if (diffYears === 1) return "1 year";
|
||||
return `${diffYears} years`;
|
||||
}
|
||||
|
||||
export function timeDiffFromNow(t: number): string {
|
||||
return timeDiff(t, time());
|
||||
}
|
||||
|
||||
export function TimeWidget(p: {
|
||||
time?: number;
|
||||
isDuration?: boolean;
|
||||
}): React.ReactElement {
|
||||
if (!p.time) return <></>;
|
||||
return (
|
||||
<Tooltip
|
||||
title={formatDate(
|
||||
p.isDuration ? new Date().getTime() / 1000 - p.time : p.time
|
||||
)}
|
||||
arrow
|
||||
>
|
||||
<span>
|
||||
{p.isDuration ? timeDiff(0, p.time) : timeDiffFromNow(p.time)}
|
||||
</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
21
moneymgr_web/src/widgets/forms/CheckboxInput.tsx
Normal file
21
moneymgr_web/src/widgets/forms/CheckboxInput.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import { Checkbox, FormControlLabel } from "@mui/material";
|
||||
|
||||
export function CheckboxInput(p: {
|
||||
editable: boolean;
|
||||
label: string;
|
||||
checked: boolean | undefined;
|
||||
onValueChange: (v: boolean) => void;
|
||||
}): React.ReactElement {
|
||||
return (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
disabled={!p.editable}
|
||||
checked={p.checked}
|
||||
onChange={(e) => p.onValueChange(e.target.checked)}
|
||||
/>
|
||||
}
|
||||
label={p.label}
|
||||
/>
|
||||
);
|
||||
}
|
62
moneymgr_web/src/widgets/forms/TextInput.tsx
Normal file
62
moneymgr_web/src/widgets/forms/TextInput.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import { TextField, TextFieldVariants } from "@mui/material";
|
||||
import { LenConstraint } from "../../api/ServerApi";
|
||||
|
||||
/**
|
||||
* Text input
|
||||
*/
|
||||
export function TextInput(p: {
|
||||
label?: string;
|
||||
editable?: boolean;
|
||||
value?: string;
|
||||
onValueChange?: (newVal: string | undefined) => void;
|
||||
size?: LenConstraint;
|
||||
checkValue?: (s: string) => boolean;
|
||||
multiline?: boolean;
|
||||
minRows?: number;
|
||||
maxRows?: number;
|
||||
type?: React.HTMLInputTypeAttribute;
|
||||
style?: React.CSSProperties;
|
||||
helperText?: string;
|
||||
variant?: TextFieldVariants;
|
||||
}): React.ReactElement {
|
||||
if (!p.editable && (p.value ?? "") === "") return <></>;
|
||||
|
||||
let valueError = undefined;
|
||||
if (p.value && p.value.length > 0) {
|
||||
if (p.size?.min && p.type !== "number" && p.value.length < p.size.min)
|
||||
valueError = `Please specify at least ${p.size.min} characters !`;
|
||||
if (p.checkValue && !p.checkValue(p.value)) valueError = "Invalid value!";
|
||||
if (
|
||||
p.type === "number" &&
|
||||
p.size &&
|
||||
(Number(p.value) > p.size.max || Number(p.value) < p.size.min)
|
||||
)
|
||||
valueError = "Invalid size range!";
|
||||
}
|
||||
|
||||
return (
|
||||
<TextField
|
||||
label={p.label}
|
||||
value={p.value ?? ""}
|
||||
onChange={(e) =>
|
||||
p.onValueChange?.(
|
||||
e.target.value.length === 0 ? undefined : e.target.value
|
||||
)
|
||||
}
|
||||
slotProps={{
|
||||
input: {
|
||||
readOnly: !p.editable,
|
||||
type: p.type,
|
||||
},
|
||||
htmlInput: { maxLength: p.size?.max },
|
||||
}}
|
||||
variant={p.variant ?? "standard"}
|
||||
style={p.style ?? { width: "100%", marginBottom: "15px" }}
|
||||
multiline={p.multiline}
|
||||
minRows={p.minRows}
|
||||
maxRows={p.maxRows}
|
||||
error={valueError !== undefined}
|
||||
helperText={valueError ?? p.helperText}
|
||||
/>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user