diff --git a/public/i18n/en.json b/public/i18n/en.json index 5ae7b896..bd1d3600 100644 --- a/public/i18n/en.json +++ b/public/i18n/en.json @@ -563,7 +563,8 @@ "join_me": "Join me", "recommend": "Recommend federation", "recommended_by_you": "Recommended by you", - "transfer_funds": "Transfer funds" + "transfer_funds": "Transfer funds", + "transfer_funds_message": "Add a second federation to enable transfers." }, "gift": { "give_sats_link": "Give sats as a gift", diff --git a/src/components/Activity.tsx b/src/components/Activity.tsx index 592b8511..a86d7cf2 100644 --- a/src/components/Activity.tsx +++ b/src/components/Activity.tsx @@ -8,7 +8,6 @@ import { createSignal, For, Match, - onMount, Show, Suspense, Switch @@ -19,6 +18,7 @@ import { Button, ButtonCard, ContactButton, + FederationPopup, LoadingShimmer, NiceP, SimpleDialog @@ -365,7 +365,7 @@ function NewContactModal(props: { profile: PseudoContact; close: () => void }) { } export function CombinedActivity() { - const [state, actions, sw] = useMegaStore(); + const [state, _actions, sw] = useMegaStore(); const i18n = useI18n(); const [detailsOpen, setDetailsOpen] = createSignal(false); @@ -408,17 +408,6 @@ export function CombinedActivity() { const [newContact, setNewContact] = createSignal(); - const [ - showFederationExpirationWarning, - setShowFederationExpirationWarning - ] = createSignal(false); - - onMount(() => { - if (state.expiration_warning) { - setShowFederationExpirationWarning(true); - } - }); - return ( <> @@ -437,30 +426,7 @@ export function CombinedActivity() { }> - { - if (!open) { - setShowFederationExpirationWarning(false); - actions.clearExpirationWarning(); - } - }} - > - - {state.expiration_warning?.expiresMessage} - - navigate("/settings/federations")} - > -
- - - {i18n.t("profile.manage_federation")} - -
-
-
+
{ + if (!open) { + setShowFederationExpirationWarning(false); + actions.clearExpirationWarning(); + } + }} + > + {state.expiration_warning?.expiresMessage} + { + actions.clearExpirationWarning(); + setShowFederationExpirationWarning(false); + navigate("/settings/federations"); + }} + > +
+ + {i18n.t("profile.manage_federation")} +
+
+ + ); +} diff --git a/src/components/index.ts b/src/components/index.ts index d3b21602..5706dba8 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -56,3 +56,4 @@ export * from "./EditProfileForm"; export * from "./ImportNsecForm"; export * from "./LightningAddressShower"; export * from "./FederationInviteShower"; +export * from "./FederationPopup"; diff --git a/src/routes/Transfer.tsx b/src/routes/Transfer.tsx index f15d78e5..a3869a7f 100644 --- a/src/routes/Transfer.tsx +++ b/src/routes/Transfer.tsx @@ -171,7 +171,11 @@ export function Transfer() { - + {i18n.t("transfer.title")}
diff --git a/src/routes/settings/ManageFederations.tsx b/src/routes/settings/ManageFederations.tsx index ffa5f839..2b8bf97c 100644 --- a/src/routes/settings/ManageFederations.tsx +++ b/src/routes/settings/ManageFederations.tsx @@ -29,6 +29,7 @@ import { ExternalLink, FancyCard, FederationInviteShower, + FederationPopup, InfoBox, KeyValue, LabelCircle, @@ -40,6 +41,7 @@ import { NavBar, NiceP, showToast, + SimpleDialog, SubtleButton, TextField, VStack @@ -59,6 +61,8 @@ export type MutinyFederationIdentity = { federation_expiry_timestamp: number; invite_code: string; meta_external_url?: string; + popup_end_timestamp?: number; + popup_countdown_message?: string; }; export type Metadata = { @@ -91,7 +95,7 @@ export function AddFederationForm(props: { browseOnly?: boolean; }) { const i18n = useI18n(); - const [_state, actions, sw] = useMegaStore(); + const [state, actions, sw] = useMegaStore(); const navigate = useNavigate(); const [error, setError] = createSignal(); const [success, setSuccess] = createSignal(""); @@ -181,6 +185,9 @@ export function AddFederationForm(props: { return (
+ + + {i18n.t("settings.manage_federations.manual")} @@ -446,8 +453,15 @@ function FederationListItem(props: { setConfirmOpen(true); } + const [transferDialogOpen, setTransferDialogOpen] = createSignal(false); + async function transferFunds() { - navigate("/transfer?from=" + props.fed.federation_id); + // If there's only one federation we need to let them know to add another + if (state.federations?.length && state.federations.length < 2) { + setTransferDialogOpen(true); + } else { + navigate("/transfer?from=" + props.fed.federation_id); + } } const [confirmOpen, setConfirmOpen] = createSignal(false); @@ -457,7 +471,6 @@ function FederationListItem(props: { <> - {/*
{JSON.stringify(props.fed, null, 2)}
*/}
{props.fed.federation_name} @@ -466,6 +479,19 @@ function FederationListItem(props: {

{props.fed.welcome_message}

+ + + {i18n.t( + "settings.manage_federations.transfer_funds_message" + )} + + - - - - {i18n.t( - "settings.manage_federations.transfer_funds" - )} - - + + + {i18n.t("settings.manage_federations.transfer_funds")} + diff --git a/src/state/megaStore.tsx b/src/state/megaStore.tsx index 1633c04b..bd0bc28e 100644 --- a/src/state/megaStore.tsx +++ b/src/state/megaStore.tsx @@ -90,7 +90,8 @@ export const makeMegaStoreContext = () => { balanceView: localStorage.getItem("balanceView") || "sats", expiration_warning: undefined as | { expiresTimestamp: number; expiresMessage: string } - | undefined + | undefined, + expiration_warning_seen: false }); const actions = { @@ -235,43 +236,14 @@ export const makeMegaStoreContext = () => { | { expiresTimestamp: number; expiresMessage: string } | undefined = undefined; - try { - if (federations.length) { - const activeFederation = federations[0]; - const metadataUrl = activeFederation.meta_external_url; - console.log("federation metadata url", metadataUrl); - if (metadataUrl) { - const response = await fetch(metadataUrl); - if (response.ok) { - const metadata = await response.json(); - console.log( - "all federation metadata", - metadata - ); - const specificFederation = - metadata[activeFederation.federation_id]; - console.log( - "specific federation metadata", - specificFederation - ); - const expiresTimestamp = - specificFederation.popup_end_timestamp; - console.log( - "federation expires", - expiresTimestamp - ); - const expiresMessage = - specificFederation.popup_countdown_message; - expiration_warning = { - expiresTimestamp, - expiresMessage - }; - } - } + federations.forEach((f) => { + if (f.popup_countdown_message && f.popup_end_timestamp) { + expiration_warning = { + expiresTimestamp: f.popup_end_timestamp, + expiresMessage: f.popup_countdown_message + }; } - } catch (e) { - console.error("Error getting federation metadata", e); - } + }); console.log("expiration_warning", expiration_warning); @@ -513,7 +485,21 @@ export const makeMegaStoreContext = () => { }, async refreshFederations() { const federations = await sw.list_federations(); - setState({ federations }); + + let expiration_warning: + | { expiresTimestamp: number; expiresMessage: string } + | undefined = undefined; + + federations.forEach((f) => { + if (f.popup_countdown_message && f.popup_end_timestamp) { + expiration_warning = { + expiresTimestamp: f.popup_end_timestamp, + expiresMessage: f.popup_countdown_message + }; + } + }); + + setState({ federations, expiration_warning }); }, cycleBalanceView() { if (state.balanceView === "sats") { @@ -556,7 +542,7 @@ export const makeMegaStoreContext = () => { }, // Only show the expiration warning once per session clearExpirationWarning() { - setState({ expiration_warning: undefined }); + setState({ expiration_warning_seen: true }); } }; diff --git a/src/workers/walletWorker.ts b/src/workers/walletWorker.ts index c75fdafa..eb1eb4b6 100644 --- a/src/workers/walletWorker.ts +++ b/src/workers/walletWorker.ts @@ -1382,6 +1382,7 @@ export async function delete_federation_recommendation( */ export async function get_federation_balances(): Promise { const balances = await wallet!.get_federation_balances(); + if (!balances) return { balances: [] } as unknown as FederationBalances; // PAIN // Have to rebuild the balances from the raw data, which is a bit of a pain const newBalances: FederationBalance[] = [];