pick a federation on setup

This commit is contained in:
Paul Miller
2024-04-11 09:56:22 -05:00
parent 936f66f454
commit 11e0b8655b
10 changed files with 188 additions and 73 deletions

View File

@@ -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) {

View File

@@ -551,13 +551,14 @@
"remove": "Remove",
"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."
},
"gift": {
"give_sats_link": "Give sats as a gift",
@@ -743,13 +744,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."
}
}
}

View File

@@ -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"
},

View File

@@ -6,7 +6,7 @@ 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("");
@@ -29,7 +29,11 @@ export function ImportNsecForm() {
undefined
);
console.log("Changed to new npub: ", new_npub);
navigate("/");
if (props.setup) {
navigate("/addfederation");
} else {
navigate("/");
}
} catch (e) {
console.error(e);
setError("Invalid nsec");

View File

@@ -32,8 +32,10 @@ export const Button: ParentComponent<ButtonProps> = (props) => {
<button
{...attrs}
disabled={props.disabled || props.loading}
class="rounded-xl p-3 font-semibold transition active:-mb-[2px] active:mt-[2px] disabled:bg-neutral-400/10 disabled:text-white/20 disabled:shadow-inner-button-disabled"
class="rounded-xl p-3 font-semibold transition active:-mb-[2px] active:mt-[2px] "
classList={{
"disabled:bg-neutral-400/10 disabled:text-white/20 disabled:shadow-inner-button-disabled":
local.intent !== "text",
"bg-white text-black": local.intent === "active",
"bg-m-grey-800 text-white shadow-inner-button text-shadow-button":
!local.intent || local.intent === "inactive",

View File

@@ -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() {
<Route path="/" component={Main} />
<Route path="/setup" component={Setup} />
<Route path="/setup/restore" component={SetupRestore} />
<Route path="/addfederation" component={AddFederation} />
<Route path="/newprofile" component={NewProfile} />
<Route path="/editprofile" component={EditProfile} />
<Route path="/importprofile" component={ImportProfile} />

View File

@@ -6,7 +6,7 @@ import {
SubmitHandler
} from "@modular-forms/solid";
import { FederationBalance, TagItem } from "@mutinywallet/mutiny-wasm";
import { A, useSearchParams } from "@solidjs/router";
import { A, useNavigate, useSearchParams } from "@solidjs/router";
import { BadgeCheck, Scan } from "lucide-solid";
import {
createResource,
@@ -26,12 +26,13 @@ import {
Button,
ConfirmDialog,
DefaultMain,
ExternalLink,
FancyCard,
InfoBox,
KeyValue,
LabelCircle,
LargeHeader,
LoadingSpinner,
LoadingShimmer,
MediumHeader,
MiniStringShower,
MutinyWalletGuard,
@@ -81,9 +82,13 @@ type RefetchType = (
| null
| undefined;
function AddFederationForm(props: { refetch?: RefetchType }) {
export function AddFederationForm(props: {
refetch?: RefetchType;
setup?: boolean;
}) {
const i18n = useI18n();
const [state, actions] = useMegaStore();
const navigate = useNavigate();
const [error, setError] = createSignal<Error>();
const [success, setSuccess] = createSignal("");
@@ -162,6 +167,9 @@ function AddFederationForm(props: { refetch?: RefetchType }) {
await props.refetch();
}
reset(feedbackForm);
if (props.setup) {
navigate("/");
}
} catch (e) {
console.error("Error submitting federation:", e);
setError(eify(e));
@@ -171,56 +179,61 @@ function AddFederationForm(props: { refetch?: RefetchType }) {
return (
<>
<MediumHeader>
{i18n.t("settings.manage_federations.manual")}
</MediumHeader>
<Form onSubmit={handleSubmit}>
<VStack>
<Field
name="federation_code"
validate={[
required(
i18n.t(
"settings.manage_federations.federation_code_required"
<Show when={!props.setup}>
<MediumHeader>
{i18n.t("settings.manage_federations.manual")}
</MediumHeader>
<Form onSubmit={handleSubmit}>
<VStack>
<Field
name="federation_code"
validate={[
required(
i18n.t(
"settings.manage_federations.federation_code_required"
)
)
)
]}
>
{(field, props) => (
<TextField
{...props}
{...field}
error={field.error}
placeholder="fed11..."
required
/>
)}
</Field>
<Button
loading={feedbackForm.submitting}
disabled={feedbackForm.invalid || !feedbackForm.dirty}
intent="blue"
type="submit"
>
{i18n.t("settings.manage_federations.add")}
</Button>
<Show when={error()}>
<InfoBox accent="red">{error()?.message}</InfoBox>
</Show>
<Show when={success()}>
<InfoBox accent="green">{success()}</InfoBox>
</Show>
</VStack>
</Form>
<MediumHeader>
{i18n.t("settings.manage_federations.discover")}
</MediumHeader>
]}
>
{(field, props) => (
<TextField
{...props}
{...field}
error={field.error}
placeholder="fed11..."
required
/>
)}
</Field>
<Button
loading={feedbackForm.submitting}
disabled={
feedbackForm.invalid || !feedbackForm.dirty
}
intent="blue"
type="submit"
>
{i18n.t("settings.manage_federations.add")}
</Button>
<Show when={error()}>
<InfoBox accent="red">{error()?.message}</InfoBox>
</Show>
<Show when={success()}>
<InfoBox accent="green">{success()}</InfoBox>
</Show>
</VStack>
</Form>
<MediumHeader>
{i18n.t("settings.manage_federations.discover")}
</MediumHeader>
</Show>
<Suspense>
<Switch>
<Match when={federations.loading}>
<div class="flex flex-col items-center justify-center">
<LoadingSpinner wide />
</div>
<FancyCard>
<LoadingShimmer />
</FancyCard>
</Match>
<Match when={federations.latest}>
<For each={federations()}>
@@ -247,13 +260,17 @@ function AddFederationForm(props: { refetch?: RefetchType }) {
</Show>
</div>
</div>
<KeyValue
key={i18n.t(
"settings.manage_federations.federation_id"
)}
>
<MiniStringShower text={fed.id} />
</KeyValue>
<Show when={!props.setup}>
<KeyValue
key={i18n.t(
"settings.manage_federations.federation_id"
)}
>
<MiniStringShower
text={fed.id}
/>
</KeyValue>
</Show>
<Show when={fed.created_at}>
<KeyValue
key={i18n.t(
@@ -517,13 +534,20 @@ export function ManageFederations() {
</A>{" "}
</Show>
</div>
{/* <BackLink href="/settings" title={i18n.t("settings.header")} /> */}
<LargeHeader>
{i18n.t("settings.manage_federations.title")}
</LargeHeader>
<NiceP>
{i18n.t("settings.manage_federations.description")}{" "}
</NiceP>
<NiceP>
{i18n.t("settings.manage_federations.descriptionpart2")}{" "}
</NiceP>
<NiceP>
<ExternalLink href="https://fedimint.org/docs/intro">
{i18n.t("settings.manage_federations.learn_more")}
</ExternalLink>
</NiceP>
<Suspense>
<Show when={!state.federations?.length}>
<AddFederationForm refetch={refetch} />

View File

@@ -0,0 +1,65 @@
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 (
<MutinyWalletGuard>
<DefaultMain>
<div class="mx-auto flex max-w-[20rem] flex-col items-center gap-4 py-4">
<h1 class="text-3xl font-semibold">
{i18n.t("setup.federation.pick")}
</h1>
<p class="text-pretty text-center text-xl font-light text-neutral-200">
{i18n.t("settings.manage_federations.description")}
</p>
<p class="text-pretty text-center text-xl font-light text-neutral-200">
{i18n.t("settings.manage_federations.descriptionpart2")}
</p>
<Button onClick={() => setConfirmOpen(true)} intent="text">
{i18n.t("setup.skip")}
</Button>
<ConfirmDialog
open={confirmOpen()}
loading={false}
onConfirm={handleSkip}
onCancel={() => setConfirmOpen(false)}
>
{i18n.t("setup.federation.skip_confirm")}
</ConfirmDialog>
<VStack>
<Suspense>
<AddFederationForm setup />
</Suspense>
</VStack>
<p class="text-pretty text-center text-xl font-light text-neutral-200">
<ExternalLink href="https://fedimint.org/docs/intro">
{i18n.t("settings.manage_federations.learn_more")}
</ExternalLink>
</p>
</div>
</DefaultMain>
</MutinyWalletGuard>
);
}

View File

@@ -31,7 +31,7 @@ export function NewProfile() {
);
console.log("profile", profile);
localStorage.setItem("profile_setup_stage", "skipped");
navigate("/");
navigate("/addfederation");
setSkipping(false);
}
@@ -46,7 +46,7 @@ export function NewProfile() {
);
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() {
<DefaultMain>
<div class="mx-auto flex max-w-[20rem] flex-1 flex-col items-center gap-4">
<div class="flex-1" />
<h1 class="text-3xl font-semibold">Create your profile</h1>
<h1 class="text-3xl font-semibold">
{i18n.t("setup.new_profile.title")}
</h1>
<p class="text-center text-xl font-light text-neutral-200">
{i18n.t("setup.new_profile.description")}
</p>

View File

@@ -2,3 +2,4 @@ export * from "./Restore";
export * from "./ImportProfile";
export * from "./NewProfile";
export * from "./Root";
export * from "./AddFederation";