From 817f2263d3118d3af7fa54025d960b9e61b30492 Mon Sep 17 00:00:00 2001 From: Paul Miller Date: Thu, 4 Apr 2024 16:19:33 -0500 Subject: [PATCH] bring back smug satisfaction hermes domain formatting fixes confirm to add contact bump to rc4 send me sats modal hide button if no hermes env --- package.json | 2 +- pnpm-lock.yaml | 8 +- public/i18n/en.json | 7 +- src/components/Activity.tsx | 92 ++++++++++++++++++++++- src/components/LightningAddressShower.tsx | 43 +++++++++-- src/routes/Chat.tsx | 2 + src/routes/Profile.tsx | 24 ++++-- src/routes/settings/LightningAddress.tsx | 33 ++++---- src/routes/settings/Plus.tsx | 12 ++- 9 files changed, 176 insertions(+), 47 deletions(-) diff --git a/package.json b/package.json index 0e2a82c..e8a383d 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@capacitor/toast": "^5.0.6", "@kobalte/core": "^0.12.6", "@kobalte/tailwindcss": "^0.9.0", - "@mutinywallet/mutiny-wasm": "0.6.2-rc3", + "@mutinywallet/mutiny-wasm": "0.6.2-rc4", "@modular-forms/solid": "^0.20.0", "@solid-primitives/upload": "^0.0.117", "@solidjs/meta": "^0.29.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 947fc3f..57dfb89 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,8 +51,8 @@ dependencies: specifier: ^0.20.0 version: 0.20.0(solid-js@1.8.16) '@mutinywallet/mutiny-wasm': - specifier: 0.6.2-rc3 - version: 0.6.2-rc3 + specifier: 0.6.2-rc4 + version: 0.6.2-rc4 '@solid-primitives/upload': specifier: ^0.0.117 version: 0.0.117(solid-js@1.8.16) @@ -2085,8 +2085,8 @@ packages: solid-js: 1.8.16 dev: false - /@mutinywallet/mutiny-wasm@0.6.2-rc3: - resolution: {integrity: sha512-/FxSLHuMxIuXYs2C6KbMNzBuGeSHri+BkIrtuJFI1JWG3+XcSiJF4HU2mqAwaZQH9jg25x+LvY71aZ7pM3tM/w==} + /@mutinywallet/mutiny-wasm@0.6.2-rc4: + resolution: {integrity: sha512-u9xzX6V6fAhOd1liOf6hsSzklTP/bkGBsqgN0DXfEu1p3alho3/5R0fqF64WbOQgwNBRS2b9WX0HDIZiXoz4Ow==} dev: false /@nodelib/fs.scandir@2.1.5: diff --git a/public/i18n/en.json b/public/i18n/en.json index 80ba631..41e9320 100644 --- a/public/i18n/en.json +++ b/public/i18n/en.json @@ -56,7 +56,8 @@ "nym": "Nym" }, "deleted": "Your nostr profile has been deleted.", - "no_lightning_address": "No lightning address set" + "no_lightning_address": "No lightning address set", + "pay_me": "Send me sats" }, "chat": { "prompt": "This is a new conversation. Try asking for money!", @@ -262,7 +263,9 @@ "sweep_delay": "Funds may take a few days to be swept back into the wallet", "no_details": "No channel details found, which means this channel has likely been closed.", "back_home": "back home" - } + }, + "start_a_chat": "Start a chat?", + "start_a_chat_are_you_sure": "This user isn't in your contact list." }, "scanner": { "paste": "Paste Something", diff --git a/src/components/Activity.tsx b/src/components/Activity.tsx index 3d7539f..8f64463 100644 --- a/src/components/Activity.tsx +++ b/src/components/Activity.tsx @@ -3,7 +3,14 @@ import { cache, createAsync, revalidate, useNavigate } from "@solidjs/router"; import { Plus, Save, Search, Shuffle, Users } from "lucide-solid"; import { createEffect, createSignal, For, Match, Show, Switch } from "solid-js"; -import { ActivityDetailsModal, ButtonCard, NiceP } from "~/components"; +import { + ActivityDetailsModal, + Button, + ButtonCard, + ContactButton, + NiceP, + SimpleDialog +} from "~/components"; import { useI18n } from "~/i18n/context"; import { PrivacyLevel } from "~/routes"; import { useMegaStore } from "~/state/megaStore"; @@ -11,6 +18,7 @@ import { actuallyFetchNostrProfile, hexpubFromNpub, profileToPseudoContact, + PseudoContact, timeAgo } from "~/utils"; @@ -36,6 +44,7 @@ export interface IActivityItem { export function UnifiedActivityItem(props: { item: IActivityItem; onClick: (id: string, kind: HackActivityType) => void; + onNewContactClick: (profile: PseudoContact) => void; }) { const navigate = useNavigate(); @@ -165,7 +174,9 @@ export function UnifiedActivityItem(props: { primaryOnClick={() => primaryContact()?.id ? navigate(`/chat/${primaryContact()?.id}`) - : undefined + : profileFromNostr() + ? props.onNewContactClick(profileFromNostr()!) + : undefined } amountOnClick={click} primaryName={ @@ -194,6 +205,74 @@ export function UnifiedActivityItem(props: { ); } +function NewContactModal(props: { profile: PseudoContact; close: () => void }) { + const i18n = useI18n(); + const navigate = useNavigate(); + + const [state, _actions] = useMegaStore(); + + async function createContact() { + try { + const existingContact = + await state.mutiny_wallet?.get_contact_for_npub( + props.profile.hexpub + ); + + if (existingContact) { + navigate(`/chat/${existingContact.id}`); + return; + } + + const contactId = await state.mutiny_wallet?.create_new_contact( + props.profile.name, + props.profile.hexpub, + props.profile.ln_address, + props.profile.lnurl, + props.profile.image_url + ); + + if (!contactId) { + throw new Error("no contact id returned"); + } + + const tagItem = await state.mutiny_wallet?.get_tag_item(contactId); + + if (!tagItem) { + throw new Error("no contact returned"); + } + + navigate(`/chat/${contactId}`); + } catch (e) { + console.error(e); + } + } + + return ( + { + props.close(); + }} + > + {i18n.t("activity.start_a_chat_are_you_sure")} + {}} /> +
+ + +
+
+ ); +} + export function CombinedActivity() { const [state, _actions] = useMegaStore(); const i18n = useI18n(); @@ -239,6 +318,8 @@ export function CombinedActivity() { } }); + const [newContact, setNewContact] = createSignal(); + return ( <> @@ -249,6 +330,12 @@ export function CombinedActivity() { setOpen={setDetailsOpen} /> + + setNewContact(undefined)} + /> + @@ -301,6 +388,7 @@ export function CombinedActivity() { )} diff --git a/src/components/LightningAddressShower.tsx b/src/components/LightningAddressShower.tsx index 2a90d83..24a3084 100644 --- a/src/components/LightningAddressShower.tsx +++ b/src/components/LightningAddressShower.tsx @@ -1,23 +1,31 @@ import { Copy, QrCode } from "lucide-solid"; -import { createSignal, Match, Switch } from "solid-js"; +import { createMemo, createSignal, Match, Show, Switch } from "solid-js"; import { QRCodeSVG } from "solid-qr-code"; -import { FancyCard, SimpleDialog } from "~/components"; +import { FancyCard, LabelCircle, SimpleDialog } from "~/components"; import { useI18n } from "~/i18n/context"; +import { UserProfile } from "~/routes"; import { useCopy } from "~/utils"; -export function LightningAddressShower(props: { lud16: string }) { +export function LightningAddressShower(props: { + lud16?: string; + profile?: UserProfile; +}) { const i18n = useI18n(); const [showQr, setShowQr] = createSignal(false); const [copy, copied] = useCopy({ copiedTimeout: 1000 }); + const lud16 = createMemo(() => { + return props.lud16 || props.profile?.lud16 || ""; + }); + return ( - +

- {props.lud16} + {lud16()}

@@ -38,11 +46,30 @@ export function LightningAddressShower(props: { lud16: string }) { setOpen={(open) => { setShowQr(open); }} - title={"Lightning Address"} + title={i18n.t("profile.pay_me")} > + +
+
+ +
+

+ {props.profile?.name} +

+
+

+ {lud16()} +

+
diff --git a/src/routes/Chat.tsx b/src/routes/Chat.tsx index d6b98c3..1af4881 100644 --- a/src/routes/Chat.tsx +++ b/src/routes/Chat.tsx @@ -243,6 +243,8 @@ function MessageList(props: { {}} />
diff --git a/src/routes/Profile.tsx b/src/routes/Profile.tsx index 1b987c3..6e62b9a 100644 --- a/src/routes/Profile.tsx +++ b/src/routes/Profile.tsx @@ -17,6 +17,13 @@ import { useI18n } from "~/i18n/context"; import { useMegaStore } from "~/state/megaStore"; import { DEFAULT_NOSTR_NAME } from "~/utils"; +export type UserProfile = { + name: string; + picture?: string; + lud16?: string; + deleted: boolean | string; +}; + export function Profile() { const [state, _actions] = useMegaStore(); const i18n = useI18n(); @@ -26,12 +33,13 @@ export function Profile() { const profile = createMemo(() => { const profile = state.mutiny_wallet?.get_nostr_profile(); - return { + const userProfile: UserProfile = { name: profile?.display_name || profile?.name || DEFAULT_NOSTR_NAME, picture: profile?.picture || undefined, lud16: profile?.lud16 || undefined, deleted: profile?.deleted || false }; + return userProfile; }); const profileDeleted = createMemo(() => { @@ -44,9 +52,9 @@ export function Profile() { if (!hermes) { return false; } - const hermesDoman = new URL(hermes).hostname; - const afterAt = profile().lud16.split("@")[1]; - if (afterAt && afterAt.includes(hermesDoman)) { + const hermesDomain = new URL(hermes).hostname; + const afterAt = profile().lud16!.split("@")[1]; + if (afterAt && afterAt.includes(hermesDomain)) { return true; } } @@ -69,7 +77,7 @@ export function Profile() { {profile().name} - + navigate("/editprofile")}>
@@ -79,7 +87,11 @@ export function Profile() {
diff --git a/src/routes/settings/LightningAddress.tsx b/src/routes/settings/LightningAddress.tsx index bf8d644..525974c 100644 --- a/src/routes/settings/LightningAddress.tsx +++ b/src/routes/settings/LightningAddress.tsx @@ -52,7 +52,11 @@ function HermesForm(props: { onSubmit: (name: string) => void }) { } }); - const network = state.mutiny_wallet?.get_network() || "signet"; + const hermes = import.meta.env.VITE_HERMES; + if (!hermes) { + throw new Error("Hermes not configured"); + } + const hermesDomain = new URL(hermes).hostname; const handleSubmit: SubmitHandler = async (f: HermesForm) => { setSuccess(""); @@ -67,13 +71,7 @@ function HermesForm(props: { onSubmit: (name: string) => void }) { await state.mutiny_wallet?.reserve_lnurl_name(name); console.log("lnurl name reserved:", name); - const hermes = import.meta.env.VITE_HERMES; - if (!hermes) { - throw new Error("Hermes not configured"); - } - const hermesDoman = new URL(hermes).hostname; - - const formattedName = `${name}${hermesDoman}`; + const formattedName = `${name}@${hermesDomain}`; const existingProfile = state.mutiny_wallet?.get_nostr_profile(); @@ -109,12 +107,7 @@ function HermesForm(props: { onSubmit: (name: string) => void }) { />
- - @signet.mutiny.plus - + @{hermesDomain}
)} @@ -145,7 +138,6 @@ export function LightningAddress() { const [error, setError] = createSignal(); const [settingLnAddress, setSettingLnAddress] = createSignal(false); - // TODO: should be able to ask mutiny-node for this const [lnurlName, { refetch }] = createResource(async () => { try { const name = await state.mutiny_wallet?.check_lnurl_name(); @@ -155,16 +147,17 @@ export function LightningAddress() { } }); const ios = Capacitor.getPlatform() === "ios"; - // const ios = true; - const network = state.mutiny_wallet?.get_network() || "signet"; + const hermes = import.meta.env.VITE_HERMES; + if (!hermes) { + throw new Error("Hermes not configured"); + } + const hermesDomain = new URL(hermes).hostname; const formattedLnAddress = createMemo(() => { const name = lnurlName(); if (name) { - const suffix = - network === "signet" ? "@signet.mutiny.plus" : "@mutiny.plus"; - return `${lnurlName()}${suffix}`; + return `${lnurlName()}@${hermesDomain}`; } }); diff --git a/src/routes/settings/Plus.tsx b/src/routes/settings/Plus.tsx index bbdc784..e009c05 100644 --- a/src/routes/settings/Plus.tsx +++ b/src/routes/settings/Plus.tsx @@ -185,10 +185,9 @@ export function Plus() { - {/* {i18n.t("settings.plus.thanks")} */} - You're part of the Mutiny! + {i18n.t("settings.plus.thanks")} - {/* */} + {i18n.t("settings.plus.renewal_time")}{" "} @@ -204,7 +203,12 @@ export function Plus() { {i18n.t("settings.plus.wallet_connection")} - + navigate("/settings/lightningaddress")