diff --git a/frontend/components/stream-creation/AmountStep.tsx b/frontend/components/stream-creation/AmountStep.tsx index 90ae7f1..9cafcff 100644 --- a/frontend/components/stream-creation/AmountStep.tsx +++ b/frontend/components/stream-creation/AmountStep.tsx @@ -1,5 +1,5 @@ "use client"; -import React from "react"; +import React, { useRef, useEffect } from "react"; interface AmountStepProps { value: string; @@ -14,6 +14,13 @@ export const AmountStep: React.FC = ({ error, token, }) => { + const inputRef = useRef(null); + + // Auto-focus on mount + useEffect(() => { + inputRef.current?.focus(); + }, []); + return (
@@ -32,6 +39,7 @@ export const AmountStep: React.FC = ({
= ({ onChange, error, }) => { + const inputRef = useRef(null); + + // Auto-focus on mount + useEffect(() => { + inputRef.current?.focus(); + }, []); + return (
@@ -30,6 +37,7 @@ export const RecipientStep: React.FC = ({ Stellar Public Key = ({ amount, token, }) => { + const durationInputRef = useRef(null); + + // Auto-focus on mount + useEffect(() => { + durationInputRef.current?.focus(); + }, []); + const ratePerSecond = useMemo(() => { if (!amount || !duration || parseFloat(amount) <= 0 || parseFloat(duration) <= 0) { return null; @@ -91,6 +98,7 @@ export const ScheduleStep: React.FC = ({ Duration = ({ if (validateStep(currentStep)) { if (currentStep < STEPS.length) { setCurrentStep(currentStep + 1); + // Scroll to top when moving to next step + const modal = document.querySelector('.glass-card'); + if (modal) { + modal.scrollTo({ top: 0, behavior: 'smooth' }); + } + } + } else { + // Scroll to first error if validation fails + const firstError = document.querySelector('[role="alert"]'); + if (firstError) { + firstError.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } }; @@ -102,6 +113,8 @@ export const StreamCreationWizard: React.FC = ({ const handleBack = () => { if (currentStep > 1) { setCurrentStep(currentStep - 1); + // Scroll to top when going back + window.scrollTo({ top: 0, behavior: 'smooth' }); } }; @@ -113,9 +126,14 @@ export const StreamCreationWizard: React.FC = ({ } catch (error) { console.error("Failed to create stream:", error); // Error handling can be added here (e.g., toast notification) - } finally { setIsSubmitting(false); } + } else { + // Scroll to first error if validation fails + const firstError = document.querySelector('[role="alert"]'); + if (firstError) { + firstError.scrollIntoView({ behavior: 'smooth', block: 'center' }); + } } }; @@ -163,8 +181,27 @@ export const StreamCreationWizard: React.FC = ({ } }; + // Handle Escape key to close + React.useEffect(() => { + const handleEscape = (e: KeyboardEvent) => { + if (e.key === 'Escape') { + onClose(); + } + }; + window.addEventListener('keydown', handleEscape); + return () => window.removeEventListener('keydown', handleEscape); + }, [onClose]); + return ( -
+
{ + // Close on backdrop click + if (e.target === e.currentTarget) { + onClose(); + } + }} + >

Create Payment Stream

@@ -192,12 +229,25 @@ export const StreamCreationWizard: React.FC = ({ -
{renderStepContent()}
+
+
+
+ Step {currentStep} of {STEPS.length} +
+
+ {Math.round((currentStep / STEPS.length) * 100)}% complete +
+
+ {renderStepContent()} +
{currentStep > 1 && ( )} @@ -207,10 +257,25 @@ export const StreamCreationWizard: React.FC = ({ Cancel {currentStep < STEPS.length ? ( - + ) : ( )}