Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions frontend/src/components/layouts/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
useCommandPaletteContext,
} from "src/contexts/CommandPaletteContext";
import { useBanner } from "src/hooks/useBanner";
import { useDocumentTitle } from "src/hooks/useDocumentTitle";
import { useInfo } from "src/hooks/useInfo";
import { useNotifyReceivedPayments } from "src/hooks/useNotifyReceivedPayments";
import { useRemoveSuccessfulChannelOrder } from "src/hooks/useRemoveSuccessfulChannelOrder";
Expand All @@ -21,6 +22,7 @@ function AppLayoutInner() {

useRemoveSuccessfulChannelOrder();
useNotifyReceivedPayments();
useDocumentTitle();

if (!info) {
return null;
Expand Down
49 changes: 49 additions & 0 deletions frontend/src/hooks/useDocumentTitle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from "react";
import { useMatches } from "react-router-dom";

/**
* Custom hook to manage document.title based on route handles.
* This ensures the browser's history entries include a proper title
* (fixes: back gesture / long-press back showing empty/incorrect titles).
*
* Looks for a `title` property in route handles (string or function),
* falling back to "Alby Hub" if not present.
*/
export function useDocumentTitle() {
const matches = useMatches();

React.useEffect(() => {
try {
// Extract title from route handles. Use a typed helper to get the title
// from the handle object (if present).
const getTitleFromHandle = (handle: unknown): string | null => {
if (handle && typeof handle === "object") {
const h = handle as { title?: unknown };
if (typeof h.title === "string") {
return h.title;
}
if (typeof h.title === "function") {
try {
return (h.title as () => string)();
} catch (err) {
return null;
}
}
}
return null;
};

// Find the last (most specific) route with a title, or default to "Alby Hub"
const routeTitle =
matches
.map((m) => getTitleFromHandle(m.handle))
.filter(Boolean)
.pop() || "Alby Hub";

// Set document title
document.title = routeTitle;
} catch (err) {
console.error("Failed to compute page title", err);
}
}, [matches]);
}
88 changes: 56 additions & 32 deletions frontend/src/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ const routes = [
{
path: "home",
element: <DefaultRedirect />,
handle: { crumb: () => "Dashboard" },
handle: { crumb: () => "Dashboard", title: "Dashboard" },
children: [
{
index: true,
Expand All @@ -113,15 +113,15 @@ const routes = [
{
path: "wallet",
element: <DefaultRedirect />,
handle: { crumb: () => "Wallet" },
handle: { crumb: () => "Wallet", title: "Wallet" },
children: [
{
index: true,
element: <Wallet />,
},
{
path: "swap",
handle: { crumb: () => "Swap" },
handle: { crumb: () => "Swap", title: "Swap" },
children: [
{
index: true,
Expand All @@ -143,32 +143,38 @@ const routes = [
},
{
path: "receive",
handle: { crumb: () => "Receive" },
handle: { crumb: () => "Receive", title: "Receive" },
children: [
{
index: true,
element: <Receive />,
},
{
handle: { crumb: () => "Receive On-chain" },
handle: {
crumb: () => "Receive On-chain",
title: "Receive On-chain",
},
path: "onchain",
element: <ReceiveOnchain />,
},
{
handle: { crumb: () => "Invoice" },
handle: { crumb: () => "Invoice", title: "Invoice" },
path: "invoice",
element: <ReceiveInvoice />,
},
{
handle: { crumb: () => "BOLT-12 Offer" },
handle: {
crumb: () => "BOLT-12 Offer",
title: "BOLT-12 Offer",
},
path: "offer",
element: <ReceiveOffer />,
},
],
},
{
path: "send",
handle: { crumb: () => "Send" },
handle: { crumb: () => "Send", title: "Send" },
children: [
{
index: true,
Expand Down Expand Up @@ -203,24 +209,27 @@ const routes = [
{
path: "sign-message",
element: <SignMessage />,
handle: { crumb: () => "Sign Message" },
handle: { crumb: () => "Sign Message", title: "Sign Message" },
},
{
path: "node-alias",
element: <NodeAlias />,
handle: { crumb: () => "Node Alias" },
handle: { crumb: () => "Node Alias", title: "Node Alias" },
},
{
path: "withdraw",
element: <WithdrawOnchainFunds />,
handle: { crumb: () => "Withdraw On-Chain Balance" },
handle: {
crumb: () => "Withdraw On-Chain Balance",
title: "Withdraw On-Chain Balance",
},
},
],
},
{
path: "settings",
element: <DefaultRedirect />,
handle: { crumb: () => "Settings" },
handle: { crumb: () => "Settings", title: "Settings" },
children: [
{
path: "",
Expand All @@ -233,22 +242,25 @@ const routes = [
{
path: "about",
element: <About />,
handle: { crumb: () => "About" },
handle: { crumb: () => "About", title: "About" },
},
{
path: "auto-unlock",
element: <AutoUnlock />,
handle: { crumb: () => "Auto Unlock" },
handle: { crumb: () => "Auto Unlock", title: "Auto Unlock" },
},
{
path: "change-unlock-password",
element: <ChangeUnlockPassword />,
handle: { crumb: () => "Unlock Password" },
handle: {
crumb: () => "Unlock Password",
title: "Change Unlock Password",
},
},
{
path: "backup",
element: <Backup />,
handle: { crumb: () => "Backup" },
handle: { crumb: () => "Backup", title: "Backup" },
},
{
path: "node-migrate",
Expand All @@ -273,7 +285,7 @@ const routes = [
{
path: "apps",
element: <DefaultRedirect />,
handle: { crumb: () => "Connections" },
handle: { crumb: () => "Connections", title: "Connections" },
children: [
{
index: true,
Expand All @@ -286,7 +298,7 @@ const routes = [
{
path: "new",
element: <NewApp />,
handle: { crumb: () => "New App" },
handle: { crumb: () => "New App", title: "New Connection" },
},
{
path: "cleanup",
Expand All @@ -297,7 +309,7 @@ const routes = [
{
path: "sub-wallets",
element: <DefaultRedirect />,
handle: { crumb: () => "Sub-wallets" },
handle: { crumb: () => "Sub-wallets", title: "Sub-wallets" },

children: [
{
Expand All @@ -317,7 +329,7 @@ const routes = [
{
path: "internal-apps",
element: <DefaultRedirect />,
handle: { crumb: () => "Connections" },
handle: { crumb: () => "Connections", title: "Internal Apps" },
children: [
{
path: "buzzpay",
Expand Down Expand Up @@ -356,7 +368,7 @@ const routes = [
{
path: "appstore",
element: <DefaultRedirect />,
handle: { crumb: () => "App Store" },
handle: { crumb: () => "App Store", title: "App Store" },
children: [
{
path: ":appStoreId",
Expand All @@ -367,15 +379,18 @@ const routes = [
{
path: "channels",
element: <DefaultRedirect />,
handle: { crumb: () => "Node" },
handle: { crumb: () => "Node", title: "Channels" },
children: [
{
index: true,
element: <Channels />,
},
{
path: "first",
handle: { crumb: () => "Your First Channel" },
handle: {
crumb: () => "Your First Channel",
title: "Your First Channel",
},
children: [
{
index: true,
Expand All @@ -393,7 +408,7 @@ const routes = [
},
{
path: "auto",
handle: { crumb: () => "New Channel" },
handle: { crumb: () => "New Channel", title: "New Channel" },
children: [
{
index: true,
Expand All @@ -412,34 +427,43 @@ const routes = [
{
path: "outgoing",
element: <IncreaseOutgoingCapacity />,
handle: { crumb: () => "Open Channel with On-Chain" },
handle: {
crumb: () => "Open Channel with On-Chain",
title: "Open Channel with On-Chain",
},
},
{
path: "incoming",
element: <IncreaseIncomingCapacity />,
handle: { crumb: () => "Open Channel with Lightning" },
handle: {
crumb: () => "Open Channel with Lightning",
title: "Open Channel with Lightning",
},
},
{
path: "order",
element: <CurrentChannelOrder />,
handle: { crumb: () => "Current Order" },
handle: { crumb: () => "Current Order", title: "Current Order" },
},
{
path: "onchain/buy-bitcoin",
element: <BuyBitcoin />,
handle: { crumb: () => "Buy Bitcoin" },
handle: { crumb: () => "Buy Bitcoin", title: "Buy Bitcoin" },
},
{
path: "onchain/deposit-bitcoin",
element: <DepositBitcoin />,
handle: { crumb: () => "Deposit Bitcoin" },
handle: {
crumb: () => "Deposit Bitcoin",
title: "Deposit Bitcoin",
},
},
],
},
{
path: "peers",
element: <DefaultRedirect />,
handle: { crumb: () => "Peers" },
handle: { crumb: () => "Peers", title: "Peers" },
children: [
{
index: true,
Expand All @@ -448,7 +472,7 @@ const routes = [
{
path: "new",
element: <ConnectPeer />,
handle: { crumb: () => "Connect Peer" },
handle: { crumb: () => "Connect Peer", title: "Connect Peer" },
},
],
},
Expand All @@ -459,7 +483,7 @@ const routes = [
{
path: "review-earn",
element: <AlbyReviews />,
handle: { crumb: () => "Review & Earn" },
handle: { crumb: () => "Review & Earn", title: "Review & Earn" },
},
],
},
Expand Down
Loading