Surface a hint when the recipient picker is closed with no selection
The campaign donate flow opens HDSendBitcoinDialog with a prefilled bitcoin:bc1q…?sp=sp1… URI. BitcoinRecipientInput auto-opens its dropdown so the donor picks between the on-chain address and the silent-payment code — privacy vs. compatibility, the explicit choice the picker was designed around (92608f14). In practice the donor's eye lands on the amount presets first. Tapping $100 counts as an outside click, dismisses the popover, and leaves `recipient` null. The Send button is disabled (correctly — no destination resolved), the input still shows the prefilled URI, and nothing on screen tells the donor what's missing. They eventually discover that re-tapping the recipient input reopens the dropdown. Add a small amber hint with a warning icon directly beneath the recipient input whenever the input has parseable candidates but no selection AND the popover is closed. The whole hint is a button that reopens the popover and refocuses the input on tap, so the recovery takes one click instead of a guessing game. Gate the hint on a new `hasOpenedForQuery` flag that flips true the first time the popover opens for the current query and resets when the query clears. That keeps the hint from flashing for one paint frame between mount and the auto-open effect on prefilled inputs. Regression-of:92608f14
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Bitcoin, EyeOff, QrCode, X } from 'lucide-react';
|
||||
import { AlertTriangle, Bitcoin, EyeOff, QrCode, X } from 'lucide-react';
|
||||
|
||||
import { Input } from '@/components/ui/input';
|
||||
import {
|
||||
@@ -108,6 +108,11 @@ export function BitcoinRecipientInput({
|
||||
// selection.
|
||||
const [query, setQuery] = useState<string>(initialInput ?? '');
|
||||
const [open, setOpen] = useState(false);
|
||||
// Tracks whether the popover has been opened at least once for the
|
||||
// current query. The "choose a payment method" hint suppresses on the
|
||||
// very first render so callers prefilling the input don't see the hint
|
||||
// flash for one frame before the auto-open effect runs.
|
||||
const [hasOpenedForQuery, setHasOpenedForQuery] = useState(false);
|
||||
const [scannerOpen, setScannerOpen] = useState(false);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
@@ -161,11 +166,20 @@ export function BitcoinRecipientInput({
|
||||
useEffect(() => {
|
||||
if (trimmed.length === 0) {
|
||||
setOpen(false);
|
||||
setHasOpenedForQuery(false);
|
||||
return;
|
||||
}
|
||||
if (hasSp || hasBtc) setOpen(true);
|
||||
}, [trimmed, hasSp, hasBtc]);
|
||||
|
||||
// Track the first time the popover opens for the current query, so the
|
||||
// "choose a payment method" hint only appears after the donor has had a
|
||||
// chance to see (and dismiss) the dropdown — not flash for one paint
|
||||
// frame between mount and the auto-open effect above.
|
||||
useEffect(() => {
|
||||
if (open) setHasOpenedForQuery(true);
|
||||
}, [open]);
|
||||
|
||||
// ── Selection callbacks ───────────────────────────────────────────────
|
||||
const selectBtc = useCallback(
|
||||
(address: string) => {
|
||||
@@ -331,6 +345,32 @@ export function BitcoinRecipientInput({
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
{/* Picker-closed reminder. When the input holds parseable candidates
|
||||
but the donor hasn't actually picked one yet — typically because
|
||||
they tapped an amount preset, which counts as an outside-click
|
||||
and dismisses the popover — the Send button is disabled with no
|
||||
visible reason. Surface an actionable hint that re-opens the
|
||||
dropdown so the donor doesn't have to guess that they're meant
|
||||
to tap the recipient input again.
|
||||
|
||||
Gated on `hasOpenedForQuery` so the hint doesn't flash for one
|
||||
paint frame between mount and the auto-open effect on prefilled
|
||||
inputs (campaign donate flow). */}
|
||||
{hasOpenedForQuery && !popoverOpen && totalItems > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
onClick={() => {
|
||||
setOpen(true);
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
className="flex items-center gap-1.5 text-xs text-amber-600 dark:text-amber-500 hover:text-amber-700 dark:hover:text-amber-400 motion-safe:transition-colors text-left"
|
||||
>
|
||||
<AlertTriangle className="size-3.5 shrink-0" />
|
||||
<span>{t('walletSend.recipient.choosePaymentMethod')}</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
<QrScannerDialog
|
||||
isOpen={scannerOpen}
|
||||
onClose={() => setScannerOpen(false)}
|
||||
|
||||
+2
-1
@@ -1158,7 +1158,8 @@
|
||||
"bitcoinAddress": "عنوان بيتكوين",
|
||||
"silentPayment": "عنوان دفع صامت",
|
||||
"toLabel": "إلى",
|
||||
"clear": "مسح المستلم"
|
||||
"clear": "مسح المستلم",
|
||||
"choosePaymentMethod": "اختر طريقة الدفع للمتابعة"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~10 دقائق",
|
||||
|
||||
+2
-1
@@ -1672,7 +1672,8 @@
|
||||
"bitcoinAddress": "Bitcoin address",
|
||||
"silentPayment": "Silent payment address",
|
||||
"toLabel": "To",
|
||||
"clear": "Clear recipient"
|
||||
"clear": "Clear recipient",
|
||||
"choosePaymentMethod": "Choose a payment method to continue"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~10 min",
|
||||
|
||||
+2
-1
@@ -1174,7 +1174,8 @@
|
||||
"bitcoinAddress": "Dirección de Bitcoin",
|
||||
"silentPayment": "Dirección de pago silencioso",
|
||||
"toLabel": "Para",
|
||||
"clear": "Borrar destinatario"
|
||||
"clear": "Borrar destinatario",
|
||||
"choosePaymentMethod": "Elige un método de pago para continuar"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~10 min",
|
||||
|
||||
+2
-1
@@ -1174,7 +1174,8 @@
|
||||
"bitcoinAddress": "نشانی بیتکوین",
|
||||
"silentPayment": "نشانی پرداخت خاموش",
|
||||
"toLabel": "به",
|
||||
"clear": "پاک کردن گیرنده"
|
||||
"clear": "پاک کردن گیرنده",
|
||||
"choosePaymentMethod": "برای ادامه یک روش پرداخت انتخاب کنید"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~۱۰ دقیقه",
|
||||
|
||||
+2
-1
@@ -1597,7 +1597,8 @@
|
||||
"bitcoinAddress": "Adresse Bitcoin",
|
||||
"silentPayment": "Adresse de paiement silencieux",
|
||||
"toLabel": "À",
|
||||
"clear": "Effacer le destinataire"
|
||||
"clear": "Effacer le destinataire",
|
||||
"choosePaymentMethod": "Choisissez un mode de paiement pour continuer"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~10 min",
|
||||
|
||||
+2
-1
@@ -1543,7 +1543,8 @@
|
||||
"bitcoinAddress": "Bitcoin एड्रेस",
|
||||
"silentPayment": "साइलेंट पेमेंट एड्रेस",
|
||||
"toLabel": "किसे",
|
||||
"clear": "प्राप्तकर्ता हटाएँ"
|
||||
"clear": "प्राप्तकर्ता हटाएँ",
|
||||
"choosePaymentMethod": "जारी रखने के लिए भुगतान विधि चुनें"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~10 मिनट",
|
||||
|
||||
+2
-1
@@ -1543,7 +1543,8 @@
|
||||
"bitcoinAddress": "Alamat Bitcoin",
|
||||
"silentPayment": "Alamat silent payment",
|
||||
"toLabel": "Kepada",
|
||||
"clear": "Hapus penerima"
|
||||
"clear": "Hapus penerima",
|
||||
"choosePaymentMethod": "Pilih metode pembayaran untuk melanjutkan"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~10 menit",
|
||||
|
||||
+2
-1
@@ -1174,7 +1174,8 @@
|
||||
"bitcoinAddress": "អាសយដ្ឋាន Bitcoin",
|
||||
"silentPayment": "អាសយដ្ឋានទូទាត់ស្ងាត់",
|
||||
"toLabel": "ជូន",
|
||||
"clear": "សម្អាតអ្នកទទួល"
|
||||
"clear": "សម្អាតអ្នកទទួល",
|
||||
"choosePaymentMethod": "ជ្រើសរើសវិធីសាស្ត្រទូទាត់ដើម្បីបន្ត"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~១០ នាទី",
|
||||
|
||||
+2
-1
@@ -1174,7 +1174,8 @@
|
||||
"bitcoinAddress": "د بټکوین پته",
|
||||
"silentPayment": "د چوپې ورکړې پته",
|
||||
"toLabel": "ته",
|
||||
"clear": "ترلاسهکوونکی پاک کړئ"
|
||||
"clear": "ترلاسهکوونکی پاک کړئ",
|
||||
"choosePaymentMethod": "د دوام لپاره د ورکړې طریقه وټاکئ"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~۱۰ دقیقې",
|
||||
|
||||
+2
-1
@@ -1607,7 +1607,8 @@
|
||||
"bitcoinAddress": "Endereço Bitcoin",
|
||||
"silentPayment": "Endereço de pagamento silencioso",
|
||||
"toLabel": "Para",
|
||||
"clear": "Limpar destinatário"
|
||||
"clear": "Limpar destinatário",
|
||||
"choosePaymentMethod": "Escolha um método de pagamento para continuar"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~10 min",
|
||||
|
||||
+2
-1
@@ -1607,7 +1607,8 @@
|
||||
"bitcoinAddress": "Bitcoin-адрес",
|
||||
"silentPayment": "Адрес тихого платежа",
|
||||
"toLabel": "Кому",
|
||||
"clear": "Очистить получателя"
|
||||
"clear": "Очистить получателя",
|
||||
"choosePaymentMethod": "Выберите способ оплаты, чтобы продолжить"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~10 мин",
|
||||
|
||||
+2
-1
@@ -1174,7 +1174,8 @@
|
||||
"bitcoinAddress": "Kero yeBitcoin",
|
||||
"silentPayment": "Kero yemubhadharo wakanyararira",
|
||||
"toLabel": "Kuna",
|
||||
"clear": "Bvisa mugamuchiri"
|
||||
"clear": "Bvisa mugamuchiri",
|
||||
"choosePaymentMethod": "Sarudza nzira yokubhadhara kuti uenderere"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~10 maminitsi",
|
||||
|
||||
+2
-1
@@ -1502,7 +1502,8 @@
|
||||
"bitcoinAddress": "Anwani ya Bitcoin",
|
||||
"silentPayment": "Anwani ya malipo ya kimya",
|
||||
"toLabel": "Kwa",
|
||||
"clear": "Futa mpokeaji"
|
||||
"clear": "Futa mpokeaji",
|
||||
"choosePaymentMethod": "Chagua njia ya malipo ili kuendelea"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~dakika 10",
|
||||
|
||||
+2
-1
@@ -1542,7 +1542,8 @@
|
||||
"bitcoinAddress": "Bitcoin adresi",
|
||||
"silentPayment": "Sessiz ödeme adresi",
|
||||
"toLabel": "Alıcı",
|
||||
"clear": "Alıcıyı temizle"
|
||||
"clear": "Alıcıyı temizle",
|
||||
"choosePaymentMethod": "Devam etmek için bir ödeme yöntemi seçin"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~10 dk",
|
||||
|
||||
@@ -1110,7 +1110,8 @@
|
||||
"bitcoinAddress": "比特幣地址",
|
||||
"silentPayment": "靜默支付地址",
|
||||
"toLabel": "收件人",
|
||||
"clear": "清除收件人"
|
||||
"clear": "清除收件人",
|
||||
"choosePaymentMethod": "請選擇付款方式以繼續"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~10 分鐘",
|
||||
|
||||
+2
-1
@@ -1174,7 +1174,8 @@
|
||||
"bitcoinAddress": "比特币地址",
|
||||
"silentPayment": "静默支付地址",
|
||||
"toLabel": "收件人",
|
||||
"clear": "清除收件人"
|
||||
"clear": "清除收件人",
|
||||
"choosePaymentMethod": "请选择支付方式以继续"
|
||||
},
|
||||
"feeSpeed": {
|
||||
"fastest": "~10 分钟",
|
||||
|
||||
Reference in New Issue
Block a user