diff --git a/packages/app/src/Element/Event/Create/NoteCreator.tsx b/packages/app/src/Element/Event/Create/NoteCreator.tsx index 0b030cbd..c116832e 100644 --- a/packages/app/src/Element/Event/Create/NoteCreator.tsx +++ b/packages/app/src/Element/Event/Create/NoteCreator.tsx @@ -408,7 +408,7 @@ export function NoteCreator() {
{[...(note.zapSplits ?? [])].map((v, i, arr) => (
-
+

@@ -423,7 +423,7 @@ export function NoteCreator() { placeholder={formatMessage({ defaultMessage: "npub / nprofile / nostr address", id: "WvGmZT" })} />
-
+

diff --git a/packages/app/src/Hooks/useRates.tsx b/packages/app/src/Hooks/useRates.tsx new file mode 100644 index 00000000..a8aa28e9 --- /dev/null +++ b/packages/app/src/Hooks/useRates.tsx @@ -0,0 +1,34 @@ +import { bech32ToHex } from "@snort/shared"; +import { EventKind, ReplaceableNoteStore, RequestBuilder } from "@snort/system"; +import { useRequestBuilder } from "@snort/system-react"; +import { useMemo } from "react"; + +// Snort backend publishes rates +const SnortPubkey = "npub1sn0rtcjcf543gj4wsg7fa59s700d5ztys5ctj0g69g2x6802npjqhjjtws"; + +export function useRates(symbol: string, leaveOpen = true) { + const sub = useMemo(() => { + const rb = new RequestBuilder(`rates:${symbol}`); + rb.withOptions({ + leaveOpen, + }); + rb.withFilter() + .kinds([1009 as EventKind]) + .authors([bech32ToHex(SnortPubkey)]) + .tag("d", [symbol]) + .limit(1); + return rb; + }, [symbol]); + + const data = useRequestBuilder(ReplaceableNoteStore, sub); + + const tag = data?.data?.tags.find(a => a[0] === "d" && a[1] === symbol); + if (!tag) return undefined; + return { + time: data.data?.created_at, + ask: Number(tag[2]), + bid: Number(tag[3]), + low: Number(tag[4]), + hight: Number(tag[5]), + }; +} diff --git a/packages/app/src/Pages/DeckLayout.tsx b/packages/app/src/Pages/DeckLayout.tsx index 7526a9e5..b3d474a6 100644 --- a/packages/app/src/Pages/DeckLayout.tsx +++ b/packages/app/src/Pages/DeckLayout.tsx @@ -71,7 +71,7 @@ export function SnortDeckLayout() { id="IOu4Xh" values={{ app: CONFIG.appNameCapitalized, - tier: mapPlanName(CONFIG.deckSubKind), + tier: mapPlanName(CONFIG.deckSubKind ?? -1), }} />
@@ -122,7 +122,11 @@ export function SnortDeckLayout() { )} {deckState.article && ( <> - setDeckState({})} className="long-form" onClick={() => setDeckState({})}> + setDeckState({})} + className="long-form" + onClick={() => setDeckState({})}>
e.stopPropagation()}>
@@ -140,11 +144,11 @@ function NotesCol() { return (
-
+
-
+
diff --git a/packages/app/src/Pages/Layout/NavSidebar.tsx b/packages/app/src/Pages/Layout/NavSidebar.tsx index 95a435b3..36e941b1 100644 --- a/packages/app/src/Pages/Layout/NavSidebar.tsx +++ b/packages/app/src/Pages/Layout/NavSidebar.tsx @@ -1,18 +1,21 @@ import { LogoHeader } from "./LogoHeader"; -import { useNavigate } from "react-router-dom"; +import { Link, useNavigate } from "react-router-dom"; import Icon from "@/Icons/Icon"; import { ProfileLink } from "../../Element/User/ProfileLink"; import Avatar from "../../Element/User/Avatar"; import useLogin from "../../Hooks/useLogin"; import { useUserProfile } from "@snort/system-react"; import { NoteCreatorButton } from "../../Element/Event/Create/NoteCreatorButton"; -import { FormattedMessage, useIntl } from "react-intl"; +import { FormattedMessage, FormattedNumber, useIntl } from "react-intl"; import classNames from "classnames"; import { getCurrentSubscription } from "@/Subscription"; import { HasNotificationsMarker } from "@/Pages/Layout/HasNotificationsMarker"; import NavLink from "@/Element/Button/NavLink"; import { subscribeToNotifications } from "@/Notifications"; import useEventPublisher from "@/Hooks/useEventPublisher"; +import { Sats, useWallet } from "@/Wallet"; +import { useEffect, useState } from "react"; +import { useRates } from "@/Hooks/useRates"; const MENU_ITEMS = [ { @@ -72,6 +75,44 @@ const getNavLinkClass = (isActive: boolean, narrow: boolean) => { }); }; +const WalletBalance = () => { + const [balance, setBalance] = useState(); + const wallet = useWallet(); + const rates = useRates("BTCUSD"); + + useEffect(() => { + setBalance(undefined); + if (wallet.wallet && wallet.wallet.canGetBalance()) { + wallet.wallet.getBalance().then(setBalance); + } + }, [wallet]); + + return ( +
+
+
+ + +
+ + + +
+
+ + ), + }} + /> +
+
+ ); +}; + export default function NavSidebar({ narrow = false }) { const { publicKey, subscriptions, readonly } = useLogin(s => ({ publicKey: s.publicKey, @@ -106,6 +147,7 @@ export default function NavSidebar({ narrow = false }) { { "xl:items-start": !narrow, "xl:gap-2": !narrow }, "gap-1 flex flex-col items-center text-lg font-bold", )}> + {MENU_ITEMS.filter(a => { if ((CONFIG.hideFromNavbar ?? []).includes(a.link)) { return false; @@ -122,7 +164,7 @@ export default function NavSidebar({ narrow = false }) { return ""; } const onClick = () => { - if (item.label === "Notifications") { + if (item.label === "Notifications" && publisher) { subscribeToNotifications(publisher); } }; diff --git a/packages/app/src/Pages/WalletPage.tsx b/packages/app/src/Pages/WalletPage.tsx index 026cac25..c1bae0c4 100644 --- a/packages/app/src/Pages/WalletPage.tsx +++ b/packages/app/src/Pages/WalletPage.tsx @@ -5,31 +5,35 @@ import { useNavigate } from "react-router-dom"; import { FormattedMessage, FormattedNumber, useIntl } from "react-intl"; import NoteTime from "@/Element/Event/NoteTime"; -import { WalletInvoice, Sats, WalletInfo, WalletInvoiceState, useWallet, LNWallet, Wallets } from "@/Wallet"; +import { WalletInvoice, Sats, useWallet, LNWallet, Wallets } from "@/Wallet"; import AsyncButton from "@/Element/Button/AsyncButton"; import { unwrap } from "@/SnortUtils"; import Icon from "@/Icons/Icon"; +import { useRates } from "@/Hooks/useRates"; +import { AsyncIcon } from "@/Element/Button/AsyncIcon"; +import classNames from "classnames"; -export default function WalletPage() { +export default function WalletPage(props: { showHistory: boolean }) { const navigate = useNavigate(); const { formatMessage } = useIntl(); - const [info, setInfo] = useState(); const [balance, setBalance] = useState(); const [history, setHistory] = useState(); const [walletPassword, setWalletPassword] = useState(); const [error, setError] = useState(); const walletState = useWallet(); const wallet = walletState.wallet; + const rates = useRates("BTCUSD"); async function loadWallet(wallet: LNWallet) { try { - const i = await wallet.getInfo(); - setInfo(i); + setError(undefined); + setBalance(0); + setHistory(undefined); if (wallet.canGetBalance()) { const b = await wallet.getBalance(); setBalance(b as Sats); } - if (wallet.canGetInvoices()) { + if (wallet.canGetInvoices() && (props.showHistory ?? true)) { const h = await wallet.getInvoices(); setHistory((h as WalletInvoice[]).sort((a, b) => b.timestamp - a.timestamp)); } @@ -43,29 +47,11 @@ export default function WalletPage() { } useEffect(() => { - if (wallet) { - if (wallet.isReady()) { - loadWallet(wallet).catch(console.warn); - } else if (wallet.canAutoLogin()) { - wallet - .login() - .then(async () => await loadWallet(wallet)) - .catch(console.warn); - } + if (wallet && wallet.isReady()) { + loadWallet(wallet).catch(console.warn); } }, [wallet]); - function stateIcon(s: WalletInvoiceState) { - switch (s) { - case WalletInvoiceState.Pending: - return ; - case WalletInvoiceState.Paid: - return ; - case WalletInvoiceState.Expired: - return ; - } - } - async function loginWallet(pw: string) { if (wallet) { await wallet.login(pw); @@ -112,11 +98,11 @@ export default function WalletPage() { ); } return ( -
-

+
+

-
+