From b4759a82368c7cfa35b996b41350e34760f39a44 Mon Sep 17 00:00:00 2001 From: Muhammad Zayyad Mukhtar <95658387+El-swaggerito@users.noreply.github.com> Date: Wed, 29 Apr 2026 12:09:01 +0100 Subject: [PATCH] refactor: improve UI components with enhanced styling and accessibility - Update SkeletonRow with refined spacing and pulse animations - Enhance StarIcon with better interactivity and visual feedback - Redesign NewsBanner with improved gradients and animations - Refactor TokenInput with better validation and styling - Add localStorage persistence to SlippageContext - Improve TabNavigation with active indicators and ARIA labels - Update ProModeSection with better layout and conditional rendering - Redesign SettingsModal with organized sections and visual hierarchy - Enhance TradeReviewModal with better visual breakdown and whale detection - Improve TokenDropdown with recent tokens and search functionality --- src/components/NewsBanner.tsx | 41 ++++- src/components/ProModeSection.tsx | 94 +++++++--- src/components/SettingsModal.tsx | 127 +++++++++++--- src/components/SkeletonRow.tsx | 44 ++++- src/components/StarIcon.tsx | 42 ++++- src/components/TabNavigation.tsx | 90 +++++++--- src/components/TokenDropdown.tsx | 261 +++++++++++++++------------- src/components/TokenInput.tsx | 50 +++++- src/components/TradeReviewModal.tsx | 149 +++++++++++----- src/contexts/SlippageContext.tsx | 54 +++++- 10 files changed, 680 insertions(+), 272 deletions(-) diff --git a/src/components/NewsBanner.tsx b/src/components/NewsBanner.tsx index f8b4900..8bfe088 100644 --- a/src/components/NewsBanner.tsx +++ b/src/components/NewsBanner.tsx @@ -1,29 +1,52 @@ +/** + * News Banner Component. + * A dismissible top-level banner for announcing major protocol updates or news. + * Persists visibility only within the current session. + */ + import React, { useState } from 'react'; -import { X } from 'lucide-react'; +import { X, Sparkles } from 'lucide-react'; +/** + * A stylized notification banner for global announcements. + */ export default function NewsBanner() { + // --- Component State --- const [isVisible, setIsVisible] = useState(true); + // 1. Conditional Rendering for Visibility if (!isVisible) return null; return ( -
+
-
- 🚀 - - TradeFlow Mainnet Beta is now live! 🚀 +
+ {/* Decorative Icon */} +
+ +
+ + TradeFlow Mainnet Beta is now live! + + + NEW
+ {/* Dismiss Button */}
); } + diff --git a/src/components/ProModeSection.tsx b/src/components/ProModeSection.tsx index 33d7499..254b370 100644 --- a/src/components/ProModeSection.tsx +++ b/src/components/ProModeSection.tsx @@ -1,3 +1,9 @@ +/** + * Pro Mode Section Component. + * Handles the logic for toggling advanced trading features, + * including token-gated access to high-resolution charts. + */ + "use client"; import React, { useState, useEffect } from "react"; @@ -5,72 +11,111 @@ import dynamic from "next/dynamic"; import Toggle from "../app/Toggle"; import { useTokenStore } from "../stores/tokenStore"; import PremiumUnlockModal from "./PremiumUnlockModal"; +import { Zap, Crown, Lock } from "lucide-react"; -// Dynamically import the heavy chart component with loading fallback +/** + * Dynamically import the heavy TradingView-style chart component. + * Uses a skeleton fallback to prevent layout shifts during hydration. + */ const LivePriceChart = dynamic(() => import("../components/LivePriceChart"), { ssr: false, loading: () => ( -
+
-
-

Loading Pro Chart...

+
+

