From c36170a3164a1fbb9d42fcc1d7814397791b5074 Mon Sep 17 00:00:00 2001 From: avatGit Date: Tue, 23 Jun 2026 00:57:44 +0200 Subject: [PATCH] feat: add clipboard paste shortcut with Stellar address validation to Send and Schedule pages --- apps/src/components/AddressInput.tsx | 69 ++++++++++++++++++++++++++++ apps/src/pages/SchedulePage.tsx | 10 +++- apps/src/pages/SendPage.tsx | 9 ++-- 3 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 apps/src/components/AddressInput.tsx diff --git a/apps/src/components/AddressInput.tsx b/apps/src/components/AddressInput.tsx new file mode 100644 index 0000000..382ee32 --- /dev/null +++ b/apps/src/components/AddressInput.tsx @@ -0,0 +1,69 @@ +import React from "react"; +import { ClipboardPaste } from "lucide-react"; +import toast from "react-hot-toast"; +import * as StellarSdk from "@stellar/stellar-sdk"; +import '../index.css' + +interface AddressInputProps { + value: string; + onChange: (value: string) => void; + placeholder?: string; + className?: string; +} + +export const AddressInput: React.FC = ({ + value, + onChange, + placeholder = "Enter the Stellar address (G...)", + className = "", +}) => { + const handlePaste = async () => { + try { + // Request to access the clipBoard + if (!navigator.clipboard) { + toast.error("Your browser does not support access to the clipboard."); + return; + } + + const text = await navigator.clipboard.readText(); + const cleanText = text.trim(); + + if (!cleanText) { + toast.error("The clipboard is empty"); + return; + } + + // Validation of the public key with StellarSdk + if (StellarSdk.StrKey.isValidEd25519PublicKey(cleanText)) { + onChange(cleanText); + toast.success("Address successfully pasted!"); + } else { + toast.error("The clipboard contents are not a valid Stellar address."); + } + } catch (error) { + // + toast.error("Clipboard access permission denied"); + console.error("Clipboard Error: ", error); + } + }; + + return ( +
+ onChange(e.target.value)} + placeholder={placeholder} + className=" input-field w-full pr-12 pl-4 py-3 bg-opacity-10 bg-white border border-gray-600 rounded-lg focus:outline-none text-white placeholder-gray-400 text-sm transition-all" + /> + +
+ ); +}; diff --git a/apps/src/pages/SchedulePage.tsx b/apps/src/pages/SchedulePage.tsx index 30e4638..2ad7d94 100644 --- a/apps/src/pages/SchedulePage.tsx +++ b/apps/src/pages/SchedulePage.tsx @@ -13,6 +13,7 @@ import { XCircle, ChevronDown, ChevronUp, Loader2, } from 'lucide-react'; import type { ScheduledPayment } from '../types'; +import {AddressInput} from '../components/AddressInput' const FREQUENCIES: ScheduledPayment['frequency'][] = ['daily', 'weekly', 'monthly']; const ASSETS = ['XLM', 'USDC']; @@ -104,8 +105,13 @@ export default function SchedulePage() {
- setDestination(e.target.value)} /> -
+ +
diff --git a/apps/src/pages/SendPage.tsx b/apps/src/pages/SendPage.tsx index b71f2fa..4c68cff 100644 --- a/apps/src/pages/SendPage.tsx +++ b/apps/src/pages/SendPage.tsx @@ -5,6 +5,7 @@ import { buildSendTx, submitTx, USDC_ASSET } from '../lib/stellar'; import AssetBadge from '../components/AssetBadge'; import toast from 'react-hot-toast'; import { CheckCircle, ArrowRight } from 'lucide-react'; +import {AddressInput} from '../components/AddressInput' const ASSETS = [ { code: 'XLM', label: 'Stellar Lumens' }, @@ -112,11 +113,11 @@ export default function SendPage() { - setDestination(e.target.value)} + onChange={setDestination} + placeholder="G..." + className="font-mono text-sm" />