mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2025-12-19 07:14:22 +01:00
add address fetching
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
import { Motion, Presence } from "@motionone/solid";
|
import { Motion, Presence } from "@motionone/solid";
|
||||||
import { MutinyBalance } from "@mutinywallet/node-manager";
|
import { MutinyBalance } from "@mutinywallet/node-manager";
|
||||||
|
import { createResource, Show } from "solid-js";
|
||||||
|
|
||||||
import { useNodeManager } from "~/state/nodeManagerState";
|
import { useNodeManager } from "~/state/nodeManagerState";
|
||||||
|
import { ButtonLink } from "./Button";
|
||||||
|
|
||||||
function prettyPrintAmount(n?: number | bigint): string {
|
function prettyPrintAmount(n?: number | bigint): string {
|
||||||
if (!n || n.valueOf() === 0) {
|
if (!n || n.valueOf() === 0) {
|
||||||
@@ -15,7 +17,15 @@ function prettyPrintBalance(b: MutinyBalance): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function BalanceBox() {
|
export default function BalanceBox() {
|
||||||
const { balance, refetchBalance } = useNodeManager();
|
const { nodeManager } = useNodeManager();
|
||||||
|
|
||||||
|
const fetchBalance = async () => {
|
||||||
|
console.log("Refetching balance");
|
||||||
|
const balance = await nodeManager()?.get_balance();
|
||||||
|
return balance
|
||||||
|
};
|
||||||
|
|
||||||
|
const [balance, { refetch: refetchBalance }] = createResource(nodeManager, fetchBalance);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Presence>
|
<Presence>
|
||||||
@@ -31,12 +41,15 @@ export default function BalanceBox() {
|
|||||||
</header>
|
</header>
|
||||||
<div onClick={refetchBalance}>
|
<div onClick={refetchBalance}>
|
||||||
<h1 class='text-4xl font-light'>
|
<h1 class='text-4xl font-light'>
|
||||||
{balance() && prettyPrintBalance(balance())} <span class='text-xl'>SAT</span>
|
<Show when={balance()}>
|
||||||
|
{/* TODO: no-non-null-asssertion but type narrowing just isn't working */}
|
||||||
|
{prettyPrintBalance(balance()!)} <span class='text-xl'>SAT</span>
|
||||||
|
</Show>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2 py-4">
|
<div class="flex gap-2 py-4">
|
||||||
<button class='bg-[#1EA67F] p-4 flex-1 rounded-xl text-xl font-semibold '><span class="drop-shadow-sm shadow-black">Send</span></button>
|
<ButtonLink href="/scanner" intent="green">Send</ButtonLink>
|
||||||
<button class='bg-[#3B6CCC] p-4 flex-1 rounded-xl text-xl font-semibold '><span class="drop-shadow-sm shadow-black">Receive</span></button>
|
<ButtonLink href="/receive" intent="blue">Receive</ButtonLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Motion>
|
</Motion>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { cva, VariantProps } from "class-variance-authority";
|
import { cva, VariantProps } from "class-variance-authority";
|
||||||
import { children, JSX, ParentComponent, splitProps } from "solid-js";
|
import { children, JSX, ParentComponent, splitProps } from "solid-js";
|
||||||
|
import { A } from "solid-start";
|
||||||
|
|
||||||
const button = cva(["p-4", "rounded-xl", "text-xl", "font-semibold"], {
|
const button = cva(["p-4", "rounded-xl", "text-xl", "font-semibold"], {
|
||||||
variants: {
|
variants: {
|
||||||
@@ -7,7 +8,8 @@ const button = cva(["p-4", "rounded-xl", "text-xl", "font-semibold"], {
|
|||||||
active: "bg-white text-black",
|
active: "bg-white text-black",
|
||||||
inactive: "bg-black text-white border border-white",
|
inactive: "bg-black text-white border border-white",
|
||||||
blue: "bg-[#3B6CCC] text-white",
|
blue: "bg-[#3B6CCC] text-white",
|
||||||
red: "bg-[#F61D5B] text-white"
|
red: "bg-[#F61D5B] text-white",
|
||||||
|
green: "bg-[#1EA67F] text-white",
|
||||||
},
|
},
|
||||||
layout: {
|
layout: {
|
||||||
flex: "flex-1",
|
flex: "flex-1",
|
||||||
@@ -43,4 +45,27 @@ export const Button: ParentComponent<ButtonProps> = props => {
|
|||||||
{slot()}
|
{slot()}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ButtonLinkProps extends JSX.ButtonHTMLAttributes<HTMLAnchorElement>, StyleProps {
|
||||||
|
href: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ButtonLink: ParentComponent<ButtonLinkProps> = props => {
|
||||||
|
const slot = children(() => props.children)
|
||||||
|
const [local, attrs] = splitProps(props, ['children', 'intent', 'layout', 'class', 'href'])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<A
|
||||||
|
href={local.href}
|
||||||
|
{...attrs}
|
||||||
|
class={button({
|
||||||
|
class: local.class || "",
|
||||||
|
intent: local.intent,
|
||||||
|
layout: local.layout,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{slot()}
|
||||||
|
</A>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
@@ -4,14 +4,16 @@ import settings from '~/assets/icons/settings.svg';
|
|||||||
|
|
||||||
import { A } from "solid-start";
|
import { A } from "solid-start";
|
||||||
|
|
||||||
type ActiveTab = 'home' | 'scan' | 'settings';
|
type ActiveTab = 'home' | 'scan' | 'settings' | 'none';
|
||||||
|
|
||||||
export default function NavBar(props: { activeTab: ActiveTab }) {
|
export default function NavBar(props: { activeTab: ActiveTab }) {
|
||||||
const activeStyle = 'h-full border-t-2 border-b-2 border-b-black flex flex-col justify-center'
|
const activeStyle = 'h-full border-t-2 border-b-2 border-b-black flex flex-col justify-center'
|
||||||
return (<nav class='bg-black fixed bottom-0 shadow-lg z-40 w-full safe-bottom'>
|
return (<nav class='bg-black fixed bottom-0 shadow-lg z-40 w-full safe-bottom'>
|
||||||
<ul class='h-16 flex justify-between px-16 items-center'>
|
<ul class='h-16 flex justify-between px-16 items-center'>
|
||||||
<li class={props.activeTab === "home" ? activeStyle : ""}>
|
<li class={props.activeTab === "home" ? activeStyle : ""}>
|
||||||
<img src={mutiny_m} alt="home" />
|
<A href="/">
|
||||||
|
<img src={mutiny_m} alt="home" />
|
||||||
|
</A>
|
||||||
</li>
|
</li>
|
||||||
<li class={props.activeTab === "scan" ? activeStyle : ""}>
|
<li class={props.activeTab === "scan" ? activeStyle : ""}>
|
||||||
<A href="/scanner">
|
<A href="/scanner">
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ export async function checkForWasm() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setupNodeManager(settings?: NodeManagerSettingStrings): Promise<NodeManager> {
|
export async function setupNodeManager(): Promise<NodeManager> {
|
||||||
const _ = await init();
|
const _ = await init();
|
||||||
|
|
||||||
console.time("Setup");
|
console.time("Setup");
|
||||||
console.log("Starting setup...")
|
console.log("Starting setup...")
|
||||||
const { network, proxy, esplora } = await setAndGetMutinySettings(settings)
|
const { network, proxy, esplora } = await setAndGetMutinySettings()
|
||||||
console.log("Initializing Node Manager")
|
console.log("Initializing Node Manager")
|
||||||
console.log("Using network", network);
|
console.log("Using network", network);
|
||||||
console.log("Using proxy", proxy);
|
console.log("Using proxy", proxy);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
Title,
|
Title,
|
||||||
} from "solid-start";
|
} from "solid-start";
|
||||||
import "./root.css";
|
import "./root.css";
|
||||||
|
import { NodeManagerProvider } from "./state/nodeManagerState";
|
||||||
|
|
||||||
export default function Root() {
|
export default function Root() {
|
||||||
return (
|
return (
|
||||||
@@ -34,9 +35,11 @@ export default function Root() {
|
|||||||
<Body>
|
<Body>
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<Routes>
|
<NodeManagerProvider>
|
||||||
<FileRoutes />
|
<Routes>
|
||||||
</Routes>
|
<FileRoutes />
|
||||||
|
</Routes>
|
||||||
|
</NodeManagerProvider>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
<Scripts />
|
<Scripts />
|
||||||
|
|||||||
31
src/routes/Receive.tsx
Normal file
31
src/routes/Receive.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { createResource, Show } from "solid-js";
|
||||||
|
import { Button } from "~/components/Button";
|
||||||
|
import NavBar from "~/components/NavBar";
|
||||||
|
import SafeArea from "~/components/SafeArea";
|
||||||
|
import { useNodeManager } from "~/state/nodeManagerState";
|
||||||
|
|
||||||
|
export default function Receive() {
|
||||||
|
const { nodeManager } = useNodeManager();
|
||||||
|
|
||||||
|
// TODO: would be nice if this was just newest unused address
|
||||||
|
const getNewAddress = async () => {
|
||||||
|
console.log("Getting new address");
|
||||||
|
const address = await nodeManager()?.get_new_address();
|
||||||
|
return address
|
||||||
|
};
|
||||||
|
|
||||||
|
const [address, { refetch: refetchAddress }] = createResource(nodeManager, getNewAddress);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeArea>
|
||||||
|
<main class='flex flex-col gap-4 py-8 px-4'>
|
||||||
|
<Show when={address()}>
|
||||||
|
<h1>{address()}</h1>
|
||||||
|
<Button onClick={refetchAddress}>Get new address</Button>
|
||||||
|
</Show>
|
||||||
|
</main>
|
||||||
|
<NavBar activeTab="none" />
|
||||||
|
</SafeArea>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -35,9 +35,7 @@ export default function Home() {
|
|||||||
<ReloadPrompt />
|
<ReloadPrompt />
|
||||||
<Switch fallback={<>Loading...</>} >
|
<Switch fallback={<>Loading...</>} >
|
||||||
<Match when={waitlistData() && waitlistData().approval_date}>
|
<Match when={waitlistData() && waitlistData().approval_date}>
|
||||||
<NodeManagerProvider>
|
<App />
|
||||||
<App />
|
|
||||||
</NodeManagerProvider>
|
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={waitlistData() && waitlistData().date}>
|
<Match when={waitlistData() && waitlistData().date}>
|
||||||
<WaitlistAlreadyIn />
|
<WaitlistAlreadyIn />
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import { Outlet } from "solid-start";
|
|
||||||
|
|
||||||
export default function UsersLayout() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h1>Users</h1>
|
|
||||||
<Outlet />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,24 +1,14 @@
|
|||||||
import { NodeManager } from "@mutinywallet/node-manager";
|
import { NodeManager } from "@mutinywallet/node-manager";
|
||||||
import { createContext, JSX, useContext, createResource } from "solid-js";
|
import { createContext, JSX, useContext, createResource, Resource } from "solid-js";
|
||||||
import { setupNodeManager } from "~/logic/nodeManagerSetup";
|
import { setupNodeManager } from "~/logic/nodeManagerSetup";
|
||||||
|
|
||||||
const NodeManagerContext = createContext();
|
const NodeManagerContext = createContext<{ nodeManager: Resource<NodeManager> }>();
|
||||||
|
|
||||||
export function NodeManagerProvider(props: { children: JSX.Element }) {
|
export function NodeManagerProvider(props: { children: JSX.Element }) {
|
||||||
const [nodeManager] = createResource({}, setupNodeManager);
|
const [nodeManager] = createResource(setupNodeManager);
|
||||||
|
|
||||||
const fetchBalance = async (nm: NodeManager) => {
|
|
||||||
console.log("refetching balance");
|
|
||||||
const balance = await nm.get_balance();
|
|
||||||
return balance
|
|
||||||
};
|
|
||||||
|
|
||||||
const [balance, { refetch }] = createResource(nodeManager, fetchBalance);
|
|
||||||
|
|
||||||
const value = {
|
const value = {
|
||||||
nodeManager,
|
nodeManager,
|
||||||
balance,
|
|
||||||
refetchBalance: refetch
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -28,4 +18,11 @@ export function NodeManagerProvider(props: { children: JSX.Element }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useNodeManager() { return useContext(NodeManagerContext); }
|
export function useNodeManager() {
|
||||||
|
// This is a trick to narrow the typescript types: https://docs.solidjs.com/references/api-reference/component-apis/createContext
|
||||||
|
const context = useContext(NodeManagerContext);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error("useNodeManager: cannot find a NodeManagerContext")
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user