diff --git a/android/app/build.gradle b/android/app/build.gradle index aac04388..0f5dba04 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "com.mutinywallet.mutinywallet" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 55 - versionName "0.6.3" + versionCode 56 + versionName "0.6.4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/e2e/utils.ts b/e2e/utils.ts index d4cafd33..603fd2d6 100644 --- a/e2e/utils.ts +++ b/e2e/utils.ts @@ -13,10 +13,14 @@ export async function loadHome(page: Page) { await page.locator("button:has-text('Skip for now')").click(); + await page.getByText("Pick a Federation").waitFor(); + + await page.locator("button:has-text('Skip for now')").click(); + + await page.locator(`button:has-text('Confirm')`).click(); + // Should have a balance up top now - await page.locator(`text=0 sats`).first(); - // Status light should be ready - await page.locator(`title="READY"`).first(); + await page.locator(`text=0 sats`).first().waitFor(); } export async function visitSettings(page: Page) { diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index c048ffab..2a5edffb 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -360,7 +360,7 @@ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance"; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 1.6.3; + MARKETING_VERSION = 1.6.4; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = com.mutinywallet.mutiny; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -387,7 +387,7 @@ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance"; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 1.6.3; + MARKETING_VERSION = 1.6.4; PRODUCT_BUNDLE_IDENTIFIER = com.mutinywallet.mutiny; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/justfile b/justfile index 70615194..efb2462f 100644 --- a/justfile +++ b/justfile @@ -20,3 +20,9 @@ test: test-ui: pnpm exec playwright test --ui + +mainnet: + cp .env.mainnet .env.local + +signet: + cp .env.signet .env.local diff --git a/package.json b/package.json index efb02a13..190083d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mutiny-wallet", - "version": "0.6.3", + "version": "0.6.4", "license": "MIT", "packageManager": "pnpm@8.6.6", "scripts": { @@ -54,7 +54,7 @@ "@capacitor/toast": "^5.0.6", "@kobalte/core": "^0.12.6", "@kobalte/tailwindcss": "^0.9.0", - "@mutinywallet/mutiny-wasm": "0.6.3", + "@mutinywallet/mutiny-wasm": "0.6.4", "@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 f3353e32..edf1ce95 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.3 - version: 0.6.3 + specifier: 0.6.4 + version: 0.6.4 '@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.3: - resolution: {integrity: sha512-mHcOoawa2HyYL1ssA0aOGN1IUVFmitiioe6XiwQiBPFtW3vE7Zg824xBZYPKnlf4jqdK1MSyRGaFoSPfe5QqCQ==} + /@mutinywallet/mutiny-wasm@0.6.4: + resolution: {integrity: sha512-fwHLZDdCAMkMv2sqipZ+77GZb2frNWUxeVpKDzUUvY42tf4hQtoWxGA6e7eo3tesD+NcdlDQojPilXWTAHBVOQ==} dev: false /@nodelib/fs.scandir@2.1.5: @@ -7567,7 +7567,6 @@ packages: /workbox-google-analytics@7.0.0: resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==} - deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained dependencies: workbox-background-sync: 7.0.0 workbox-core: 7.0.0 diff --git a/public/i18n/en.json b/public/i18n/en.json index c3ee1abf..1b2305a4 100644 --- a/public/i18n/en.json +++ b/public/i18n/en.json @@ -548,16 +548,20 @@ "federation_added_success": "Federation added successfully", "federation_remove_confirm": "Are you sure you want to remove this federation? Make sure any funds you have are transferred to your lightning balance or another wallet first.", "add": "Add", - "remove": "Remove", + "remove": "Leave federation", "expires": "Expires", "federation_id": "Federation ID", - "description": "Mutiny has experimental support for the Fedimint protocol. Store funds in a federation at your own risk!", - "learn_more": "Learn more about Fedimint.", + "description": "Federations are bitcoin-based networks that make it cheaper, quicker, and easier to use bitcoin.", + "learn_more": "Learn more", "discover": "Discover Federations", "manual": "Invite Code", "created_at": "Created At", "recommended_by": "Recommended By", - "already_in_fed": "You're already in a federation!" + "already_in_fed": "You're already in a federation!", + "descriptionpart2": "Each one is ran by a group of different inviduals or companies. Discover one that you or your friends might trust below.", + "join_me": "Join me", + "recommend": "Recommend federation", + "recommended_by_you": "Recommended by you" }, "gift": { "give_sats_link": "Give sats as a gift", @@ -743,13 +747,18 @@ }, "setup": { "new_profile": { - "description": "Mutiny makes payments social." + "description": "Mutiny makes payments social.", + "title": "Create your profile" }, "skip": "Skip for now", "import_profile": "Import existing nostr profile", "import": { "title": "Import nostr profile", "description": "Login with an existing nostr account." + }, + "federation": { + "pick": "Pick a federation", + "skip_confirm": "You'll need to pay chain and channel fees to use Mutiny, and miss out on advanced features such as lightning address. You can change your mind later in the settings." } } } diff --git a/public/i18n/es.json b/public/i18n/es.json index 25e4e417..05e39539 100644 --- a/public/i18n/es.json +++ b/public/i18n/es.json @@ -495,8 +495,8 @@ "remove": "Eliminar", "expires": "Expira", "federation_id": "ID federación", - "description": "Mutiny tiene soporte experimental para el protocolo Fedimint. ¡Almacene fondos en una federación bajo su propio riesgo!", - "learn_more": "Aprenda más sobre Fedimint.", + "description": "", + "learn_more": "Aprenda más", "created_at": "Creado En", "recommended_by": "Recomendado por" }, diff --git a/src/components/Activity.tsx b/src/components/Activity.tsx index 8f644638..d0b9d313 100644 --- a/src/components/Activity.tsx +++ b/src/components/Activity.tsx @@ -1,7 +1,17 @@ import { TagItem } from "@mutinywallet/mutiny-wasm"; -import { cache, createAsync, revalidate, useNavigate } from "@solidjs/router"; +import { cache, createAsync, useNavigate } from "@solidjs/router"; import { Plus, Save, Search, Shuffle, Users } from "lucide-solid"; -import { createEffect, createSignal, For, Match, Show, Switch } from "solid-js"; +import { + createEffect, + createMemo, + createResource, + createSignal, + For, + Match, + Show, + Suspense, + Switch +} from "solid-js"; import { ActivityDetailsModal, @@ -16,6 +26,7 @@ import { PrivacyLevel } from "~/routes"; import { useMegaStore } from "~/state/megaStore"; import { actuallyFetchNostrProfile, + createDeepSignal, hexpubFromNpub, profileToPseudoContact, PseudoContact, @@ -41,6 +52,21 @@ export interface IActivityItem { privacy_level: PrivacyLevel; } +async function fetchContactForNpub( + npub: string +): Promise { + const hexpub = await hexpubFromNpub(npub); + if (!hexpub) { + return undefined; + } + const profile = await actuallyFetchNostrProfile(hexpub); + if (!profile) { + return undefined; + } + const pseudoContact = profileToPseudoContact(profile); + return pseudoContact; +} + export function UnifiedActivityItem(props: { item: IActivityItem; onClick: (id: string, kind: HackActivityType) => void; @@ -55,12 +81,16 @@ export function UnifiedActivityItem(props: { ); }; - const primaryContact = () => { + const primaryContact = createMemo(() => { if (props.item.contacts.length === 0) { return undefined; } return props.item.contacts[0]; - }; + }); + + const getContact = cache(async (npub) => { + return await fetchContactForNpub(npub); + }, "profile"); const profileFromNostr = createAsync(async () => { if (props.item.contacts.length === 0) { @@ -69,17 +99,10 @@ export function UnifiedActivityItem(props: { l.startsWith("npub") ); if (npub) { + await new Promise((r) => setTimeout(r, 1000)); try { - const hexpub = await hexpubFromNpub(npub); - if (!hexpub) { - return undefined; - } - const profile = await actuallyFetchNostrProfile(hexpub); - if (!profile) { - return undefined; - } - const pseudoContact = profileToPseudoContact(profile); - return pseudoContact; + const newContact = await getContact(npub); + return newContact; } catch (e) { console.error(e); } @@ -164,43 +187,70 @@ export function UnifiedActivityItem(props: { return (
- : undefined} - primaryOnClick={() => - primaryContact()?.id - ? navigate(`/chat/${primaryContact()?.id}`) - : profileFromNostr() - ? props.onNewContactClick(profileFromNostr()!) - : undefined - } - amountOnClick={click} - primaryName={ - props.item.inbound - ? primaryContact()?.name - ? primaryContact()!.name - : profileFromNostr()?.name || "Unknown" - : "You" - } - genericAvatar={shouldShowGeneric()} - verb={verb()} - message={message()} - secondaryName={secondaryName()} - amount={ - props.item.amount_sats - ? BigInt(props.item.amount_sats || 0) - : undefined - } - date={timeAgo(props.item.last_updated)} - accent={props.item.inbound ? "green" : undefined} - visibility={ - props.item.privacy_level === "Public" ? "public" : "private" + } - /> + > + : undefined} + primaryOnClick={() => + primaryContact()?.id + ? navigate(`/chat/${primaryContact()?.id}`) + : profileFromNostr() + ? props.onNewContactClick(profileFromNostr()!) + : undefined + } + amountOnClick={click} + primaryName={ + props.item.inbound + ? primaryContact()?.name + ? primaryContact()!.name + : profileFromNostr()?.name || "Unknown" + : "You" + } + genericAvatar={shouldShowGeneric()} + verb={verb()} + message={message()} + secondaryName={secondaryName()} + amount={ + props.item.amount_sats + ? BigInt(props.item.amount_sats || 0) + : undefined + } + date={timeAgo(props.item.last_updated)} + accent={props.item.inbound ? "green" : undefined} + visibility={ + props.item.privacy_level === "Public" + ? "public" + : "private" + } + /> +
); } @@ -295,26 +345,32 @@ export function CombinedActivity() { setDetailsOpen(true); } - const getActivity = cache(async () => { + async function getActivity() { try { console.log("refetching activity"); const activity = await state.mutiny_wallet?.get_activity( 50, undefined ); - return (activity || []) as IActivityItem[]; + + if (!activity) return []; + + return activity as IActivityItem[]; } catch (e) { console.error(e); return [] as IActivityItem[]; } - }, "activity"); + } - const activity = createAsync(() => getActivity(), { initialValue: [] }); + const [activity, { refetch }] = createResource(getActivity, { + initialValue: [], + storage: createDeepSignal + }); createEffect(() => { // Should re-run after every sync if (!state.is_syncing) { - revalidate("activity"); + refetch(); } }); @@ -337,7 +393,7 @@ export function CombinedActivity() { /> - + navigate("/settings/federations")} @@ -371,7 +427,7 @@ export function CombinedActivity() { - = 0}> + = 0}> navigate("/settings/backup")} @@ -383,7 +439,7 @@ export function CombinedActivity() {
- + {(activityItem) => ( +
+ + +
{" "} + { + setShowQr(open); + }} + title={i18n.t("settings.manage_federations.join_me")} + > + +

+ {props.name} +

+
+
+ +
+
+ + ); +} diff --git a/src/components/ImportNsecForm.tsx b/src/components/ImportNsecForm.tsx index c2a4da4c..45a60e11 100644 --- a/src/components/ImportNsecForm.tsx +++ b/src/components/ImportNsecForm.tsx @@ -1,10 +1,14 @@ import { MutinyWallet } from "@mutinywallet/mutiny-wasm"; +import { useNavigate } from "@solidjs/router"; import { SecureStoragePlugin } from "capacitor-secure-storage-plugin"; import { createSignal, Show } from "solid-js"; import { Button, InfoBox, SimpleInput } from "~/components"; +import { useMegaStore } from "~/state/megaStore"; -export function ImportNsecForm() { +export function ImportNsecForm(props: { setup?: boolean }) { + const [state, _actions] = useMegaStore(); + const navigate = useNavigate(); const [nsec, setNsec] = createSignal(""); const [saving, setSaving] = createSignal(false); const [error, setError] = createSignal(); @@ -19,8 +23,17 @@ export function ImportNsecForm() { throw new Error("Invalid nsec"); } await SecureStoragePlugin.set({ key: "nsec", value: trimmedNsec }); - // TODO: right now we need a reload to set the nsec - window.location.href = "/"; + + const new_npub = await state.mutiny_wallet?.change_nostr_keys( + trimmedNsec, + undefined + ); + console.log("Changed to new npub: ", new_npub); + if (props.setup) { + navigate("/addfederation"); + } else { + navigate("/"); + } } catch (e) { console.error(e); setError("Invalid nsec"); diff --git a/src/components/ReceiveWarnings.tsx b/src/components/ReceiveWarnings.tsx index 746051f1..3ba75d40 100644 --- a/src/components/ReceiveWarnings.tsx +++ b/src/components/ReceiveWarnings.tsx @@ -32,7 +32,10 @@ export function ReceiveWarnings(props: { if (state.federations?.length !== 0 && props.from_fedi_to_ln !== true) { return undefined; } - if ((state.balance?.lightning || 0n) === 0n) { + if ( + (state.balance?.lightning || 0n) === 0n && + !state.settings?.lsps_connection_string + ) { return i18n.t("receive.amount_editable.receive_too_small", { amount: "100,000" }); diff --git a/src/components/index.ts b/src/components/index.ts index ab5ed260..b2c9e40e 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -57,3 +57,4 @@ export * from "./HomeBalance"; export * from "./EditProfileForm"; export * from "./ImportNsecForm"; export * from "./LightningAddressShower"; +export * from "./FederationInviteShower"; diff --git a/src/components/layout/Button.tsx b/src/components/layout/Button.tsx index c9627ba4..c7ffb213 100644 --- a/src/components/layout/Button.tsx +++ b/src/components/layout/Button.tsx @@ -32,8 +32,10 @@ export const Button: ParentComponent = (props) => { + ); +} diff --git a/src/components/layout/index.ts b/src/components/layout/index.ts index 739257d4..55d58f7a 100644 --- a/src/components/layout/index.ts +++ b/src/components/layout/index.ts @@ -6,3 +6,4 @@ export * from "./Radio"; export * from "./TextField"; export * from "./ExternalLink"; export * from "./LoadingSpinner"; +export * from "./SubtleButton"; diff --git a/src/logic/errorDispatch.ts b/src/logic/errorDispatch.ts index f9002cdc..e8eae7ae 100644 --- a/src/logic/errorDispatch.ts +++ b/src/logic/errorDispatch.ts @@ -44,6 +44,7 @@ type MutinyError = | "Failed to read or write json from the front end" | "The given node pubkey is invalid." | "Failed to get nostr data." + | "Error with NIP-07 extension" | "Failed to get the bitcoin price." | "Satoshi amount is invalid" | "Failed to execute a dlc function" @@ -54,6 +55,11 @@ type MutinyError = | "Failed to create payjoin request." | "Payjoin response error: {0}" | "Payjoin configuration failed." + | "Error calling Cashu Mint" + | "Mint URL in token is empty" + | "Token has been already spent." + | "A federation is required" + | "Failed to connect to a federation." | "Unknown Error"; export function matchError(e: unknown): Error { diff --git a/src/logic/mutinyWalletSetup.ts b/src/logic/mutinyWalletSetup.ts index 079cf7ab..c9c76675 100644 --- a/src/logic/mutinyWalletSetup.ts +++ b/src/logic/mutinyWalletSetup.ts @@ -321,7 +321,7 @@ export async function setupMutinyWallet( network, esplora, rgs, - lsp, + shouldUseLSPS ? undefined : lsp, shouldUseLSPS ? lsps_connection_string : undefined, shouldUseLSPS ? lsps_token : undefined, auth, diff --git a/src/router.tsx b/src/router.tsx index 2adeb60e..1c78239f 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -54,7 +54,13 @@ import { Servers, Settings } from "~/routes/settings"; -import { ImportProfile, NewProfile, Setup, SetupRestore } from "~/routes/setup"; +import { + AddFederation, + ImportProfile, + NewProfile, + Setup, + SetupRestore +} from "~/routes/setup"; import { Provider as MegaStoreProvider, useMegaStore } from "~/state/megaStore"; function GlobalListeners() { @@ -159,6 +165,7 @@ export function Router() { + diff --git a/src/routes/Chat.tsx b/src/routes/Chat.tsx index 1af48816..aab1b87a 100644 --- a/src/routes/Chat.tsx +++ b/src/routes/Chat.tsx @@ -76,9 +76,20 @@ function SingleMessage(props: { const parsed = createAsync( async () => { - const result = toParsedParams(props.dm.message, network); + let result = undefined; + + // Look for a long word that might be an invoice + const split_message_by_whitespace = props.dm.message.split(/\s+/g); + for (const word of split_message_by_whitespace) { + if (word.length > 15) { + result = toParsedParams(word, network); + if (result.ok) { + break; + } + } + } - if (!result.ok) { + if (!result || !result.ok) { return undefined; } @@ -92,6 +103,10 @@ function SingleMessage(props: { return { type: "invoice", status: "paid", + message_without_invoice: props.dm.message.replace( + result.value.original, + "" + ), value: result.value.invoice, amount: result.value.amount_sats }; @@ -103,6 +118,10 @@ function SingleMessage(props: { return { type: "invoice", status: "unpaid", + message_without_invoice: props.dm.message.replace( + result.value.original, + "" + ), from: props.dm.from, value: result.value.invoice, amount: result.value.amount_sats @@ -130,9 +149,9 @@ function SingleMessage(props: { navWithContactId(); } - function handlePay() { + function handlePay(invoice: string) { actions.handleIncomingString( - props.dm.message, + invoice, (error) => { showToast(error); }, @@ -153,6 +172,11 @@ function SingleMessage(props: {
+ +

+ {parsed()?.message_without_invoice} +

+
Lightning Invoice @@ -167,7 +191,7 @@ function SingleMessage(props: { @@ -179,7 +203,9 @@ function SingleMessage(props: {
-

{props.dm.message}

+

+ {props.dm.message} +

- - - + + + + + - {/* FIXME: do something smarter than just taking first code */} - + + + )} @@ -296,12 +340,13 @@ function AddFederationForm(props: { refetch?: RefetchType }) {
- + ); } function RecommendButton(props: { fed: MutinyFederationIdentity }) { const [state] = useMegaStore(); + const i18n = useI18n(); const [recommendLoading, setRecommendLoading] = createSignal(false); // This is just some local state that makes it feel like they've recommended it // even if they aren't a "real person" @@ -335,22 +380,46 @@ function RecommendButton(props: { fed: MutinyFederationIdentity }) { setRecommendLoading(false); } + async function deleteRecommendation() { + setRecommendLoading(true); + try { + await state.mutiny_wallet?.delete_federation_recommendation( + props.fed.federation_id + ); + setRecommended(false); + refetch(); + } catch (e) { + console.error("Error deleting federation recommendation: ", e); + } + setRecommendLoading(false); + } + return ( -

- - Recommended by you -

+
+
+ + {i18n.t( + "settings.manage_federations.recommended_by_you" + )} +
+ + + +
- + + {i18n.t("settings.manage_federations.recommend")} +
); @@ -422,18 +491,19 @@ function FederationListItem(props: { > + + + -
- -
- + {" "} - {/* */} {i18n.t("settings.manage_federations.title")} {i18n.t("settings.manage_federations.description")}{" "} + + {i18n.t("settings.manage_federations.descriptionpart2")}{" "} + + + + {i18n.t("settings.manage_federations.learn_more")} + + @@ -535,6 +612,11 @@ export function ManageFederations() { + + + + + diff --git a/src/routes/setup/AddFederation.tsx b/src/routes/setup/AddFederation.tsx new file mode 100644 index 00000000..20867ae3 --- /dev/null +++ b/src/routes/setup/AddFederation.tsx @@ -0,0 +1,63 @@ +import { useNavigate } from "@solidjs/router"; +import { createSignal, Suspense } from "solid-js"; + +import { + Button, + ConfirmDialog, + DefaultMain, + ExternalLink, + MutinyWalletGuard, + VStack +} from "~/components"; +import { useI18n } from "~/i18n/context"; + +import { AddFederationForm } from "../settings"; + +export function AddFederation() { + const i18n = useI18n(); + const navigate = useNavigate(); + + const [confirmOpen, setConfirmOpen] = createSignal(false); + + async function handleSkip() { + navigate("/"); + } + + return ( + + +
+

+ {i18n.t("setup.federation.pick")} +

+

+ {i18n.t("settings.manage_federations.description")} +

+

+ {i18n.t("settings.manage_federations.descriptionpart2")} +

+ + + setConfirmOpen(false)} + > + {i18n.t("setup.federation.skip_confirm")} + + + + +

+ + {i18n.t("settings.manage_federations.learn_more")} + +

+
+
+
+ ); +} diff --git a/src/routes/setup/NewProfile.tsx b/src/routes/setup/NewProfile.tsx index 3850ec7c..dfdec0fd 100644 --- a/src/routes/setup/NewProfile.tsx +++ b/src/routes/setup/NewProfile.tsx @@ -23,7 +23,7 @@ export function NewProfile() { async function handleSkip() { setSkipping(true); // set up an empty profile so we at least have some kind0 event - const profile = await state.mutiny_wallet?.edit_nostr_profile( + const profile = await state.mutiny_wallet?.setup_new_profile( DEFAULT_NOSTR_NAME, undefined, undefined, @@ -31,22 +31,22 @@ export function NewProfile() { ); console.log("profile", profile); localStorage.setItem("profile_setup_stage", "skipped"); - navigate("/"); + navigate("/addfederation"); setSkipping(false); } async function createProfile(p: EditableProfile) { setCreating(true); try { - const profile = await state.mutiny_wallet?.edit_nostr_profile( - p.nym ? p.nym : undefined, + const profile = await state.mutiny_wallet?.setup_new_profile( + p.nym ? p.nym : DEFAULT_NOSTR_NAME, p.imageUrl ? p.imageUrl : undefined, p.lightningAddress ? p.lightningAddress : undefined, undefined ); console.log("profile", profile); localStorage.setItem("profile_setup_stage", "saved"); - navigate("/"); + navigate("/addfederation"); } catch (e) { console.error(e); } @@ -57,7 +57,9 @@ export function NewProfile() {
-

Create your profile

+

+ {i18n.t("setup.new_profile.title")} +

{i18n.t("setup.new_profile.description")}

diff --git a/src/routes/setup/index.ts b/src/routes/setup/index.ts index 577594d3..81866c13 100644 --- a/src/routes/setup/index.ts +++ b/src/routes/setup/index.ts @@ -2,3 +2,4 @@ export * from "./Restore"; export * from "./ImportProfile"; export * from "./NewProfile"; export * from "./Root"; +export * from "./AddFederation"; diff --git a/src/state/megaStore.tsx b/src/state/megaStore.tsx index 8c441266..0d7dda32 100644 --- a/src/state/megaStore.tsx +++ b/src/state/megaStore.tsx @@ -22,6 +22,7 @@ import { getSettings, initializeWasm, MutinyWalletSettingStrings, + setSettings, setupMutinyWallet } from "~/logic/mutinyWalletSetup"; import { ParsedParams, toParsedParams } from "~/logic/waila"; @@ -194,6 +195,15 @@ export const Provider: ParentComponent = (props) => { const settings = await getSettings(); setState({ load_stage: "setup" }); + // handle lsp settings + if (searchParams.lsps) { + settings.lsp = ""; + settings.lsps_connection_string = searchParams.lsps; + settings.lsps_token = searchParams.token; + + await setSettings(settings); + } + const mutinyWallet = await setupMutinyWallet( settings, password, @@ -509,6 +519,8 @@ export const Provider: ParentComponent = (props) => { }; } + const [params, _] = useSearchParams(); + onMount(async () => { await checkForExistingTab(); if (state.existing_tab_detected) { @@ -528,7 +540,7 @@ export const Provider: ParentComponent = (props) => { setState({ load_stage: "checking_for_existing_wallet" }); const existing = await MutinyWallet.has_node_manager(); - if (!existing) { + if (!existing && !params.skip_setup) { navigate("/setup"); return; }