diff --git a/alby/alby_oauth_service.go b/alby/alby_oauth_service.go
index b95349154..488da6a71 100644
--- a/alby/alby_oauth_service.go
+++ b/alby/alby_oauth_service.go
@@ -21,7 +21,6 @@ import (
"github.com/getAlby/hub/events"
"github.com/getAlby/hub/lnclient"
"github.com/getAlby/hub/logger"
- nip47 "github.com/getAlby/hub/nip47/models"
"github.com/getAlby/hub/service/keys"
)
@@ -262,7 +261,7 @@ func (svc *albyOAuthService) DrainSharedWallet(ctx context.Context, lnClient lnc
amountSat := int64(math.Floor(
balanceSat- // Alby shared node balance in sats
- (balanceSat*(8/1000))- // Alby service fee (0.8%)
+ (balanceSat*(8.0/1000.0))- // Alby service fee (0.8%)
(balanceSat*0.01))) - // Maximum potential routing fees (1%)
10 // Alby fee reserve (10 sats)
@@ -379,7 +378,7 @@ func (svc *albyOAuthService) GetAuthUrl() string {
return svc.oauthConf.AuthCodeURL("unused")
}
-func (svc *albyOAuthService) LinkAccount(ctx context.Context, lnClient lnclient.LNClient) error {
+func (svc *albyOAuthService) LinkAccount(ctx context.Context, lnClient lnclient.LNClient, budget uint64, renewal string) error {
connectionPubkey, err := svc.createAlbyAccountNWCNode(ctx)
if err != nil {
logger.Logger.WithError(err).Error("Failed to create alby account nwc node")
@@ -389,8 +388,8 @@ func (svc *albyOAuthService) LinkAccount(ctx context.Context, lnClient lnclient.
app, _, err := db.NewDBService(svc.db, svc.eventPublisher).CreateApp(
"getalby.com",
connectionPubkey,
- 1_000_000,
- nip47.BUDGET_RENEWAL_MONTHLY,
+ budget,
+ renewal,
nil,
lnClient.GetSupportedNIP47Methods(),
)
diff --git a/alby/models.go b/alby/models.go
index 625f8b4e1..ea76217af 100644
--- a/alby/models.go
+++ b/alby/models.go
@@ -13,7 +13,7 @@ type AlbyOAuthService interface {
GetAuthUrl() string
GetUserIdentifier() (string, error)
IsConnected(ctx context.Context) bool
- LinkAccount(ctx context.Context, lnClient lnclient.LNClient) error
+ LinkAccount(ctx context.Context, lnClient lnclient.LNClient, budget uint64, renewal string) error
CallbackHandler(ctx context.Context, code string) error
GetBalance(ctx context.Context) (*AlbyBalance, error)
GetMe(ctx context.Context) (*AlbyMe, error)
@@ -29,6 +29,11 @@ type AlbyPayRequest struct {
Invoice string `json:"invoice"`
}
+type AlbyLinkAccountRequest struct {
+ Budget int `json:"budget"`
+ Renewal string `json:"renewal"`
+}
+
type AlbyMe struct {
Identifier string `json:"identifier"`
NPub string `json:"nostr_pubkey"`
diff --git a/frontend/src/components/BudgetAmountSelect.tsx b/frontend/src/components/BudgetAmountSelect.tsx
new file mode 100644
index 000000000..4f598175f
--- /dev/null
+++ b/frontend/src/components/BudgetAmountSelect.tsx
@@ -0,0 +1,32 @@
+import { budgetOptions } from "src/types";
+
+function BudgetAmountSelect({
+ value,
+ onChange,
+}: {
+ value?: number;
+ onChange: (value: number) => void;
+}) {
+ return (
+
+ {Object.keys(budgetOptions).map((budget) => {
+ const amount = budgetOptions[budget];
+ return (
+
onChange(amount)}
+ className={`col-span-2 md:col-span-1 cursor-pointer rounded border-2 ${
+ value === amount ? "border-primary" : "border-muted"
+ } text-center py-4`}
+ >
+ {budget}
+
+ {amount ? "sats" : "#reckless"}
+
+ );
+ })}
+
+ );
+}
+
+export default BudgetAmountSelect;
diff --git a/frontend/src/components/BudgetRenewalSelect.tsx b/frontend/src/components/BudgetRenewalSelect.tsx
new file mode 100644
index 000000000..b058fd386
--- /dev/null
+++ b/frontend/src/components/BudgetRenewalSelect.tsx
@@ -0,0 +1,38 @@
+import React from "react";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "src/components/ui/select";
+import { BudgetRenewalType, validBudgetRenewals } from "src/types";
+
+interface BudgetRenewalProps {
+ value: BudgetRenewalType;
+ onChange: (value: BudgetRenewalType) => void;
+ disabled?: boolean;
+}
+
+const BudgetRenewalSelect: React.FC = ({
+ value,
+ onChange,
+ disabled,
+}) => {
+ return (
+
+ );
+};
+
+export default BudgetRenewalSelect;
diff --git a/frontend/src/components/Permissions.tsx b/frontend/src/components/Permissions.tsx
index d061ed62c..2dbbf9058 100644
--- a/frontend/src/components/Permissions.tsx
+++ b/frontend/src/components/Permissions.tsx
@@ -1,26 +1,19 @@
import { PlusCircle } from "lucide-react";
import React, { useEffect, useState } from "react";
+import BudgetAmountSelect from "src/components/BudgetAmountSelect";
+import BudgetRenewalSelect from "src/components/BudgetRenewalSelect";
import { Button } from "src/components/ui/button";
import { Checkbox } from "src/components/ui/checkbox";
import { Label } from "src/components/ui/label";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "src/components/ui/select";
import { useCapabilities } from "src/hooks/useCapabilities";
import { cn } from "src/lib/utils";
import {
AppPermissions,
BudgetRenewalType,
Scope,
- budgetOptions,
expiryOptions,
iconMap,
scopeDescriptions,
- validBudgetRenewals,
} from "src/types";
interface PermissionsProps {
@@ -164,55 +157,17 @@ const Permissions: React.FC = ({
{!canEditPermissions ? (
permissions.budgetRenewal
) : (
-
+ />
)}
-
- {Object.keys(budgetOptions).map((budget) => {
- return (
- // replace with something else and then remove dark prefixes
-
- handleMaxAmountChange(budgetOptions[budget])
- }
- className={`col-span-2 md:col-span-1 cursor-pointer rounded border-2 ${
- permissions.maxAmount == budgetOptions[budget]
- ? "border-primary"
- : "border-muted"
- } text-center py-4 dark:text-white`}
- >
- {budget}
-
- {budgetOptions[budget] ? "sats" : "#reckless"}
-
- );
- })}
-
+
>
) : isNewConnection ? (
<>
diff --git a/frontend/src/components/SidebarHint.tsx b/frontend/src/components/SidebarHint.tsx
index 0ec49db5d..67bf68f7b 100644
--- a/frontend/src/components/SidebarHint.tsx
+++ b/frontend/src/components/SidebarHint.tsx
@@ -87,9 +87,9 @@ function SidebarHint() {
return (
);
diff --git a/frontend/src/components/connections/AlbyConnectionCard.tsx b/frontend/src/components/connections/AlbyConnectionCard.tsx
index c8882402e..ab3e39a8e 100644
--- a/frontend/src/components/connections/AlbyConnectionCard.tsx
+++ b/frontend/src/components/connections/AlbyConnectionCard.tsx
@@ -6,9 +6,11 @@ import {
Link2Icon,
ZapIcon,
} from "lucide-react";
-import albyButton from "public/images/illustrations/login-with-alby.png";
import { useState } from "react";
import { Link } from "react-router-dom";
+
+import BudgetAmountSelect from "src/components/BudgetAmountSelect";
+import BudgetRenewalSelect from "src/components/BudgetRenewalSelect";
import ExternalLink from "src/components/ExternalLink";
import Loading from "src/components/Loading";
import UserAvatar from "src/components/UserAvatar";
@@ -32,23 +34,20 @@ import {
} from "src/components/ui/dialog";
import { Label } from "src/components/ui/label";
import { LoadingButton } from "src/components/ui/loading-button";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "src/components/ui/select";
import { Separator } from "src/components/ui/separator";
import { useAlbyMe } from "src/hooks/useAlbyMe";
import { LinkStatus, useLinkAccount } from "src/hooks/useLinkAccount";
-import { App, budgetOptions, validBudgetRenewals } from "src/types";
+import { App, BudgetRenewalType } from "src/types";
+import albyButton from "/images/illustrations/login-with-alby.png";
function AlbyConnectionCard({ connection }: { connection?: App }) {
const { data: albyMe } = useAlbyMe();
const { loading, linkStatus, loadingLinkStatus, linkAccount } =
useLinkAccount();
- const [maxAmount, setMaxAmount] = useState();
+
+ const [maxAmount, setMaxAmount] = useState(1_000_000);
+ const [budgetRenewal, setBudgetRenewal] =
+ useState("monthly");
return (
@@ -91,68 +90,29 @@ function AlbyConnectionCard({ connection }: { connection?: App }) {
Link to Alby Account
-
- After you link your account, every app you access
- through your Alby Account will handle payments via the
- Hub.
-
+ After you link your account, every app you access through
+ your Alby Account will handle payments via the Hub.
-
- You can add a budget that will restrict how much can be
- spent from the Hub with your Alby Account.
-
-
-
-
-
-
- {Object.keys(budgetOptions).map((budget) => {
- return (
- // replace with something else and then remove dark prefixes
-
- setMaxAmount(budgetOptions[budget])
- }
- className={`col-span-2 md:col-span-1 cursor-pointer rounded border-2 ${
- maxAmount == budgetOptions[budget]
- ? "border-primary"
- : "border-muted"
- } text-center py-4`}
- >
- {budget}
-
- {budgetOptions[budget] ? "sats" : "#reckless"}
-
- );
- })}
-
+ You can add a budget that will restrict how much can be
+ spent from the Hub with your Alby Account.
+
+
+
+
+
-
- Link to Alby Account
+ linkAccount(maxAmount, budgetRenewal)}
+ loading={loading}
+ >
+ Link to Alby Account
diff --git a/frontend/src/components/connections/AppCard.tsx b/frontend/src/components/connections/AppCard.tsx
index 7276e3235..edb3864c6 100644
--- a/frontend/src/components/connections/AppCard.tsx
+++ b/frontend/src/components/connections/AppCard.tsx
@@ -1,6 +1,6 @@
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
-import { Link } from "react-router-dom";
+import { useNavigate } from "react-router-dom";
import AppAvatar from "src/components/AppAvatar";
import { AppCardConnectionInfo } from "src/components/connections/AppCardConnectionInfo";
import { AppCardNotice } from "src/components/connections/AppCardNotice";
@@ -20,26 +20,27 @@ type Props = {
};
export default function AppCard({ app }: Props) {
+ const navigate = useNavigate();
+
return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
+ navigate(`/apps/${app.nostrPubkey}`)}
+ >
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/frontend/src/components/connections/AppCardConnectionInfo.tsx b/frontend/src/components/connections/AppCardConnectionInfo.tsx
index ba2d50df9..8e3d6ee7b 100644
--- a/frontend/src/components/connections/AppCardConnectionInfo.tsx
+++ b/frontend/src/components/connections/AppCardConnectionInfo.tsx
@@ -93,7 +93,10 @@ export function AppCardConnectionInfo({
<>Last used: {dayjs(connection.lastEventAt).fromNow()}>
)}
-
+ e.stopPropagation()}
+ >