diff --git a/app/api/alchemy-iscontract/route.ts b/app/api/alchemy-iscontract/route.ts new file mode 100644 index 0000000..5840e4a --- /dev/null +++ b/app/api/alchemy-iscontract/route.ts @@ -0,0 +1,165 @@ +import { NextResponse } from "next/server"; + +const ALCHEMY_API_KEY = process.env.ALCHEMY_API_KEY; +const ALCHEMY_API_URL = `https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}`; + +interface ContractData { + isContract: boolean; + contractInfo?: { + name: string; + symbol?: string; + tokenType?: 'ERC20' | 'ERC721' | 'ERC1155'; + totalSupply?: string; + decimals?: number; + logo?: string; + holders?: number; + transactions?: number; + deployedAt?: string; + implementationAddress?: string; + verified: boolean; + }; +} + +export async function GET(request: Request) { + const { searchParams } = new URL(request.url); + const address = searchParams.get("address"); + + if (!address) { + return NextResponse.json( + { error: "Address is required" }, + { status: 400 } + ); + } + + try { + // Check if address is a contract + const codeResponse = await fetch(ALCHEMY_API_URL, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 1, + method: 'eth_getCode', + params: [address, 'latest'] + }) + }); + + const codeData = await codeResponse.json(); + const isContract = codeData.result !== '0x'; + + if (!isContract) { + return NextResponse.json({ isContract: false }); + } + + // Check contract interfaces to determine type + const [erc721Response, erc1155Response] = await Promise.all([ + // Check ERC721 interface + fetch(ALCHEMY_API_URL, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 2, + method: 'eth_call', + params: [{ + to: address, + data: '0x01ffc9a780ac58cd00000000000000000000000000000000000000000000000000000000' + }, 'latest'] + }) + }), + // Check ERC1155 interface + fetch(ALCHEMY_API_URL, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 3, + method: 'eth_call', + params: [{ + to: address, + data: '0x01ffc9a7d9b67a2600000000000000000000000000000000000000000000000000000000' + }, 'latest'] + }) + }) + ]); + + const [erc721Data, erc1155Data] = await Promise.all([ + erc721Response.json(), + erc1155Response.json() + ]); + + // Get token metadata + const metadataResponse = await fetch(ALCHEMY_API_URL, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 4, + method: 'alchemy_getTokenMetadata', + params: [address] + }) + }); + + const metadataData = await metadataResponse.json(); + const metadata = metadataData.result; + + // Determine token type + let tokenType: 'ERC20' | 'ERC721' | 'ERC1155' | undefined; + + if (erc721Data.result === '0x0000000000000000000000000000000000000000000000000000000000000001') { + tokenType = 'ERC721'; + } else if (erc1155Data.result === '0x0000000000000000000000000000000000000000000000000000000000000001') { + tokenType = 'ERC1155'; + } else if (metadata?.decimals !== undefined) { + tokenType = 'ERC20'; + } + + // Get deployment info + const deploymentResponse = await fetch(ALCHEMY_API_URL, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 5, + method: 'alchemy_getAssetTransfers', + params: [ + { + fromBlock: "0x0", + toAddress: address, + category: ["external"], + withMetadata: true, + excludeZeroValue: true, + maxCount: "0x1" + } + ] + }) + }); + + const deploymentData = await deploymentResponse.json(); + const deployment = deploymentData.result?.transfers?.[0]; + + const contractData: ContractData = { + isContract: true, + contractInfo: { + name: metadata?.name || "Unknown Contract", + symbol: metadata?.symbol, + tokenType, + totalSupply: metadata?.totalSupply, + decimals: metadata?.decimals, + logo: metadata?.logo, + holders: 0, + transactions: 0, + deployedAt: deployment?.metadata?.blockTimestamp, + verified: Boolean(metadata?.name), + } + }; + + return NextResponse.json(contractData); + } catch (error) { + console.error("Error detecting contract:", error); + return NextResponse.json( + { error: "Failed to detect contract" }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/app/block-txns/page.tsx b/app/block-txns/page.tsx index fc73da0..ddd206e 100644 --- a/app/block-txns/page.tsx +++ b/app/block-txns/page.tsx @@ -57,6 +57,12 @@ export default function BlockTransactions() { useEffect(() => { const fetchBlockData = async () => { + // Reset states when starting a new fetch + setLoading(true); + setError(null); + setBlockData(null); + setPage(1); // Reset pagination when new block is loaded + if (!blockNumber) { setError("Block number is required"); setLoading(false); @@ -82,7 +88,6 @@ export default function BlockTransactions() { } }; - setLoading(true); fetchBlockData(); }, [blockNumber]); @@ -166,7 +171,7 @@ export default function BlockTransactions() { - + {totalTransactions > 0 ? ( <> diff --git a/app/block/page.tsx b/app/block/page.tsx index 5a00745..39ab721 100644 --- a/app/block/page.tsx +++ b/app/block/page.tsx @@ -10,7 +10,7 @@ import { Loader2, Copy, ExternalLink, Clock, Hash, ChevronUp, Cpu, Fuel, Pickaxe, - Database, Layers + Database, Layers, ArrowLeft } from "lucide-react"; import { toast } from "sonner"; import { format } from "date-fns"; @@ -54,6 +54,11 @@ export default function BlockDetails() { useEffect(() => { const fetchBlock = async () => { + // Reset states when starting a new fetch + setLoading(true); + setError(null); + setBlock(null); + if (!blockNumber) { setError("Block number is required"); setLoading(false); @@ -69,8 +74,11 @@ export default function BlockDetails() { } setBlock(data); + setError(null); } catch (err) { + console.error("Error fetching block:", err); setError(err instanceof Error ? err.message : "Failed to fetch block details"); + setBlock(null); } finally { setLoading(false); } @@ -99,15 +107,30 @@ export default function BlockDetails() { if (error || !block) { return ( -
- - -
-

{error || "Block not found"}

-
-
-
-
+ <> + + + + +
+

{error || "Block not found"}

+ +
+
+
+
+ ); } @@ -120,7 +143,7 @@ export default function BlockDetails() { transition={{ duration: 0.5 }} className="container mx-auto p-4" > - +
diff --git a/app/page.tsx b/app/page.tsx index cf5a49b..fa8b157 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,13 +1,14 @@ 'use client'; -import React, { useState, useEffect } from 'react'; + +import React, { useState, useEffect, useRef } from 'react'; import Link from 'next/link'; import Image from "next/legacy/image"; -import { motion } from 'framer-motion'; -import { FaFacebookF, FaGithub, FaLinkedinIn, FaCoins, FaExchangeAlt, FaPalette, FaChartLine, FaGamepad } from 'react-icons/fa'; +import { motion, useScroll, useTransform, AnimatePresence } from 'framer-motion'; +import { FaFacebookF, FaGithub, FaLinkedinIn, FaCoins, FaExchangeAlt, FaPalette, FaChartLine, FaGamepad, FaUsers, FaRocket } from 'react-icons/fa'; import ParticlesBackground from '@/components/ParticlesBackground'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; -import { ArrowRight, TrendingUp, Wallet, Box } from 'lucide-react'; +import { ArrowRight, TrendingUp, Wallet, Box, ChevronDown, BarChart3, Zap, ArrowUpRight } from 'lucide-react'; import DemoShowcase from '@/components/home/DemoShowcase'; import EthPriceLine from '@/components/home/EthPriceLine'; import CryptoPathExplorer from '@/components/home/CryptoExplorer'; @@ -18,6 +19,24 @@ import FAQ from './FAQ'; import AOS from 'aos'; import 'aos/dist/aos.css'; import toast from 'react-hot-toast'; +import CountUp from 'react-countup'; +import { Swiper, SwiperSlide } from 'swiper/react'; + +// Import Swiper modules +import SwiperCore from 'swiper'; +import { Autoplay, Pagination, Navigation, EffectCoverflow } from 'swiper/modules'; + +// Install Swiper modules +SwiperCore.use([Autoplay, Pagination, Navigation, EffectCoverflow]); + +// Import Swiper styles +import 'swiper/css'; +import 'swiper/css/pagination'; +import 'swiper/css/navigation'; +import 'swiper/css/effect-coverflow'; + +// Remove this line - no longer needed +// SwiperCore.use([Autoplay, Pagination, Navigation, EffectCoverflow]); // FeatureCardProps interface should include language interface FeatureCardProps { @@ -194,6 +213,42 @@ const teamMembers = [ }, ]; +// New stats for animated counter section +const platformStats = [ + { icon: , value: 25000, label: "Active Users", suffix: "+" }, + { icon: , value: 1000000, label: "Transactions Tracked", suffix: "+" }, + { icon: , value: 99.9, label: "Uptime", suffix: "%" }, + { icon: , value: 240, label: "Blockchains", suffix: "" } +]; + +// News items for the "What's New" carousel +const whatsNewItems = [ + { + title: "Multichain Support", + description: "We've expanded our blockchain explorer to support all major networks including Ethereum, BSC, Polygon, and more.", + image: "/feature-market.png", + link: "/market-overview" + }, + { + title: "Advanced Analytics", + description: "New dashboard features with customizable charts and real-time data visualization for crypto assets.", + image: "/feature-transaction.png", + link: "/search" + }, + { + title: "NFT Collections", + description: "Explore trending NFT collections across multiple blockchains with our enhanced NFT browser.", + image: "/feature-nft.png", + link: "/NFT" + }, + { + title: "Play-to-Earn Game", + description: "Our new click-to-earn game lets you collect PATH tokens while having fun with our ecosystem.", + image: "/feature-game.png", + link: "/clickgame" + } +]; + const LandingPage = () => { const [activeTab, setActiveTab] = useState('sgd'); const [email, setEmail] = useState(''); @@ -201,6 +256,40 @@ const LandingPage = () => { const [isSubmitting, setIsSubmitting] = useState(false); const [isSuccess, setIsSuccess] = useState(false); const [language, setLanguage] = useState('en'); + const [scrollY, setScrollY] = useState(0); + const heroRef = useRef(null); + const statsRef = useRef(null); + const [statsVisible, setStatsVisible] = useState(false); + + // Animated cursor effect - follows mouse with delay + const [cursorPos, setCursorPos] = useState({ x: 0, y: 0 }); + const cursorVariants = { + default: { + x: cursorPos.x - 32, + y: cursorPos.y - 32, + transition: { + type: "spring", + mass: 1, + damping: 14, + stiffness: 120, + restDelta: 0.001 + } + } + }; + + // Parallax scroll effect + const { scrollYProgress } = useScroll(); + const headerOpacity = useTransform(scrollYProgress, [0, 0.2], [1, 0]); + + // Floating elements animation + const floatingAnimation = { + y: [0, -10, 0], + transition: { + duration: 4, + repeat: Infinity, + repeatType: "reverse" as const + } + }; // Declare t only once const t = translations[language]; @@ -209,6 +298,8 @@ const LandingPage = () => { AOS.init({ duration: 1000, once: true, + mirror: true, // Animate elements each time they appear in the viewport + anchorPlacement: 'top-bottom' }); // Initialize language based on browser preference @@ -220,6 +311,33 @@ const LandingPage = () => { if (storedLanguage) { setLanguage(storedLanguage); } + + // Scroll listener for parallax effects + const handleScroll = () => { + setScrollY(window.scrollY); + + // Check if stats section is in view + if (statsRef.current) { + const rect = (statsRef.current as HTMLElement).getBoundingClientRect(); + if (rect.top < window.innerHeight && rect.bottom > 0) { + setStatsVisible(true); + } + } + }; + + window.addEventListener('scroll', handleScroll); + + // Mouse move listener for custom cursor + const handleMouseMove = (e: MouseEvent) => { + setCursorPos({ x: e.clientX, y: e.clientY }); + }; + + window.addEventListener('mousemove', handleMouseMove); + + return () => { + window.removeEventListener('scroll', handleScroll); + window.removeEventListener('mousemove', handleMouseMove); + }; }, []); // Simple browser language detection @@ -285,100 +403,340 @@ const LandingPage = () => { } }; + // Smooth scroll to the next section + const scrollToNextSection = () => { + window.scrollTo({ + top: window.innerHeight, + behavior: 'smooth' + }); + }; + return ( -
+
+ + + + + + - {/* Hero Section */} -
-
- {/* CryptoPath Explorer Section */} + {/* Hero Section with 3D Blockchain Visualization */} +
+
+ +
+ {/* CryptoPath Explorer Section */} +
-

- {t.vietnamPremierCrypto} -

-

- {t.joinAllInOne}{t.appInVietnam} -

-
-
- - {emailError &&

{emailError}

} - {isSuccess &&

- {t.signUpSuccess} -

} -
- -
-
- + - - - - - - - + {t.joinAllInOne} + + {t.appInVietnam} + + +
+
+ + + {emailError &&

{emailError}

} + {isSuccess &&

+ {t.signUpSuccess} +

} +
+
+ + + {isSubmitting ? t.processing : t.tryCryptoPath} + +
+
+ + + + + + + +
- + + + + + {/* Floating blockchain nodes */} + +
+ Ethereum +
+
+ + +
+ BNB +
+
+ + +
+ Polygon +
+
+
+ + {/* Scroll down indicator */} + + +
+
+
+
+ +

Platform Metrics

+

Real-time statistics showcasing our blockchain explorer's performance and reach

+
+ +
+ {platformStats.map((stat, index) => ( + +
+
+ {stat.icon} +
+
+

+ {statsVisible ? ( + + ) : '0'} +

+

{stat.label}

+
+ ))} +
+
+
+ + {/* What's New Section with Modern Carousel */} +
+
+ +

What's New

+

Latest features and improvements to enhance your blockchain experience

+
+ + + {whatsNewItems.map((item, index) => ( + + +
+
+ {item.title} +
+
+

{item.title}

+

{item.description}

+ + + Learn more + + +
+
+
+ ))} +
+
+
- {/* Trending Projects & Partner Bar */} - {/* Demo Showcase Section */} + {/* Demo Showcase Section with enhanced animations */} {/* Trade Like a Pro Section */}
-

{t.tradeLikePro}{t.aPro}

-

+ + {t.tradeLikePro}{t.aPro} + + {t.getLowestFees} -

+
-
-
+ +
-
-
+
+
- {/* Features Section */} -
+ {/* Features Section with glass morphism cards */} +
+
{
- {/* Dynamic Content Section */} -
-
-
- CryptoPath Content -
-
-

{t.oneApplication}{t.infinitePotential}

-

- {activeTab === 'sgd' ? t.exploreNFTMarketplace : t.exploreDecentralized} -

-
- - -
-
-
-
- - {/* Trending NFTs Section */} + {/* Continue with the rest of the page sections with enhanced styling */} {/* Evolution Illustration Section */} @@ -585,115 +906,349 @@ const LandingPage = () => {
- {/* New Features Section */} -
-
-

- Platform Features -

- -
- {/* Market Analysis */} -
-
- -
-

Market Analysis

-

- Real-time market data and analysis tools to help you make informed decisions. -

- - Explore Markets → - -
+ {/* New Features Section - Enhanced grid with hover effects */} +
+
+ + Platform Features + + +
+ {/* Market Analysis */} + +
+ +
+

Market Analysis

+

+ Real-time market data and analysis tools to help you make informed decisions. +

+ + Explore Markets + +
+ + {/* Token Swapping */} + +
+ +
+

Token Swapping

+

+ Easily exchange different cryptocurrencies with our simple swap interface. +

+ + Swap Tokens + +
+ + {/* NFT Marketplace */} + +
+ +
+

NFT Marketplace

+

+ Buy, sell, and trade unique digital collectibles on our NFT marketplace. +

+ + Discover NFTs + +
+ + {/* Token Faucet */} + +
+ +
+

Token Faucet

+

+ Get free tokens to start your journey and explore the CryptoPath ecosystem. +

+ + Claim Tokens + +
+ + {/* Clicker Game (NEW FEATURE) */} + +
+ NEW +
+
+
+ +
+

Clicker Game

+

+ Earn PATH tokens by playing our addictive click-to-earn game with upgrades and boosts. +

+ + Play Now + +
+
+ + {/* Add Search Function Feature (BETA) */} + +
+
+ HOT +
+
+
+ + + + +
+

Blockchain Search

+

+ Explore blockchain transactions, addresses, and tokens with our powerful search engine. Get detailed insights into any blockchain activity. +

+ + Search Blockchain + +
+
+
+
+
+ + + {/* Call to Action with enhanced visual effects */} +
+ {/* Background Elements */} +
+
+ + {/* Dynamic animated glow effects */} + + + + +
+ + ✨ + - {/* Token Swapping */} -
-
- -
-

Token Swapping

-

- Easily exchange different cryptocurrencies with our simple swap interface. -

- - Swap Tokens → - -
+ + Ready to Start Your Crypto Journey? + - {/* NFT Marketplace */} -
-
- -
-

NFT Marketplace

-

- Buy, sell, and trade unique digital collectibles on our NFT marketplace. -

- - Discover NFTs → - -
+
- {/* Faucet */} -
-
- -
-

Token Faucet

-

- Get free tokens to start your journey and explore the CryptoPath ecosystem. -

- - Claim Tokens → +

+ Join thousands of users exploring the crypto universe with CryptoPath's intuitive tools and comprehensive analytics +

+ +
+ + + + + Get Started Now + + + -
- - {/* Click-to-Earn Game - NEW FEATURE */} -
-
- NEW -
-
- -
-

Clicker Game

-

- Earn PATH tokens by playing our addictive click-to-earn game with upgrades and boosts. -

- - Play Now → + + + + + + + Try the Game + +
+ + {/* Trust indicators */} + +

Trusted by crypto enthusiasts

+
+ {[...Array(5)].map((_, i) => ( + + + + ))} + 4.9/5 +
+

Based on 2,500+ user reviews

+
-
+
- {/* Call to Action */} -
-
-

- Ready to Start Your Crypto Journey? -

-

- Join thousands of users exploring the crypto universe with CryptoPath -

- -
- - Get Started Now - - - Try the Game - -
-
-
+ {/* Add global styles */} +
); }; -// FeatureCard component updated to use language prop +// FeatureCard component enhanced with more interactive elements const FeatureCard = ({ icon, title, description, href, imageUrl, delay, language }: FeatureCardProps) => { const [isHovered, setIsHovered] = useState(false); @@ -707,23 +1262,39 @@ const FeatureCard = ({ icon, title, description, href, imageUrl, delay, language onMouseLeave={() => setIsHovered(false)} > - +
{imageUrl && ( -
-
+
+ {title} +
)}
-
{icon}
-

{title}

-

{description}

+ + {icon} + +

{title}

+

{description}

- {translations[language].explore} {/* Use language prop */} - + {translations[language].explore} +
diff --git a/app/token/page.tsx b/app/token/page.tsx index fda2f57..c5e7840 100644 --- a/app/token/page.tsx +++ b/app/token/page.tsx @@ -12,7 +12,7 @@ import { Coins, Users, ArrowLeftRight, Calendar, Shield, Clock, TrendingUp, DollarSign, BarChart3, - ArrowUpRight, ArrowDownRight + ArrowUpRight, ArrowDownRight, ArrowLeft } from "lucide-react"; import { toast } from "sonner"; import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from "@/components/ui/table"; @@ -98,6 +98,11 @@ export default function TokenPage() { useEffect(() => { const fetchToken = async () => { + // Reset states when starting a new fetch + setLoading(true); + setError(null); + setToken(null); + if (!address) { setError("Token address is required"); setLoading(false); @@ -113,16 +118,18 @@ export default function TokenPage() { } setToken(data); + setError(null); } catch (err) { console.error("Error fetching token:", err); setError(err instanceof Error ? err.message : "Failed to fetch token details"); + setToken(null); } finally { setLoading(false); } }; fetchToken(); - }, [address]); + }, [address]); const copyToClipboard = (text: string) => { navigator.clipboard.writeText(text); @@ -144,15 +151,30 @@ export default function TokenPage() { if (error || !token) { return ( -
- - -
-

{error || "Token not found"}

-
-
-
-
+ <> + + + + +
+

{error || "Token not found"}

+ +
+
+
+
+ ); } @@ -165,7 +187,7 @@ export default function TokenPage() { transition={{ duration: 0.5 }} className="container mx-auto p-4" > - + ( - - - -

{children}

+ + + +

{children}

); -// Error boundary component -const ErrorCard = ({ error }: { error: string }) => ( - - - {error} - - +// Section header component +const SectionHeader = ({ icon, title, description }: { icon: React.ReactNode, title: string, description: string }) => ( + +
+
+ {icon} +
+

{title}

+
+

{description}

+
); export default function TransactionExplorer() { const [selectedCoin, setSelectedCoin] = useState(null); + // Animation variants for staggered animations + const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { + staggerChildren: 0.15 + } + } + }; + + const itemVariants = { + hidden: { opacity: 0, y: 20 }, + visible: { opacity: 1, y: 0, transition: { duration: 0.6 } } + }; + return (
- + {/* Fix: Keep particles background with correct z-index */} +
+ +
-
-
- {/* Revenue Graph */} -
- Loading revenue graph...}> + +
+ {/* Page Title */} + +

+ Cryptocurrency Transaction Explorer +

+

+ Analyze real-time cryptocurrency market data, track transactions, and monitor network statistics +

+
+ + {/* Revenue Graph Section */} + + } + title="Market Analytics" + description="Track price and volume movements of cryptocurrencies with detailed historical data" + /> + Loading market analytics...}> -
+
- {/* Wallet Charts */} -
- Loading wallet charts...}> + {/* Wallet Charts Section */} + + } + title="Wallet Statistics" + description="Visual representation of wallet activities and distribution across the blockchain" + /> + Loading wallet statistics...}> -
+ - {/* Binance Trading View - New Component */} -
- Loading trading view...}> + {/* Trading View Section */} + + } + title="Live Trading Charts" + description="Professional trading charts with technical analysis indicators powered by TradingView" + /> + Loading trading charts...}> -
+ - {/* Network Stats */} -
- Loading network stats...}> + {/* Network Stats Section */} + + } + title="Network Health" + description="Real-time stats tracking blockchain network performance, congestion, and gas fees" + /> + Loading network health data...}> -
+ - {/* Transaction Section - At the very end */} -
- Loading transactions...}> + {/* Transaction Section */} + + } + title="Recent Transactions" + description="Latest blockchain transactions with detailed insights and tracking information" + /> + Loading transaction history...}> -
+
-
+
); } \ No newline at end of file diff --git a/app/txn-hash/page.tsx b/app/txn-hash/page.tsx index ca5bea7..429c04c 100644 --- a/app/txn-hash/page.tsx +++ b/app/txn-hash/page.tsx @@ -9,7 +9,7 @@ import { Loader2, ExternalLink, Copy, XCircle } from "lucide-react"; import { toast } from "sonner"; import { format } from "date-fns"; import { motion } from "framer-motion"; -import { ArrowRight, ArrowDownRight } from "lucide-react"; +import { ArrowRight, ArrowDownRight, ArrowLeft } from "lucide-react"; import ParticlesBackground from "@/components/ParticlesBackground"; interface TransactionDetails { @@ -46,6 +46,11 @@ export default function TransactionDetails() { useEffect(() => { const fetchTransaction = async () => { + // Reset states when starting a new fetch + setLoading(true); + setError(null); + setTransaction(null); + if (!hash) { setError("Transaction hash is required"); setLoading(false); @@ -61,9 +66,11 @@ export default function TransactionDetails() { } setTransaction(data); + setError(null); } catch (err) { console.error("Error fetching transaction:", err); setError(err instanceof Error ? err.message : "Failed to fetch transaction details"); + setTransaction(null); } finally { setLoading(false); } @@ -98,17 +105,34 @@ export default function TransactionDetails() { ); } - if (error) { + if (error || !transaction) { return ( - - -
- -

Transaction Error

-

{error}

-
-
-
+ <> + + + + +
+ +

Transaction Error

+

{error || "Transaction not found"}

+ +
+
+
+
+ ); } @@ -123,7 +147,7 @@ export default function TransactionDetails() { transition={{ duration: 0.5 }} className="container mx-auto p-4" > - + ; isPlaceholder?: boolean; + verified?: boolean; } interface AnimatedNFTCardProps { @@ -26,10 +27,19 @@ interface AnimatedNFTCardProps { onClick?: () => void; index?: number; isVirtualized?: boolean; + highlight?: boolean; } -export default function AnimatedNFTCard({ nft, onClick, index = 0, isVirtualized = false }: AnimatedNFTCardProps) { +// Component implementation with animations and optimizations +const AnimatedNFTCardComponent = ({ + nft, + onClick, + index = 0, + isVirtualized = false, + highlight = false +}: AnimatedNFTCardProps) => { const [imageLoaded, setImageLoaded] = useState(false); + const [hovered, setHovered] = useState(false); const cardRef = useRef(null); // Process image URL for IPFS compatibility @@ -82,6 +92,8 @@ export default function AnimatedNFTCard({ nft, onClick, index = 0, isVirtualized }, [shineX, shineY, shineOpacity]); function handleMouseMove(e: React.MouseEvent) { + if (nft.isPlaceholder) return; + if (cardRef.current) { const rect = cardRef.current.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; @@ -94,10 +106,12 @@ export default function AnimatedNFTCard({ nft, onClick, index = 0, isVirtualized function handleMouseLeave() { x.set(0); y.set(0); + setHovered(false); } function handleMouseEnter() { scale.set(1.02); + setHovered(true); } function handleMouseExit() { @@ -127,6 +141,19 @@ export default function AnimatedNFTCard({ nft, onClick, index = 0, isVirtualized duration: 0.3, ease: [0.4, 0, 0.2, 1], } + }, + highlight: { + scale: [1, 1.03, 1], + boxShadow: [ + "0 0 0px rgba(255,255,255,0)", + "0 0 15px rgba(255,255,255,0.5)", + "0 0 0px rgba(255,255,255,0)" + ], + transition: { + duration: 1.5, + repeat: 2, + repeatType: "reverse" as const, // Fix type error by explicitly typing as const + } } }; @@ -186,10 +213,19 @@ export default function AnimatedNFTCard({ nft, onClick, index = 0, isVirtualized return 'hover:shadow-[0_0_15px_rgba(107,141,247,0.3)]'; }; - // If this is a placeholder card (for virtualization), show a simpler version + // If this is a placeholder card (for virtualization), show a loading skeleton if (nft.isPlaceholder) { return ( -
+