Skip to content
This repository has been archived by the owner on Sep 2, 2024. It is now read-only.

Commit

Permalink
Merge pull request #38 from getAlby/task-finish-screen
Browse files Browse the repository at this point in the history
feat: add finish screen for setup
  • Loading branch information
rolznz authored Feb 14, 2024
2 parents 552407a + 27a1d78 commit 1e60d96
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 161 deletions.
14 changes: 5 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,32 +86,28 @@ _If you get a blank screen the first load, close the window and start the app ag

Breez SDK requires gcc to build the Breez bindings. Run `choco install mingw` and copy the breez SDK bindings file into the root of this directory (from your go installation directory) as per the [Breez SDK instructions](https://github.com/breez/breez-sdk-go?tab=readme-ov-file#windows). ALSO copy the bindings file into the output directory alongside the .exe in order to run it.

## Configuration parameters
## Optional configuration parameters

- `NOSTR_PRIVKEY`: the private key of this service. Should be a securely randomly generated 32 byte hex string.
- `CLIENT_NOSTR_PUBKEY`: if set, this service will only listen to events authored by this public key. You can set this to your own nostr public key.
- `RELAY`: default: "wss://relay.getalby.com/v1"
- `COOKIE_SECRET`: a randomly generated secret string. (only needed in http mode)
- `DATABASE_URI`: a sqlite filename. Default: .data/nwc.db
- `PORT`: the port on which the app should listen on (default: 8080)
- `LN_BACKEND_TYPE`: LND or BREEZ
- `WORK_DIR`: directory to store NWC data files. Default: .data
-

### LND Backend parameters

_For cert and macaroon, either hex or file options can be used._
Currently only LND can be configured via env. Other node types must be configured via the UI.

_To configure via env, the following parameters must be provided:_

- `LN_BACKEND_TYPE`: LND
- `LND_ADDRESS`: the LND gRPC address, eg. `localhost:10009` (used with the LND backend)
- `LND_CERT_FILE`: the location where LND's `tls.cert` file can be found (used with the LND backend)
- `LND_MACAROON_FILE`: the location where LND's `admin.macaroon` file can be found (used with the LND backend)

### BREEZ Backend parameters

- `BREEZ_MNEMONIC`: your bip39 mnemonic key phrase e.g. "define limit soccer guilt trim mechanic beyond outside best give south shine"
- `BREEZ_API_KEY`: contact breez for more info
- `GREENLIGHT_INVITE_CODE`: contact blockstream for more info

## Application deeplink options

### `/apps/new` deeplink options
Expand Down
4 changes: 2 additions & 2 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,8 @@ func (api *API) Setup(setupRequest *models.SetupRequest) error {
if setupRequest.BreezAPIKey != "" {
api.svc.cfg.SetUpdate("BreezAPIKey", setupRequest.BreezAPIKey, setupRequest.UnlockPassword)
}
if setupRequest.BreezMnemonic != "" {
api.svc.cfg.SetUpdate("BreezMnemonic", setupRequest.BreezMnemonic, setupRequest.UnlockPassword)
if setupRequest.Mnemonic != "" {
api.svc.cfg.SetUpdate("Mnemonic", setupRequest.Mnemonic, setupRequest.UnlockPassword)
}
if setupRequest.GreenlightInviteCode != "" {
api.svc.cfg.SetUpdate("GreenlightInviteCode", setupRequest.GreenlightInviteCode, setupRequest.UnlockPassword)
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { HomeRedirect } from "src/components/redirects/HomeRedirect";
import Unlock from "src/screens/Unlock";
import { SetupRedirect } from "src/components/redirects/SetupRedirect";
import { SetupMnemonic } from "src/screens/setup/SetupMnemonic";
import { SetupFinish } from "src/screens/setup/SetupFinish";

function App() {
return (
Expand All @@ -45,6 +46,7 @@ function App() {
<Route path="node" element={<SetupNode />} />
<Route path="wallet" element={<SetupWallet />} />
<Route path="mnemonic" element={<SetupMnemonic />} />
<Route path="finish" element={<SetupFinish />} />
</Route>
<Route path="apps" element={<AppsRedirect />}>
<Route index path="" element={<AppsList />} />
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/screens/Start.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ export default function Start() {
try {
setLoading(true);
if (!csrf) {
throw new Error("info not loaded");
throw new Error("csrf not loaded");
}
const res = await request("/api/start", {
await request("/api/start", {
method: "POST",
headers: {
"X-CSRF-Token": csrf,
Expand All @@ -34,7 +34,6 @@ export default function Start() {
unlockPassword,
}),
});
console.log({ res });
await refetchInfo();

navigate("/");
Expand Down
95 changes: 95 additions & 0 deletions frontend/src/screens/setup/SetupFinish.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import Container from "src/components/Container";
import { useInfo } from "src/hooks/useInfo";
import useSetupStore from "src/state/SetupStore";
import { useCSRF } from "src/hooks/useCSRF";
import { handleRequestError } from "src/utils/handleRequestError";
import { request } from "src/utils/request";
import Loading from "src/components/Loading";
import { NodeInfo } from "src/types";
import React from "react";

export function SetupFinish() {
const navigate = useNavigate();
const { nodeInfo, unlockPassword } = useSetupStore();

const { mutate: refetchInfo } = useInfo();
const { data: csrf } = useCSRF();
const [connectionError, setConnectionError] = React.useState(false);
const hasFetchedRef = React.useRef(false);

useEffect(() => {
// ensure setup call is only called once
if (!csrf || hasFetchedRef.current) {
return;
}
hasFetchedRef.current = true;

(async () => {
const succeeded = await finishSetup(csrf, nodeInfo, unlockPassword);
if (succeeded) {
await refetchInfo();
navigate("/");
} else {
setConnectionError(true);
}
})();
}, [csrf, nodeInfo, refetchInfo, navigate, unlockPassword]);

if (connectionError) {
return (
<Container>
<h1 className="font-semibold text-lg font-headline mt-16 mb-8 dark:text-white">
Connection Failed
</h1>

<p>Navigate back to check your configuration, then try again.</p>
</Container>
);
}

return (
<Container>
<h1 className="font-semibold text-lg font-headline mt-16 mb-8 dark:text-white">
Connecting...
</h1>

<Loading />
</Container>
);
}

const finishSetup = async (
csrf: string,
nodeInfo: NodeInfo,
unlockPassword: string
): Promise<boolean> => {
try {
await request("/api/setup", {
method: "POST",
headers: {
"X-CSRF-Token": csrf,
"Content-Type": "application/json",
},
body: JSON.stringify({
...nodeInfo,
unlockPassword,
}),
});
await request("/api/start", {
method: "POST",
headers: {
"X-CSRF-Token": csrf,
"Content-Type": "application/json",
},
body: JSON.stringify({
unlockPassword,
}),
});
return true;
} catch (error) {
handleRequestError("Failed to connect", error);
return false;
}
};
49 changes: 10 additions & 39 deletions frontend/src/screens/setup/SetupMnemonic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,28 @@ import {
PopiconsShieldLine,
PopiconsTriangleExclamationLine,
} from "@popicons/react";
import * as bip39 from "@scure/bip39";
import { wordlist } from "@scure/bip39/wordlists/english";
import { useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";

import { useInfo } from "src/hooks/useInfo";
import * as bip39 from "@scure/bip39";
import { wordlist } from "@scure/bip39/wordlists/english";
import MnemonicInputs from "src/components/MnemonicInputs";
import ConnectButton from "src/components/ConnectButton";
import { useCSRF } from "src/hooks/useCSRF";
import { handleRequestError } from "src/utils/handleRequestError";
import { request } from "src/utils/request";
import useSetupStore from "src/state/SetupStore";
import toast from "src/components/Toast";

export function SetupMnemonic() {
const navigate = useNavigate();
const { state, search } = useLocation();
const { search } = useLocation();
const setupStore = useSetupStore();
const params = new URLSearchParams(search);
const isNew = params.get("wallet") === "new";

const data = state as object;

const [mnemonic, setMnemonic] = useState<string>(
isNew ? bip39.generateMnemonic(wordlist, 128) : ""
setupStore.nodeInfo.mnemonic ||
(isNew ? bip39.generateMnemonic(wordlist, 128) : "")
);
const [backedUp, isBackedUp] = useState<boolean>(false);
const [isConnecting, setConnecting] = useState(false);

const { mutate: refetchInfo } = useInfo();
const { data: csrf } = useCSRF();

async function onSubmit(e: React.FormEvent) {
e.preventDefault();
Expand All @@ -43,30 +36,8 @@ export function SetupMnemonic() {
return;
}

try {
setConnecting(true);
if (!csrf) {
throw new Error("info not loaded");
}
await request("/api/setup", {
method: "POST",
headers: {
"X-CSRF-Token": csrf,
"Content-Type": "application/json",
},
body: JSON.stringify({
breezMnemonic: mnemonic,
...data,
}),
});

await refetchInfo();
navigate("/");
} catch (error) {
handleRequestError("Failed to connect", error);
} finally {
setConnecting(false);
}
setupStore.updateNodeInfo({ mnemonic });
navigate(`/setup/finish`);
}

return (
Expand Down Expand Up @@ -159,7 +130,7 @@ export function SetupMnemonic() {
<ConnectButton
submitText="Finish"
loadingText="Saving..."
isConnecting={isConnecting}
isConnecting={false}
disabled={isNew ? !backedUp : false}
/>
</form>
Expand Down
Loading

0 comments on commit 1e60d96

Please sign in to comment.