+ {/* Summary cards */}
+ {stakingPositions.length > 0 && (
+
+ {/* Total staked */}
+
+
+
{totalStaked.toFixed(2)}
+
Across {stakingPositions.length} positions
+
+
+ {/* Total rewards */}
+
+
+
{totalRewards.toFixed(4)}
+
Earned to date
+
+
+ {/* Average APY */}
+
+
+
+ {(
+ stakingPositions.reduce((sum, pos) => sum + pos.apy, 0) / stakingPositions.length
+ ).toFixed(1)}
+ %
+
+
Weighted average
+
+
+ )}
+
+ {/* Tabs */}
+
+ {(['protocols', 'positions', 'rewards'] as const).map((tab) => (
+
+ ))}
+
+
+ {/* Protocols tab */}
+ {activeTab === 'protocols' && (
+
+ {protocols.map((protocol) => (
+
+
+
+
{protocol.name}
+
{protocol.description}
+
+
+ {protocol.riskLevel}
+
+
+
+ {/* Protocol stats */}
+
+
+
APY
+
{protocol.apy}%
+
+
+
+
Min Stake
+
{protocol.minStake}
+
+
+
+ {/* Supported tokens */}
+
+
Supported Tokens
+
+ {protocol.tokens.map((token) => (
+
+ {token}
+
+ ))}
+
+
+
+ {/* Stake button */}
+
+
+ ))}
+
+ )}
+
+ {/* Positions tab */}
+ {activeTab === 'positions' && (
+
+ {isLoading ? (
+
+
+
+ ) : stakingPositions.length === 0 ? (
+
+
+
No active staking positions
+
+
+ ) : (
+ stakingPositions.map((position) => (
+
+
+
+
+ {position.amount} {position.token}
+
+
+ APY: {position.apy}% • Lock: {position.lockPeriod} days
+
+
+
+ +{position.unrealizedRewards}
+
+
+
+
+
+
Harvested
+
{position.rewards} {position.token}
+
+
+
Unlocks
+
+ {new Date(position.endDate).toLocaleDateString()}
+
+
+
+
+
+
+ ))
+ )}
+
+ )}
+
+ {/* Rewards tab */}
+ {activeTab === 'rewards' && (
+
+
+
Reward tracking coming soon
+
Monitor all your staking rewards in one place
+
+ )}
+
+ {/* Staking modal */}
+ {selectedProtocol && (
+
setSelectedProtocol(null)}
+ >
+
e.stopPropagation()}
+ >
+
+
+ Stake in {selectedProtocol.name}
+
+
+
+
+
+ {/* Amount input */}
+
+
+
setStakeAmount(e.target.value)}
+ placeholder="0.0"
+ min={parseFloat(selectedProtocol.minStake)}
+ disabled={isStaking}
+ className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-blue-500 disabled:opacity-50"
+ />
+
Min: {selectedProtocol.minStake}
+
+
+ {/* Duration select */}
+
+
+
+
+
+ {/* Info */}
+
+
+
+ Your funds will be locked for the selected duration. You'll earn{' '}
+ {selectedProtocol.apy}% APY.
+
+
+
+ {/* Submit button */}
+
+
+
+
+ )}
+
+ );
+};
+
+export default DeFiInterface;
diff --git a/src/components/web3/NFTGallery.tsx b/src/components/web3/NFTGallery.tsx
new file mode 100644
index 00000000..e0081a0c
--- /dev/null
+++ b/src/components/web3/NFTGallery.tsx
@@ -0,0 +1,444 @@
+'use client';
+
+import React, { useCallback, useState, useEffect } from 'react';
+import {
+ Image as ImageIcon,
+ Loader2,
+ AlertCircle,
+ Zap,
+ ChevronLeft,
+ ChevronRight,
+ ExternalLink,
+ Plus,
+ Grid3x3,
+ List,
+} from 'lucide-react';
+import { useWeb3Wallet } from '@/hooks/useWeb3Wallet';
+
+interface NFT {
+ id: string;
+ name: string;
+ description: string;
+ image: string;
+ tokenId: string;
+ contractAddress: string;
+ chainId: string;
+ rarity?: string;
+ attributes?: Array<{
+ trait_type: string;
+ value: string;
+ }>;
+}
+
+interface NFTGalleryProps {
+ className?: string;
+ onNFTSelect?: (nft: NFT) => void;
+ showMintButton?: boolean;
+ onMintClick?: () => void;
+}
+
+type ViewMode = 'grid' | 'list';
+
+/**
+ * NFTGallery Component
+ *
+ * Comprehensive NFT viewing and interaction:
+ * - Display user's NFT collection
+ * - Grid and list view modes
+ * - NFT details and attributes
+ * - Mint new NFTs
+ * - Integration with multiple NFT standards (ERC-721, ERC-1155)
+ *
+ * Features:
+ * - Responsive gallery layout
+ * - Loading states
+ * - Error handling
+ * - Metadata parsing from various sources
+ */
+export const NFTGallery: React.FC