Hydrating Pro Engine...

), }); +/** + * A section that manages the state and access control for "Pro Mode". + */ export default function ProModeSection() { + // --- Component State --- + /** Local toggle state for the current session */ const [isProMode, setIsProMode] = useState(false); + /** Controls visibility of the TF token paywall modal */ const [showPaywall, setShowPaywall] = useState(false); + /** Access logic from the token store */ const { tfTokenBalance, isConnected, hasProModeAccess } = useTokenStore(); + /** + * Handles user interaction with the Pro Mode toggle. + * Validates wallet connection and token requirements before enabling. + */ const handleProModeToggle = () => { - // If trying to enable pro mode + // 1. Logic for enabling Pro Mode if (!isProMode) { if (!isConnected) { - // User is not connected to wallet - alert('Please connect your wallet to enable Pro Mode'); + // TODO: Replace with a non-blocking toast notification + alert('Please connect your Stellar wallet to access Pro Mode features.'); return; } if (!hasProModeAccess()) { - // User doesn't have enough TF tokens - show paywall + // User is connected but lacks sufficient TF token balance setShowPaywall(true); return; } } - // Allow toggle (either disabling pro mode or user has access) + // 2. Commit the toggle state change setIsProMode(!isProMode); }; return ( <> -
-
-
-

Pro Mode Charts

-

- Enable advanced TradingView-style charts with live data. - {!isConnected && " (Connect wallet to enable)"} - {isConnected && !hasProModeAccess() && " (Requires 1,000+ TF tokens)"} +

+
+
+
+
+ {isProMode ? : } +
+

Pro Mode Analytics

+
+

+ Unlock advanced technical indicators and sub-second price feeds. + {!isConnected && ( + + Connect wallet to unlock + + )} + {isConnected && !hasProModeAccess() && ( + + Requires 1,000+ TF utility tokens + + )}

- + +
+ + {isProMode ? "Active" : "Inactive"} + + +
+ {/* Conditional Rendering of Pro Content */} {isProMode && ( -
+
)} -
+
+ {/* Paywall Modal Overlay */} setShowPaywall(false)} @@ -79,3 +124,4 @@ export default function ProModeSection() { ); } + diff --git a/src/components/SettingsModal.tsx b/src/components/SettingsModal.tsx index e5f434d..f174e86 100644 --- a/src/components/SettingsModal.tsx +++ b/src/components/SettingsModal.tsx @@ -1,30 +1,72 @@ +/** + * Settings Modal Component. + * Provides a centralized interface for configuring trade parameters + * like slippage tolerance, transaction deadlines, and Expert Mode. + */ + "use client"; import React, { useState } from 'react'; -import { X } from 'lucide-react'; +import { X, Settings, ShieldAlert, Zap, Clock } from 'lucide-react'; import Card from './Card'; import { useSlippage } from '../contexts/SlippageContext'; import { useExpertMode } from '../contexts/ExpertModeContext'; import ExpertModeModal from './ExpertModeModal'; +/** + * Props for the SettingsModal component. + */ interface SettingsModalProps { + /** Visibility toggle for the modal */ isOpen: boolean; + /** Callback to close the modal */ onClose: () => void; } +/** + * A modal overlay for managing user preferences and trade constraints. + */ export default function SettingsModal({ isOpen, onClose }: SettingsModalProps) { - const { slippageTolerance, setSlippageTolerance, isSlippageAuto, setIsSlippageAuto, transactionDeadline, setTransactionDeadline } = useSlippage(); + // --- Context & Store Hooks --- + const { + slippageTolerance, + setSlippageTolerance, + isSlippageAuto, + setIsSlippageAuto, + transactionDeadline, + setTransactionDeadline + } = useSlippage(); + const { isExpertMode, setExpertMode, hasAcceptedRisk, acceptRisk } = useExpertMode(); + + // --- Component State --- + /** Controls visibility of the high-risk confirmation modal */ const [isExpertModalOpen, setIsExpertModalOpen] = useState(false); + /** Standard slippage preset options (as percentages) */ const presetOptions = [0.1, 0.5, 1.0, 3.0, 5.0]; + // --- Handlers --- + + /** + * Updates the slippage tolerance to a preset value. + * Only applicable when "Auto" mode is disabled. + * + * @param {number} value - The preset percentage. + */ const handlePresetClick = (value: number) => { if (!isSlippageAuto) { setSlippageTolerance(value); + console.log(`[Settings] Slippage preset applied: ${value}%`); } }; + /** + * Handles manual entry of custom slippage values. + * Constraints: 0% to 50%. + * + * @param {React.ChangeEvent} e - The input change event. + */ const handleCustomChange = (e: React.ChangeEvent) => { if (!isSlippageAuto) { const value = parseFloat(e.target.value); @@ -34,67 +76,91 @@ export default function SettingsModal({ isOpen, onClose }: SettingsModalProps) { } }; + /** + * Toggles between automatic and manual slippage management. + */ const handleAutoToggle = () => { const newAutoState = !isSlippageAuto; setIsSlippageAuto(newAutoState); - // When enabling auto, set to safe default (0.5%) + // Reset to a safe protocol default (0.5%) when re-enabling Auto if (newAutoState) { setSlippageTolerance(0.5); } }; + /** + * Toggles Expert Mode with security checks. + */ const handleExpertModeToggle = () => { if (isExpertMode) { - // Turning off Expert Mode doesn't require confirmation + // Disabling expert mode is always allowed setExpertMode(false); } else { - // Turning on Expert Mode: check if user already accepted risk + // Enabling expert mode requires explicit risk acknowledgment if (hasAcceptedRisk) { - // Bypass modal if already accepted setExpertMode(true); } else { - // Show modal for first-time acceptance setIsExpertModalOpen(true); } } }; + /** + * Callback for the Expert Mode confirmation modal. + */ const handleExpertModeConfirm = () => { acceptRisk(); setExpertMode(true); + setIsExpertModalOpen(false); }; + // 1. Conditional Rendering for Visibility if (!isOpen) return null; return ( <> -
- -
-

Settings

+
+ + {/* Modal Header */} +
+
+
+ +
+

Settings

+
-
- {/* Expert Mode Toggle */} -
-

Expert Mode

-

- Enable advanced trading features and detailed transaction data. +

+ {/* --- Expert Mode Configuration --- */} +
+
+ +

Expert Mode

+
+

+ Allows high-slippage trades and customizes complex transaction parameters. Use with extreme caution.

-
- Expert Mode +
+ Active Status
@@ -230,3 +300,4 @@ export default function SettingsModal({ isOpen, onClose }: SettingsModalProps) { ); } + diff --git a/src/components/SkeletonRow.tsx b/src/components/SkeletonRow.tsx index 19a2355..03ca0ca 100644 --- a/src/components/SkeletonRow.tsx +++ b/src/components/SkeletonRow.tsx @@ -1,22 +1,48 @@ +/** + * Skeleton Row Component. + * A loading placeholder for table rows, providing visual feedback while + * asynchronous data (like invoice lists) is being fetched. + */ + import React from 'react'; +/** + * Renders a set of pulsing placeholder elements that mimic the layout + * of a standard table row. + */ const SkeletonRow = () => { return ( - - -
+ + {/* 1. Asset ID Placeholder */} + +
+ + + {/* 2. Amount Placeholder */} + +
- -
+ + {/* 3. Interest/Badge Placeholder */} + +
- -
+ + {/* 4. Status Placeholder */} + +
- -
+ + {/* 5. Action Button Placeholder */} + +
); }; export default SkeletonRow; + diff --git a/src/components/StarIcon.tsx b/src/components/StarIcon.tsx index 47d43b4..4bdfb7f 100644 --- a/src/components/StarIcon.tsx +++ b/src/components/StarIcon.tsx @@ -1,28 +1,56 @@ +/** + * Star Icon Component. + * A reusable interactive toggle for marking assets as favorites or + * adding them to a watchlist. + */ + import React from 'react'; import { Star } from 'lucide-react'; +/** + * Props for the StarIcon component. + */ interface StarIconProps { + /** Current state of the star (filled vs outline) */ isStarred: boolean; - onClick: () => void; + /** Callback triggered when the icon is clicked */ + onClick: (e: React.MouseEvent) => void; + /** Size of the icon in pixels (default: 16) */ size?: number; + /** Additional CSS classes for custom styling */ className?: string; } -export default function StarIcon({ isStarred, onClick, size = 16, className = '' }: StarIconProps) { +/** + * A stylized star toggle button with smooth transitions and accessibility. + */ +export default function StarIcon({ + isStarred, + onClick, + size = 16, + className = '' +}: StarIconProps) { return ( ); } + diff --git a/src/components/TabNavigation.tsx b/src/components/TabNavigation.tsx index 583bb8d..6510788 100644 --- a/src/components/TabNavigation.tsx +++ b/src/components/TabNavigation.tsx @@ -1,39 +1,89 @@ -import React, { useState } from 'react'; +/** + * Tab Navigation Component. + * A reusable horizontal navigation bar for switching between different + * content views within a page. + */ +import React from 'react'; + +/** + * Represents a single tab item in the navigation. + */ interface Tab { + /** Unique identifier for the tab (e.g., "overview") */ id: string; + /** Human-readable text label for the tab */ label: string; + /** Optional Lucide icon to display alongside the label */ icon?: React.ReactNode; } +/** + * Props for the TabNavigation component. + */ interface TabNavigationProps { + /** Array of tab definitions to render */ tabs: Tab[]; + /** The ID of the currently selected tab */ activeTab: string; + /** Callback triggered when a new tab is selected */ onTabChange: (tabId: string) => void; + /** Additional CSS classes for the container */ className?: string; } -export default function TabNavigation({ tabs, activeTab, onTabChange, className = '' }: TabNavigationProps) { +/** + * A stylized tab bar with animated indicators and accessibility support. + */ +export default function TabNavigation({ + tabs, + activeTab, + onTabChange, + className = '' +}: TabNavigationProps) { return ( -
-