fix: use deep link instead of QR on mobile, show extension only on desktop

This commit is contained in:
2026-02-22 22:16:55 +03:00
parent a5eea60858
commit 0f2ed1c14f
7 changed files with 107 additions and 33 deletions
@@ -1,6 +1,6 @@
import React, { useEffect, useState, useCallback } from 'react'; import React, { useEffect, useState, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Smartphone, Loader2, CheckCircle, XCircle } from 'lucide-react'; import { Smartphone, Loader2, CheckCircle, XCircle, ExternalLink } from 'lucide-react';
import QRCode from 'qrcode'; import QRCode from 'qrcode';
import { import {
Dialog, Dialog,
@@ -11,6 +11,7 @@ import {
} from '@/components/ui/dialog'; } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { usePezkuwi } from '@/contexts/PezkuwiContext'; import { usePezkuwi } from '@/contexts/PezkuwiContext';
import { useIsMobile } from '@/hooks/use-mobile';
interface WalletConnectModalProps { interface WalletConnectModalProps {
isOpen: boolean; isOpen: boolean;
@@ -22,7 +23,9 @@ type ConnectionState = 'generating' | 'waiting' | 'connected' | 'error';
export const WalletConnectModal: React.FC<WalletConnectModalProps> = ({ isOpen, onClose }) => { export const WalletConnectModal: React.FC<WalletConnectModalProps> = ({ isOpen, onClose }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { connectWalletConnect, selectedAccount, wcPeerName } = usePezkuwi(); const { connectWalletConnect, selectedAccount, wcPeerName } = usePezkuwi();
const isMobile = useIsMobile();
const [qrDataUrl, setQrDataUrl] = useState<string>(''); const [qrDataUrl, setQrDataUrl] = useState<string>('');
const [wcUri, setWcUri] = useState<string>('');
const [connectionState, setConnectionState] = useState<ConnectionState>('generating'); const [connectionState, setConnectionState] = useState<ConnectionState>('generating');
const [errorMsg, setErrorMsg] = useState<string>(''); const [errorMsg, setErrorMsg] = useState<string>('');
@@ -32,24 +35,31 @@ export const WalletConnectModal: React.FC<WalletConnectModalProps> = ({ isOpen,
try { try {
const uri = await connectWalletConnect(); const uri = await connectWalletConnect();
setWcUri(uri);
// Generate QR code as data URL if (isMobile) {
const dataUrl = await QRCode.toDataURL(uri, { // Mobile: open pezWallet via deep link automatically
width: 300, const deepLink = `pezkuwiwallet://wc?uri=${encodeURIComponent(uri)}`;
margin: 2, window.location.href = deepLink;
color: { setConnectionState('waiting');
dark: '#000000', } else {
light: '#ffffff', // Desktop: generate QR code
}, const dataUrl = await QRCode.toDataURL(uri, {
}); width: 300,
margin: 2,
setQrDataUrl(dataUrl); color: {
setConnectionState('waiting'); dark: '#000000',
light: '#ffffff',
},
});
setQrDataUrl(dataUrl);
setConnectionState('waiting');
}
} catch (err) { } catch (err) {
setConnectionState('error'); setConnectionState('error');
setErrorMsg(err instanceof Error ? err.message : 'Connection failed'); setErrorMsg(err instanceof Error ? err.message : 'Connection failed');
} }
}, [connectWalletConnect]); }, [connectWalletConnect, isMobile]);
// Start connection when modal opens // Start connection when modal opens
useEffect(() => { useEffect(() => {
@@ -59,6 +69,7 @@ export const WalletConnectModal: React.FC<WalletConnectModalProps> = ({ isOpen,
return () => { return () => {
setQrDataUrl(''); setQrDataUrl('');
setWcUri('');
setConnectionState('generating'); setConnectionState('generating');
}; };
}, [isOpen, startConnection]); }, [isOpen, startConnection]);
@@ -75,6 +86,12 @@ export const WalletConnectModal: React.FC<WalletConnectModalProps> = ({ isOpen,
return () => window.removeEventListener('walletconnect_connected', handleConnected); return () => window.removeEventListener('walletconnect_connected', handleConnected);
}, [onClose]); }, [onClose]);
const handleOpenPezWallet = () => {
if (wcUri) {
window.location.href = `pezkuwiwallet://wc?uri=${encodeURIComponent(wcUri)}`;
}
};
return ( return (
<Dialog open={isOpen} onOpenChange={onClose}> <Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent className="sm:max-w-md"> <DialogContent className="sm:max-w-md">
@@ -84,7 +101,9 @@ export const WalletConnectModal: React.FC<WalletConnectModalProps> = ({ isOpen,
WalletConnect WalletConnect
</DialogTitle> </DialogTitle>
<DialogDescription> <DialogDescription>
{t('walletModal.wcScanQR', 'Scan with pezWallet to connect')} {isMobile
? t('walletModal.wcOpenWallet', 'Connect with pezWallet app')
: t('walletModal.wcScanQR', 'Scan with pezWallet to connect')}
</DialogDescription> </DialogDescription>
</DialogHeader> </DialogHeader>
@@ -94,28 +113,59 @@ export const WalletConnectModal: React.FC<WalletConnectModalProps> = ({ isOpen,
<div className="flex flex-col items-center gap-3 py-8"> <div className="flex flex-col items-center gap-3 py-8">
<Loader2 className="h-8 w-8 animate-spin text-purple-400" /> <Loader2 className="h-8 w-8 animate-spin text-purple-400" />
<p className="text-sm text-gray-400"> <p className="text-sm text-gray-400">
{t('walletModal.wcGenerating', 'Generating QR code...')} {t('walletModal.wcGenerating', 'Generating connection...')}
</p> </p>
</div> </div>
)} )}
{/* QR Code display - waiting for scan */} {/* Waiting state */}
{connectionState === 'waiting' && qrDataUrl && ( {connectionState === 'waiting' && (
<> <>
<div className="bg-white rounded-xl p-3"> {isMobile ? (
<img // Mobile: deep link button
src={qrDataUrl} <div className="flex flex-col items-center gap-4 py-4 w-full">
alt="WalletConnect QR Code" <div className="w-16 h-16 bg-purple-500/20 rounded-full flex items-center justify-center">
className="w-[280px] h-[280px]" <Smartphone className="h-8 w-8 text-purple-400" />
/> </div>
</div> <p className="text-sm text-gray-400 text-center">
<div className="flex items-center gap-2 text-sm text-gray-400"> {t('walletModal.wcWaitingMobile', 'Approve the connection in pezWallet')}
<Loader2 className="h-4 w-4 animate-spin" /> </p>
{t('walletModal.wcWaiting', 'Waiting for wallet to connect...')} <div className="flex items-center gap-2 text-sm text-gray-500">
</div> <Loader2 className="h-4 w-4 animate-spin" />
<p className="text-xs text-gray-500 text-center max-w-[280px]"> {t('walletModal.wcWaiting', 'Waiting for wallet to connect...')}
{t('walletModal.wcInstructions', 'Open pezWallet app → Settings → WalletConnect → Scan QR code')} </div>
</p> <Button
onClick={handleOpenPezWallet}
className="w-full bg-gradient-to-r from-purple-600 to-cyan-400 hover:from-purple-700 hover:to-cyan-500"
>
<ExternalLink className="mr-2 h-4 w-4" />
{t('walletModal.wcOpenApp', 'Open pezWallet')}
</Button>
<p className="text-xs text-gray-500 text-center">
{t('walletModal.wcInstallHint', "Don't have pezWallet? It will be available on Play Store soon.")}
</p>
</div>
) : (
// Desktop: QR code
<>
{qrDataUrl && (
<div className="bg-white rounded-xl p-3">
<img
src={qrDataUrl}
alt="WalletConnect QR Code"
className="w-[280px] h-[280px]"
/>
</div>
)}
<div className="flex items-center gap-2 text-sm text-gray-400">
<Loader2 className="h-4 w-4 animate-spin" />
{t('walletModal.wcWaiting', 'Waiting for wallet to connect...')}
</div>
<p className="text-xs text-gray-500 text-center max-w-[280px]">
{t('walletModal.wcInstructions', 'Open pezWallet app → Settings → WalletConnect → Scan QR code')}
</p>
</>
)}
</> </>
)} )}
+4
View File
@@ -1827,6 +1827,10 @@ export default {
'walletModal.or': 'أو', 'walletModal.or': 'أو',
'walletModal.connectWC': 'اتصل عبر pezWallet (الجوال)', 'walletModal.connectWC': 'اتصل عبر pezWallet (الجوال)',
'walletModal.wcScanQR': 'امسح بـ pezWallet للاتصال', 'walletModal.wcScanQR': 'امسح بـ pezWallet للاتصال',
'walletModal.wcOpenWallet': 'اتصل بتطبيق pezWallet',
'walletModal.wcWaitingMobile': 'وافق على الاتصال في pezWallet',
'walletModal.wcOpenApp': 'افتح pezWallet',
'walletModal.wcInstallHint': 'ليس لديك pezWallet؟ سيكون متاحاً قريباً على Play Store.',
'walletModal.wcGenerating': 'جاري إنشاء رمز QR...', 'walletModal.wcGenerating': 'جاري إنشاء رمز QR...',
'walletModal.wcWaiting': 'في انتظار اتصال المحفظة...', 'walletModal.wcWaiting': 'في انتظار اتصال المحفظة...',
'walletModal.wcConnected': 'تم الاتصال!', 'walletModal.wcConnected': 'تم الاتصال!',
+4
View File
@@ -1817,6 +1817,10 @@ export default {
'walletModal.or': 'یان', 'walletModal.or': 'یان',
'walletModal.connectWC': 'بە pezWallet پەیوەندی بکە (مۆبایل)', 'walletModal.connectWC': 'بە pezWallet پەیوەندی بکە (مۆبایل)',
'walletModal.wcScanQR': 'بۆ پەیوەندیکردن بە pezWallet سکان بکە', 'walletModal.wcScanQR': 'بۆ پەیوەندیکردن بە pezWallet سکان بکە',
'walletModal.wcOpenWallet': 'بە pezWallet پەیوەندی بکە',
'walletModal.wcWaitingMobile': 'لە pezWallet پەیوەندییەکە پشتڕاست بکەوە',
'walletModal.wcOpenApp': 'pezWallet بکەوە',
'walletModal.wcInstallHint': 'pezWallet نییە؟ بەم زووانە لە Play Store بەردەست دەبێت.',
'walletModal.wcGenerating': 'QR کۆد دروستدەکرێت...', 'walletModal.wcGenerating': 'QR کۆد دروستدەکرێت...',
'walletModal.wcWaiting': 'چاوەڕوانی پەیوەندیکردنی جزدان...', 'walletModal.wcWaiting': 'چاوەڕوانی پەیوەندیکردنی جزدان...',
'walletModal.wcConnected': 'پەیوەندی کرا!', 'walletModal.wcConnected': 'پەیوەندی کرا!',
+5 -1
View File
@@ -2186,8 +2186,12 @@ export default {
'walletModal.or': 'or', 'walletModal.or': 'or',
'walletModal.connectWC': 'Connect with pezWallet (Mobile)', 'walletModal.connectWC': 'Connect with pezWallet (Mobile)',
'walletModal.wcScanQR': 'Scan with pezWallet to connect', 'walletModal.wcScanQR': 'Scan with pezWallet to connect',
'walletModal.wcGenerating': 'Generating QR code...', 'walletModal.wcOpenWallet': 'Connect with pezWallet app',
'walletModal.wcGenerating': 'Generating connection...',
'walletModal.wcWaiting': 'Waiting for wallet to connect...', 'walletModal.wcWaiting': 'Waiting for wallet to connect...',
'walletModal.wcWaitingMobile': 'Approve the connection in pezWallet',
'walletModal.wcOpenApp': 'Open pezWallet',
'walletModal.wcInstallHint': "Don't have pezWallet? It will be available on Play Store soon.",
'walletModal.wcConnected': 'Connected!', 'walletModal.wcConnected': 'Connected!',
'walletModal.wcInstructions': 'Open pezWallet app → Settings → WalletConnect → Scan QR code', 'walletModal.wcInstructions': 'Open pezWallet app → Settings → WalletConnect → Scan QR code',
'walletModal.wcRetry': 'Try Again', 'walletModal.wcRetry': 'Try Again',
+4
View File
@@ -1787,6 +1787,10 @@ export default {
'walletModal.or': 'یا', 'walletModal.or': 'یا',
'walletModal.connectWC': 'اتصال با pezWallet (موبایل)', 'walletModal.connectWC': 'اتصال با pezWallet (موبایل)',
'walletModal.wcScanQR': 'برای اتصال با pezWallet اسکن کنید', 'walletModal.wcScanQR': 'برای اتصال با pezWallet اسکن کنید',
'walletModal.wcOpenWallet': 'اتصال با اپلیکیشن pezWallet',
'walletModal.wcWaitingMobile': 'اتصال را در pezWallet تأیید کنید',
'walletModal.wcOpenApp': 'باز کردن pezWallet',
'walletModal.wcInstallHint': 'pezWallet ندارید؟ به زودی در Play Store در دسترس خواهد بود.',
'walletModal.wcGenerating': 'در حال ایجاد کد QR...', 'walletModal.wcGenerating': 'در حال ایجاد کد QR...',
'walletModal.wcWaiting': 'در انتظار اتصال کیف پول...', 'walletModal.wcWaiting': 'در انتظار اتصال کیف پول...',
'walletModal.wcConnected': 'متصل شد!', 'walletModal.wcConnected': 'متصل شد!',
+4
View File
@@ -1844,6 +1844,10 @@ export default {
'walletModal.or': 'an jî', 'walletModal.or': 'an jî',
'walletModal.connectWC': 'Bi pezWallet ve girêbide (Mobîl)', 'walletModal.connectWC': 'Bi pezWallet ve girêbide (Mobîl)',
'walletModal.wcScanQR': 'Ji bo girêdanê bi pezWallet re bişopîne', 'walletModal.wcScanQR': 'Ji bo girêdanê bi pezWallet re bişopîne',
'walletModal.wcOpenWallet': 'Bi pezWallet ve girêbide',
'walletModal.wcWaitingMobile': 'Di pezWallet de girêdanê bipejirîne',
'walletModal.wcOpenApp': 'pezWallet Veke',
'walletModal.wcInstallHint': 'pezWallet tune? Di demek nêzîk de li Play Store dê hebe.',
'walletModal.wcGenerating': 'QR kod tê çêkirin...', 'walletModal.wcGenerating': 'QR kod tê çêkirin...',
'walletModal.wcWaiting': 'Li benda girêdana berîkê...', 'walletModal.wcWaiting': 'Li benda girêdana berîkê...',
'walletModal.wcConnected': 'Girêdayî!', 'walletModal.wcConnected': 'Girêdayî!',
+4
View File
@@ -1838,6 +1838,10 @@ export default {
'walletModal.or': 'veya', 'walletModal.or': 'veya',
'walletModal.connectWC': 'pezWallet ile Bağlan (Mobil)', 'walletModal.connectWC': 'pezWallet ile Bağlan (Mobil)',
'walletModal.wcScanQR': 'Bağlanmak için pezWallet ile tarayın', 'walletModal.wcScanQR': 'Bağlanmak için pezWallet ile tarayın',
'walletModal.wcOpenWallet': 'pezWallet uygulamasıyla bağlan',
'walletModal.wcWaitingMobile': 'pezWallet\'ta bağlantıyı onaylayın',
'walletModal.wcOpenApp': 'pezWallet\'ı Aç',
'walletModal.wcInstallHint': 'pezWallet yok mu? Yakında Play Store\'da olacak.',
'walletModal.wcGenerating': 'QR kod oluşturuluyor...', 'walletModal.wcGenerating': 'QR kod oluşturuluyor...',
'walletModal.wcWaiting': 'Cüzdan bağlantısı bekleniyor...', 'walletModal.wcWaiting': 'Cüzdan bağlantısı bekleniyor...',
'walletModal.wcConnected': 'Bağlandı!', 'walletModal.wcConnected': 'Bağlandı!',