Skip to content

Commit

Permalink
add transfer funds screen
Browse files Browse the repository at this point in the history
  • Loading branch information
futurepaul committed May 8, 2024
1 parent 1dfc11e commit feed465
Show file tree
Hide file tree
Showing 9 changed files with 377 additions and 116 deletions.
12 changes: 10 additions & 2 deletions public/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,8 @@
"back_home": "back home"
},
"start_a_chat": "Start a chat?",
"start_a_chat_are_you_sure": "This user isn't in your contact list."
"start_a_chat_are_you_sure": "This user isn't in your contact list.",
"federation_message": "Federation Message"
},
"scanner": {
"paste": "Paste Something",
Expand Down Expand Up @@ -563,7 +564,8 @@
"descriptionpart2": "Each one is run 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"
"recommended_by_you": "Recommended by you",
"transfer_funds": "Transfer funds"
},
"gift": {
"give_sats_link": "Give sats as a gift",
Expand Down Expand Up @@ -784,5 +786,11 @@
"nowish": "Nowish",
"seconds_future": "Seconds from now",
"seconds_past": "Just now"
},
"transfer": {
"completed": "Transfer Completed",
"sats_moved": "+{{amount}} sats have been moved to {{federation_name}}",
"confirm": "Confirm Transfer",
"title": "Transfer funds"
}
}
21 changes: 15 additions & 6 deletions src/components/Activity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,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);
Expand Down Expand Up @@ -448,19 +448,28 @@ export function CombinedActivity() {
<Suspense fallback={<LoadingShimmer />}>
<Show when={state.expiration_warning}>
<SimpleDialog
title={"OH NO!"}
title={i18n.t("activity.federation_message")}
open={showFederationExpirationWarning()}
setOpen={(open: boolean) => {
if (!open)
if (!open) {
setShowFederationExpirationWarning(false);
actions.clearExpirationWarning();
}
}}
>
<pre>
{JSON.stringify(state.expiration_warning, null, 2)}
</pre>
<NiceP>
{state.expiration_warning?.expiresMessage}
</NiceP>
<ButtonCard
onClick={() => navigate("/settings/federations")}
>
<div class="flex items-center gap-2">
<Users class="inline-block text-m-red" />
<NiceP>
{i18n.t("profile.manage_federation")}
</NiceP>
</div>
</ButtonCard>
</SimpleDialog>
</Show>
<Show when={!state.has_backed_up}>
Expand Down
4 changes: 3 additions & 1 deletion src/components/AmountEditable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
} from "~/utils";

export type MethodChoice = {
method: "lightning" | "onchain";
method: "lightning" | "onchain" | "fedimint";
maxAmountSats?: bigint;
};

