From 0a0d2e015b828e6e01ccda4725e73cef95372a7d Mon Sep 17 00:00:00 2001 From: PEDZEO Date: Tue, 20 Jan 2026 17:19:22 +0300 Subject: [PATCH] Refactor TopUpModal and ConnectionModal for improved layout and icon integration - Adjusted layout in ConnectionModal for better vertical alignment. - Introduced new icons for payment methods in TopUpModal, enhancing visual representation. - Updated input fields and buttons for a more modern design and improved user experience. - Enhanced mobile responsiveness and accessibility features. --- src/components/ConnectionModal.tsx | 2 +- src/components/TopUpModal.tsx | 331 ++++++++++++++++++++--------- 2 files changed, 226 insertions(+), 107 deletions(-) diff --git a/src/components/ConnectionModal.tsx b/src/components/ConnectionModal.tsx index 1833984..3b5ccb4 100644 --- a/src/components/ConnectionModal.tsx +++ b/src/components/ConnectionModal.tsx @@ -274,7 +274,7 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) { // Desktop centered return ( -
+
e.stopPropagation()} diff --git a/src/components/TopUpModal.tsx b/src/components/TopUpModal.tsx index 8618c65..ffe11a6 100644 --- a/src/components/TopUpModal.tsx +++ b/src/components/TopUpModal.tsx @@ -37,6 +37,36 @@ const CloseIcon = () => ( ) +const WalletIcon = () => ( + + + +) + +const StarIcon = () => ( + + + +) + +const CardIcon = () => ( + + + +) + +const CryptoIcon = () => ( + + + +) + +const SparklesIcon = () => ( + + + +) + interface TopUpModalProps { method: PaymentMethod onClose: () => void @@ -56,6 +86,14 @@ function useIsMobile() { return isMobile } +// Get method icon based on method type +const getMethodIcon = (methodId: string) => { + const id = methodId.toLowerCase() + if (id.includes('stars')) return + if (id.includes('crypto') || id.includes('ton') || id.includes('usdt')) return + return +} + export default function TopUpModal({ method, onClose, initialAmountRubles }: TopUpModalProps) { const { t } = useTranslation() const { formatAmount, currencySymbol, convertAmount, convertToRub, targetCurrency } = useCurrency() @@ -79,6 +117,7 @@ export default function TopUpModal({ method, onClose, initialAmountRubles }: Top method.options && method.options.length > 0 ? method.options[0].id : null ) const popupRef = useRef(null) + const [isInputFocused, setIsInputFocused] = useState(false) const handleClose = useCallback(() => { onClose() @@ -107,7 +146,7 @@ export default function TopUpModal({ method, onClose, initialAmountRubles }: Top } }, [webApp, handleClose]) - // Scroll lock - simple version without position:fixed + // Scroll lock useEffect(() => { const scrollY = window.scrollY const preventScroll = (e: TouchEvent) => { @@ -194,7 +233,6 @@ export default function TopUpModal({ method, onClose, initialAmountRubles }: Top } const amountKopeks = Math.round(amountRubles * 100) - // IMPORTANT: Pre-open window on PC to avoid popup blockers if (!isTelegramMiniApp) { try { popupRef.current = window.open('', '_blank') } catch { popupRef.current = null } } @@ -217,104 +255,88 @@ export default function TopUpModal({ method, onClose, initialAmountRubles }: Top return () => clearTimeout(timer) }, [isMobileScreen]) - // Mobile bottom sheet - const MobileModal = () => ( - <> -
-
e.stopPropagation()} - > - {/* Handle */} -
-
-
- {/* Header */} -
- {methodName} - -
- {/* Content */} -
- {renderContent()} -
-
- - ) - - // Desktop centered modal - const DesktopModal = () => ( -
-
e.stopPropagation()} - > - {/* Header */} -
- {methodName} - -
- {/* Content */} -
- {renderContent()} -
-
-
- ) + // Calculate display amount for preview + const displayAmount = amount && parseFloat(amount) > 0 ? parseFloat(amount) : 0 const renderContent = () => ( - <> - {/* Payment options */} +
+ {/* Header icon and method */} +
+
+
+ {getMethodIcon(method.id)} +
+
+
+

{methodName}

+

+ {formatAmount(minRubles, 0)} – {formatAmount(maxRubles, 0)} {currencySymbol} +

+
+
+ + {/* Payment options (if any) */} {hasOptions && method.options && ( -
- {method.options.map((opt) => ( - - ))} +
+ +
+ {method.options.map((opt) => ( + + ))} +
)} - {/* Amount input */} -
- setAmount(e.target.value)} - onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); handleSubmit() } }} - placeholder={`${formatAmount(minRubles, 0)} – ${formatAmount(maxRubles, 0)}`} - className="w-full h-12 px-4 pr-12 text-lg font-semibold bg-dark-800 border border-dark-700 rounded-xl text-dark-100 placeholder:text-dark-500 focus:outline-none focus:border-accent-500 transition-colors" - style={{ fontSize: '18px' }} - autoComplete="off" - /> - - {currencySymbol} - + {/* Amount input - modern design */} +
+ +
+ setAmount(e.target.value)} + onFocus={() => setIsInputFocused(true)} + onBlur={() => setIsInputFocused(false)} + onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); handleSubmit() } }} + placeholder="0" + className="w-full h-16 px-5 pr-16 text-2xl font-bold bg-transparent text-dark-100 placeholder:text-dark-600 focus:outline-none" + style={{ fontSize: '24px' }} + autoComplete="off" + /> + + {currencySymbol} + +
- {/* Quick amounts */} + {/* Quick amount buttons */} {quickAmounts.length > 0 && (
{quickAmounts.map((a) => { @@ -325,10 +347,10 @@ export default function TopUpModal({ method, onClose, initialAmountRubles }: Top key={a} type="button" onClick={() => { setAmount(val); inputRef.current?.blur() }} - className={`flex-1 py-2.5 rounded-xl text-sm font-semibold transition-all ${ + className={`flex-1 py-3 rounded-xl text-sm font-bold transition-all duration-200 ${ isSelected - ? 'bg-accent-500/15 text-accent-400 ring-1 ring-accent-500/30' - : 'bg-dark-800 text-dark-300 hover:bg-dark-700' + ? 'bg-accent-500/20 text-accent-400 ring-1 ring-accent-500/40' + : 'bg-dark-800/50 text-dark-400 hover:bg-dark-800 hover:text-dark-300 border border-dark-700/30' }`} > {formatAmount(a, 0)} @@ -338,32 +360,129 @@ export default function TopUpModal({ method, onClose, initialAmountRubles }: Top
)} - {/* Error */} + {/* Error message */} {error && ( -
{error}
+
+ + + + {error} +
)} - {/* Submit */} + {/* Submit button */} +
+ ) + + // Mobile bottom sheet + const MobileModal = () => ( + <> + {/* Backdrop */} +
+ {/* Bottom sheet */} +
e.stopPropagation()} + > + {/* Handle bar */} +
+
+
+ + {/* Header */} +
+
+ + {t('balance.topUp')} +
+ +
+ + {/* Divider */} +
+ + {/* Content */} +
+ {renderContent()} +
+
) + // Desktop centered modal + const DesktopModal = () => ( +
+
e.stopPropagation()} + > + {/* Header */} +
+
+
+ +
+ {t('balance.topUp')} +
+ +
+ + {/* Content */} +
+ {renderContent()} +
+
+
+ ) + const content = isMobileScreen ? : if (typeof document !== 'undefined') {