import { Dialog } from "@kobalte/core"; import { MutinyChannel, MutinyInvoice, TagItem } from "@mutinywallet/mutiny-wasm"; import { createEffect, createMemo, createResource, Match, Show, Suspense, Switch } from "solid-js"; import bolt from "~/assets/icons/bolt.svg"; import chain from "~/assets/icons/chain.svg"; import copyIcon from "~/assets/icons/copy.svg"; import shuffle from "~/assets/icons/shuffle.svg"; import { ActivityAmount, AmountFiat, AmountSats, FancyCard, HackActivityType, Hr, InfoBox, KeyValue, ModalCloseButton, TinyButton, TruncateMiddle, VStack } from "~/components"; import { useI18n } from "~/i18n/context"; import { Network } from "~/logic/mutinyWalletSetup"; import { BalanceBar } from "~/routes/settings/Channels"; import { useMegaStore } from "~/state/megaStore"; import { mempoolTxUrl, prettyPrintTime, useCopy } from "~/utils"; interface ChannelClosure { channel_id: string; node_id: string; reason: string; timestamp: number; } interface OnChainTx { txid: string; received: number; sent: number; fee?: number; confirmation_time?: { Confirmed?: { height: number; time: number; }; }; labels: string[]; } export const OVERLAY = "fixed inset-0 z-50 bg-black/50 backdrop-blur-sm"; export const DIALOG_POSITIONER = "fixed inset-0 z-50 flex items-center justify-center"; export const DIALOG_CONTENT = "max-w-[500px] w-[90vw] max-h-device overflow-y-scroll disable-scrollbars bg-neutral-900/80 backdrop-blur-md shadow-xl rounded-xl border border-white/10"; function LightningHeader(props: { info: MutinyInvoice }) { const i18n = useI18n(); return (
{props.info.inbound ? i18n.t("activity.transaction_details.lightning_receive") : i18n.t("activity.transaction_details.lightning_send")} lightning bolt
); } function OnchainHeader(props: { info: OnChainTx; kind?: HackActivityType }) { const i18n = useI18n(); const isSend = () => { return props.info.sent > props.info.received; }; const amount = () => { if (isSend()) { return (props.info.sent - props.info.received).toString(); } else { return (props.info.received - props.info.sent).toString(); } }; return (
{props.kind === "ChannelOpen" ? i18n.t("activity.transaction_details.channel_open") : props.kind === "ChannelClose" ? i18n.t("activity.transaction_details.channel_close") : isSend() ? i18n.t("activity.transaction_details.onchain_send") : i18n.t("activity.transaction_details.onchain_receive")} swap blockchain
); } export function MiniStringShower(props: { text: string }) { const [copy, copied] = useCopy({ copiedTimeout: 1000 }); return (
); } export function FormatPrettyPrint(props: { ts: number }) { return (
{prettyPrintTime(props.ts).split(",", 2).join(",")}
{prettyPrintTime(props.ts).split(", ")[2]}
); } function LightningDetails(props: { info: MutinyInvoice; tags?: TagItem }) { const i18n = useI18n(); const [state, _actions] = useMegaStore(); return ( ); } function OnchainDetails(props: { info: OnChainTx; kind?: HackActivityType; tags?: TagItem; }) { const i18n = useI18n(); const [state, _actions] = useMegaStore(); const [copy, copied] = useCopy({ copiedTimeout: 1000 }); const confirmationTime = () => { return props.info.confirmation_time?.Confirmed?.time; }; const network = state.mutiny_wallet?.get_network() as Network; // Can return nothing if the channel is already closed const [channelInfo] = createResource(async () => { if (props.kind === "ChannelOpen") { try { const channels = await (state.mutiny_wallet?.list_channels() as Promise< MutinyChannel[] >); const channel = channels.find( (channel) => channel.outpoint?.startsWith(props.info.txid) ); return channel; } catch (e) { console.error(e); } } else { return undefined; } }); return ( {/*
{JSON.stringify(channelInfo() || "", null, 2)}
*/}
); } function ChannelCloseDetails(props: { info: ChannelClosure }) { const i18n = useI18n(); return ( {/*
{JSON.stringify(props.info.value, null, 2)}
*/}
); } export function ActivityDetailsModal(props: { open: boolean; kind?: HackActivityType; id: string; setOpen: (open: boolean) => void; }) { const [state, _actions] = useMegaStore(); const id = () => props.id; const kind = () => props.kind; const [data, { refetch }] = createResource(async () => { try { if (kind() === "Lightning") { console.debug("reading invoice: ", id()); const invoice = await state.mutiny_wallet?.get_invoice_by_hash( id() ); return invoice; } else if (kind() === "ChannelClose") { console.debug("reading channel close: ", id()); const closeItem = await state.mutiny_wallet?.get_channel_closure(id()); return closeItem; } else { console.debug("reading tx: ", id()); const tx = await state.mutiny_wallet?.get_transaction(id()); return tx; } } catch (e) { console.error(e); return undefined; } }); const tags = createMemo(() => { if ( !!data() && data()?.labels !== undefined && typeof data()?.labels[0] === "string" ) { try { // find if there's just one for now const contacts = state.mutiny_wallet?.get_contact( data().labels[0] ); if (contacts) { return contacts; } else { return; } } catch (e) { console.error(e); } } else { return; } }); createEffect(() => { if (props.id && props.kind && props.open) { refetch(); } }); return (

); }