diff --git a/public/i18n/en.json b/public/i18n/en.json index fb1b2d88..656e853d 100644 --- a/public/i18n/en.json +++ b/public/i18n/en.json @@ -540,8 +540,10 @@ "remove": "Remove", "expires": "Expires", "federation_id": "Federation ID", - "description": "Mutiny has experimental support for the Fedimint protocol. You'll need a federation invite code to use this feature. Store funds in a federation at your own risk!", - "learn_more": "Learn more about Fedimint." + "description": "Mutiny has experimental support for the Fedimint protocol. Store funds in a federation at your own risk!", + "learn_more": "Learn more about Fedimint.", + "discover": "Discover Federations", + "manual": "Invite Code" }, "gift": { "give_sats_link": "Give sats as a gift", diff --git a/public/i18n/es.json b/public/i18n/es.json index 5b38e39c..037f948e 100644 --- a/public/i18n/es.json +++ b/public/i18n/es.json @@ -495,7 +495,7 @@ "remove": "Eliminar", "expires": "Expira", "federation_id": "ID federación", - "description": "Mutiny tiene soporte experimental para el protocolo Fedimint. Necesitará un código de invitación a la federación para poder usar esta funcionalidad ¡Almacene fondos en una federación bajo su propio riesgo!", + "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." }, "gift": { diff --git a/src/components/BalanceBox.tsx b/src/components/BalanceBox.tsx index 608b4e9e..c714974d 100644 --- a/src/components/BalanceBox.tsx +++ b/src/components/BalanceBox.tsx @@ -63,55 +63,46 @@ export function BalanceBox(props: { loading?: boolean; small?: boolean }) { -
- Fedimint - - } - > -
-
-
- -
-
- -
+ Fedimint + + } + > +
+
+
+ +
+
+
- - 0n - } - > -
- - - -
-
- - -
+ + 0n} + > +
+ + + +
+
+
+ + navigate("/settings/federations")} > @@ -132,80 +123,78 @@ export function BalanceBox(props: { loading?: boolean; small?: boolean }) { -
- {i18n.t("profile.self_custody")} - - }> - - -
- - {i18n.t("common.error_safe_mode")} - -
-
- -
-
- -
-
- -
-
-
-
-
-
- }> -
+ {i18n.t("profile.self_custody")} + + }> + + +
+ + {i18n.t("common.error_safe_mode")} + +
+
+
-
- - - {i18n.t("common.pending")} - - - -
- - 0n}> -
- - - -
-
+ + + +
+ }> +
+
+
+ +
+
+
- - -
+
+ + + {i18n.t("common.pending")} + + + +
+ + 0n}> +
+ + + +
+
+
+
+
+ ); } diff --git a/src/components/layout/Misc.tsx b/src/components/layout/Misc.tsx index 101c2545..716818be 100644 --- a/src/components/layout/Misc.tsx +++ b/src/components/layout/Misc.tsx @@ -78,9 +78,11 @@ export const FancyCard: ParentComponent<{ }> = (props) => { return ( -
- {props.title} -
+ +
+ {props.title} +
+
{props.children}
diff --git a/src/routes/Profile.tsx b/src/routes/Profile.tsx index ba1b367f..4b7fb722 100644 --- a/src/routes/Profile.tsx +++ b/src/routes/Profile.tsx @@ -103,17 +103,6 @@ export function Profile() {
- {/*
- {i18n.t("profile.social")} - - - - - - - - -
*/} navigate("/editprofile")}>
{/* */} @@ -122,7 +111,6 @@ export function Profile() {
- diff --git a/src/routes/settings/ManageFederations.tsx b/src/routes/settings/ManageFederations.tsx index d1510f2b..cb912328 100644 --- a/src/routes/settings/ManageFederations.tsx +++ b/src/routes/settings/ManageFederations.tsx @@ -5,7 +5,7 @@ import { setValue, SubmitHandler } from "@modular-forms/solid"; -import { FederationBalance } from "@mutinywallet/mutiny-wasm"; +import { FederationBalance, TagItem } from "@mutinywallet/mutiny-wasm"; import { A, useSearchParams } from "@solidjs/router"; import { Scan } from "lucide-solid"; import { @@ -30,7 +30,10 @@ import { FancyCard, InfoBox, KeyValue, + LabelCircle, LargeHeader, + LoadingSpinner, + MediumHeader, MiniStringShower, MutinyWalletGuard, NavBar, @@ -54,6 +57,22 @@ export type MutinyFederationIdentity = { invite_code: string; }; +export type Metadata = { + name: string; + picture?: string; + about?: string; +}; + +export type DiscoveredFederation = { + id: string; + invite_codes: string[]; + pubkey: string; + created_at: number; + event_id: string; + metadata: Metadata | undefined; + recommendations: TagItem[]; // fixme, not the best type to use here +}; + type RefetchType = ( info?: unknown ) => @@ -68,6 +87,8 @@ function AddFederationForm(props: { refetch?: RefetchType }) { const [error, setError] = createSignal(); const [success, setSuccess] = createSignal(""); + const [loadingFederation, setLoadingFederation] = createSignal(""); + const [params, setParams] = useSearchParams(); onMount(() => { @@ -88,12 +109,28 @@ function AddFederationForm(props: { refetch?: RefetchType }) { const handleSubmit: SubmitHandler = async ( f: FederationForm ) => { + const federation_code = f.federation_code.trim(); + await onSelect(federation_code); + }; + + const [federations] = createResource(async () => { + try { + const federations: DiscoveredFederation[] = + await state.mutiny_wallet?.discover_federations(); + return federations; + } catch (e) { + console.error(e); + return []; + } + }); + + const onSelect = async (inviteCode: string) => { setSuccess(""); setError(undefined); + setLoadingFederation(inviteCode); try { - const federation_code = f.federation_code.trim(); const newFederation = - await state.mutiny_wallet?.new_federation(federation_code); + await state.mutiny_wallet?.new_federation(inviteCode); console.log("New federation added:", newFederation); setSuccess( i18n.t("settings.manage_federations.federation_added_success") @@ -107,50 +144,163 @@ function AddFederationForm(props: { refetch?: RefetchType }) { console.error("Error submitting federation:", e); setError(eify(e)); } + setLoadingFederation(""); }; return ( -
- - + + {i18n.t("settings.manage_federations.manual")} + + + + - {(field, props) => ( - + {(field, props) => ( + + )} + + + + {error()?.message} + + + {success()} + + + + + {i18n.t("settings.manage_federations.discover")} + + + + +
+ +
+
+ + + {(fed) => ( + + +
+ +
+
+ {fed.metadata?.name} +
+ +

{fed.metadata?.about}

+
+
+
+ + + + + + {/* todo i18n */} + + + + + {/* todo i18n, handle singular vs plural */} + + {(invite) => ( + + )} + + + 0 + } + > + + {/* todo i18n */} +
+ + {(contact) => ( + + )} + +
+
+
+ {/* FIXME: do something smarter than just taking first code */} + +
+
)} - placeholder="fed11..." - required - /> - )} -
- - - {error()?.message} - - - {success()} - -
- + + + + + ); } @@ -174,50 +324,73 @@ function FederationListItem(props: { setConfirmLoading(false); } + async function recommendFederation() { + setRecommendLoading(true); + try { + const event_id = await state.mutiny_wallet?.recommend_federation( + props.fed.invite_code + ); + console.log("Recommended federation: ", event_id); + } catch (e) { + console.error("Error recommending federation: ", e); + } + setRecommendLoading(false); + } + async function confirmRemove() { setConfirmOpen(true); } const [confirmOpen, setConfirmOpen] = createSignal(false); const [confirmLoading, setConfirmLoading] = createSignal(false); + const [recommendLoading, setRecommendLoading] = createSignal(false); return ( <> - -
- {props.fed.federation_name} -
-
- -

{props.fed.welcome_message}

-
- + + +
+ {props.fed.federation_name} +
+
+ +

{props.fed.welcome_message}

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