From 07b59b9642eefd983fd1f691fef22e7de762142b Mon Sep 17 00:00:00 2001 From: oscar24357 Date: Fri, 28 Aug 2026 15:11:09 +0100 Subject: [PATCH 1/2] feat: add dismissNotification per-item control --- components/layout/notification-bell.tsx | 29 +++++++++++++++++++------ hooks/use-notifications.ts | 10 ++++++++- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/components/layout/notification-bell.tsx b/components/layout/notification-bell.tsx index c8a6426..2b54286 100644 --- a/components/layout/notification-bell.tsx +++ b/components/layout/notification-bell.tsx @@ -1,12 +1,18 @@ 'use client' import { useState, useRef, useEffect } from 'react' -import { Bell } from 'lucide-react' +import { Bell, X } from 'lucide-react' import { formatTimeAgo } from '@/lib/stream-utils' import { useWallet } from '@/hooks/use-wallet' import { useNotifications, type AppNotification } from '@/hooks/use-notifications' -function NotificationItem({ notification }: { notification: AppNotification }) { +function NotificationItem({ + notification, + onDismiss, +}: { + notification: AppNotification + onDismiss: (id: string) => void +}) { return (

{notification.title}

- {!notification.read && ( - - )} +
+ {!notification.read && ( + + )} + +

{notification.body}

{formatTimeAgo(notification.timestamp)}

@@ -28,7 +43,7 @@ function NotificationItem({ notification }: { notification: AppNotification }) { export function NotificationBell() { const { address } = useWallet() - const { notifications, unreadCount, markAllRead, clearAll } = useNotifications(address) + const { notifications, unreadCount, markAllRead, clearAll, dismissNotification } = useNotifications(address) const [open, setOpen] = useState(false) const ref = useRef(null) const triggerRef = useRef(null) @@ -105,7 +120,7 @@ export function NotificationBell() {

) : ( notifications.map((n) => ( - + )) )}
diff --git a/hooks/use-notifications.ts b/hooks/use-notifications.ts index 238dca1..bf7244a 100644 --- a/hooks/use-notifications.ts +++ b/hooks/use-notifications.ts @@ -252,6 +252,14 @@ export function useNotifications(walletAddress: string | null) { saveNotifications([]); }, []); + const dismissNotification = useCallback((id: string) => { + setNotifications((prev) => { + const updated = prev.filter((n) => n.id !== id); + saveNotifications(updated); + return updated; + }); + }, []); + useEffect(() => { const rpcUrl = config.rpcUrl; const contractId = config.streamContractId; @@ -388,5 +396,5 @@ export function useNotifications(walletAddress: string | null) { network, ]); - return { notifications, unreadCount, markAllRead, clearAll }; + return { notifications, unreadCount, markAllRead, clearAll, dismissNotification }; } From 1263c6234fbd9b39d065458f866cdeb029fddc1a Mon Sep 17 00:00:00 2001 From: oscar24357 Date: Fri, 28 Aug 2026 15:17:22 +0100 Subject: [PATCH 2/2] feat: show Not installed badge with install link in wallet dialog --- components/layout/connect-wallet-button.tsx | 23 +++++++++++++++++++-- components/providers/wallet-provider.tsx | 11 ++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/components/layout/connect-wallet-button.tsx b/components/layout/connect-wallet-button.tsx index 00614de..bce2f58 100644 --- a/components/layout/connect-wallet-button.tsx +++ b/components/layout/connect-wallet-button.tsx @@ -1,7 +1,7 @@ 'use client' import { useState } from 'react' -import { Check, Copy, LogOut, Loader2, Wallet } from 'lucide-react' +import { Check, Copy, LogOut, Loader2, Wallet, ExternalLink } from 'lucide-react' import { Button } from '@/components/ui/button' import { Dialog, @@ -19,7 +19,7 @@ import { DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' import { useWallet } from '@/hooks/use-wallet' -import { WALLET_OPTIONS } from '@/components/providers/wallet-provider' +import { WALLET_OPTIONS, ADAPTERS } from '@/components/providers/wallet-provider' import { shortenAddress } from '@/lib/stream-utils' import { cn } from '@/lib/utils' import { toast } from 'sonner' @@ -114,6 +114,7 @@ export function ConnectWalletButton({ className }: { className?: string }) { {WALLET_OPTIONS.map((wallet) => { const isPending = connecting && pendingId === wallet.id + const available = ADAPTERS[wallet.id]?.isAvailable() ?? true return ( ) })} diff --git a/components/providers/wallet-provider.tsx b/components/providers/wallet-provider.tsx index e8f29bb..7c8fdac 100644 --- a/components/providers/wallet-provider.tsx +++ b/components/providers/wallet-provider.tsx @@ -50,6 +50,7 @@ export interface WalletOption { id: string; name: string; detail: string; + installUrl?: string; } export const WALLET_OPTIONS: WalletOption[] = [ @@ -57,8 +58,14 @@ export const WALLET_OPTIONS: WalletOption[] = [ id: "freighter", name: "Freighter", detail: "Browser extension · stellar.org", + installUrl: "https://www.freighter.app", + }, + { + id: "xbull", + name: "xBull", + detail: "Extension & web", + installUrl: "https://xbull.app", }, - { id: "xbull", name: "xBull", detail: "Extension & web" }, { id: "lobstr", name: "LOBSTR", detail: "Mobile & extension" }, { id: "albedo", name: "Albedo", detail: "Web signer" }, ]; @@ -287,7 +294,7 @@ const albedoAdapter: WalletAdapter = { // ─── Adapter registry ───────────────────────────────────────────────────────── -const ADAPTERS: Record = { +export const ADAPTERS: Record = { freighter: freighterAdapter, xbull: xbullAdapter, lobstr: lobstrAdapter,