Expand All @@ -29,6 +29,8 @@ function methodToIcon(method: MethodChoice["method"]) {
return "lightning";
} else if (method === "onchain") {
return "chain";
} else if (method === "fedimint") {
return "community";
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ import {
Search,
Send,
Swap,
SwapLightning
SwapLightning,
Transfer
} from "~/routes";
import {
Admin,
Expand Down Expand Up @@ -179,6 +180,7 @@ export function Router() {
<Route path="/send" component={Send} />
<Route path="/swap" component={Swap} />
<Route path="/swaplightning" component={SwapLightning} />
<Route path="/transfer" component={Transfer} />
<Route path="/search" component={Search} />
<Route path="/settings">
<Route path="/" component={Settings} />
Expand Down
216 changes: 216 additions & 0 deletions src/routes/Transfer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import { FedimintSweepResult } from "@mutinywallet/mutiny-wasm";
import { createAsync, useNavigate, useSearchParams } from "@solidjs/router";
import { ArrowDown, Users } from "lucide-solid";
import { createMemo, createSignal, Match, Suspense, Switch } from "solid-js";

import {
AmountEditable,
AmountFiat,
AmountSats,
BackLink,
Button,
DefaultMain,
Failure,
Fee,
LargeHeader,
MegaCheck,
MutinyWalletGuard,
SharpButton,
SuccessModal,
VStack
} from "~/components";
import { useI18n } from "~/i18n/context";
import { useMegaStore } from "~/state/megaStore";
import { eify, vibrateSuccess } from "~/utils";

type TransferResultDetails = {
result?: FedimintSweepResult;
failure_reason?: string;
};

export function Transfer() {
const [state, _actions, sw] = useMegaStore();
const i18n = useI18n();
const navigate = useNavigate();
const [amountSats, setAmountSats] = createSignal(0n);
const [loading, setLoading] = createSignal(false);
const [params] = useSearchParams();

const canTransfer = createMemo(() => {
return true;
});

const [transferResult, setTransferResult] =
createSignal<TransferResultDetails>();

const fromFed = () => {
return state.federations?.find((f) => f.federation_id === params.from);
};

const toFed = () => {
return state.federations?.find((f) => f.federation_id !== params.from);
};

const federationBalances = createAsync(async () => {
try {
const balances = await sw.get_federation_balances();
return balances?.balances || [];
} catch (e) {
console.error(e);
return [];
}
});

const calculateMaxFederation = createAsync(async () => {
return federationBalances()?.find(
(f) => f.identity_federation_id === fromFed()?.federation_id
)?.balance;
});

const toBalance = createAsync(async () => {
return federationBalances()?.find(
(f) => f.identity_federation_id === toFed()?.federation_id
)?.balance;
});

const isMax = createMemo(() => {
return amountSats() === calculateMaxFederation();
});

async function handleTransfer() {
try {
setLoading(true);
if (!fromFed()) throw new Error("No from federation");
if (!toFed()) throw new Error("No to federation");

if (isMax()) {
const result = await sw.sweep_federation_balance(
undefined,
fromFed()?.federation_id,
toFed()?.federation_id
);

setTransferResult({ result: result });
} else {
const result = await sw.sweep_federation_balance(
amountSats(),
fromFed()?.federation_id,
toFed()?.federation_id
);

setTransferResult({ result: result });
}

await vibrateSuccess();
} catch (e) {
const error = eify(e);
setTransferResult({ failure_reason: error.message });
console.error(e);
} finally {
setLoading(false);
}
}

// const fromFederatationId = params.from;

return (
<MutinyWalletGuard>
<DefaultMain>
<SuccessModal
confirmText={
transferResult()?.result
? i18n.t("common.nice")
: i18n.t("common.home")
}
open={!!transferResult()}
setOpen={(open: boolean) => {
if (!open) setTransferResult(undefined);
}}
onConfirm={() => {
setTransferResult(undefined);
navigate("/");
}}
>
<Switch>
<Match when={transferResult()?.failure_reason}>
<Failure
reason={transferResult()!.failure_reason!}
/>
</Match>
<Match when={transferResult()?.result}>
<MegaCheck />
<div class="flex flex-col justify-center">
<h1 class="mb-2 mt-4 w-full justify-center text-center text-2xl font-semibold md:text-3xl">
{i18n.t("transfer.completed")}
</h1>
<p class="text-center text-xl">
{i18n.t("transfer.sats_moved", {
amount: Number(
transferResult()?.result?.amount
).toLocaleString(),
federation_name:
toFed()?.federation_name
})}
</p>
<div class="text-center text-sm text-white/70">
<Suspense>
<AmountFiat
amountSats={Number(
transferResult()?.result?.amount
)}
/>
</Suspense>
</div>
</div>
<hr class="w-16 bg-m-grey-400" />
<Fee
amountSats={Number(
transferResult()?.result?.fees
)}
/>
</Match>
</Switch>
</SuccessModal>
<BackLink href="/settings/federations" />
<LargeHeader>{i18n.t("transfer.title")}</LargeHeader>
<div class="flex flex-1 flex-col justify-between gap-2">
<div class="flex-1" />
<div class="flex flex-col items-center">
<AmountEditable
initialAmountSats={amountSats()}
setAmountSats={setAmountSats}
/>
<SharpButton disabled onClick={() => {}}>
<Users class="w-[18px]" />
{fromFed()?.federation_name}
<AmountSats
amountSats={calculateMaxFederation()}
denominationSize="sm"
/>
</SharpButton>
<ArrowDown class="h-4 w-4" />
<SharpButton disabled onClick={() => {}}>
<Users class="w-[18px]" />
{toFed()?.federation_name}
<AmountSats
amountSats={toBalance()}
denominationSize="sm"
/>
</SharpButton>
</div>
<div class="flex-1" />
<VStack>
<Button
disabled={!canTransfer()}
intent="blue"
onClick={handleTransfer}
loading={loading()}
>
{i18n.t("transfer.confirm")}
</Button>
</VStack>
</div>
</DefaultMain>
</MutinyWalletGuard>
);
}
1 change: 1 addition & 0 deletions src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export * from "./Request";
export * from "./EditProfile";
export * from "./Swap";
export * from "./SwapLightning";
export * from "./Transfer";
Loading

0 comments on commit feed465

Please sign in to comment.