diff --git a/e2e/routes.spec.ts b/e2e/routes.spec.ts
index dc4ba7d..e9a9bbe 100644
--- a/e2e/routes.spec.ts
+++ b/e2e/routes.spec.ts
@@ -25,8 +25,8 @@ const settingsRoutes = [
"/plus",
"/restore",
"/servers",
- "/syncnostrcontacts"
- "/managefederations"
+ "/syncnostrcontacts",
+ "/federations"
];
const settingsRoutesPrefixed = settingsRoutes.map((route) => {
@@ -128,7 +128,7 @@ test("visit each route", async ({ page }) => {
// Manage Federations
await checkRoute(
page,
- "/settings/managefederations",
+ "/settings/federations",
"Manage Federations",
checklist
);
diff --git a/src/components/AmountEditable.tsx b/src/components/AmountEditable.tsx
index 2d3b255..d5d0b8f 100644
--- a/src/components/AmountEditable.tsx
+++ b/src/components/AmountEditable.tsx
@@ -19,7 +19,6 @@ import currencySwap from "~/assets/icons/currency-swap.svg";
import pencil from "~/assets/icons/pencil.svg";
import { Button, FeesModal, InfoBox, InlineAmount, VStack } from "~/components";
import { useI18n } from "~/i18n/context";
-import { Network } from "~/logic/mutinyWalletSetup";
import { useMegaStore } from "~/state/megaStore";
import { DIALOG_CONTENT, DIALOG_POSITIONER } from "~/styles/dialogs";
import { Currency, fiatToSats, satsToFiat } from "~/utils";
@@ -404,17 +403,13 @@ export const AmountEditable: ParentComponent<{
});
const warningText = () => {
+ if (state.federations?.length !== 0) {
+ return undefined;
+ }
if ((state.balance?.lightning || 0n) === 0n) {
- const network = state.mutiny_wallet?.get_network() as Network;
- if (network === "bitcoin") {
- return i18n.t("receive.amount_editable.receive_too_small", {
- amount: "100,000"
- });
- } else {
- return i18n.t("receive.amount_editable.receive_too_small", {
- amount: "10,000"
- });
- }
+ return i18n.t("receive.amount_editable.receive_too_small", {
+ amount: "100,000"
+ });
}
const parsed = Number(localSats());
diff --git a/src/components/BalanceBox.tsx b/src/components/BalanceBox.tsx
index 98fefec..5ad7678 100644
--- a/src/components/BalanceBox.tsx
+++ b/src/components/BalanceBox.tsx
@@ -1,5 +1,5 @@
import { A, useNavigate } from "@solidjs/router";
-import { createResource, Match, Show, Suspense, Switch } from "solid-js";
+import { Match, Show, Switch } from "solid-js";
import shuffle from "~/assets/icons/shuffle.svg";
import {
@@ -91,10 +91,25 @@ export function BalanceBox(props: { loading?: boolean }) {
-
-
-
-
+
+ }>
+
+
+
}>
@@ -157,39 +172,3 @@ export function BalanceBox(props: { loading?: boolean }) {
>
);
}
-
-function FederationsBalance() {
- const [state, _actions] = useMegaStore();
-
- async function fetchFederations() {
- const result = await state.mutiny_wallet?.list_federations();
- return result ?? [];
- }
-
- const [federations] = createResource(fetchFederations);
-
- return (
-
-
-
-
-
-
-
-
- );
-}
diff --git a/src/i18n/en/translations.ts b/src/i18n/en/translations.ts
index c95507a..dc88887 100644
--- a/src/i18n/en/translations.ts
+++ b/src/i18n/en/translations.ts
@@ -538,10 +538,15 @@ export default {
federation_code_label: "Federation code",
federation_code_required: "Federation code can't be blank",
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",
expires: "Expires",
- federation_id: "Federation ID"
+ federation_id: "Federation ID",
+ description:
+ "Mutiny has experimental support for the Fedimint protocol. You'll need a federation invite code to use this feature. These funds are currently not backed up remotely. Store funds in a federation at your own risk!",
+ learn_more: "Learn more about Fedimint."
},
gift: {
give_sats_link: "Give sats as a gift",
diff --git a/src/router.tsx b/src/router.tsx
index ca2fa5e..9c997e9 100644
--- a/src/router.tsx
+++ b/src/router.tsx
@@ -26,12 +26,12 @@ import {
EmergencyKit,
Encrypt,
Gift,
+ ManageFederations,
Plus,
Restore,
Servers,
Settings,
- SyncNostrContacts,
- ManageFederations
+ SyncNostrContacts
} from "~/routes/settings";
import { useMegaStore } from "./state/megaStore";
@@ -119,7 +119,10 @@ export function Router() {
path="/syncnostrcontacts"
component={SyncNostrContacts}
/>
-
+
diff --git a/src/routes/settings/ManageFederations.tsx b/src/routes/settings/ManageFederations.tsx
index e96022b..ce1658e 100644
--- a/src/routes/settings/ManageFederations.tsx
+++ b/src/routes/settings/ManageFederations.tsx
@@ -1,10 +1,17 @@
-import { createForm, required, SubmitHandler } from "@modular-forms/solid";
-import { createResource, createSignal, For, Show } from "solid-js";
+import {
+ createForm,
+ required,
+ reset,
+ SubmitHandler
+} from "@modular-forms/solid";
+import { createSignal, For, Show } from "solid-js";
import {
BackLink,
Button,
+ ConfirmDialog,
DefaultMain,
+ ExternalLink,
FancyCard,
InfoBox,
KeyValue,
@@ -12,6 +19,7 @@ import {
MiniStringShower,
MutinyWalletGuard,
NavBar,
+ NiceP,
SafeArea,
TextField,
VStack
@@ -24,16 +32,16 @@ type FederationForm = {
federation_code: string;
};
-type MutinyFederationIdentity = {
+export type MutinyFederationIdentity = {
federation_id: string;
federation_name: string;
welcome_message: string;
federation_expiry_timestamp: number;
};
-function AddFederationForm(props: { refetch: () => void }) {
+function AddFederationForm() {
const i18n = useI18n();
- const [state, _actions] = useMegaStore();
+ const [state, actions] = useMegaStore();
const [error, setError] = createSignal();
const [success, setSuccess] = createSignal("");
@@ -56,7 +64,8 @@ function AddFederationForm(props: { refetch: () => void }) {
setSuccess(
i18n.t("settings.manage_federations.federation_added_success")
);
- await props.refetch();
+ await actions.refreshFederations();
+ reset(feedbackForm);
} catch (e) {
console.error("Error submitting federation:", e);
setError(eify(e));
@@ -89,90 +98,89 @@ function AddFederationForm(props: { refetch: () => void }) {
/>
)}
-
- {error()?.message}
-
-
- {success()}
-
+
+ {error()?.message}
+
+
+ {success()}
+
);
}
-function ListAndRemoveFederations(props: {
- federations?: MutinyFederationIdentity[];
- refetch: () => void;
-}) {
+function FederationListItem(props: { fed: MutinyFederationIdentity }) {
const i18n = useI18n();
- const [state, _actions] = useMegaStore();
- const [error, setError] = createSignal();
+ const [state, actions] = useMegaStore();
- const removeFederation = async (federationId: string) => {
+ async function removeFederation() {
+ setConfirmLoading(true);
try {
- await state.mutiny_wallet?.remove_federation(federationId);
- props.refetch();
+ await state.mutiny_wallet?.remove_federation(
+ props.fed.federation_id
+ );
+ await actions.refreshFederations();
} catch (e) {
console.error(e);
- setError(eify(e));
}
- };
+ setConfirmLoading(false);
+ }
+
+ async function confirmRemove() {
+ setConfirmOpen(true);
+ }
+
+ const [confirmOpen, setConfirmOpen] = createSignal(false);
+ const [confirmLoading, setConfirmLoading] = createSignal(false);
return (
-
-
- {(fed) => (
-
-
-
- {fed.federation_name}
-
-
-
- {fed.welcome_message}
-
-
-
-
-
-
-
-
-
-
-
+ <>
+
+
+
+ {props.fed.federation_name}
+
+
+
+ {props.fed.welcome_message}
+
+
+
+
+
+
+
+
+
+
+
+ setConfirmOpen(false)}
+ >
+ {i18n.t(
+ "settings.manage_federations.federation_remove_confirm"
)}
-
-
- No federations available.
-
-
- {error()?.message}
-
-
+
+ >
);
}
@@ -180,19 +188,6 @@ export function ManageFederations() {
const i18n = useI18n();
const [state, _actions] = useMegaStore();
- async function fetchFederations() {
- try {
- const result =
- (await state.mutiny_wallet?.list_federations()) as MutinyFederationIdentity[];
- return result ?? [];
- } catch (e) {
- console.error(e);
- return [];
- }
- }
-
- const [federations, { refetch }] = createResource(fetchFederations);
-
return (
@@ -204,11 +199,18 @@ export function ManageFederations() {
{i18n.t("settings.manage_federations.title")}
-
-
+
+ {i18n.t("settings.manage_federations.description")}{" "}
+
+ {i18n.t("settings.manage_federations.learn_more")}
+
+
+
+
+
+ {(fed) => }
+
+
diff --git a/src/routes/settings/Root.tsx b/src/routes/settings/Root.tsx
index c45c37a..ee14177 100644
--- a/src/routes/settings/Root.tsx
+++ b/src/routes/settings/Root.tsx
@@ -153,7 +153,7 @@ export function Settings() {
text: "Sync Nostr Contacts"
},
{
- href: "/settings/managefederations",
+ href: "/settings/federations",
text: "Manage Federations"
}
]}
diff --git a/src/state/megaStore.tsx b/src/state/megaStore.tsx
index 5275d20..429d3ea 100644
--- a/src/state/megaStore.tsx
+++ b/src/state/megaStore.tsx
@@ -25,6 +25,7 @@ import {
setupMutinyWallet
} from "~/logic/mutinyWalletSetup";
import { ParsedParams, toParsedParams } from "~/logic/waila";
+import { MutinyFederationIdentity } from "~/routes/settings";
import {
BTC_OPTION,
Currency,
@@ -70,6 +71,7 @@ export type MegaStore = [
betaWarned: boolean;
testflightPromptDismissed: boolean;
should_zap_hodl: boolean;
+ federations?: MutinyFederationIdentity[];
},
{
setup(password?: string): Promise;
@@ -94,6 +96,7 @@ export type MegaStore = [
setTestFlightPromptDismissed(): void;
toggleHodl(): void;
dropMutinyWallet(): void;
+ refreshFederations(): Promise;
}
];
@@ -134,7 +137,8 @@ export const Provider: ParentComponent = (props) => {
betaWarned: localStorage.getItem("betaWarned") === "true",
should_zap_hodl: localStorage.getItem("should_zap_hodl") === "true",
testflightPromptDismissed:
- localStorage.getItem("testflightPromptDismissed") === "true"
+ localStorage.getItem("testflightPromptDismissed") === "true",
+ federations: undefined as MutinyFederationIdentity[] | undefined
});
const actions = {
@@ -211,11 +215,16 @@ export const Provider: ParentComponent = (props) => {
// Get balance
const balance = await mutinyWallet.get_balance();
+ // Get federations
+ const federations =
+ (await mutinyWallet.list_federations()) as MutinyFederationIdentity[];
+
setState({
mutiny_wallet: mutinyWallet,
wallet_loading: false,
load_stage: "done",
- balance
+ balance,
+ federations
});
} catch (e) {
console.error(e);
@@ -408,6 +417,11 @@ export const Provider: ParentComponent = (props) => {
},
dropMutinyWallet() {
setState({ mutiny_wallet: undefined });
+ },
+ async refreshFederations() {
+ const federations =
+ (await state.mutiny_wallet?.list_federations()) as MutinyFederationIdentity[];
+ setState({ federations });
}
};