mirror of
https://github.com/getAlby/hub.git
synced 2026-08-13 12:33:39 +02:00
fix: delete lightning address when deleting a sub-wallet (#1858)
* fix: delete lightning address when deleting a sub-wallet * fix: pass app to useDeleteApp hook * fix: move deletion to server * fix: merge changes * Update frontend/src/components/connections/DisconnectApp.tsx Co-authored-by: Adithya Vardhan <imadithyavardhan@gmail.com> * fix: create helper function --------- Co-authored-by: Roland Bewick <roland.bewick@gmail.com> Co-authored-by: Adithya Vardhan <imadithyavardhan@gmail.com>
This commit is contained in:
parent
377a3169c6
commit
0c7cf4fcf6
5 changed files with 88 additions and 36 deletions
10
api/api.go
10
api/api.go
|
|
@ -320,6 +320,16 @@ func (api *api) UpdateApp(userApp *db.App, updateAppRequest *UpdateAppRequest) e
|
|||
}
|
||||
|
||||
func (api *api) DeleteApp(userApp *db.App) error {
|
||||
// Delete lightning address if one exists
|
||||
if api.appsSvc.HasLightningAddress(userApp) {
|
||||
err := api.DeleteLightningAddress(context.Background(), userApp.ID)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"app_id": userApp.ID,
|
||||
}).Error("Failed to delete lightning address during app deletion")
|
||||
}
|
||||
}
|
||||
|
||||
return api.appsSvc.DeleteApp(userApp)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ type AppsService interface {
|
|||
GetAppByPubkey(pubkey string) *db.App
|
||||
GetAppById(id uint) *db.App
|
||||
SetAppMetadata(appId uint, metadata map[string]interface{}) error
|
||||
HasLightningAddress(app *db.App) bool
|
||||
}
|
||||
|
||||
type appsService struct {
|
||||
|
|
@ -232,3 +233,18 @@ func (svc *appsService) SetAppMetadata(id uint, metadata map[string]interface{})
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc *appsService) HasLightningAddress(app *db.App) bool {
|
||||
if app.Metadata == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
var metadata map[string]interface{}
|
||||
err := json.Unmarshal(app.Metadata, &metadata)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
lud16, exists := metadata["lud16"]
|
||||
return exists && lud16 != nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export function DisconnectApp({
|
|||
}) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { deleteApp, isDeleting } = useDeleteApp(() => {
|
||||
const { deleteApp, isDeleting } = useDeleteApp(app, () => {
|
||||
navigate(
|
||||
app.metadata?.app_store_app_id !== SUBWALLET_APPSTORE_APP_ID
|
||||
? "/apps?tab=connected-apps"
|
||||
|
|
@ -33,6 +33,11 @@ export function DisconnectApp({
|
|||
);
|
||||
});
|
||||
|
||||
// Check if this is a sub-wallet with a lightning address
|
||||
const isSubwallet =
|
||||
app.metadata?.app_store_app_id === SUBWALLET_APPSTORE_APP_ID;
|
||||
const hasLightningAddress = !!app.metadata?.lud16;
|
||||
|
||||
return (
|
||||
<AlertDialog open>
|
||||
<AlertDialogTrigger asChild>
|
||||
|
|
@ -54,14 +59,17 @@ export function DisconnectApp({
|
|||
remain in your wallet.
|
||||
</>
|
||||
)}
|
||||
{isSubwallet && hasLightningAddress && (
|
||||
<p className="font-medium mt-4">
|
||||
This sub-wallet has a lightning address ({app.metadata?.lud16})
|
||||
that will also be deleted.
|
||||
</p>
|
||||
)}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel onClick={onClose}>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={() => deleteApp(app.appPubkey)}
|
||||
disabled={isDeleting}
|
||||
>
|
||||
<AlertDialogAction onClick={deleteApp} disabled={isDeleting}>
|
||||
Confirm
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
|
|
|
|||
|
|
@ -1,34 +1,35 @@
|
|||
import React from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { App } from "src/types";
|
||||
import { handleRequestError } from "src/utils/handleRequestError";
|
||||
import { request } from "src/utils/request";
|
||||
|
||||
export function useDeleteApp(onSuccess?: (appPubkey: string) => void) {
|
||||
export function useDeleteApp(app: App, onSuccess?: () => void) {
|
||||
const [isDeleting, setDeleting] = React.useState(false);
|
||||
|
||||
const deleteApp = React.useCallback(
|
||||
async (appPubkey: string) => {
|
||||
setDeleting(true);
|
||||
try {
|
||||
await request(`/api/apps/${appPubkey}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
toast("Connection deleted");
|
||||
if (onSuccess) {
|
||||
onSuccess(appPubkey);
|
||||
}
|
||||
} catch (error) {
|
||||
await handleRequestError("Failed to delete connection", error);
|
||||
} finally {
|
||||
setDeleting(false);
|
||||
const deleteApp = React.useCallback(async () => {
|
||||
setDeleting(true);
|
||||
try {
|
||||
// Delete the app/sub-wallet
|
||||
await request(`/api/apps/${app.appPubkey}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
toast("Connection deleted");
|
||||
|
||||
if (onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
},
|
||||
[onSuccess]
|
||||
);
|
||||
} catch (error) {
|
||||
await handleRequestError("Failed to delete connection", error);
|
||||
} finally {
|
||||
setDeleting(false);
|
||||
}
|
||||
}, [onSuccess, app]);
|
||||
|
||||
return React.useMemo(
|
||||
() => ({ deleteApp, isDeleting }),
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ export function AppsCleanup() {
|
|||
const [skippedCount, setSkippedCount] = React.useState<number>(0);
|
||||
const [deletedCount, setDeletedCount] = React.useState<number>(0);
|
||||
const [appsToReview, setAppsToReview] = React.useState<App[]>();
|
||||
const { deleteApp } = useDeleteApp();
|
||||
React.useEffect(() => {
|
||||
if (!unusedApps) {
|
||||
return;
|
||||
|
|
@ -86,17 +85,13 @@ export function AppsCleanup() {
|
|||
<SkipForwardIcon />
|
||||
Skip
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={() => {
|
||||
deleteApp(currentApp.appPubkey);
|
||||
<DeleteAppButton
|
||||
app={currentApp}
|
||||
onDelete={() => {
|
||||
setAppIndex(appIndex + 1);
|
||||
setDeletedCount((current) => current + 1);
|
||||
}}
|
||||
>
|
||||
<Trash2Icon />
|
||||
Delete
|
||||
</Button>
|
||||
/>
|
||||
</>
|
||||
}
|
||||
readonly
|
||||
|
|
@ -133,3 +128,25 @@ export function AppsCleanup() {
|
|||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function DeleteAppButton({
|
||||
app,
|
||||
onDelete,
|
||||
}: {
|
||||
app: App;
|
||||
onDelete: () => void;
|
||||
}) {
|
||||
const { deleteApp } = useDeleteApp(app);
|
||||
return (
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={() => {
|
||||
deleteApp();
|
||||
onDelete();
|
||||
}}
|
||||
>
|
||||
<Trash2Icon />
|
||||
Delete
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue