From 53d0b688007db2a13a43a4dc63f0629c24ec941d Mon Sep 17 00:00:00 2001
From: saunter <68239231+stackingsaunter@users.noreply.github.com>
Date: Tue, 19 May 2026 18:27:06 +0200
Subject: [PATCH] feat: add first channel step to onboarding
---
.../layouts/TwoColumnFullScreenLayout.tsx | 20 ++++++++++++---
.../components/redirects/SetupRedirect.tsx | 7 ++++++
frontend/src/hooks/useOnboardingData.ts | 10 +++++---
frontend/src/routes.tsx | 25 +++++++++++++++++++
.../channels/first/OpenedFirstChannel.tsx | 14 ++++++++---
.../channels/first/OpeningFirstChannel.tsx | 12 ++++++---
frontend/src/screens/setup/SetupFinish.tsx | 6 +++++
7 files changed, 82 insertions(+), 12 deletions(-)
diff --git a/frontend/src/components/layouts/TwoColumnFullScreenLayout.tsx b/frontend/src/components/layouts/TwoColumnFullScreenLayout.tsx
index fce027b9..d2f2c62e 100644
--- a/frontend/src/components/layouts/TwoColumnFullScreenLayout.tsx
+++ b/frontend/src/components/layouts/TwoColumnFullScreenLayout.tsx
@@ -4,6 +4,7 @@ import { Outlet, useLocation, useNavigate } from "react-router";
import { AlbyHubLogo } from "src/components/icons/AlbyHubLogo";
import { Button } from "src/components/ui/button.tsx";
import { useInfo } from "src/hooks/useInfo";
+import { cn } from "src/lib/utils";
import AntonopoulosSVG from "public/images/quotes/antonopoulos.svg";
import BackSVG from "public/images/quotes/back.svg";
@@ -65,6 +66,7 @@ export default function TwoColumnFullScreenLayout() {
const { data: info } = useInfo();
const navigate = useNavigate();
const { pathname } = useLocation();
+ const anchorFirstChannelExpansion = pathname === "/setup/first-channel";
const [quote, setQuote] = useState(
// eslint-disable-next-line react-hooks/purity
quotes[Math.floor(Math.random() * quotes.length)]
@@ -100,9 +102,15 @@ export default function TwoColumnFullScreenLayout() {
-
+
{pathname.startsWith("/setup") &&
- !pathname.startsWith("/setup/finish") && (
+ !pathname.startsWith("/setup/finish") &&
+ !pathname.startsWith("/setup/first-channel") && (
// show the back button on setup pages, except the setup finish page
);
diff --git a/frontend/src/components/redirects/SetupRedirect.tsx b/frontend/src/components/redirects/SetupRedirect.tsx
index 709aee94..b775bfac 100644
--- a/frontend/src/components/redirects/SetupRedirect.tsx
+++ b/frontend/src/components/redirects/SetupRedirect.tsx
@@ -13,6 +13,13 @@ export function SetupRedirect() {
return;
}
if (info.setupCompleted && info.running) {
+ if (location.pathname.startsWith("/setup/first-channel")) {
+ return;
+ }
+ if (location.pathname.startsWith("/setup/finish")) {
+ navigate("/setup/first-channel", { replace: true });
+ return;
+ }
navigate("/");
return;
}
diff --git a/frontend/src/hooks/useOnboardingData.ts b/frontend/src/hooks/useOnboardingData.ts
index 318d4762..6f3ac777 100644
--- a/frontend/src/hooks/useOnboardingData.ts
+++ b/frontend/src/hooks/useOnboardingData.ts
@@ -45,8 +45,12 @@ export const useOnboardingData = (): UseOnboardingDataResponse => {
!!albyMe &&
nodeConnectionInfo &&
albyMe?.keysend_pubkey === nodeConnectionInfo?.pubkey;
- const hasChannel =
- !hasChannelManagement || (hasChannelManagement && channels.length > 0);
+ const hasOpenedChannel =
+ !hasChannelManagement ||
+ channels.some(
+ (channel) =>
+ channel.active || ["online", "offline"].includes(channel.status)
+ );
const hasBackedUp =
hasMnemonic === true &&
info &&
@@ -64,7 +68,7 @@ export const useOnboardingData = (): UseOnboardingDataResponse => {
title: "Open your first channel",
description:
"Establish a new Lightning channel to enable fast and low-fee Bitcoin transactions.",
- checked: hasChannel,
+ checked: hasOpenedChannel,
to: "/channels/first",
},
]
diff --git a/frontend/src/routes.tsx b/frontend/src/routes.tsx
index 41f25ce0..d2511e7d 100644
--- a/frontend/src/routes.tsx
+++ b/frontend/src/routes.tsx
@@ -575,6 +575,31 @@ const routes: RouteObject[] = [
path: "finish",
element: ,
},
+ {
+ path: "first-channel",
+ handle: { crumb: () => "Your First Channel" },
+ children: [
+ {
+ index: true,
+ element: ,
+ },
+ {
+ path: "opening",
+ element: (
+
+ ),
+ },
+ {
+ path: "opened",
+ element: (
+
+ ),
+ },
+ ],
+ },
],
},
],
diff --git a/frontend/src/screens/channels/first/OpenedFirstChannel.tsx b/frontend/src/screens/channels/first/OpenedFirstChannel.tsx
index 2061ffda..3ea195b8 100644
--- a/frontend/src/screens/channels/first/OpenedFirstChannel.tsx
+++ b/frontend/src/screens/channels/first/OpenedFirstChannel.tsx
@@ -2,7 +2,15 @@ import TickSVG from "public/images/illustrations/tick.svg";
import TwoColumnLayoutHeader from "src/components/TwoColumnLayoutHeader";
import { LinkButton } from "src/components/ui/custom/link-button";
-export function OpenedFirstChannel() {
+type OpenedFirstChannelProps = {
+ ctaLabel?: string;
+ ctaTo?: string;
+};
+
+export function OpenedFirstChannel({
+ ctaLabel = "Receive Your First Payment",
+ ctaTo = "/wallet/receive",
+}: OpenedFirstChannelProps) {
return (
-
- Receive Your First Payment
+
+ {ctaLabel}
);
diff --git a/frontend/src/screens/channels/first/OpeningFirstChannel.tsx b/frontend/src/screens/channels/first/OpeningFirstChannel.tsx
index 73c6ac20..3428effa 100644
--- a/frontend/src/screens/channels/first/OpeningFirstChannel.tsx
+++ b/frontend/src/screens/channels/first/OpeningFirstChannel.tsx
@@ -4,7 +4,13 @@ import { ChannelWaitingForConfirmations } from "src/components/channels/ChannelW
import { useChannels } from "src/hooks/useChannels";
import { useSyncWallet } from "src/hooks/useSyncWallet";
-export function OpeningFirstChannel() {
+type OpeningFirstChannelProps = {
+ openedPath?: string;
+};
+
+export function OpeningFirstChannel({
+ openedPath = "/channels/first/opened",
+}: OpeningFirstChannelProps) {
useSyncWallet();
const { data: channels } = useChannels(true);
const navigate = useNavigate();
@@ -13,9 +19,9 @@ export function OpeningFirstChannel() {
React.useEffect(() => {
if (firstChannel?.active) {
- navigate("/channels/first/opened");
+ navigate(openedPath);
}
- }, [firstChannel, navigate]);
+ }, [firstChannel, navigate, openedPath]);
return ;
}
diff --git a/frontend/src/screens/setup/SetupFinish.tsx b/frontend/src/screens/setup/SetupFinish.tsx
index f38da094..28680616 100644
--- a/frontend/src/screens/setup/SetupFinish.tsx
+++ b/frontend/src/screens/setup/SetupFinish.tsx
@@ -57,6 +57,12 @@ export function SetupFinish() {
};
}, [loading]);
+ useEffect(() => {
+ if (info?.setupCompleted && info.running) {
+ navigate("/setup/first-channel", { replace: true });
+ }
+ }, [info?.setupCompleted, info?.running, navigate]);
+
useEffect(() => {
if (!info) {
return;