Files
mutiny-web/src/components/AmountCard.tsx
2023-06-26 17:58:15 -05:00

195 lines
7.6 KiB
TypeScript

import { Match, ParentComponent, Show, Switch, createMemo } from "solid-js";
import { Card, VStack } from "~/components/layout";
import { useMegaStore } from "~/state/megaStore";
import { satsToUsd } from "~/utils/conversions";
import { AmountEditable } from "./AmountEditable";
const noop = () => {
// do nothing
};
const KeyValue: ParentComponent<{ key: string; gray?: boolean }> = (props) => {
return (
<div
class="flex justify-between items-center"
classList={{ "text-neutral-400": props.gray }}
>
<div class="font-semibold uppercase">{props.key}</div>
<div class="font-light">{props.children}</div>
</div>
);
};
export const InlineAmount: ParentComponent<{
amount: string;
sign?: string;
fiat?: boolean;
}> = (props) => {
const prettyPrint = createMemo(() => {
const parsed = Number(props.amount);
if (isNaN(parsed)) {
return props.amount;
} else {
return parsed.toLocaleString();
}
});
return (
<div class="inline-block text-lg">
{props.sign ? `${props.sign} ` : ""}
{props.fiat ? "$" : ""}
{prettyPrint()}{" "}
<span class="text-sm">{props.fiat ? "USD" : "SATS"}</span>
</div>
);
};
function USDShower(props: { amountSats: string; fee?: string }) {
const [state, _] = useMegaStore();
const amountInUsd = () =>
satsToUsd(state.price, add(props.amountSats, props.fee), true);
return (
<Show when={!(props.amountSats === "0")}>
<KeyValue gray key="">
<div class="self-end">
~{amountInUsd()}&nbsp;
<span class="text-sm">USD</span>
</div>
</KeyValue>
</Show>
);
}
function add(a: string, b?: string) {
return Number(a || 0) + Number(b || 0);
}
export function AmountCard(props: {
amountSats: string;
fee?: string;
reserve?: string;
initialOpen?: boolean;
isAmountEditable?: boolean;
setAmountSats?: (amount: bigint) => void;
skipWarnings?: boolean;
exitRoute?: string;
maxAmountSats?: bigint;
}) {
// Normally we want to add the fee to the amount, but for max amount we just show the max
const totalOrTotalLessFee = () => {
if (
props.fee &&
props.maxAmountSats &&
props.amountSats === props.maxAmountSats?.toString()
) {
return props.maxAmountSats.toLocaleString();
} else {
return add(props.amountSats, props.fee).toString();
}
};
return (
<Card>
<VStack>
<Switch>
<Match when={props.fee}>
<div class="flex flex-col gap-1">
<KeyValue key="Amount">
<Show
when={props.isAmountEditable}
fallback={
<InlineAmount
amount={props.amountSats}
/>
}
>
<AmountEditable
initialOpen={props.initialOpen ?? false}
initialAmountSats={props.amountSats.toString()}
setAmountSats={
props.setAmountSats
? props.setAmountSats
: noop
}
skipWarnings={props.skipWarnings}
exitRoute={props.exitRoute}
maxAmountSats={props.maxAmountSats}
fee={props.fee}
/>
</Show>
</KeyValue>
<KeyValue gray key="+ Fee">
<InlineAmount amount={props.fee || "0"} />
</KeyValue>
</div>
<hr class="border-white/20" />
<div class="flex flex-col gap-1">
<KeyValue key="Total">
<InlineAmount amount={totalOrTotalLessFee()} />
</KeyValue>
<USDShower
amountSats={props.amountSats}
fee={props.fee}
/>
</div>
</Match>
<Match when={props.reserve}>
<div class="flex flex-col gap-1">
<KeyValue key="Channel size">
<InlineAmount
amount={add(
props.amountSats,
props.reserve
).toString()}
/>
</KeyValue>
<KeyValue gray key="- Channel Reserve">
<InlineAmount amount={props.reserve || "0"} />
</KeyValue>
</div>
<hr class="border-white/20" />
<div class="flex flex-col gap-1">
<KeyValue key="Spendable">
<InlineAmount amount={props.amountSats} />
</KeyValue>
<USDShower
amountSats={props.amountSats}
fee={props.reserve}
/>
</div>
</Match>
<Match when={!props.fee && !props.reserve}>
<div class="flex flex-col gap-1">
<KeyValue key="Amount">
<Show
when={props.isAmountEditable}
fallback={
<InlineAmount
amount={props.amountSats}
/>
}
>
<AmountEditable
initialOpen={props.initialOpen ?? false}
initialAmountSats={props.amountSats.toString()}
setAmountSats={
props.setAmountSats
? props.setAmountSats
: noop
}
skipWarnings={props.skipWarnings}
exitRoute={props.exitRoute}
maxAmountSats={props.maxAmountSats}
fee={props.fee}
/>
</Show>
</KeyValue>
<USDShower amountSats={props.amountSats} />
</div>
</Match>
</Switch>
</VStack>
</Card>
);
}