Wallet QR + mint UX: honest scan feedback, truthful auto-distribute affordance (1.2.27)

QR scanner (CashuWalletCard.handleQRScanResult):
- The classifier recognizes bitcoin_address, npub, and CLINK offer/debit codes,
  but all of them fell through to a misleading "Could not recognize the scanned
  content" toast. Now each gets an honest, specific message:
    • Bitcoin address → "On-chain not supported here" (this is an ecash/Lightning
      wallet with no on-chain send)
    • npub → "That's a Nostr profile"
    • noffer/ndebit → "Payment code not supported yet"
  Only genuinely unclassified input shows the generic "unrecognized" message.

MintPrivacyManager:
- Auto-distribute toggle was a live Switch that flipped on and then admitted
  "Coming soon — does nothing." Replaced with a disabled switch + "Soon" badge
  so users can't think they enabled a feature that isn't real. Removed the now
  dead autoDistribute state.
- Dropped unused imports (Progress, Lock, Eye, EyeOff).

The mint manager itself (distribution viz, privacy score, trust/balance
removal warnings) was already excellent and left untouched.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy 2026-09-07 21:54:43 +07:00
parent 2b50f2b496
commit 2b3ee73292
3 changed files with 39 additions and 22 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "skate-spots", "name": "skate-spots",
"private": true, "private": true,
"version": "1.2.26", "version": "1.2.27",
"type": "module", "type": "module",
"homepage": "https://skate-spots.com", "homepage": "https://skate-spots.com",
"scripts": { "scripts": {

View file

@ -242,11 +242,34 @@ function CashuWalletCardNative() {
case 'lightning_address': case 'lightning_address':
setLightningAddress(result.value); setLightningAddress(result.value);
break; break;
case 'bitcoin_address':
// Recognized, but this is an ecash/Lightning wallet — no on-chain send.
toast({
variant: 'destructive',
title: 'On-chain not supported here',
description: 'That’s a Bitcoin address. This wallet only sends Cashu tokens and Lightning payments.',
});
break;
case 'npub':
toast({
variant: 'destructive',
title: 'That’s a Nostr profile',
description: 'Scan a Cashu token, Lightning invoice, or Lightning address to pay.',
});
break;
case 'clink_offer':
case 'clink_debit':
toast({
variant: 'destructive',
title: 'Payment code not supported yet',
description: 'This wallet can’t pay CLINK codes yet. Use a Lightning invoice or address instead.',
});
break;
default: default:
toast({ toast({
variant: 'destructive', variant: 'destructive',
title: 'Unknown QR code', title: 'Unrecognized QR code',
description: 'Could not recognize the scanned content' description: 'Scan a Cashu token, Lightning invoice, or Lightning address.',
}); });
} }
}, [coco, setTokenInput, setLightningInvoice, toast]); }, [coco, setTokenInput, setLightningInvoice, toast]);

View file

@ -6,7 +6,6 @@ import { Label } from '@/components/ui/label';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { Alert, AlertDescription } from '@/components/ui/alert'; import { Alert, AlertDescription } from '@/components/ui/alert';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { Progress } from '@/components/ui/progress';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { import {
Shield, Shield,
@ -19,9 +18,6 @@ import {
ChevronUp, ChevronUp,
Star, Star,
Globe, Globe,
Lock,
Eye,
EyeOff,
} from 'lucide-react'; } from 'lucide-react';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
@ -91,7 +87,6 @@ export function MintPrivacyManager({
const [mintUrl, setMintUrl] = useState(''); const [mintUrl, setMintUrl] = useState('');
const [isAddingMint, setIsAddingMint] = useState(false); const [isAddingMint, setIsAddingMint] = useState(false);
const [mintToRemove, setMintToRemove] = useState<Mint | null>(null); const [mintToRemove, setMintToRemove] = useState<Mint | null>(null);
const [autoDistribute, setAutoDistribute] = useState(false);
const { toast } = useToast(); const { toast } = useToast();
// Calculate distribution across mints // Calculate distribution across mints
@ -287,24 +282,23 @@ export function MintPrivacyManager({
Add Mint Add Mint
</Button> </Button>
{/* Auto Distribution Toggle */} {/* Auto Distribution Toggle — not yet implemented, so it's shown as a
<div className="flex items-center justify-between p-3 rounded-lg bg-muted/50"> disabled affordance with a "Soon" badge rather than a switch that
flips on but does nothing. */}
<div className="flex items-center justify-between p-3 rounded-lg bg-muted/50 opacity-70">
<div className="space-y-0.5"> <div className="space-y-0.5">
<div className="flex items-center gap-2">
<Label className="text-sm font-medium">Auto-distribute funds</Label> <Label className="text-sm font-medium">Auto-distribute funds</Label>
<Badge variant="outline" className="text-[10px] text-amber-400 border-amber-500/30">
Soon
</Badge>
</div>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
Spread received funds across multiple mints Spread received funds across multiple mints
</p> </p>
</div> </div>
<Switch <Switch checked={false} disabled aria-label="Auto-distribute funds (coming soon)" />
checked={autoDistribute}
onCheckedChange={setAutoDistribute}
/>
</div> </div>
{autoDistribute && (
<p className="text-xs text-amber-500 italic">
Coming soon - this feature is planned for a future update
</p>
)}
{/* Privacy Tips Toggle */} {/* Privacy Tips Toggle */}
<Button <Button