@burdenoff/microfe-atheletebridge 2026.624.1 → 2026.625.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/atheletebridge/components/EmptyState.js +18 -11
- package/dist/atheletebridge/components/EmptyState.js.map +1 -1
- package/dist/atheletebridge/components/InvestmentCard.js +7 -7
- package/dist/atheletebridge/components/InvestmentCard.js.map +1 -1
- package/dist/atheletebridge/components/MetricsCard.js +20 -14
- package/dist/atheletebridge/components/MetricsCard.js.map +1 -1
- package/dist/atheletebridge/components/PageLayout.js +30 -19
- package/dist/atheletebridge/components/PageLayout.js.map +1 -1
- package/dist/atheletebridge/pages/HomePage.js +218 -207
- package/dist/atheletebridge/pages/HomePage.js.map +1 -1
- package/dist/atheletebridge/pages/common/NotificationCenterPage.js +1 -0
- package/dist/atheletebridge/pages/common/NotificationCenterPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/BookingDetailsPage.js +1 -0
- package/dist/atheletebridge/pages/customer/BookingDetailsPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/CartDetailPage.js +1 -0
- package/dist/atheletebridge/pages/customer/CartDetailPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/CartDiscoveryPage.js +1 -0
- package/dist/atheletebridge/pages/customer/CartDiscoveryPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/DirectServiceBookingPage.js +1 -0
- package/dist/atheletebridge/pages/customer/DirectServiceBookingPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/FavoritesPage.js +1 -0
- package/dist/atheletebridge/pages/customer/FavoritesPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/OrderHistoryPage.js +1 -0
- package/dist/atheletebridge/pages/customer/OrderHistoryPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/OrderTrackingPage.js +1 -0
- package/dist/atheletebridge/pages/customer/OrderTrackingPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/PaymentMethodsPage.js +1 -0
- package/dist/atheletebridge/pages/customer/PaymentMethodsPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/ReviewsPage.js +1 -0
- package/dist/atheletebridge/pages/customer/ReviewsPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/SavedAddressesPage.js +1 -0
- package/dist/atheletebridge/pages/customer/SavedAddressesPage.js.map +1 -1
- package/dist/atheletebridge/pages/investor/InvestmentOpportunitiesPage.js +1 -0
- package/dist/atheletebridge/pages/investor/InvestmentOpportunitiesPage.js.map +1 -1
- package/dist/atheletebridge/pages/investor/InvestorInvestmentsPage.js +1 -0
- package/dist/atheletebridge/pages/investor/InvestorInvestmentsPage.js.map +1 -1
- package/dist/atheletebridge/pages/worker/TaskDetailsPage.js +1 -0
- package/dist/atheletebridge/pages/worker/TaskDetailsPage.js.map +1 -1
- package/dist/atheletebridge/pages/worker/WorkerOrdersPage.js +1 -0
- package/dist/atheletebridge/pages/worker/WorkerOrdersPage.js.map +1 -1
- package/dist/atheletebridge/pages/worker/WorkerSchedulePage.js +2 -0
- package/dist/atheletebridge/pages/worker/WorkerSchedulePage.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InvestmentOpportunitiesPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/investor/InvestmentOpportunitiesPage.tsx"],"sourcesContent":["/**\n * Investment Opportunities Page\n * @module atheletebridge/pages/investor\n *\n * Platform stats, 6 filters (search/category/risk/amount/location/sort),\n * invest modal with amount calculator, opportunity cards with images/funding\n * progress/business metrics/documents.\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport {\n Search,\n SlidersHorizontal,\n MapPin,\n Star,\n Clock,\n Users,\n TrendingUp,\n FileText,\n IndianRupee,\n Eye,\n X,\n Briefcase,\n Target,\n Award,\n CheckCircle2,\n} from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatNumber } from '../../utils/formatters';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface InvestmentOpportunity {\n id: string;\n cartId: string;\n cartName: string;\n cartOwner: string;\n description: string;\n targetAmount: number;\n raisedAmount: number;\n minimumInvestment: number;\n maximumInvestment: number;\n investorCount: number;\n daysLeft: number;\n expectedReturns: number;\n paybackPeriod: number;\n riskLevel: 'low' | 'medium' | 'high';\n category: string;\n location: string;\n image: string;\n businessMetrics: {\n monthlyRevenue: number;\n monthlyOrders: number;\n averageOrderValue: number;\n rating: number;\n reviewCount: number;\n operatingSince: string;\n };\n financials: {\n grossMargin: number;\n netMargin: number;\n monthlyExpenses: number;\n breakEvenAchieved: boolean;\n };\n investmentTerms: {\n equityOffered: number;\n dividendFrequency: 'monthly' | 'quarterly' | 'yearly';\n lockInPeriod: number;\n exitOptions: string[];\n };\n documents: Array<{ name: string; type: string; uploadedOn: string }>;\n status: 'active' | 'funded' | 'closed';\n}\n\ninterface OpportunityFilters {\n searchQuery: string;\n category: string;\n riskLevel: string;\n minimumAmount: string;\n location: string;\n sortBy: string;\n}\n\n// ---------------------------------------------------------------------------\n// Mock data\n// ---------------------------------------------------------------------------\n\nconst mockOpportunities: InvestmentOpportunity[] = [\n {\n id: 'opp-001',\n cartId: 'cart-005',\n cartName: 'Organic Salad Bar',\n cartOwner: 'Sarah Johnson',\n description:\n 'Premium organic salad bar serving health-conscious customers in tech parks. Looking to expand to 3 new locations.',\n targetAmount: 500000,\n raisedAmount: 325000,\n minimumInvestment: 25000,\n maximumInvestment: 100000,\n investorCount: 8,\n daysLeft: 15,\n expectedReturns: 22,\n paybackPeriod: 36,\n riskLevel: 'low',\n category: 'Healthy Food',\n location: 'Whitefield, Bangalore',\n image: 'https://images.unsplash.com/photo-1512621776951-a57141f2eefd?w=400',\n businessMetrics: {\n monthlyRevenue: 280000,\n monthlyOrders: 1800,\n averageOrderValue: 156,\n rating: 4.9,\n reviewCount: 342,\n operatingSince: '2022-03-15',\n },\n financials: {\n grossMargin: 65,\n netMargin: 28,\n monthlyExpenses: 78000,\n breakEvenAchieved: true,\n },\n investmentTerms: {\n equityOffered: 25,\n dividendFrequency: 'monthly',\n lockInPeriod: 24,\n exitOptions: ['Buyback', 'Secondary Sale', 'IPO'],\n },\n documents: [\n { name: 'Business Plan', type: 'PDF', uploadedOn: '2024-06-01' },\n { name: 'Financial Statements', type: 'PDF', uploadedOn: '2024-06-01' },\n { name: 'Legal Documents', type: 'PDF', uploadedOn: '2024-06-01' },\n ],\n status: 'active',\n },\n {\n id: 'opp-002',\n cartId: 'cart-006',\n cartName: 'Midnight Munchies',\n cartOwner: 'Ravi Mehta',\n description:\n 'Late-night food delivery cart specializing in comfort food for night shift workers and students. Operating near IT corridors.',\n targetAmount: 300000,\n raisedAmount: 180000,\n minimumInvestment: 15000,\n maximumInvestment: 75000,\n investorCount: 12,\n daysLeft: 22,\n expectedReturns: 18,\n paybackPeriod: 30,\n riskLevel: 'medium',\n category: 'Fast Food',\n location: 'Electronic City, Bangalore',\n image: 'https://images.unsplash.com/photo-1565299624946-b28f40a0ae38?w=400',\n businessMetrics: {\n monthlyRevenue: 195000,\n monthlyOrders: 1200,\n averageOrderValue: 163,\n rating: 4.7,\n reviewCount: 256,\n operatingSince: '2023-01-10',\n },\n financials: {\n grossMargin: 58,\n netMargin: 22,\n monthlyExpenses: 65000,\n breakEvenAchieved: true,\n },\n investmentTerms: {\n equityOffered: 20,\n dividendFrequency: 'quarterly',\n lockInPeriod: 18,\n exitOptions: ['Buyback', 'Secondary Sale'],\n },\n documents: [\n { name: 'Business Plan', type: 'PDF', uploadedOn: '2024-06-05' },\n { name: 'Market Analysis', type: 'PDF', uploadedOn: '2024-06-05' },\n ],\n status: 'active',\n },\n {\n id: 'opp-003',\n cartId: 'cart-007',\n cartName: 'Fusion Street Tacos',\n cartOwner: 'Maria Rodriguez',\n description:\n 'Innovative fusion taco cart combining Mexican and Indian flavors. Winner of Street Food Awards 2023.',\n targetAmount: 400000,\n raisedAmount: 400000,\n minimumInvestment: 20000,\n maximumInvestment: 80000,\n investorCount: 15,\n daysLeft: 0,\n expectedReturns: 25,\n paybackPeriod: 24,\n riskLevel: 'low',\n category: 'Fusion Food',\n location: 'Indiranagar, Bangalore',\n image: 'https://images.unsplash.com/photo-1551504734-5ee1c4a1479b?w=400',\n businessMetrics: {\n monthlyRevenue: 320000,\n monthlyOrders: 2100,\n averageOrderValue: 152,\n rating: 4.8,\n reviewCount: 512,\n operatingSince: '2021-08-20',\n },\n financials: {\n grossMargin: 68,\n netMargin: 32,\n monthlyExpenses: 85000,\n breakEvenAchieved: true,\n },\n investmentTerms: {\n equityOffered: 30,\n dividendFrequency: 'monthly',\n lockInPeriod: 12,\n exitOptions: ['Buyback', 'Franchise Conversion'],\n },\n documents: [\n { name: 'Business Plan', type: 'PDF', uploadedOn: '2024-05-20' },\n { name: 'Awards & Recognition', type: 'PDF', uploadedOn: '2024-05-20' },\n ],\n status: 'funded',\n },\n {\n id: 'opp-004',\n cartId: 'cart-008',\n cartName: 'Bubble Tea Express',\n cartOwner: 'Chen Wei',\n description:\n 'Trendy bubble tea cart with proprietary recipes. Planning expansion through franchise model.',\n targetAmount: 600000,\n raisedAmount: 120000,\n minimumInvestment: 30000,\n maximumInvestment: 150000,\n investorCount: 4,\n daysLeft: 45,\n expectedReturns: 20,\n paybackPeriod: 36,\n riskLevel: 'high',\n category: 'Beverages',\n location: 'Koramangala, Bangalore',\n image: 'https://images.unsplash.com/photo-1558857563-b371033873b8?w=400',\n businessMetrics: {\n monthlyRevenue: 150000,\n monthlyOrders: 900,\n averageOrderValue: 167,\n rating: 4.6,\n reviewCount: 189,\n operatingSince: '2023-11-01',\n },\n financials: {\n grossMargin: 72,\n netMargin: 18,\n monthlyExpenses: 55000,\n breakEvenAchieved: false,\n },\n investmentTerms: {\n equityOffered: 35,\n dividendFrequency: 'quarterly',\n lockInPeriod: 36,\n exitOptions: ['Franchise Sale', 'Acquisition'],\n },\n documents: [\n { name: 'Franchise Plan', type: 'PDF', uploadedOn: '2024-06-10' },\n { name: 'Recipe Patents', type: 'PDF', uploadedOn: '2024-06-10' },\n ],\n status: 'active',\n },\n];\n\nconst platformStats = {\n totalOpportunities: 24,\n averageReturns: 21.5,\n totalFunded: 15600000,\n successRate: 89,\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getRiskBadgeColor(risk: string): string {\n switch (risk) {\n case 'low':\n return 'bg-green-500/20 text-green-600 dark:text-green-400';\n case 'medium':\n return 'bg-yellow-500/20 text-yellow-600 dark:text-yellow-400';\n case 'high':\n return 'bg-red-500/20 text-red-600 dark:text-red-400';\n default:\n return 'bg-secondary text-secondary-foreground';\n }\n}\n\nfunction getRiskLabel(risk: string): string {\n switch (risk) {\n case 'low':\n return 'Low Risk';\n case 'medium':\n return 'Medium Risk';\n case 'high':\n return 'High Risk';\n default:\n return risk;\n }\n}\n\nfunction getFundingPercentage(raised: number, target: number): number {\n return target > 0 ? Math.min((raised / target) * 100, 100) : 0;\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function InvestmentOpportunitiesPage() {\n const { navigateTo } = useAthleteBridge();\n const [isLoading, setIsLoading] = useState(true);\n const [selectedOpportunity, setSelectedOpportunity] = useState<InvestmentOpportunity | null>(\n null\n );\n const [showInvestModal, setShowInvestModal] = useState(false);\n const [investmentAmount, setInvestmentAmount] = useState('');\n const [investStatus, setInvestStatus] = useState<'idle' | 'success' | 'error'>('idle');\n\n const [filters, setFilters] = useState<OpportunityFilters>({\n searchQuery: '',\n category: '',\n riskLevel: '',\n minimumAmount: '',\n location: '',\n sortBy: 'featured',\n });\n\n useEffect(() => {\n const timer = setTimeout(() => setIsLoading(false), 600);\n return () => clearTimeout(timer);\n }, []);\n\n const handleFilterChange = useCallback((key: keyof OpportunityFilters, value: string) => {\n setFilters((prev) => ({ ...prev, [key]: value }));\n }, []);\n\n const filteredOpportunities = useMemo(() => {\n let filtered = [...mockOpportunities];\n\n // Search\n if (filters.searchQuery.trim()) {\n const query = filters.searchQuery.toLowerCase();\n filtered = filtered.filter(\n (opp) =>\n opp.cartName.toLowerCase().includes(query) ||\n opp.description.toLowerCase().includes(query) ||\n opp.category.toLowerCase().includes(query)\n );\n }\n\n // Category\n if (filters.category) {\n filtered = filtered.filter((opp) => opp.category === filters.category);\n }\n\n // Risk level\n if (filters.riskLevel) {\n filtered = filtered.filter((opp) => opp.riskLevel === filters.riskLevel);\n }\n\n // Location\n if (filters.location) {\n filtered = filtered.filter((opp) => opp.location.includes(filters.location));\n }\n\n // Minimum amount\n if (filters.minimumAmount) {\n const minAmount = parseInt(filters.minimumAmount, 10);\n filtered = filtered.filter((opp) => opp.minimumInvestment <= minAmount);\n }\n\n // Sort\n switch (filters.sortBy) {\n case 'returns':\n filtered.sort((a, b) => b.expectedReturns - a.expectedReturns);\n break;\n case 'funding':\n filtered.sort((a, b) => b.raisedAmount / b.targetAmount - a.raisedAmount / a.targetAmount);\n break;\n case 'closing':\n filtered.sort((a, b) => a.daysLeft - b.daysLeft);\n break;\n case 'minimum':\n filtered.sort((a, b) => a.minimumInvestment - b.minimumInvestment);\n break;\n default:\n break;\n }\n\n return filtered;\n }, [filters]);\n\n const handleInvest = useCallback(() => {\n if (!selectedOpportunity || !investmentAmount) return;\n\n const amount = parseInt(investmentAmount, 10);\n if (isNaN(amount)) return;\n\n if (amount < selectedOpportunity.minimumInvestment) {\n setInvestStatus('error');\n return;\n }\n if (amount > selectedOpportunity.maximumInvestment) {\n setInvestStatus('error');\n return;\n }\n\n setInvestStatus('success');\n setTimeout(() => {\n setShowInvestModal(false);\n setInvestmentAmount('');\n setInvestStatus('idle');\n navigateTo('/investor/portfolio');\n }, 1500);\n }, [selectedOpportunity, investmentAmount, navigateTo]);\n\n const openInvestModal = useCallback((opportunity: InvestmentOpportunity) => {\n setSelectedOpportunity(opportunity);\n setInvestmentAmount('');\n setInvestStatus('idle');\n setShowInvestModal(true);\n }, []);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Investment Opportunities\" description=\"Loading opportunities...\">\n <div className=\"flex items-center justify-center py-20\">\n <div className=\"text-center\">\n <div className=\"mx-auto mb-4 h-12 w-12 animate-spin rounded-full border-b-2 border-primary\" />\n <p className=\"text-sm text-text-secondary\">Loading opportunities...</p>\n </div>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Investment Opportunities\"\n description=\"Discover and invest in growing local businesses\"\n actions={\n <span className=\"text-sm text-text-secondary\">\n {filteredOpportunities.length} opportunities\n </span>\n }\n >\n {/* Platform Stats */}\n <div className=\"grid grid-cols-2 gap-3 sm:gap-4 lg:grid-cols-4\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3 sm:p-4\">\n <p className=\"text-xs text-text-secondary\">Active Opportunities</p>\n <p className=\"text-lg font-bold text-text-primary sm:text-2xl\">\n {platformStats.totalOpportunities}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3 sm:p-4\">\n <p className=\"text-xs text-text-secondary\">Average Returns</p>\n <p className=\"text-lg font-bold text-green-600 dark:text-green-400 sm:text-2xl\">\n {platformStats.averageReturns}%\n </p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3 sm:p-4\">\n <p className=\"text-xs text-text-secondary\">Total Funded</p>\n <p className=\"text-lg font-bold text-text-primary sm:text-2xl\">\n {formatCurrency(platformStats.totalFunded, {\n minimumFractionDigits: 0,\n notation: 'compact',\n })}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3 sm:p-4\">\n <p className=\"text-xs text-text-secondary\">Success Rate</p>\n <p className=\"text-lg font-bold text-text-primary sm:text-2xl\">\n {platformStats.successRate}%\n </p>\n </div>\n </div>\n\n {/* Filters */}\n <div className=\"mt-6 rounded-lg border border-border-subtle bg-bg-surface p-4 sm:p-6\">\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6\">\n {/* Search */}\n <div className=\"relative sm:col-span-2 lg:col-span-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"text\"\n placeholder=\"Search opportunities...\"\n value={filters.searchQuery}\n onChange={(e) => handleFilterChange('searchQuery', e.target.value)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-10 pr-4 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n\n {/* Category */}\n <select\n value={filters.category}\n onChange={(e) => handleFilterChange('category', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Categories</option>\n <option value=\"Healthy Food\">Healthy Food</option>\n <option value=\"Fast Food\">Fast Food</option>\n <option value=\"Fusion Food\">Fusion Food</option>\n <option value=\"Beverages\">Beverages</option>\n <option value=\"Street Food\">Street Food</option>\n </select>\n\n {/* Risk Level */}\n <select\n value={filters.riskLevel}\n onChange={(e) => handleFilterChange('riskLevel', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Risk Levels</option>\n <option value=\"low\">Low Risk</option>\n <option value=\"medium\">Medium Risk</option>\n <option value=\"high\">High Risk</option>\n </select>\n\n {/* Minimum Amount */}\n <select\n value={filters.minimumAmount}\n onChange={(e) => handleFilterChange('minimumAmount', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">Any Amount</option>\n <option value=\"15000\">Under ₹15,000</option>\n <option value=\"25000\">Under ₹25,000</option>\n <option value=\"50000\">Under ₹50,000</option>\n <option value=\"100000\">Under ₹1,00,000</option>\n </select>\n\n {/* Location */}\n <select\n value={filters.location}\n onChange={(e) => handleFilterChange('location', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Locations</option>\n <option value=\"Whitefield\">Whitefield</option>\n <option value=\"Koramangala\">Koramangala</option>\n <option value=\"Indiranagar\">Indiranagar</option>\n <option value=\"Electronic City\">Electronic City</option>\n </select>\n\n {/* Sort By */}\n <select\n value={filters.sortBy}\n onChange={(e) => handleFilterChange('sortBy', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"featured\">Featured</option>\n <option value=\"returns\">Highest Returns</option>\n <option value=\"funding\">Most Funded</option>\n <option value=\"closing\">Closing Soon</option>\n <option value=\"minimum\">Lowest Minimum</option>\n </select>\n </div>\n </div>\n\n {/* Opportunities Grid */}\n {filteredOpportunities.length === 0 ? (\n <div className=\"mt-6\">\n <EmptyState\n icon={<Search className=\"h-10 w-10\" />}\n title=\"No opportunities found\"\n description=\"Try adjusting your filters to find more opportunities\"\n action={\n <button\n type=\"button\"\n onClick={() =>\n setFilters({\n searchQuery: '',\n category: '',\n riskLevel: '',\n minimumAmount: '',\n location: '',\n sortBy: 'featured',\n })\n }\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n Clear Filters\n </button>\n }\n />\n </div>\n ) : (\n <div className=\"mt-6 grid grid-cols-1 gap-4 lg:grid-cols-2\">\n {filteredOpportunities.map((opportunity) => {\n const fundingPct = getFundingPercentage(\n opportunity.raisedAmount,\n opportunity.targetAmount\n );\n\n return (\n <div\n key={opportunity.id}\n className=\"rounded-lg border border-border-subtle bg-bg-surface shadow-sm hover:shadow-md transition-shadow\"\n >\n {/* Image */}\n <div className=\"relative\">\n <div className=\"h-40 w-full overflow-hidden rounded-t-lg bg-bg-sunken sm:h-48\">\n <img\n src={opportunity.image}\n alt={opportunity.cartName}\n className=\"h-full w-full object-cover\"\n loading=\"lazy\"\n />\n </div>\n {opportunity.status === 'funded' && (\n <div className=\"absolute right-2 top-2 rounded-full bg-green-500 px-2 py-1 text-xs font-medium text-white sm:right-4 sm:top-4 sm:px-3\">\n Fully Funded\n </div>\n )}\n {opportunity.daysLeft > 0 && opportunity.daysLeft <= 7 && (\n <div className=\"absolute left-2 top-2 rounded-full bg-red-500 px-2 py-1 text-xs font-medium text-white sm:left-4 sm:top-4 sm:px-3\">\n {opportunity.daysLeft} days left\n </div>\n )}\n </div>\n\n <div className=\"p-4 sm:p-6\">\n {/* Header */}\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex-1\">\n <h3 className=\"text-base font-semibold text-text-primary sm:text-xl\">\n {opportunity.cartName}\n </h3>\n <p className=\"text-xs text-text-secondary sm:text-sm\">\n by {opportunity.cartOwner}\n </p>\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n <span className=\"text-xs text-text-secondary sm:text-sm\">\n {opportunity.category}\n </span>\n <span\n className={cn(\n 'rounded-full px-2 py-0.5 text-xs font-medium',\n getRiskBadgeColor(opportunity.riskLevel)\n )}\n >\n {getRiskLabel(opportunity.riskLevel)}\n </span>\n </div>\n </div>\n <div className=\"text-left sm:text-right\">\n <p className=\"text-xl font-bold text-green-600 dark:text-green-400 sm:text-2xl\">\n {opportunity.expectedReturns}%\n </p>\n <p className=\"text-xs text-text-secondary\">Expected Returns</p>\n </div>\n </div>\n\n {/* Description */}\n <p className=\"mb-4 text-sm leading-relaxed text-text-secondary line-clamp-2\">\n {opportunity.description}\n </p>\n\n {/* Funding Progress */}\n <div className=\"mb-4\">\n <div className=\"mb-1 flex justify-between text-xs sm:text-sm\">\n <span className=\"font-medium text-text-primary\">\n {formatCurrency(opportunity.raisedAmount, { minimumFractionDigits: 0 })}{' '}\n raised\n </span>\n <span className=\"text-text-secondary\">\n of {formatCurrency(opportunity.targetAmount, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <div className=\"h-2 w-full overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg transition-all duration-300\"\n style={{ width: `${fundingPct}%` }}\n />\n </div>\n <div className=\"mt-1 flex justify-between text-xs text-text-secondary\">\n <span>{opportunity.investorCount} investors</span>\n <span>{fundingPct.toFixed(0)}% funded</span>\n </div>\n </div>\n\n {/* Key Metrics */}\n <div className=\"mb-4 grid grid-cols-3 gap-2 text-center sm:gap-4\">\n <div>\n <p className=\"text-sm font-bold text-text-primary sm:text-lg\">\n {formatCurrency(opportunity.minimumInvestment, {\n minimumFractionDigits: 0,\n })}\n </p>\n <p className=\"text-xs text-text-secondary\">Min Investment</p>\n </div>\n <div>\n <p className=\"text-sm font-bold text-text-primary sm:text-lg\">\n {opportunity.paybackPeriod} mo\n </p>\n <p className=\"text-xs text-text-secondary\">Payback Period</p>\n </div>\n <div>\n <div className=\"flex items-center justify-center gap-1\">\n <Star className=\"h-3.5 w-3.5 fill-yellow-400 text-yellow-400\" />\n <p className=\"text-sm font-bold text-text-primary sm:text-lg\">\n {opportunity.businessMetrics.rating}\n </p>\n </div>\n <p className=\"text-xs text-text-secondary\">Rating</p>\n </div>\n </div>\n\n {/* Business Performance */}\n <div className=\"mb-4 border-t border-border-subtle pt-3 sm:pt-4\">\n <p className=\"mb-2 text-xs font-medium text-text-secondary sm:text-sm\">\n Business Performance\n </p>\n <div className=\"grid grid-cols-1 gap-2 text-xs sm:grid-cols-2 sm:text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Monthly Revenue:</span>\n <span className=\"font-medium text-text-primary\">\n {formatCurrency(opportunity.businessMetrics.monthlyRevenue, {\n minimumFractionDigits: 0,\n })}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Gross Margin:</span>\n <span className=\"font-medium text-text-primary\">\n {opportunity.financials.grossMargin}%\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Monthly Orders:</span>\n <span className=\"font-medium text-text-primary\">\n {formatNumber(opportunity.businessMetrics.monthlyOrders)}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Net Margin:</span>\n <span className=\"font-medium text-text-primary\">\n {opportunity.financials.netMargin}%\n </span>\n </div>\n </div>\n </div>\n\n {/* Documents */}\n <div className=\"mb-4 border-t border-border-subtle pt-3\">\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <FileText className=\"h-3.5 w-3.5\" />\n <span>{opportunity.documents.length} documents available</span>\n </div>\n </div>\n\n {/* Location */}\n <div className=\"mb-4 flex items-center gap-1.5 text-xs text-text-secondary\">\n <MapPin className=\"h-3.5 w-3.5\" />\n <span>{opportunity.location}</span>\n </div>\n\n {/* Actions */}\n <div className=\"flex flex-col gap-2 sm:flex-row sm:gap-3\">\n <button\n type=\"button\"\n onClick={() => openInvestModal(opportunity)}\n disabled={opportunity.status === 'funded'}\n className={cn(\n 'flex-1 rounded-lg px-4 py-2.5 text-sm font-medium transition-colors',\n opportunity.status === 'funded'\n ? 'cursor-not-allowed bg-bg-sunken text-text-secondary'\n : 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90'\n )}\n >\n {opportunity.status === 'funded' ? 'Fully Funded' : 'Invest Now'}\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/investor/opportunities/${opportunity.id}`)}\n className=\"flex flex-1 items-center justify-center gap-2 rounded-lg border border-border-subtle px-4 py-2.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Eye className=\"h-4 w-4\" />\n View Details\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {/* Investment Modal */}\n {showInvestModal && selectedOpportunity && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\">\n <div className=\"relative max-h-[90vh] w-full max-w-md overflow-y-auto rounded-lg border border-border-subtle bg-bg-surface p-4 sm:p-6\">\n {/* Close button */}\n <button\n type=\"button\"\n onClick={() => {\n setShowInvestModal(false);\n setInvestmentAmount('');\n setInvestStatus('idle');\n }}\n className=\"absolute right-3 top-3 rounded-lg p-1 text-text-secondary hover:bg-accent transition-colors\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n\n <h3 className=\"mb-4 text-base font-semibold text-text-primary sm:text-lg\">\n Invest in {selectedOpportunity.cartName}\n </h3>\n\n {investStatus === 'success' ? (\n <div className=\"py-8 text-center\">\n <CheckCircle2 className=\"mx-auto mb-3 h-12 w-12 text-green-600 dark:text-green-400\" />\n <p className=\"text-sm font-medium text-text-primary\">Investment successful!</p>\n <p className=\"mt-1 text-xs text-text-secondary\">\n Redirecting to your portfolio...\n </p>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {/* Investment Range */}\n <div>\n <p className=\"mb-1 text-xs text-text-secondary sm:text-sm\">Investment Range</p>\n <p className=\"text-sm font-medium text-text-primary sm:text-base\">\n {formatCurrency(selectedOpportunity.minimumInvestment, {\n minimumFractionDigits: 0,\n })}{' '}\n -{' '}\n {formatCurrency(selectedOpportunity.maximumInvestment, {\n minimumFractionDigits: 0,\n })}\n </p>\n </div>\n\n {/* Amount Input */}\n <div>\n <label className=\"mb-1 block text-xs font-medium text-text-primary sm:text-sm\">\n Investment Amount\n </label>\n <div className=\"relative\">\n <IndianRupee className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"number\"\n value={investmentAmount}\n onChange={(e) => {\n setInvestmentAmount(e.target.value);\n setInvestStatus('idle');\n }}\n placeholder=\"Enter amount\"\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-10 pr-4 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n {investStatus === 'error' && (\n <p className=\"mt-1 text-xs text-red-600 dark:text-red-400\">\n Amount must be between{' '}\n {formatCurrency(selectedOpportunity.minimumInvestment, {\n minimumFractionDigits: 0,\n })}{' '}\n and{' '}\n {formatCurrency(selectedOpportunity.maximumInvestment, {\n minimumFractionDigits: 0,\n })}\n </p>\n )}\n </div>\n\n {/* Returns Calculator */}\n {investmentAmount &&\n !isNaN(parseInt(investmentAmount, 10)) &&\n parseInt(investmentAmount, 10) > 0 && (\n <div className=\"rounded-lg border border-border-subtle bg-bg-sunken/50 p-3 sm:p-4\">\n <p className=\"mb-2 text-xs text-text-secondary sm:text-sm\">\n Expected Returns\n </p>\n <div className=\"space-y-1.5\">\n <div className=\"flex justify-between\">\n <span className=\"text-xs text-text-primary sm:text-sm\">Investment:</span>\n <span className=\"text-xs font-medium text-text-primary sm:text-sm\">\n {formatCurrency(parseInt(investmentAmount, 10), {\n minimumFractionDigits: 0,\n })}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-xs text-text-primary sm:text-sm\">\n Expected Return ({selectedOpportunity.expectedReturns}%):\n </span>\n <span className=\"text-xs font-medium text-green-600 dark:text-green-400 sm:text-sm\">\n +\n {formatCurrency(\n (parseInt(investmentAmount, 10) *\n selectedOpportunity.expectedReturns) /\n 100,\n { minimumFractionDigits: 0 }\n )}\n </span>\n </div>\n <div className=\"flex justify-between border-t border-border-subtle pt-2\">\n <span className=\"text-xs font-medium text-text-primary sm:text-sm\">\n Total Value:\n </span>\n <span className=\"text-xs font-bold text-text-primary sm:text-sm\">\n {formatCurrency(\n parseInt(investmentAmount, 10) *\n (1 + selectedOpportunity.expectedReturns / 100),\n { minimumFractionDigits: 0 }\n )}\n </span>\n </div>\n </div>\n </div>\n )}\n\n {/* Investment Terms */}\n <div className=\"space-y-1 text-xs text-text-secondary sm:text-sm\">\n <p>\n • Minimum lock-in period:{' '}\n {selectedOpportunity.investmentTerms.lockInPeriod} months\n </p>\n <p>\n • Dividend frequency:{' '}\n {selectedOpportunity.investmentTerms.dividendFrequency}\n </p>\n <p>\n • Your equity stake:{' '}\n {(\n ((parseInt(investmentAmount, 10) || 0) / selectedOpportunity.targetAmount) *\n selectedOpportunity.investmentTerms.equityOffered\n ).toFixed(2)}\n %\n </p>\n <p>\n • Exit options:{' '}\n {selectedOpportunity.investmentTerms.exitOptions.join(', ')}\n </p>\n </div>\n\n {/* Actions */}\n <div className=\"flex flex-col gap-2 pt-2 sm:flex-row sm:gap-3\">\n <button\n type=\"button\"\n onClick={() => {\n setShowInvestModal(false);\n setInvestmentAmount('');\n setInvestStatus('idle');\n }}\n className=\"flex-1 rounded-lg border border-border-subtle px-4 py-2.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleInvest}\n disabled={\n !investmentAmount ||\n isNaN(parseInt(investmentAmount, 10)) ||\n parseInt(investmentAmount, 10) < selectedOpportunity.minimumInvestment\n }\n className={cn(\n 'flex-1 rounded-lg px-4 py-2.5 text-sm font-medium transition-colors',\n !investmentAmount ||\n isNaN(parseInt(investmentAmount, 10)) ||\n parseInt(investmentAmount, 10) < selectedOpportunity.minimumInvestment\n ? 'cursor-not-allowed bg-bg-sunken text-text-secondary'\n : 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90'\n )}\n >\n Confirm Investment\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InvestmentOpportunitiesPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/investor/InvestmentOpportunitiesPage.tsx"],"sourcesContent":["/**\n * Investment Opportunities Page\n * @module atheletebridge/pages/investor\n *\n * Platform stats, 6 filters (search/category/risk/amount/location/sort),\n * invest modal with amount calculator, opportunity cards with images/funding\n * progress/business metrics/documents.\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport {\n Search,\n SlidersHorizontal,\n MapPin,\n Star,\n Clock,\n Users,\n TrendingUp,\n FileText,\n IndianRupee,\n Eye,\n X,\n Briefcase,\n Target,\n Award,\n CheckCircle2,\n} from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatNumber } from '../../utils/formatters';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface InvestmentOpportunity {\n id: string;\n cartId: string;\n cartName: string;\n cartOwner: string;\n description: string;\n targetAmount: number;\n raisedAmount: number;\n minimumInvestment: number;\n maximumInvestment: number;\n investorCount: number;\n daysLeft: number;\n expectedReturns: number;\n paybackPeriod: number;\n riskLevel: 'low' | 'medium' | 'high';\n category: string;\n location: string;\n image: string;\n businessMetrics: {\n monthlyRevenue: number;\n monthlyOrders: number;\n averageOrderValue: number;\n rating: number;\n reviewCount: number;\n operatingSince: string;\n };\n financials: {\n grossMargin: number;\n netMargin: number;\n monthlyExpenses: number;\n breakEvenAchieved: boolean;\n };\n investmentTerms: {\n equityOffered: number;\n dividendFrequency: 'monthly' | 'quarterly' | 'yearly';\n lockInPeriod: number;\n exitOptions: string[];\n };\n documents: Array<{ name: string; type: string; uploadedOn: string }>;\n status: 'active' | 'funded' | 'closed';\n}\n\ninterface OpportunityFilters {\n searchQuery: string;\n category: string;\n riskLevel: string;\n minimumAmount: string;\n location: string;\n sortBy: string;\n}\n\n// ---------------------------------------------------------------------------\n// Mock data\n// ---------------------------------------------------------------------------\n\nconst mockOpportunities: InvestmentOpportunity[] = [\n {\n id: 'opp-001',\n cartId: 'cart-005',\n cartName: 'Organic Salad Bar',\n cartOwner: 'Sarah Johnson',\n description:\n 'Premium organic salad bar serving health-conscious customers in tech parks. Looking to expand to 3 new locations.',\n targetAmount: 500000,\n raisedAmount: 325000,\n minimumInvestment: 25000,\n maximumInvestment: 100000,\n investorCount: 8,\n daysLeft: 15,\n expectedReturns: 22,\n paybackPeriod: 36,\n riskLevel: 'low',\n category: 'Healthy Food',\n location: 'Whitefield, Bangalore',\n image: 'https://images.unsplash.com/photo-1512621776951-a57141f2eefd?w=400',\n businessMetrics: {\n monthlyRevenue: 280000,\n monthlyOrders: 1800,\n averageOrderValue: 156,\n rating: 4.9,\n reviewCount: 342,\n operatingSince: '2022-03-15',\n },\n financials: {\n grossMargin: 65,\n netMargin: 28,\n monthlyExpenses: 78000,\n breakEvenAchieved: true,\n },\n investmentTerms: {\n equityOffered: 25,\n dividendFrequency: 'monthly',\n lockInPeriod: 24,\n exitOptions: ['Buyback', 'Secondary Sale', 'IPO'],\n },\n documents: [\n { name: 'Business Plan', type: 'PDF', uploadedOn: '2024-06-01' },\n { name: 'Financial Statements', type: 'PDF', uploadedOn: '2024-06-01' },\n { name: 'Legal Documents', type: 'PDF', uploadedOn: '2024-06-01' },\n ],\n status: 'active',\n },\n {\n id: 'opp-002',\n cartId: 'cart-006',\n cartName: 'Midnight Munchies',\n cartOwner: 'Ravi Mehta',\n description:\n 'Late-night food delivery cart specializing in comfort food for night shift workers and students. Operating near IT corridors.',\n targetAmount: 300000,\n raisedAmount: 180000,\n minimumInvestment: 15000,\n maximumInvestment: 75000,\n investorCount: 12,\n daysLeft: 22,\n expectedReturns: 18,\n paybackPeriod: 30,\n riskLevel: 'medium',\n category: 'Fast Food',\n location: 'Electronic City, Bangalore',\n image: 'https://images.unsplash.com/photo-1565299624946-b28f40a0ae38?w=400',\n businessMetrics: {\n monthlyRevenue: 195000,\n monthlyOrders: 1200,\n averageOrderValue: 163,\n rating: 4.7,\n reviewCount: 256,\n operatingSince: '2023-01-10',\n },\n financials: {\n grossMargin: 58,\n netMargin: 22,\n monthlyExpenses: 65000,\n breakEvenAchieved: true,\n },\n investmentTerms: {\n equityOffered: 20,\n dividendFrequency: 'quarterly',\n lockInPeriod: 18,\n exitOptions: ['Buyback', 'Secondary Sale'],\n },\n documents: [\n { name: 'Business Plan', type: 'PDF', uploadedOn: '2024-06-05' },\n { name: 'Market Analysis', type: 'PDF', uploadedOn: '2024-06-05' },\n ],\n status: 'active',\n },\n {\n id: 'opp-003',\n cartId: 'cart-007',\n cartName: 'Fusion Street Tacos',\n cartOwner: 'Maria Rodriguez',\n description:\n 'Innovative fusion taco cart combining Mexican and Indian flavors. Winner of Street Food Awards 2023.',\n targetAmount: 400000,\n raisedAmount: 400000,\n minimumInvestment: 20000,\n maximumInvestment: 80000,\n investorCount: 15,\n daysLeft: 0,\n expectedReturns: 25,\n paybackPeriod: 24,\n riskLevel: 'low',\n category: 'Fusion Food',\n location: 'Indiranagar, Bangalore',\n image: 'https://images.unsplash.com/photo-1551504734-5ee1c4a1479b?w=400',\n businessMetrics: {\n monthlyRevenue: 320000,\n monthlyOrders: 2100,\n averageOrderValue: 152,\n rating: 4.8,\n reviewCount: 512,\n operatingSince: '2021-08-20',\n },\n financials: {\n grossMargin: 68,\n netMargin: 32,\n monthlyExpenses: 85000,\n breakEvenAchieved: true,\n },\n investmentTerms: {\n equityOffered: 30,\n dividendFrequency: 'monthly',\n lockInPeriod: 12,\n exitOptions: ['Buyback', 'Franchise Conversion'],\n },\n documents: [\n { name: 'Business Plan', type: 'PDF', uploadedOn: '2024-05-20' },\n { name: 'Awards & Recognition', type: 'PDF', uploadedOn: '2024-05-20' },\n ],\n status: 'funded',\n },\n {\n id: 'opp-004',\n cartId: 'cart-008',\n cartName: 'Bubble Tea Express',\n cartOwner: 'Chen Wei',\n description:\n 'Trendy bubble tea cart with proprietary recipes. Planning expansion through franchise model.',\n targetAmount: 600000,\n raisedAmount: 120000,\n minimumInvestment: 30000,\n maximumInvestment: 150000,\n investorCount: 4,\n daysLeft: 45,\n expectedReturns: 20,\n paybackPeriod: 36,\n riskLevel: 'high',\n category: 'Beverages',\n location: 'Koramangala, Bangalore',\n image: 'https://images.unsplash.com/photo-1558857563-b371033873b8?w=400',\n businessMetrics: {\n monthlyRevenue: 150000,\n monthlyOrders: 900,\n averageOrderValue: 167,\n rating: 4.6,\n reviewCount: 189,\n operatingSince: '2023-11-01',\n },\n financials: {\n grossMargin: 72,\n netMargin: 18,\n monthlyExpenses: 55000,\n breakEvenAchieved: false,\n },\n investmentTerms: {\n equityOffered: 35,\n dividendFrequency: 'quarterly',\n lockInPeriod: 36,\n exitOptions: ['Franchise Sale', 'Acquisition'],\n },\n documents: [\n { name: 'Franchise Plan', type: 'PDF', uploadedOn: '2024-06-10' },\n { name: 'Recipe Patents', type: 'PDF', uploadedOn: '2024-06-10' },\n ],\n status: 'active',\n },\n];\n\nconst platformStats = {\n totalOpportunities: 24,\n averageReturns: 21.5,\n totalFunded: 15600000,\n successRate: 89,\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getRiskBadgeColor(risk: string): string {\n switch (risk) {\n case 'low':\n return 'bg-green-500/20 text-green-600 dark:text-green-400';\n case 'medium':\n return 'bg-yellow-500/20 text-yellow-600 dark:text-yellow-400';\n case 'high':\n return 'bg-red-500/20 text-red-600 dark:text-red-400';\n default:\n return 'bg-secondary text-secondary-foreground';\n }\n}\n\nfunction getRiskLabel(risk: string): string {\n switch (risk) {\n case 'low':\n return 'Low Risk';\n case 'medium':\n return 'Medium Risk';\n case 'high':\n return 'High Risk';\n default:\n return risk;\n }\n}\n\nfunction getFundingPercentage(raised: number, target: number): number {\n return target > 0 ? Math.min((raised / target) * 100, 100) : 0;\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function InvestmentOpportunitiesPage() {\n const { navigateTo } = useAthleteBridge();\n const [isLoading, setIsLoading] = useState(true);\n const [selectedOpportunity, setSelectedOpportunity] = useState<InvestmentOpportunity | null>(\n null\n );\n const [showInvestModal, setShowInvestModal] = useState(false);\n const [investmentAmount, setInvestmentAmount] = useState('');\n const [investStatus, setInvestStatus] = useState<'idle' | 'success' | 'error'>('idle');\n\n const [filters, setFilters] = useState<OpportunityFilters>({\n searchQuery: '',\n category: '',\n riskLevel: '',\n minimumAmount: '',\n location: '',\n sortBy: 'featured',\n });\n\n useEffect(() => {\n const timer = setTimeout(() => setIsLoading(false), 600);\n return () => clearTimeout(timer);\n }, []);\n\n const handleFilterChange = useCallback((key: keyof OpportunityFilters, value: string) => {\n setFilters((prev) => ({ ...prev, [key]: value }));\n }, []);\n\n const filteredOpportunities = useMemo(() => {\n let filtered = [...mockOpportunities];\n\n // Search\n if (filters.searchQuery.trim()) {\n const query = filters.searchQuery.toLowerCase();\n filtered = filtered.filter(\n (opp) =>\n opp.cartName.toLowerCase().includes(query) ||\n opp.description.toLowerCase().includes(query) ||\n opp.category.toLowerCase().includes(query)\n );\n }\n\n // Category\n if (filters.category) {\n filtered = filtered.filter((opp) => opp.category === filters.category);\n }\n\n // Risk level\n if (filters.riskLevel) {\n filtered = filtered.filter((opp) => opp.riskLevel === filters.riskLevel);\n }\n\n // Location\n if (filters.location) {\n filtered = filtered.filter((opp) => opp.location.includes(filters.location));\n }\n\n // Minimum amount\n if (filters.minimumAmount) {\n const minAmount = parseInt(filters.minimumAmount, 10);\n filtered = filtered.filter((opp) => opp.minimumInvestment <= minAmount);\n }\n\n // Sort\n switch (filters.sortBy) {\n case 'returns':\n filtered.sort((a, b) => b.expectedReturns - a.expectedReturns);\n break;\n case 'funding':\n filtered.sort((a, b) => b.raisedAmount / b.targetAmount - a.raisedAmount / a.targetAmount);\n break;\n case 'closing':\n filtered.sort((a, b) => a.daysLeft - b.daysLeft);\n break;\n case 'minimum':\n filtered.sort((a, b) => a.minimumInvestment - b.minimumInvestment);\n break;\n default:\n break;\n }\n\n return filtered;\n }, [filters]);\n\n const handleInvest = useCallback(() => {\n if (!selectedOpportunity || !investmentAmount) return;\n\n const amount = parseInt(investmentAmount, 10);\n if (isNaN(amount)) return;\n\n if (amount < selectedOpportunity.minimumInvestment) {\n setInvestStatus('error');\n return;\n }\n if (amount > selectedOpportunity.maximumInvestment) {\n setInvestStatus('error');\n return;\n }\n\n setInvestStatus('success');\n setTimeout(() => {\n setShowInvestModal(false);\n setInvestmentAmount('');\n setInvestStatus('idle');\n navigateTo('/investor/portfolio');\n }, 1500);\n }, [selectedOpportunity, investmentAmount, navigateTo]);\n\n const openInvestModal = useCallback((opportunity: InvestmentOpportunity) => {\n setSelectedOpportunity(opportunity);\n setInvestmentAmount('');\n setInvestStatus('idle');\n setShowInvestModal(true);\n }, []);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Investment Opportunities\" description=\"Loading opportunities...\">\n <div className=\"flex items-center justify-center py-20\">\n <div className=\"text-center\">\n <div className=\"mx-auto mb-4 h-12 w-12 animate-spin rounded-full border-b-2 border-primary\" />\n <p className=\"text-sm text-text-secondary\">Loading opportunities...</p>\n </div>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Investment Opportunities\"\n description=\"Discover and invest in growing local businesses\"\n actions={\n <span className=\"text-sm text-text-secondary\">\n {filteredOpportunities.length} opportunities\n </span>\n }\n >\n {/* Platform Stats */}\n <div className=\"grid grid-cols-2 gap-3 sm:gap-4 lg:grid-cols-4\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3 sm:p-4\">\n <p className=\"text-xs text-text-secondary\">Active Opportunities</p>\n <p className=\"text-lg font-bold text-text-primary sm:text-2xl\">\n {platformStats.totalOpportunities}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3 sm:p-4\">\n <p className=\"text-xs text-text-secondary\">Average Returns</p>\n <p className=\"text-lg font-bold text-green-600 dark:text-green-400 sm:text-2xl\">\n {platformStats.averageReturns}%\n </p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3 sm:p-4\">\n <p className=\"text-xs text-text-secondary\">Total Funded</p>\n <p className=\"text-lg font-bold text-text-primary sm:text-2xl\">\n {formatCurrency(platformStats.totalFunded, {\n minimumFractionDigits: 0,\n notation: 'compact',\n })}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3 sm:p-4\">\n <p className=\"text-xs text-text-secondary\">Success Rate</p>\n <p className=\"text-lg font-bold text-text-primary sm:text-2xl\">\n {platformStats.successRate}%\n </p>\n </div>\n </div>\n\n {/* Filters */}\n <div className=\"mt-6 rounded-lg border border-border-subtle bg-bg-surface p-4 sm:p-6\">\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6\">\n {/* Search */}\n <div className=\"relative sm:col-span-2 lg:col-span-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"text\"\n placeholder=\"Search opportunities...\"\n value={filters.searchQuery}\n onChange={(e) => handleFilterChange('searchQuery', e.target.value)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-10 pr-4 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n\n {/* Category */}\n <select\n value={filters.category}\n onChange={(e) => handleFilterChange('category', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Categories</option>\n <option value=\"Healthy Food\">Healthy Food</option>\n <option value=\"Fast Food\">Fast Food</option>\n <option value=\"Fusion Food\">Fusion Food</option>\n <option value=\"Beverages\">Beverages</option>\n <option value=\"Street Food\">Street Food</option>\n </select>\n\n {/* Risk Level */}\n <select\n value={filters.riskLevel}\n onChange={(e) => handleFilterChange('riskLevel', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Risk Levels</option>\n <option value=\"low\">Low Risk</option>\n <option value=\"medium\">Medium Risk</option>\n <option value=\"high\">High Risk</option>\n </select>\n\n {/* Minimum Amount */}\n <select\n value={filters.minimumAmount}\n onChange={(e) => handleFilterChange('minimumAmount', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">Any Amount</option>\n <option value=\"15000\">Under ₹15,000</option>\n <option value=\"25000\">Under ₹25,000</option>\n <option value=\"50000\">Under ₹50,000</option>\n <option value=\"100000\">Under ₹1,00,000</option>\n </select>\n\n {/* Location */}\n <select\n value={filters.location}\n onChange={(e) => handleFilterChange('location', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Locations</option>\n <option value=\"Whitefield\">Whitefield</option>\n <option value=\"Koramangala\">Koramangala</option>\n <option value=\"Indiranagar\">Indiranagar</option>\n <option value=\"Electronic City\">Electronic City</option>\n </select>\n\n {/* Sort By */}\n <select\n value={filters.sortBy}\n onChange={(e) => handleFilterChange('sortBy', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"featured\">Featured</option>\n <option value=\"returns\">Highest Returns</option>\n <option value=\"funding\">Most Funded</option>\n <option value=\"closing\">Closing Soon</option>\n <option value=\"minimum\">Lowest Minimum</option>\n </select>\n </div>\n </div>\n\n {/* Opportunities Grid */}\n {filteredOpportunities.length === 0 ? (\n <div className=\"mt-6\">\n <EmptyState\n illustration=\"empty-search\"\n icon={<Search className=\"h-10 w-10\" />}\n title=\"No opportunities found\"\n description=\"Try adjusting your filters to find more opportunities\"\n action={\n <button\n type=\"button\"\n onClick={() =>\n setFilters({\n searchQuery: '',\n category: '',\n riskLevel: '',\n minimumAmount: '',\n location: '',\n sortBy: 'featured',\n })\n }\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n Clear Filters\n </button>\n }\n />\n </div>\n ) : (\n <div className=\"mt-6 grid grid-cols-1 gap-4 lg:grid-cols-2\">\n {filteredOpportunities.map((opportunity) => {\n const fundingPct = getFundingPercentage(\n opportunity.raisedAmount,\n opportunity.targetAmount\n );\n\n return (\n <div\n key={opportunity.id}\n className=\"rounded-lg border border-border-subtle bg-bg-surface shadow-sm hover:shadow-md transition-shadow\"\n >\n {/* Image */}\n <div className=\"relative\">\n <div className=\"h-40 w-full overflow-hidden rounded-t-lg bg-bg-sunken sm:h-48\">\n <img\n src={opportunity.image}\n alt={opportunity.cartName}\n className=\"h-full w-full object-cover\"\n loading=\"lazy\"\n />\n </div>\n {opportunity.status === 'funded' && (\n <div className=\"absolute right-2 top-2 rounded-full bg-green-500 px-2 py-1 text-xs font-medium text-white sm:right-4 sm:top-4 sm:px-3\">\n Fully Funded\n </div>\n )}\n {opportunity.daysLeft > 0 && opportunity.daysLeft <= 7 && (\n <div className=\"absolute left-2 top-2 rounded-full bg-red-500 px-2 py-1 text-xs font-medium text-white sm:left-4 sm:top-4 sm:px-3\">\n {opportunity.daysLeft} days left\n </div>\n )}\n </div>\n\n <div className=\"p-4 sm:p-6\">\n {/* Header */}\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex-1\">\n <h3 className=\"text-base font-semibold text-text-primary sm:text-xl\">\n {opportunity.cartName}\n </h3>\n <p className=\"text-xs text-text-secondary sm:text-sm\">\n by {opportunity.cartOwner}\n </p>\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n <span className=\"text-xs text-text-secondary sm:text-sm\">\n {opportunity.category}\n </span>\n <span\n className={cn(\n 'rounded-full px-2 py-0.5 text-xs font-medium',\n getRiskBadgeColor(opportunity.riskLevel)\n )}\n >\n {getRiskLabel(opportunity.riskLevel)}\n </span>\n </div>\n </div>\n <div className=\"text-left sm:text-right\">\n <p className=\"text-xl font-bold text-green-600 dark:text-green-400 sm:text-2xl\">\n {opportunity.expectedReturns}%\n </p>\n <p className=\"text-xs text-text-secondary\">Expected Returns</p>\n </div>\n </div>\n\n {/* Description */}\n <p className=\"mb-4 text-sm leading-relaxed text-text-secondary line-clamp-2\">\n {opportunity.description}\n </p>\n\n {/* Funding Progress */}\n <div className=\"mb-4\">\n <div className=\"mb-1 flex justify-between text-xs sm:text-sm\">\n <span className=\"font-medium text-text-primary\">\n {formatCurrency(opportunity.raisedAmount, { minimumFractionDigits: 0 })}{' '}\n raised\n </span>\n <span className=\"text-text-secondary\">\n of {formatCurrency(opportunity.targetAmount, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <div className=\"h-2 w-full overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg transition-all duration-300\"\n style={{ width: `${fundingPct}%` }}\n />\n </div>\n <div className=\"mt-1 flex justify-between text-xs text-text-secondary\">\n <span>{opportunity.investorCount} investors</span>\n <span>{fundingPct.toFixed(0)}% funded</span>\n </div>\n </div>\n\n {/* Key Metrics */}\n <div className=\"mb-4 grid grid-cols-3 gap-2 text-center sm:gap-4\">\n <div>\n <p className=\"text-sm font-bold text-text-primary sm:text-lg\">\n {formatCurrency(opportunity.minimumInvestment, {\n minimumFractionDigits: 0,\n })}\n </p>\n <p className=\"text-xs text-text-secondary\">Min Investment</p>\n </div>\n <div>\n <p className=\"text-sm font-bold text-text-primary sm:text-lg\">\n {opportunity.paybackPeriod} mo\n </p>\n <p className=\"text-xs text-text-secondary\">Payback Period</p>\n </div>\n <div>\n <div className=\"flex items-center justify-center gap-1\">\n <Star className=\"h-3.5 w-3.5 fill-yellow-400 text-yellow-400\" />\n <p className=\"text-sm font-bold text-text-primary sm:text-lg\">\n {opportunity.businessMetrics.rating}\n </p>\n </div>\n <p className=\"text-xs text-text-secondary\">Rating</p>\n </div>\n </div>\n\n {/* Business Performance */}\n <div className=\"mb-4 border-t border-border-subtle pt-3 sm:pt-4\">\n <p className=\"mb-2 text-xs font-medium text-text-secondary sm:text-sm\">\n Business Performance\n </p>\n <div className=\"grid grid-cols-1 gap-2 text-xs sm:grid-cols-2 sm:text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Monthly Revenue:</span>\n <span className=\"font-medium text-text-primary\">\n {formatCurrency(opportunity.businessMetrics.monthlyRevenue, {\n minimumFractionDigits: 0,\n })}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Gross Margin:</span>\n <span className=\"font-medium text-text-primary\">\n {opportunity.financials.grossMargin}%\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Monthly Orders:</span>\n <span className=\"font-medium text-text-primary\">\n {formatNumber(opportunity.businessMetrics.monthlyOrders)}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Net Margin:</span>\n <span className=\"font-medium text-text-primary\">\n {opportunity.financials.netMargin}%\n </span>\n </div>\n </div>\n </div>\n\n {/* Documents */}\n <div className=\"mb-4 border-t border-border-subtle pt-3\">\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <FileText className=\"h-3.5 w-3.5\" />\n <span>{opportunity.documents.length} documents available</span>\n </div>\n </div>\n\n {/* Location */}\n <div className=\"mb-4 flex items-center gap-1.5 text-xs text-text-secondary\">\n <MapPin className=\"h-3.5 w-3.5\" />\n <span>{opportunity.location}</span>\n </div>\n\n {/* Actions */}\n <div className=\"flex flex-col gap-2 sm:flex-row sm:gap-3\">\n <button\n type=\"button\"\n onClick={() => openInvestModal(opportunity)}\n disabled={opportunity.status === 'funded'}\n className={cn(\n 'flex-1 rounded-lg px-4 py-2.5 text-sm font-medium transition-colors',\n opportunity.status === 'funded'\n ? 'cursor-not-allowed bg-bg-sunken text-text-secondary'\n : 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90'\n )}\n >\n {opportunity.status === 'funded' ? 'Fully Funded' : 'Invest Now'}\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/investor/opportunities/${opportunity.id}`)}\n className=\"flex flex-1 items-center justify-center gap-2 rounded-lg border border-border-subtle px-4 py-2.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Eye className=\"h-4 w-4\" />\n View Details\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {/* Investment Modal */}\n {showInvestModal && selectedOpportunity && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\">\n <div className=\"relative max-h-[90vh] w-full max-w-md overflow-y-auto rounded-lg border border-border-subtle bg-bg-surface p-4 sm:p-6\">\n {/* Close button */}\n <button\n type=\"button\"\n onClick={() => {\n setShowInvestModal(false);\n setInvestmentAmount('');\n setInvestStatus('idle');\n }}\n className=\"absolute right-3 top-3 rounded-lg p-1 text-text-secondary hover:bg-accent transition-colors\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n\n <h3 className=\"mb-4 text-base font-semibold text-text-primary sm:text-lg\">\n Invest in {selectedOpportunity.cartName}\n </h3>\n\n {investStatus === 'success' ? (\n <div className=\"py-8 text-center\">\n <CheckCircle2 className=\"mx-auto mb-3 h-12 w-12 text-green-600 dark:text-green-400\" />\n <p className=\"text-sm font-medium text-text-primary\">Investment successful!</p>\n <p className=\"mt-1 text-xs text-text-secondary\">Redirecting to your portfolio...</p>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {/* Investment Range */}\n <div>\n <p className=\"mb-1 text-xs text-text-secondary sm:text-sm\">Investment Range</p>\n <p className=\"text-sm font-medium text-text-primary sm:text-base\">\n {formatCurrency(selectedOpportunity.minimumInvestment, {\n minimumFractionDigits: 0,\n })}{' '}\n -{' '}\n {formatCurrency(selectedOpportunity.maximumInvestment, {\n minimumFractionDigits: 0,\n })}\n </p>\n </div>\n\n {/* Amount Input */}\n <div>\n <label className=\"mb-1 block text-xs font-medium text-text-primary sm:text-sm\">\n Investment Amount\n </label>\n <div className=\"relative\">\n <IndianRupee className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"number\"\n value={investmentAmount}\n onChange={(e) => {\n setInvestmentAmount(e.target.value);\n setInvestStatus('idle');\n }}\n placeholder=\"Enter amount\"\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-10 pr-4 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n {investStatus === 'error' && (\n <p className=\"mt-1 text-xs text-red-600 dark:text-red-400\">\n Amount must be between{' '}\n {formatCurrency(selectedOpportunity.minimumInvestment, {\n minimumFractionDigits: 0,\n })}{' '}\n and{' '}\n {formatCurrency(selectedOpportunity.maximumInvestment, {\n minimumFractionDigits: 0,\n })}\n </p>\n )}\n </div>\n\n {/* Returns Calculator */}\n {investmentAmount &&\n !isNaN(parseInt(investmentAmount, 10)) &&\n parseInt(investmentAmount, 10) > 0 && (\n <div className=\"rounded-lg border border-border-subtle bg-bg-sunken/50 p-3 sm:p-4\">\n <p className=\"mb-2 text-xs text-text-secondary sm:text-sm\">\n Expected Returns\n </p>\n <div className=\"space-y-1.5\">\n <div className=\"flex justify-between\">\n <span className=\"text-xs text-text-primary sm:text-sm\">Investment:</span>\n <span className=\"text-xs font-medium text-text-primary sm:text-sm\">\n {formatCurrency(parseInt(investmentAmount, 10), {\n minimumFractionDigits: 0,\n })}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-xs text-text-primary sm:text-sm\">\n Expected Return ({selectedOpportunity.expectedReturns}%):\n </span>\n <span className=\"text-xs font-medium text-green-600 dark:text-green-400 sm:text-sm\">\n +\n {formatCurrency(\n (parseInt(investmentAmount, 10) *\n selectedOpportunity.expectedReturns) /\n 100,\n { minimumFractionDigits: 0 }\n )}\n </span>\n </div>\n <div className=\"flex justify-between border-t border-border-subtle pt-2\">\n <span className=\"text-xs font-medium text-text-primary sm:text-sm\">\n Total Value:\n </span>\n <span className=\"text-xs font-bold text-text-primary sm:text-sm\">\n {formatCurrency(\n parseInt(investmentAmount, 10) *\n (1 + selectedOpportunity.expectedReturns / 100),\n { minimumFractionDigits: 0 }\n )}\n </span>\n </div>\n </div>\n </div>\n )}\n\n {/* Investment Terms */}\n <div className=\"space-y-1 text-xs text-text-secondary sm:text-sm\">\n <p>\n • Minimum lock-in period:{' '}\n {selectedOpportunity.investmentTerms.lockInPeriod} months\n </p>\n <p>\n • Dividend frequency:{' '}\n {selectedOpportunity.investmentTerms.dividendFrequency}\n </p>\n <p>\n • Your equity stake:{' '}\n {(\n ((parseInt(investmentAmount, 10) || 0) / selectedOpportunity.targetAmount) *\n selectedOpportunity.investmentTerms.equityOffered\n ).toFixed(2)}\n %\n </p>\n <p>\n • Exit options:{' '}\n {selectedOpportunity.investmentTerms.exitOptions.join(', ')}\n </p>\n </div>\n\n {/* Actions */}\n <div className=\"flex flex-col gap-2 pt-2 sm:flex-row sm:gap-3\">\n <button\n type=\"button\"\n onClick={() => {\n setShowInvestModal(false);\n setInvestmentAmount('');\n setInvestStatus('idle');\n }}\n className=\"flex-1 rounded-lg border border-border-subtle px-4 py-2.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleInvest}\n disabled={\n !investmentAmount ||\n isNaN(parseInt(investmentAmount, 10)) ||\n parseInt(investmentAmount, 10) < selectedOpportunity.minimumInvestment\n }\n className={cn(\n 'flex-1 rounded-lg px-4 py-2.5 text-sm font-medium transition-colors',\n !investmentAmount ||\n isNaN(parseInt(investmentAmount, 10)) ||\n parseInt(investmentAmount, 10) < selectedOpportunity.minimumInvestment\n ? 'cursor-not-allowed bg-bg-sunken text-text-secondary'\n : 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90'\n )}\n >\n Confirm Investment\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;AA4FA,IAAM,IAA6C;CACjD;EACE,IAAI;EACJ,QAAQ;EACR,UAAU;EACV,WAAW;EACX,aACE;EACF,cAAc;EACd,cAAc;EACd,mBAAmB;EACnB,mBAAmB;EACnB,eAAe;EACf,UAAU;EACV,iBAAiB;EACjB,eAAe;EACf,WAAW;EACX,UAAU;EACV,UAAU;EACV,OAAO;EACP,iBAAiB;GACf,gBAAgB;GAChB,eAAe;GACf,mBAAmB;GACnB,QAAQ;GACR,aAAa;GACb,gBAAgB;GACjB;EACD,YAAY;GACV,aAAa;GACb,WAAW;GACX,iBAAiB;GACjB,mBAAmB;GACpB;EACD,iBAAiB;GACf,eAAe;GACf,mBAAmB;GACnB,cAAc;GACd,aAAa;IAAC;IAAW;IAAkB;IAAM;GAClD;EACD,WAAW;GACT;IAAE,MAAM;IAAiB,MAAM;IAAO,YAAY;IAAc;GAChE;IAAE,MAAM;IAAwB,MAAM;IAAO,YAAY;IAAc;GACvE;IAAE,MAAM;IAAmB,MAAM;IAAO,YAAY;IAAc;GACnE;EACD,QAAQ;EACT;CACD;EACE,IAAI;EACJ,QAAQ;EACR,UAAU;EACV,WAAW;EACX,aACE;EACF,cAAc;EACd,cAAc;EACd,mBAAmB;EACnB,mBAAmB;EACnB,eAAe;EACf,UAAU;EACV,iBAAiB;EACjB,eAAe;EACf,WAAW;EACX,UAAU;EACV,UAAU;EACV,OAAO;EACP,iBAAiB;GACf,gBAAgB;GAChB,eAAe;GACf,mBAAmB;GACnB,QAAQ;GACR,aAAa;GACb,gBAAgB;GACjB;EACD,YAAY;GACV,aAAa;GACb,WAAW;GACX,iBAAiB;GACjB,mBAAmB;GACpB;EACD,iBAAiB;GACf,eAAe;GACf,mBAAmB;GACnB,cAAc;GACd,aAAa,CAAC,WAAW,iBAAiB;GAC3C;EACD,WAAW,CACT;GAAE,MAAM;GAAiB,MAAM;GAAO,YAAY;GAAc,EAChE;GAAE,MAAM;GAAmB,MAAM;GAAO,YAAY;GAAc,CACnE;EACD,QAAQ;EACT;CACD;EACE,IAAI;EACJ,QAAQ;EACR,UAAU;EACV,WAAW;EACX,aACE;EACF,cAAc;EACd,cAAc;EACd,mBAAmB;EACnB,mBAAmB;EACnB,eAAe;EACf,UAAU;EACV,iBAAiB;EACjB,eAAe;EACf,WAAW;EACX,UAAU;EACV,UAAU;EACV,OAAO;EACP,iBAAiB;GACf,gBAAgB;GAChB,eAAe;GACf,mBAAmB;GACnB,QAAQ;GACR,aAAa;GACb,gBAAgB;GACjB;EACD,YAAY;GACV,aAAa;GACb,WAAW;GACX,iBAAiB;GACjB,mBAAmB;GACpB;EACD,iBAAiB;GACf,eAAe;GACf,mBAAmB;GACnB,cAAc;GACd,aAAa,CAAC,WAAW,uBAAuB;GACjD;EACD,WAAW,CACT;GAAE,MAAM;GAAiB,MAAM;GAAO,YAAY;GAAc,EAChE;GAAE,MAAM;GAAwB,MAAM;GAAO,YAAY;GAAc,CACxE;EACD,QAAQ;EACT;CACD;EACE,IAAI;EACJ,QAAQ;EACR,UAAU;EACV,WAAW;EACX,aACE;EACF,cAAc;EACd,cAAc;EACd,mBAAmB;EACnB,mBAAmB;EACnB,eAAe;EACf,UAAU;EACV,iBAAiB;EACjB,eAAe;EACf,WAAW;EACX,UAAU;EACV,UAAU;EACV,OAAO;EACP,iBAAiB;GACf,gBAAgB;GAChB,eAAe;GACf,mBAAmB;GACnB,QAAQ;GACR,aAAa;GACb,gBAAgB;GACjB;EACD,YAAY;GACV,aAAa;GACb,WAAW;GACX,iBAAiB;GACjB,mBAAmB;GACpB;EACD,iBAAiB;GACf,eAAe;GACf,mBAAmB;GACnB,cAAc;GACd,aAAa,CAAC,kBAAkB,cAAc;GAC/C;EACD,WAAW,CACT;GAAE,MAAM;GAAkB,MAAM;GAAO,YAAY;GAAc,EACjE;GAAE,MAAM;GAAkB,MAAM;GAAO,YAAY;GAAc,CAClE;EACD,QAAQ;EACT;CACF,EAEK,IAAgB;CACpB,oBAAoB;CACpB,gBAAgB;CAChB,aAAa;CACb,aAAa;CACd;AAMD,SAAS,EAAkB,GAAsB;AAC/C,SAAQ,GAAR;EACE,KAAK,MACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,QACE,QAAO;;;AAIb,SAAS,EAAa,GAAsB;AAC1C,SAAQ,GAAR;EACE,KAAK,MACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,QACE,QAAO;;;AAIb,SAAS,EAAqB,GAAgB,GAAwB;AACpE,QAAO,IAAS,IAAI,KAAK,IAAK,IAAS,IAAU,KAAK,IAAI,GAAG;;AAO/D,SAAgB,IAA8B;CAC5C,IAAM,EAAE,kBAAe,GAAkB,EACnC,CAAC,GAAW,KAAgB,EAAS,GAAK,EAC1C,CAAC,GAAqB,KAA0B,EACpD,KACD,EACK,CAAC,GAAiB,KAAsB,EAAS,GAAM,EACvD,CAAC,GAAkB,KAAuB,EAAS,GAAG,EACtD,CAAC,GAAc,KAAmB,EAAuC,OAAO,EAEhF,CAAC,GAAS,KAAc,EAA6B;EACzD,aAAa;EACb,UAAU;EACV,WAAW;EACX,eAAe;EACf,UAAU;EACV,QAAQ;EACT,CAAC;AAEF,SAAgB;EACd,IAAM,IAAQ,iBAAiB,EAAa,GAAM,EAAE,IAAI;AACxD,eAAa,aAAa,EAAM;IAC/B,EAAE,CAAC;CAEN,IAAM,IAAqB,GAAa,GAA+B,MAAkB;AACvF,KAAY,OAAU;GAAE,GAAG;IAAO,IAAM;GAAO,EAAE;IAChD,EAAE,CAAC,EAEA,IAAwB,QAAc;EAC1C,IAAI,IAAW,CAAC,GAAG,EAAkB;AAGrC,MAAI,EAAQ,YAAY,MAAM,EAAE;GAC9B,IAAM,IAAQ,EAAQ,YAAY,aAAa;AAC/C,OAAW,EAAS,QACjB,MACC,EAAI,SAAS,aAAa,CAAC,SAAS,EAAM,IAC1C,EAAI,YAAY,aAAa,CAAC,SAAS,EAAM,IAC7C,EAAI,SAAS,aAAa,CAAC,SAAS,EAAM,CAC7C;;AAmBH,MAfI,EAAQ,aACV,IAAW,EAAS,QAAQ,MAAQ,EAAI,aAAa,EAAQ,SAAS,GAIpE,EAAQ,cACV,IAAW,EAAS,QAAQ,MAAQ,EAAI,cAAc,EAAQ,UAAU,GAItE,EAAQ,aACV,IAAW,EAAS,QAAQ,MAAQ,EAAI,SAAS,SAAS,EAAQ,SAAS,CAAC,GAI1E,EAAQ,eAAe;GACzB,IAAM,IAAY,SAAS,EAAQ,eAAe,GAAG;AACrD,OAAW,EAAS,QAAQ,MAAQ,EAAI,qBAAqB,EAAU;;AAIzE,UAAQ,EAAQ,QAAhB;GACE,KAAK;AACH,MAAS,MAAM,GAAG,MAAM,EAAE,kBAAkB,EAAE,gBAAgB;AAC9D;GACF,KAAK;AACH,MAAS,MAAM,GAAG,MAAM,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,aAAa;AAC1F;GACF,KAAK;AACH,MAAS,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,SAAS;AAChD;GACF,KAAK;AACH,MAAS,MAAM,GAAG,MAAM,EAAE,oBAAoB,EAAE,kBAAkB;AAClE;GACF,QACE;;AAGJ,SAAO;IACN,CAAC,EAAQ,CAAC,EAEP,IAAe,QAAkB;AACrC,MAAI,CAAC,KAAuB,CAAC,EAAkB;EAE/C,IAAM,IAAS,SAAS,GAAkB,GAAG;AACzC,aAAM,EAAO,EAEjB;OAAI,IAAS,EAAoB,mBAAmB;AAClD,MAAgB,QAAQ;AACxB;;AAEF,OAAI,IAAS,EAAoB,mBAAmB;AAClD,MAAgB,QAAQ;AACxB;;AAIF,GADA,EAAgB,UAAU,EAC1B,iBAAiB;AAIf,IAHA,EAAmB,GAAM,EACzB,EAAoB,GAAG,EACvB,EAAgB,OAAO,EACvB,EAAW,sBAAsB;MAChC,KAAK;;IACP;EAAC;EAAqB;EAAkB;EAAW,CAAC,EAEjD,IAAkB,GAAa,MAAuC;AAI1E,EAHA,EAAuB,EAAY,EACnC,EAAoB,GAAG,EACvB,EAAgB,OAAO,EACvB,EAAmB,GAAK;IACvB,EAAE,CAAC;AAeN,QAbI,IAEA,kBAAC,GAAD;EAAY,OAAM;EAA2B,aAAY;YACvD,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAK,WAAU,8EAA+E,CAAA,EAC9F,kBAAC,KAAD;KAAG,WAAU;eAA8B;KAA4B,CAAA,CACnE;;GACF,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,QAAD;GAAM,WAAU;aAAhB,CACG,EAAsB,QAAO,iBACzB;;YANX;GAUE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAAwB,CAAA,EACnE,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAc;OACb,CAAA,CACA;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAAmB,CAAA,EAC9D,kBAAC,KAAD;OAAG,WAAU;iBAAb,CACG,EAAc,gBAAe,IAC5B;SACA;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAAgB,CAAA,EAC3D,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAe,EAAc,aAAa;QACzC,uBAAuB;QACvB,UAAU;QACX,CAAC;OACA,CAAA,CACA;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAAgB,CAAA,EAC3D,kBAAC,KAAD;OAAG,WAAU;iBAAb,CACG,EAAc,aAAY,IACzB;SACA;;KACF;;GAGN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eAAf;MAEE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,wEAAyE,CAAA,EAC3F,kBAAC,SAAD;QACE,MAAK;QACL,aAAY;QACZ,OAAO,EAAQ;QACf,WAAW,MAAM,EAAmB,eAAe,EAAE,OAAO,MAAM;QAClE,WAAU;QACV,CAAA,CACE;;MAGN,kBAAC,UAAD;OACE,OAAO,EAAQ;OACf,WAAW,MAAM,EAAmB,YAAY,EAAE,OAAO,MAAM;OAC/D,WAAU;iBAHZ;QAKE,kBAAC,UAAD;SAAQ,OAAM;mBAAG;SAAuB,CAAA;QACxC,kBAAC,UAAD;SAAQ,OAAM;mBAAe;SAAqB,CAAA;QAClD,kBAAC,UAAD;SAAQ,OAAM;mBAAY;SAAkB,CAAA;QAC5C,kBAAC,UAAD;SAAQ,OAAM;mBAAc;SAAoB,CAAA;QAChD,kBAAC,UAAD;SAAQ,OAAM;mBAAY;SAAkB,CAAA;QAC5C,kBAAC,UAAD;SAAQ,OAAM;mBAAc;SAAoB,CAAA;QACzC;;MAGT,kBAAC,UAAD;OACE,OAAO,EAAQ;OACf,WAAW,MAAM,EAAmB,aAAa,EAAE,OAAO,MAAM;OAChE,WAAU;iBAHZ;QAKE,kBAAC,UAAD;SAAQ,OAAM;mBAAG;SAAwB,CAAA;QACzC,kBAAC,UAAD;SAAQ,OAAM;mBAAM;SAAiB,CAAA;QACrC,kBAAC,UAAD;SAAQ,OAAM;mBAAS;SAAoB,CAAA;QAC3C,kBAAC,UAAD;SAAQ,OAAM;mBAAO;SAAkB,CAAA;QAChC;;MAGT,kBAAC,UAAD;OACE,OAAO,EAAQ;OACf,WAAW,MAAM,EAAmB,iBAAiB,EAAE,OAAO,MAAM;OACpE,WAAU;iBAHZ;QAKE,kBAAC,UAAD;SAAQ,OAAM;mBAAG;SAAmB,CAAA;QACpC,kBAAC,UAAD;SAAQ,OAAM;mBAAQ;SAA6B,CAAA;QACnD,kBAAC,UAAD;SAAQ,OAAM;mBAAQ;SAA6B,CAAA;QACnD,kBAAC,UAAD;SAAQ,OAAM;mBAAQ;SAA6B,CAAA;QACnD,kBAAC,UAAD;SAAQ,OAAM;mBAAS;SAA+B,CAAA;QAC/C;;MAGT,kBAAC,UAAD;OACE,OAAO,EAAQ;OACf,WAAW,MAAM,EAAmB,YAAY,EAAE,OAAO,MAAM;OAC/D,WAAU;iBAHZ;QAKE,kBAAC,UAAD;SAAQ,OAAM;mBAAG;SAAsB,CAAA;QACvC,kBAAC,UAAD;SAAQ,OAAM;mBAAa;SAAmB,CAAA;QAC9C,kBAAC,UAAD;SAAQ,OAAM;mBAAc;SAAoB,CAAA;QAChD,kBAAC,UAAD;SAAQ,OAAM;mBAAc;SAAoB,CAAA;QAChD,kBAAC,UAAD;SAAQ,OAAM;mBAAkB;SAAwB,CAAA;QACjD;;MAGT,kBAAC,UAAD;OACE,OAAO,EAAQ;OACf,WAAW,MAAM,EAAmB,UAAU,EAAE,OAAO,MAAM;OAC7D,WAAU;iBAHZ;QAKE,kBAAC,UAAD;SAAQ,OAAM;mBAAW;SAAiB,CAAA;QAC1C,kBAAC,UAAD;SAAQ,OAAM;mBAAU;SAAwB,CAAA;QAChD,kBAAC,UAAD;SAAQ,OAAM;mBAAU;SAAoB,CAAA;QAC5C,kBAAC,UAAD;SAAQ,OAAM;mBAAU;SAAqB,CAAA;QAC7C,kBAAC,UAAD;SAAQ,OAAM;mBAAU;SAAuB,CAAA;QACxC;;MACL;;IACF,CAAA;GAGL,EAAsB,WAAW,IAChC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KACE,cAAa;KACb,MAAM,kBAAC,GAAD,EAAQ,WAAU,aAAc,CAAA;KACtC,OAAM;KACN,aAAY;KACZ,QACE,kBAAC,UAAD;MACE,MAAK;MACL,eACE,EAAW;OACT,aAAa;OACb,UAAU;OACV,WAAW;OACX,eAAe;OACf,UAAU;OACV,QAAQ;OACT,CAAC;MAEJ,WAAU;gBACX;MAEQ,CAAA;KAEX,CAAA;IACE,CAAA,GAEN,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAsB,KAAK,MAAgB;KAC1C,IAAM,IAAa,EACjB,EAAY,cACZ,EAAY,aACb;AAED,YACE,kBAAC,OAAD;MAEE,WAAU;gBAFZ,CAKE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,OAAD;UACE,KAAK,EAAY;UACjB,KAAK,EAAY;UACjB,WAAU;UACV,SAAQ;UACR,CAAA;SACE,CAAA;QACL,EAAY,WAAW,YACtB,kBAAC,OAAD;SAAK,WAAU;mBAAwH;SAEjI,CAAA;QAEP,EAAY,WAAW,KAAK,EAAY,YAAY,KACnD,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACG,EAAY,UAAS,aAClB;;QAEJ;UAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QAEE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD;UAAK,WAAU;oBAAf;WACE,kBAAC,MAAD;YAAI,WAAU;sBACX,EAAY;YACV,CAAA;WACL,kBAAC,KAAD;YAAG,WAAU;sBAAb,CAAsD,OAChD,EAAY,UACd;;WACJ,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,QAAD;aAAM,WAAU;uBACb,EAAY;aACR,CAAA,EACP,kBAAC,QAAD;aACE,WAAW,EACT,gDACA,EAAkB,EAAY,UAAU,CACzC;uBAEA,EAAa,EAAY,UAAU;aAC/B,CAAA,CACH;;WACF;aACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,KAAD;WAAG,WAAU;qBAAb,CACG,EAAY,iBAAgB,IAC3B;cACJ,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAoB,CAAA,CAC3D;YACF;;QAGN,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAY;SACX,CAAA;QAGJ,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAhB;aACG,EAAe,EAAY,cAAc,EAAE,uBAAuB,GAAG,CAAC;aAAE;aAAI;aAExE;eACP,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CAAsC,OAChC,EAAe,EAAY,cAAc,EAAE,uBAAuB,GAAG,CAAC,CACrE;cACH;;UACN,kBAAC,OAAD;WAAK,WAAU;qBACb,kBAAC,OAAD;YACE,WAAU;YACV,OAAO,EAAE,OAAO,GAAG,EAAW,IAAI;YAClC,CAAA;WACE,CAAA;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD,EAAA,UAAA,CAAO,EAAY,eAAc,aAAiB,EAAA,CAAA,EAClD,kBAAC,QAAD,EAAA,UAAA,CAAO,EAAW,QAAQ,EAAE,EAAC,WAAe,EAAA,CAAA,CACxC;;UACF;;QAGN,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;WAAG,WAAU;qBACV,EAAe,EAAY,mBAAmB,EAC7C,uBAAuB,GACxB,CAAC;WACA,CAAA,EACJ,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAkB,CAAA,CACzD,EAAA,CAAA;UACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;WAAG,WAAU;qBAAb,CACG,EAAY,eAAc,MACzB;cACJ,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAkB,CAAA,CACzD,EAAA,CAAA;UACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD,EAAM,WAAU,+CAAgD,CAAA,EAChE,kBAAC,KAAD;YAAG,WAAU;sBACV,EAAY,gBAAgB;YAC3B,CAAA,CACA;cACN,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAU,CAAA,CACjD,EAAA,CAAA;UACF;;QAGN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA0D;UAEnE,CAAA,EACJ,kBAAC,OAAD;UAAK,WAAU;oBAAf;WACE,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,QAAD;aAAM,WAAU;uBAAsB;aAAuB,CAAA,EAC7D,kBAAC,QAAD;aAAM,WAAU;uBACb,EAAe,EAAY,gBAAgB,gBAAgB,EAC1D,uBAAuB,GACxB,CAAC;aACG,CAAA,CACH;;WACN,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,QAAD;aAAM,WAAU;uBAAsB;aAAoB,CAAA,EAC1D,kBAAC,QAAD;aAAM,WAAU;uBAAhB,CACG,EAAY,WAAW,aAAY,IAC/B;eACH;;WACN,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,QAAD;aAAM,WAAU;uBAAsB;aAAsB,CAAA,EAC5D,kBAAC,QAAD;aAAM,WAAU;uBACb,EAAa,EAAY,gBAAgB,cAAc;aACnD,CAAA,CACH;;WACN,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,QAAD;aAAM,WAAU;uBAAsB;aAAkB,CAAA,EACxD,kBAAC,QAAD;aAAM,WAAU;uBAAhB,CACG,EAAY,WAAW,WAAU,IAC7B;eACH;;WACF;YACF;;QAGN,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,EACpC,kBAAC,QAAD,EAAA,UAAA,CAAO,EAAY,UAAU,QAAO,uBAA2B,EAAA,CAAA,CAC3D;;SACF,CAAA;QAGN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,eAAgB,CAAA,EAClC,kBAAC,QAAD,EAAA,UAAO,EAAY,UAAgB,CAAA,CAC/B;;QAGN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,UAAD;UACE,MAAK;UACL,eAAe,EAAgB,EAAY;UAC3C,UAAU,EAAY,WAAW;UACjC,WAAW,EACT,uEACA,EAAY,WAAW,WACnB,wDACA,8EACL;oBAEA,EAAY,WAAW,WAAW,iBAAiB;UAC7C,CAAA,EACT,kBAAC,UAAD;UACE,MAAK;UACL,eAAe,EAAW,2BAA2B,EAAY,KAAK;UACtE,WAAU;oBAHZ,CAKE,kBAAC,GAAD,EAAK,WAAU,WAAY,CAAA,EAAA,eAEpB;YACL;;QACF;SACF;QA1LC,EAAY,GA0Lb;MAER;IACE,CAAA;GAIP,KAAmB,KAClB,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eAAf;MAEE,kBAAC,UAAD;OACE,MAAK;OACL,eAAe;AAGb,QAFA,EAAmB,GAAM,EACzB,EAAoB,GAAG,EACvB,EAAgB,OAAO;;OAEzB,WAAU;iBAEV,kBAAC,GAAD,EAAG,WAAU,WAAY,CAAA;OAClB,CAAA;MAET,kBAAC,MAAD;OAAI,WAAU;iBAAd,CAA0E,cAC7D,EAAoB,SAC5B;;MAEJ,MAAiB,YAChB,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,GAAD,EAAc,WAAU,6DAA8D,CAAA;QACtF,kBAAC,KAAD;SAAG,WAAU;mBAAwC;SAA0B,CAAA;QAC/E,kBAAC,KAAD;SAAG,WAAU;mBAAmC;SAAoC,CAAA;QAChF;WAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QAEE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAA8C;SAAoB,CAAA,EAC/E,kBAAC,KAAD;SAAG,WAAU;mBAAb;UACG,EAAe,EAAoB,mBAAmB,EACrD,uBAAuB,GACxB,CAAC;UAAE;UAAI;UACN;UACD,EAAe,EAAoB,mBAAmB,EACrD,uBAAuB,GACxB,CAAC;UACA;WACA,EAAA,CAAA;QAGN,kBAAC,OAAD,EAAA,UAAA;SACE,kBAAC,SAAD;UAAO,WAAU;oBAA8D;UAEvE,CAAA;SACR,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD,EAAa,WAAU,wEAAyE,CAAA,EAChG,kBAAC,SAAD;WACE,MAAK;WACL,OAAO;WACP,WAAW,MAAM;AAEf,YADA,EAAoB,EAAE,OAAO,MAAM,EACnC,EAAgB,OAAO;;WAEzB,aAAY;WACZ,WAAU;WACV,CAAA,CACE;;SACL,MAAiB,WAChB,kBAAC,KAAD;UAAG,WAAU;oBAAb;WAA2D;WAClC;WACtB,EAAe,EAAoB,mBAAmB,EACrD,uBAAuB,GACxB,CAAC;WAAE;WAAI;WACJ;WACH,EAAe,EAAoB,mBAAmB,EACrD,uBAAuB,GACxB,CAAC;WACA;;SAEF,EAAA,CAAA;QAGL,KACC,CAAC,MAAM,SAAS,GAAkB,GAAG,CAAC,IACtC,SAAS,GAAkB,GAAG,GAAG,KAC/B,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8C;UAEvD,CAAA,EACJ,kBAAC,OAAD;UAAK,WAAU;oBAAf;WACE,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,QAAD;aAAM,WAAU;uBAAuC;aAAkB,CAAA,EACzE,kBAAC,QAAD;aAAM,WAAU;uBACb,EAAe,SAAS,GAAkB,GAAG,EAAE,EAC9C,uBAAuB,GACxB,CAAC;aACG,CAAA,CACH;;WACN,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,QAAD;aAAM,WAAU;uBAAhB;cAAuD;cACnC,EAAoB;cAAgB;cACjD;gBACP,kBAAC,QAAD;aAAM,WAAU;uBAAhB,CAAoF,KAEjF,EACE,SAAS,GAAkB,GAAG,GAC7B,EAAoB,kBACpB,KACF,EAAE,uBAAuB,GAAG,CAC7B,CACI;eACH;;WACN,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,QAAD;aAAM,WAAU;uBAAmD;aAE5D,CAAA,EACP,kBAAC,QAAD;aAAM,WAAU;uBACb,EACC,SAAS,GAAkB,GAAG,IAC3B,IAAI,EAAoB,kBAAkB,MAC7C,EAAE,uBAAuB,GAAG,CAC7B;aACI,CAAA,CACH;;WACF;YACF;;QAIV,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,KAAD,EAAA,UAAA;WAAG;WAC8B;WAC9B,EAAoB,gBAAgB;WAAa;WAChD,EAAA,CAAA;UACJ,kBAAC,KAAD,EAAA,UAAA;WAAG;WAC0B;WAC1B,EAAoB,gBAAgB;WACnC,EAAA,CAAA;UACJ,kBAAC,KAAD,EAAA,UAAA;WAAG;WACyB;aAEtB,SAAS,GAAkB,GAAG,IAAI,KAAK,EAAoB,eAC7D,EAAoB,gBAAgB,eACpC,QAAQ,EAAE;WAAC;WAEX,EAAA,CAAA;UACJ,kBAAC,KAAD,EAAA,UAAA;WAAG;WACoB;WACpB,EAAoB,gBAAgB,YAAY,KAAK,KAAK;WACzD,EAAA,CAAA;UACA;;QAGN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,UAAD;UACE,MAAK;UACL,eAAe;AAGb,WAFA,EAAmB,GAAM,EACzB,EAAoB,GAAG,EACvB,EAAgB,OAAO;;UAEzB,WAAU;oBACX;UAEQ,CAAA,EACT,kBAAC,UAAD;UACE,MAAK;UACL,SAAS;UACT,UACE,CAAC,KACD,MAAM,SAAS,GAAkB,GAAG,CAAC,IACrC,SAAS,GAAkB,GAAG,GAAG,EAAoB;UAEvD,WAAW,EACT,uEACA,CAAC,KACC,MAAM,SAAS,GAAkB,GAAG,CAAC,IACrC,SAAS,GAAkB,GAAG,GAAG,EAAoB,oBACnD,wDACA,8EACL;oBACF;UAEQ,CAAA,CACL;;QACF;;MAEJ;;IACF,CAAA;GAEG"}
|
|
@@ -379,6 +379,7 @@ function T() {
|
|
|
379
379
|
})]
|
|
380
380
|
})]
|
|
381
381
|
}, e.id)) : /* @__PURE__ */ y(i, {
|
|
382
|
+
illustration: "empty-data",
|
|
382
383
|
icon: /* @__PURE__ */ y(g, { className: "h-12 w-12" }),
|
|
383
384
|
title: `No ${E === "all" ? "" : E} investments found`,
|
|
384
385
|
description: E === "all" ? "You haven't made any investments yet. Start exploring opportunities to grow your wealth." : `You don't have any ${E} investments at the moment.`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InvestorInvestmentsPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/investor/InvestorInvestmentsPage.tsx"],"sourcesContent":["/**\n * Investor Investments Page\n * @module atheletebridge/pages/investor\n *\n * MetricsGrid summary cards, filter tabs (all/active/pending/matured) with counts,\n * responsive mobile/desktop layouts, P&L display, ROI display, status icons,\n * empty state.\n */\n\nimport { useState, useEffect, useMemo } from 'react';\nimport {\n TrendingUp,\n TrendingDown,\n Briefcase,\n Eye,\n BarChart3,\n AlertCircle,\n CheckCircle2,\n Clock,\n Wallet,\n IndianRupee,\n Plus,\n Target,\n} from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { EmptyState } from '../../components/EmptyState';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatDate } from '../../utils/formatters';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface Investment {\n id: string;\n cartName: string;\n cartOwner: string;\n investmentAmount: number;\n currentValue: number;\n profitLoss: number;\n profitLossPercentage: number;\n investmentDate: string;\n status: 'active' | 'pending' | 'matured' | 'withdrawn';\n roiAnnual: number;\n duration: string;\n nextPayout: string;\n totalReturns: number;\n}\n\ninterface InvestmentSummary {\n totalInvested: number;\n currentValue: number;\n totalReturns: number;\n activeInvestments: number;\n averageRoi: number;\n profitLoss: number;\n profitLossPercentage: number;\n}\n\ntype FilterKey = 'all' | 'active' | 'pending' | 'matured';\n\n// ---------------------------------------------------------------------------\n// Mock data\n// ---------------------------------------------------------------------------\n\nconst mockInvestments: Investment[] = [\n {\n id: 'inv-001',\n cartName: 'South Indian Express',\n cartOwner: 'Raj Kumar',\n investmentAmount: 50000,\n currentValue: 58500,\n profitLoss: 8500,\n profitLossPercentage: 17.0,\n investmentDate: '2024-01-15',\n status: 'active',\n roiAnnual: 22.5,\n duration: '18 months',\n nextPayout: '2024-12-15',\n totalReturns: 8500,\n },\n {\n id: 'inv-002',\n cartName: 'Pizza Corner',\n cartOwner: 'Priya Singh',\n investmentAmount: 75000,\n currentValue: 82000,\n profitLoss: 7000,\n profitLossPercentage: 9.3,\n investmentDate: '2024-03-10',\n status: 'active',\n roiAnnual: 18.0,\n duration: '24 months',\n nextPayout: '2024-12-10',\n totalReturns: 7000,\n },\n {\n id: 'inv-003',\n cartName: 'Healthy Bites',\n cartOwner: 'Amit Patel',\n investmentAmount: 30000,\n currentValue: 31200,\n profitLoss: 1200,\n profitLossPercentage: 4.0,\n investmentDate: '2024-06-01',\n status: 'active',\n roiAnnual: 15.0,\n duration: '12 months',\n nextPayout: '2024-12-01',\n totalReturns: 1200,\n },\n {\n id: 'inv-004',\n cartName: 'Street Food Junction',\n cartOwner: 'Neha Sharma',\n investmentAmount: 40000,\n currentValue: 40000,\n profitLoss: 0,\n profitLossPercentage: 0,\n investmentDate: '2024-08-15',\n status: 'pending',\n roiAnnual: 20.0,\n duration: '15 months',\n nextPayout: '2025-01-15',\n totalReturns: 0,\n },\n {\n id: 'inv-005',\n cartName: 'Biryani House',\n cartOwner: 'Suresh Reddy',\n investmentAmount: 60000,\n currentValue: 72000,\n profitLoss: 12000,\n profitLossPercentage: 20.0,\n investmentDate: '2023-12-01',\n status: 'matured',\n roiAnnual: 25.0,\n duration: '12 months',\n nextPayout: '-',\n totalReturns: 12000,\n },\n];\n\nconst mockSummary: InvestmentSummary = {\n totalInvested: 255000,\n currentValue: 283700,\n totalReturns: 28700,\n activeInvestments: 3,\n averageRoi: 19.6,\n profitLoss: 28700,\n profitLossPercentage: 11.3,\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getStatusColor(status: string): string {\n switch (status) {\n case 'active':\n return 'bg-green-500/20 text-green-600 dark:text-green-400';\n case 'pending':\n return 'bg-yellow-500/20 text-yellow-600 dark:text-yellow-400';\n case 'matured':\n return 'bg-blue-500/20 text-blue-600 dark:text-blue-400';\n case 'withdrawn':\n return 'bg-secondary text-secondary-foreground';\n default:\n return 'bg-secondary text-secondary-foreground';\n }\n}\n\nfunction getStatusIcon(status: string) {\n switch (status) {\n case 'active':\n return <CheckCircle2 className=\"h-4 w-4\" />;\n case 'pending':\n return <Clock className=\"h-4 w-4\" />;\n case 'matured':\n return <CheckCircle2 className=\"h-4 w-4\" />;\n default:\n return <AlertCircle className=\"h-4 w-4\" />;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function InvestorInvestmentsPage() {\n const { navigateTo } = useAthleteBridge();\n const [isLoading, setIsLoading] = useState(true);\n const [filter, setFilter] = useState<FilterKey>('all');\n\n useEffect(() => {\n const timer = setTimeout(() => setIsLoading(false), 600);\n return () => clearTimeout(timer);\n }, []);\n\n const filteredInvestments = useMemo(() => {\n if (filter === 'all') return mockInvestments;\n return mockInvestments.filter((inv) => inv.status === filter);\n }, [filter]);\n\n const filterTabs: Array<{ key: FilterKey; label: string }> = [\n { key: 'all', label: 'All Investments' },\n { key: 'active', label: 'Active' },\n { key: 'pending', label: 'Pending' },\n { key: 'matured', label: 'Matured' },\n ];\n\n function getCount(key: FilterKey): number {\n if (key === 'all') return mockInvestments.length;\n return mockInvestments.filter((inv) => inv.status === key).length;\n }\n\n if (isLoading) {\n return (\n <PageLayout title=\"My Investments\" description=\"Loading your investments...\">\n <div className=\"flex items-center justify-center py-20\">\n <div className=\"text-center\">\n <div className=\"mx-auto mb-4 h-12 w-12 animate-spin rounded-full border-b-2 border-primary\" />\n <p className=\"text-sm text-text-secondary\">Loading your investments...</p>\n </div>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"My Investments\"\n description=\"Track and manage your investment portfolio\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/opportunities')}\n className=\"flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n <Plus className=\"h-4 w-4\" />\n New Investment\n </button>\n }\n >\n {/* Investment Summary */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <MetricsCard\n icon={<Wallet className=\"h-5 w-5\" />}\n value={formatCurrency(mockSummary.totalInvested, { minimumFractionDigits: 0 })}\n label=\"Total Invested\"\n trend=\"up\"\n trendValue=\"Total amount invested\"\n />\n <MetricsCard\n icon={<IndianRupee className=\"h-5 w-5\" />}\n value={formatCurrency(mockSummary.currentValue, { minimumFractionDigits: 0 })}\n label=\"Current Value\"\n trend={mockSummary.profitLoss > 0 ? 'up' : 'down'}\n trendValue={`${mockSummary.profitLossPercentage > 0 ? '+' : ''}${mockSummary.profitLossPercentage}% total returns`}\n />\n <MetricsCard\n icon={<TrendingUp className=\"h-5 w-5\" />}\n value={formatCurrency(mockSummary.totalReturns, { minimumFractionDigits: 0 })}\n label=\"Total Returns\"\n trend=\"up\"\n trendValue=\"Total profit earned\"\n />\n <MetricsCard\n icon={<CheckCircle2 className=\"h-5 w-5\" />}\n value={String(mockSummary.activeInvestments)}\n label=\"Active Investments\"\n trend=\"neutral\"\n trendValue={`${mockSummary.averageRoi}% avg ROI`}\n />\n </div>\n\n {/* Filter Tabs */}\n <div className=\"mt-6 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex flex-wrap gap-2\">\n {filterTabs.map((tab) => (\n <button\n key={tab.key}\n type=\"button\"\n onClick={() => setFilter(tab.key)}\n className={cn(\n 'flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-colors',\n filter === tab.key\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-primary hover:bg-bg-sunken/80'\n )}\n >\n {tab.label}\n <span\n className={cn(\n 'rounded-full px-2 py-0.5 text-xs',\n filter === tab.key\n ? 'bg-primary-foreground/20 text-action-primary-text'\n : 'bg-action-primary-bg/10 text-primary'\n )}\n >\n {getCount(tab.key)}\n </span>\n </button>\n ))}\n </div>\n </div>\n\n {/* Investments List */}\n <div className=\"mt-6 space-y-4\">\n {filteredInvestments.length > 0 ? (\n filteredInvestments.map((investment) => (\n <div key={investment.id} className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 sm:p-6\">\n {/* Mobile Layout */}\n <div className=\"block space-y-4 lg:hidden\">\n <div className=\"flex items-start justify-between\">\n <div>\n <h3 className=\"text-lg font-semibold text-text-primary\">{investment.cartName}</h3>\n <p className=\"text-sm text-text-secondary\">by {investment.cartOwner}</p>\n </div>\n <span\n className={cn(\n 'flex items-center gap-1 rounded-full px-3 py-1 text-sm font-medium',\n getStatusColor(investment.status)\n )}\n >\n {getStatusIcon(investment.status)}\n <span className=\"capitalize\">{investment.status}</span>\n </span>\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Invested</p>\n <p className=\"font-semibold text-text-primary\">\n {formatCurrency(investment.investmentAmount, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Current Value</p>\n <p className=\"font-semibold text-text-primary\">\n {formatCurrency(investment.currentValue, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">P&L</p>\n <p\n className={cn(\n 'font-semibold',\n investment.profitLoss >= 0\n ? 'text-green-600 dark:text-green-400'\n : 'text-red-600 dark:text-red-400'\n )}\n >\n {investment.profitLoss >= 0 ? '+' : ''}\n {formatCurrency(investment.profitLoss, { minimumFractionDigits: 0 })} (\n {investment.profitLossPercentage >= 0 ? '+' : ''}\n {investment.profitLossPercentage}%)\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">ROI</p>\n <p className=\"font-semibold text-text-primary\">{investment.roiAnnual}% p.a.</p>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between border-t border-border-subtle pt-2\">\n <div>\n <p className=\"text-xs text-text-secondary\">Invested on</p>\n <p className=\"text-sm font-medium text-text-primary\">\n {formatDate(investment.investmentDate, {\n hour: undefined,\n minute: undefined,\n })}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/investor/investments/${investment.id}`)}\n className=\"flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Eye className=\"h-4 w-4\" />\n View Details\n </button>\n </div>\n </div>\n\n {/* Desktop Layout */}\n <div className=\"hidden lg:flex lg:items-center lg:justify-between\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"mb-2 flex items-center justify-between\">\n <h3 className=\"text-lg font-semibold text-text-primary\">{investment.cartName}</h3>\n <span\n className={cn(\n 'flex items-center gap-1 rounded-full px-3 py-1 text-sm font-medium',\n getStatusColor(investment.status)\n )}\n >\n {getStatusIcon(investment.status)}\n <span className=\"capitalize\">{investment.status}</span>\n </span>\n </div>\n <p className=\"mb-4 text-sm text-text-secondary\">by {investment.cartOwner}</p>\n\n <div className=\"grid grid-cols-5 gap-6\">\n <div>\n <p className=\"text-sm text-text-secondary\">Invested</p>\n <p className=\"font-semibold text-text-primary\">\n {formatCurrency(investment.investmentAmount, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Current Value</p>\n <p className=\"font-semibold text-text-primary\">\n {formatCurrency(investment.currentValue, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">P&L</p>\n <p\n className={cn(\n 'font-semibold',\n investment.profitLoss >= 0\n ? 'text-green-600 dark:text-green-400'\n : 'text-red-600 dark:text-red-400'\n )}\n >\n {investment.profitLoss >= 0 ? '+' : ''}\n {formatCurrency(investment.profitLoss, { minimumFractionDigits: 0 })}\n </p>\n <p\n className={cn(\n 'text-xs',\n investment.profitLoss >= 0\n ? 'text-green-600 dark:text-green-400'\n : 'text-red-600 dark:text-red-400'\n )}\n >\n ({investment.profitLossPercentage >= 0 ? '+' : ''}\n {investment.profitLossPercentage}%)\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">ROI</p>\n <p className=\"font-semibold text-text-primary\">{investment.roiAnnual}% p.a.</p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Invested on</p>\n <p className=\"font-semibold text-text-primary\">\n {formatDate(investment.investmentDate, {\n hour: undefined,\n minute: undefined,\n })}\n </p>\n </div>\n </div>\n </div>\n\n <div className=\"ml-6\">\n <button\n type=\"button\"\n onClick={() => navigateTo(`/investor/investments/${investment.id}`)}\n className=\"flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Eye className=\"h-4 w-4\" />\n View Details\n </button>\n </div>\n </div>\n </div>\n ))\n ) : (\n <EmptyState\n icon={<TrendingDown className=\"h-12 w-12\" />}\n title={`No ${filter !== 'all' ? filter : ''} investments found`}\n description={\n filter === 'all'\n ? \"You haven't made any investments yet. Start exploring opportunities to grow your wealth.\"\n : `You don't have any ${filter} investments at the moment.`\n }\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/opportunities')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n Explore Investment Opportunities\n </button>\n }\n />\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;AAmEA,IAAM,IAAgC;CACpC;EACE,IAAI;EACJ,UAAU;EACV,WAAW;EACX,kBAAkB;EAClB,cAAc;EACd,YAAY;EACZ,sBAAsB;EACtB,gBAAgB;EAChB,QAAQ;EACR,WAAW;EACX,UAAU;EACV,YAAY;EACZ,cAAc;EACf;CACD;EACE,IAAI;EACJ,UAAU;EACV,WAAW;EACX,kBAAkB;EAClB,cAAc;EACd,YAAY;EACZ,sBAAsB;EACtB,gBAAgB;EAChB,QAAQ;EACR,WAAW;EACX,UAAU;EACV,YAAY;EACZ,cAAc;EACf;CACD;EACE,IAAI;EACJ,UAAU;EACV,WAAW;EACX,kBAAkB;EAClB,cAAc;EACd,YAAY;EACZ,sBAAsB;EACtB,gBAAgB;EAChB,QAAQ;EACR,WAAW;EACX,UAAU;EACV,YAAY;EACZ,cAAc;EACf;CACD;EACE,IAAI;EACJ,UAAU;EACV,WAAW;EACX,kBAAkB;EAClB,cAAc;EACd,YAAY;EACZ,sBAAsB;EACtB,gBAAgB;EAChB,QAAQ;EACR,WAAW;EACX,UAAU;EACV,YAAY;EACZ,cAAc;EACf;CACD;EACE,IAAI;EACJ,UAAU;EACV,WAAW;EACX,kBAAkB;EAClB,cAAc;EACd,YAAY;EACZ,sBAAsB;EACtB,gBAAgB;EAChB,QAAQ;EACR,WAAW;EACX,UAAU;EACV,YAAY;EACZ,cAAc;EACf;CACF,EAEK,IAAiC;CACrC,eAAe;CACf,cAAc;CACd,cAAc;CACd,mBAAmB;CACnB,YAAY;CACZ,YAAY;CACZ,sBAAsB;CACvB;AAMD,SAAS,EAAe,GAAwB;AAC9C,SAAQ,GAAR;EACE,KAAK,SACH,QAAO;EACT,KAAK,UACH,QAAO;EACT,KAAK,UACH,QAAO;EACT,KAAK,YACH,QAAO;EACT,QACE,QAAO;;;AAIb,SAAS,EAAc,GAAgB;AACrC,SAAQ,GAAR;EACE,KAAK,SACH,QAAO,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA;EAC7C,KAAK,UACH,QAAO,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;EACtC,KAAK,UACH,QAAO,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA;EAC7C,QACE,QAAO,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA;;;AAQhD,SAAgB,IAA0B;CACxC,IAAM,EAAE,kBAAe,GAAkB,EACnC,CAAC,GAAW,KAAgB,EAAS,GAAK,EAC1C,CAAC,GAAQ,KAAa,EAAoB,MAAM;AAEtD,SAAgB;EACd,IAAM,IAAQ,iBAAiB,EAAa,GAAM,EAAE,IAAI;AACxD,eAAa,aAAa,EAAM;IAC/B,EAAE,CAAC;CAEN,IAAM,IAAsB,QACtB,MAAW,QAAc,IACtB,EAAgB,QAAQ,MAAQ,EAAI,WAAW,EAAO,EAC5D,CAAC,EAAO,CAAC,EAEN,IAAuD;EAC3D;GAAE,KAAK;GAAO,OAAO;GAAmB;EACxC;GAAE,KAAK;GAAU,OAAO;GAAU;EAClC;GAAE,KAAK;GAAW,OAAO;GAAW;EACpC;GAAE,KAAK;GAAW,OAAO;GAAW;EACrC;CAED,SAAS,EAAS,GAAwB;AAExC,SADI,MAAQ,QAAc,EAAgB,SACnC,EAAgB,QAAQ,MAAQ,EAAI,WAAW,EAAI,CAAC;;AAgB7D,QAbI,IAEA,kBAAC,GAAD;EAAY,OAAM;EAAiB,aAAY;YAC7C,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAK,WAAU,8EAA+E,CAAA,EAC9F,kBAAC,KAAD;KAAG,WAAU;eAA8B;KAA+B,CAAA,CACtE;;GACF,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,0BAA0B;GACpD,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,iBAErB;;YAXb;GAeE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;MACpC,OAAO,EAAe,EAAY,eAAe,EAAE,uBAAuB,GAAG,CAAC;MAC9E,OAAM;MACN,OAAM;MACN,YAAW;MACX,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA;MACzC,OAAO,EAAe,EAAY,cAAc,EAAE,uBAAuB,GAAG,CAAC;MAC7E,OAAM;MACN,OAAO,EAAY,aAAa,IAAI,OAAO;MAC3C,YAAY,GAAG,EAAY,uBAAuB,IAAI,MAAM,KAAK,EAAY,qBAAqB;MAClG,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;MACxC,OAAO,EAAe,EAAY,cAAc,EAAE,uBAAuB,GAAG,CAAC;MAC7E,OAAM;MACN,OAAM;MACN,YAAW;MACX,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA;MAC1C,OAAO,OAAO,EAAY,kBAAkB;MAC5C,OAAM;MACN,OAAM;MACN,YAAY,GAAG,EAAY,WAAW;MACtC,CAAA;KACE;;GAGN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAW,KAAK,MACf,kBAAC,UAAD;MAEE,MAAK;MACL,eAAe,EAAU,EAAI,IAAI;MACjC,WAAW,EACT,sFACA,MAAW,EAAI,MACX,kDACA,uDACL;gBATH,CAWG,EAAI,OACL,kBAAC,QAAD;OACE,WAAW,EACT,oCACA,MAAW,EAAI,MACX,sDACA,uCACL;iBAEA,EAAS,EAAI,IAAI;OACb,CAAA,CACA;QArBF,EAAI,IAqBF,CACT;KACE,CAAA;IACF,CAAA;GAGN,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAoB,SAAS,IAC5B,EAAoB,KAAK,MACvB,kBAAC,OAAD;KAAyB,WAAU;eAAnC,CAEE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBAA2C,EAAW;SAAc,CAAA,EAClF,kBAAC,KAAD;SAAG,WAAU;mBAAb,CAA2C,OAAI,EAAW,UAAc;WACpE,EAAA,CAAA,EACN,kBAAC,QAAD;SACE,WAAW,EACT,sEACA,EAAe,EAAW,OAAO,CAClC;mBAJH,CAMG,EAAc,EAAW,OAAO,EACjC,kBAAC,QAAD;UAAM,WAAU;oBAAc,EAAW;UAAc,CAAA,CAClD;WACH;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B;UAAY,CAAA,EACvD,kBAAC,KAAD;UAAG,WAAU;oBACV,EAAe,EAAW,kBAAkB,EAAE,uBAAuB,GAAG,CAAC;UACxE,CAAA,CACA,EAAA,CAAA;SACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B;UAAiB,CAAA,EAC5D,kBAAC,KAAD;UAAG,WAAU;oBACV,EAAe,EAAW,cAAc,EAAE,uBAAuB,GAAG,CAAC;UACpE,CAAA,CACA,EAAA,CAAA;SACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B;UAAO,CAAA,EAClD,kBAAC,KAAD;UACE,WAAW,EACT,iBACA,EAAW,cAAc,IACrB,uCACA,iCACL;oBANH;WAQG,EAAW,cAAc,IAAI,MAAM;WACnC,EAAe,EAAW,YAAY,EAAE,uBAAuB,GAAG,CAAC;WAAC;WACpE,EAAW,wBAAwB,IAAI,MAAM;WAC7C,EAAW;WAAqB;WAC/B;YACA,EAAA,CAAA;SACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B;UAAO,CAAA,EAClD,kBAAC,KAAD;UAAG,WAAU;oBAAb,CAAgD,EAAW,WAAU,SAAU;YAC3E,EAAA,CAAA;SACF;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAA8B;SAAe,CAAA,EAC1D,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAW,EAAW,gBAAgB;UACrC,MAAM,KAAA;UACN,QAAQ,KAAA;UACT,CAAC;SACA,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAW,yBAAyB,EAAW,KAAK;SACnE,WAAU;mBAHZ,CAKE,kBAAC,GAAD,EAAK,WAAU,WAAY,CAAA,EAAA,eAEpB;WACL;;OACF;SAGN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAA2C,EAAW;UAAc,CAAA,EAClF,kBAAC,QAAD;UACE,WAAW,EACT,sEACA,EAAe,EAAW,OAAO,CAClC;oBAJH,CAMG,EAAc,EAAW,OAAO,EACjC,kBAAC,QAAD;WAAM,WAAU;qBAAc,EAAW;WAAc,CAAA,CAClD;YACH;;QACN,kBAAC,KAAD;SAAG,WAAU;mBAAb,CAAgD,OAAI,EAAW,UAAc;;QAE7E,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAY,CAAA,EACvD,kBAAC,KAAD;WAAG,WAAU;qBACV,EAAe,EAAW,kBAAkB,EAAE,uBAAuB,GAAG,CAAC;WACxE,CAAA,CACA,EAAA,CAAA;UACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAiB,CAAA,EAC5D,kBAAC,KAAD;WAAG,WAAU;qBACV,EAAe,EAAW,cAAc,EAAE,uBAAuB,GAAG,CAAC;WACpE,CAAA,CACA,EAAA,CAAA;UACN,kBAAC,OAAD,EAAA,UAAA;WACE,kBAAC,KAAD;YAAG,WAAU;sBAA8B;YAAO,CAAA;WAClD,kBAAC,KAAD;YACE,WAAW,EACT,iBACA,EAAW,cAAc,IACrB,uCACA,iCACL;sBANH,CAQG,EAAW,cAAc,IAAI,MAAM,IACnC,EAAe,EAAW,YAAY,EAAE,uBAAuB,GAAG,CAAC,CAClE;;WACJ,kBAAC,KAAD;YACE,WAAW,EACT,WACA,EAAW,cAAc,IACrB,uCACA,iCACL;sBANH;aAOC;aACG,EAAW,wBAAwB,IAAI,MAAM;aAC9C,EAAW;aAAqB;aAC/B;;WACA,EAAA,CAAA;UACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAO,CAAA,EAClD,kBAAC,KAAD;WAAG,WAAU;qBAAb,CAAgD,EAAW,WAAU,SAAU;aAC3E,EAAA,CAAA;UACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAe,CAAA,EAC1D,kBAAC,KAAD;WAAG,WAAU;qBACV,EAAW,EAAW,gBAAgB;YACrC,MAAM,KAAA;YACN,QAAQ,KAAA;YACT,CAAC;WACA,CAAA,CACA,EAAA,CAAA;UACF;;QACF;UAEN,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAW,yBAAyB,EAAW,KAAK;QACnE,WAAU;kBAHZ,CAKE,kBAAC,GAAD,EAAK,WAAU,WAAY,CAAA,EAAA,eAEpB;;OACL,CAAA,CACF;QACF;OA7JI,EAAW,GA6Jf,CACN,GAEF,kBAAC,GAAD;KACE,MAAM,kBAAC,GAAD,EAAc,WAAU,aAAc,CAAA;KAC5C,OAAO,MAAM,MAAW,QAAiB,KAAT,EAAY;KAC5C,aACE,MAAW,QACP,6FACA,sBAAsB,EAAO;KAEnC,QACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAW,0BAA0B;MACpD,WAAU;gBACX;MAEQ,CAAA;KAEX,CAAA;IAEA,CAAA;GACK"}
|
|
1
|
+
{"version":3,"file":"InvestorInvestmentsPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/investor/InvestorInvestmentsPage.tsx"],"sourcesContent":["/**\n * Investor Investments Page\n * @module atheletebridge/pages/investor\n *\n * MetricsGrid summary cards, filter tabs (all/active/pending/matured) with counts,\n * responsive mobile/desktop layouts, P&L display, ROI display, status icons,\n * empty state.\n */\n\nimport { useState, useEffect, useMemo } from 'react';\nimport {\n TrendingUp,\n TrendingDown,\n Briefcase,\n Eye,\n BarChart3,\n AlertCircle,\n CheckCircle2,\n Clock,\n Wallet,\n IndianRupee,\n Plus,\n Target,\n} from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { EmptyState } from '../../components/EmptyState';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatDate } from '../../utils/formatters';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface Investment {\n id: string;\n cartName: string;\n cartOwner: string;\n investmentAmount: number;\n currentValue: number;\n profitLoss: number;\n profitLossPercentage: number;\n investmentDate: string;\n status: 'active' | 'pending' | 'matured' | 'withdrawn';\n roiAnnual: number;\n duration: string;\n nextPayout: string;\n totalReturns: number;\n}\n\ninterface InvestmentSummary {\n totalInvested: number;\n currentValue: number;\n totalReturns: number;\n activeInvestments: number;\n averageRoi: number;\n profitLoss: number;\n profitLossPercentage: number;\n}\n\ntype FilterKey = 'all' | 'active' | 'pending' | 'matured';\n\n// ---------------------------------------------------------------------------\n// Mock data\n// ---------------------------------------------------------------------------\n\nconst mockInvestments: Investment[] = [\n {\n id: 'inv-001',\n cartName: 'South Indian Express',\n cartOwner: 'Raj Kumar',\n investmentAmount: 50000,\n currentValue: 58500,\n profitLoss: 8500,\n profitLossPercentage: 17.0,\n investmentDate: '2024-01-15',\n status: 'active',\n roiAnnual: 22.5,\n duration: '18 months',\n nextPayout: '2024-12-15',\n totalReturns: 8500,\n },\n {\n id: 'inv-002',\n cartName: 'Pizza Corner',\n cartOwner: 'Priya Singh',\n investmentAmount: 75000,\n currentValue: 82000,\n profitLoss: 7000,\n profitLossPercentage: 9.3,\n investmentDate: '2024-03-10',\n status: 'active',\n roiAnnual: 18.0,\n duration: '24 months',\n nextPayout: '2024-12-10',\n totalReturns: 7000,\n },\n {\n id: 'inv-003',\n cartName: 'Healthy Bites',\n cartOwner: 'Amit Patel',\n investmentAmount: 30000,\n currentValue: 31200,\n profitLoss: 1200,\n profitLossPercentage: 4.0,\n investmentDate: '2024-06-01',\n status: 'active',\n roiAnnual: 15.0,\n duration: '12 months',\n nextPayout: '2024-12-01',\n totalReturns: 1200,\n },\n {\n id: 'inv-004',\n cartName: 'Street Food Junction',\n cartOwner: 'Neha Sharma',\n investmentAmount: 40000,\n currentValue: 40000,\n profitLoss: 0,\n profitLossPercentage: 0,\n investmentDate: '2024-08-15',\n status: 'pending',\n roiAnnual: 20.0,\n duration: '15 months',\n nextPayout: '2025-01-15',\n totalReturns: 0,\n },\n {\n id: 'inv-005',\n cartName: 'Biryani House',\n cartOwner: 'Suresh Reddy',\n investmentAmount: 60000,\n currentValue: 72000,\n profitLoss: 12000,\n profitLossPercentage: 20.0,\n investmentDate: '2023-12-01',\n status: 'matured',\n roiAnnual: 25.0,\n duration: '12 months',\n nextPayout: '-',\n totalReturns: 12000,\n },\n];\n\nconst mockSummary: InvestmentSummary = {\n totalInvested: 255000,\n currentValue: 283700,\n totalReturns: 28700,\n activeInvestments: 3,\n averageRoi: 19.6,\n profitLoss: 28700,\n profitLossPercentage: 11.3,\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getStatusColor(status: string): string {\n switch (status) {\n case 'active':\n return 'bg-green-500/20 text-green-600 dark:text-green-400';\n case 'pending':\n return 'bg-yellow-500/20 text-yellow-600 dark:text-yellow-400';\n case 'matured':\n return 'bg-blue-500/20 text-blue-600 dark:text-blue-400';\n case 'withdrawn':\n return 'bg-secondary text-secondary-foreground';\n default:\n return 'bg-secondary text-secondary-foreground';\n }\n}\n\nfunction getStatusIcon(status: string) {\n switch (status) {\n case 'active':\n return <CheckCircle2 className=\"h-4 w-4\" />;\n case 'pending':\n return <Clock className=\"h-4 w-4\" />;\n case 'matured':\n return <CheckCircle2 className=\"h-4 w-4\" />;\n default:\n return <AlertCircle className=\"h-4 w-4\" />;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function InvestorInvestmentsPage() {\n const { navigateTo } = useAthleteBridge();\n const [isLoading, setIsLoading] = useState(true);\n const [filter, setFilter] = useState<FilterKey>('all');\n\n useEffect(() => {\n const timer = setTimeout(() => setIsLoading(false), 600);\n return () => clearTimeout(timer);\n }, []);\n\n const filteredInvestments = useMemo(() => {\n if (filter === 'all') return mockInvestments;\n return mockInvestments.filter((inv) => inv.status === filter);\n }, [filter]);\n\n const filterTabs: Array<{ key: FilterKey; label: string }> = [\n { key: 'all', label: 'All Investments' },\n { key: 'active', label: 'Active' },\n { key: 'pending', label: 'Pending' },\n { key: 'matured', label: 'Matured' },\n ];\n\n function getCount(key: FilterKey): number {\n if (key === 'all') return mockInvestments.length;\n return mockInvestments.filter((inv) => inv.status === key).length;\n }\n\n if (isLoading) {\n return (\n <PageLayout title=\"My Investments\" description=\"Loading your investments...\">\n <div className=\"flex items-center justify-center py-20\">\n <div className=\"text-center\">\n <div className=\"mx-auto mb-4 h-12 w-12 animate-spin rounded-full border-b-2 border-primary\" />\n <p className=\"text-sm text-text-secondary\">Loading your investments...</p>\n </div>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"My Investments\"\n description=\"Track and manage your investment portfolio\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/opportunities')}\n className=\"flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n <Plus className=\"h-4 w-4\" />\n New Investment\n </button>\n }\n >\n {/* Investment Summary */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <MetricsCard\n icon={<Wallet className=\"h-5 w-5\" />}\n value={formatCurrency(mockSummary.totalInvested, { minimumFractionDigits: 0 })}\n label=\"Total Invested\"\n trend=\"up\"\n trendValue=\"Total amount invested\"\n />\n <MetricsCard\n icon={<IndianRupee className=\"h-5 w-5\" />}\n value={formatCurrency(mockSummary.currentValue, { minimumFractionDigits: 0 })}\n label=\"Current Value\"\n trend={mockSummary.profitLoss > 0 ? 'up' : 'down'}\n trendValue={`${mockSummary.profitLossPercentage > 0 ? '+' : ''}${mockSummary.profitLossPercentage}% total returns`}\n />\n <MetricsCard\n icon={<TrendingUp className=\"h-5 w-5\" />}\n value={formatCurrency(mockSummary.totalReturns, { minimumFractionDigits: 0 })}\n label=\"Total Returns\"\n trend=\"up\"\n trendValue=\"Total profit earned\"\n />\n <MetricsCard\n icon={<CheckCircle2 className=\"h-5 w-5\" />}\n value={String(mockSummary.activeInvestments)}\n label=\"Active Investments\"\n trend=\"neutral\"\n trendValue={`${mockSummary.averageRoi}% avg ROI`}\n />\n </div>\n\n {/* Filter Tabs */}\n <div className=\"mt-6 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex flex-wrap gap-2\">\n {filterTabs.map((tab) => (\n <button\n key={tab.key}\n type=\"button\"\n onClick={() => setFilter(tab.key)}\n className={cn(\n 'flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-colors',\n filter === tab.key\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-primary hover:bg-bg-sunken/80'\n )}\n >\n {tab.label}\n <span\n className={cn(\n 'rounded-full px-2 py-0.5 text-xs',\n filter === tab.key\n ? 'bg-primary-foreground/20 text-action-primary-text'\n : 'bg-action-primary-bg/10 text-primary'\n )}\n >\n {getCount(tab.key)}\n </span>\n </button>\n ))}\n </div>\n </div>\n\n {/* Investments List */}\n <div className=\"mt-6 space-y-4\">\n {filteredInvestments.length > 0 ? (\n filteredInvestments.map((investment) => (\n <div\n key={investment.id}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 sm:p-6\"\n >\n {/* Mobile Layout */}\n <div className=\"block space-y-4 lg:hidden\">\n <div className=\"flex items-start justify-between\">\n <div>\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {investment.cartName}\n </h3>\n <p className=\"text-sm text-text-secondary\">by {investment.cartOwner}</p>\n </div>\n <span\n className={cn(\n 'flex items-center gap-1 rounded-full px-3 py-1 text-sm font-medium',\n getStatusColor(investment.status)\n )}\n >\n {getStatusIcon(investment.status)}\n <span className=\"capitalize\">{investment.status}</span>\n </span>\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Invested</p>\n <p className=\"font-semibold text-text-primary\">\n {formatCurrency(investment.investmentAmount, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Current Value</p>\n <p className=\"font-semibold text-text-primary\">\n {formatCurrency(investment.currentValue, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">P&L</p>\n <p\n className={cn(\n 'font-semibold',\n investment.profitLoss >= 0\n ? 'text-green-600 dark:text-green-400'\n : 'text-red-600 dark:text-red-400'\n )}\n >\n {investment.profitLoss >= 0 ? '+' : ''}\n {formatCurrency(investment.profitLoss, { minimumFractionDigits: 0 })} (\n {investment.profitLossPercentage >= 0 ? '+' : ''}\n {investment.profitLossPercentage}%)\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">ROI</p>\n <p className=\"font-semibold text-text-primary\">{investment.roiAnnual}% p.a.</p>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between border-t border-border-subtle pt-2\">\n <div>\n <p className=\"text-xs text-text-secondary\">Invested on</p>\n <p className=\"text-sm font-medium text-text-primary\">\n {formatDate(investment.investmentDate, {\n hour: undefined,\n minute: undefined,\n })}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/investor/investments/${investment.id}`)}\n className=\"flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Eye className=\"h-4 w-4\" />\n View Details\n </button>\n </div>\n </div>\n\n {/* Desktop Layout */}\n <div className=\"hidden lg:flex lg:items-center lg:justify-between\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"mb-2 flex items-center justify-between\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {investment.cartName}\n </h3>\n <span\n className={cn(\n 'flex items-center gap-1 rounded-full px-3 py-1 text-sm font-medium',\n getStatusColor(investment.status)\n )}\n >\n {getStatusIcon(investment.status)}\n <span className=\"capitalize\">{investment.status}</span>\n </span>\n </div>\n <p className=\"mb-4 text-sm text-text-secondary\">by {investment.cartOwner}</p>\n\n <div className=\"grid grid-cols-5 gap-6\">\n <div>\n <p className=\"text-sm text-text-secondary\">Invested</p>\n <p className=\"font-semibold text-text-primary\">\n {formatCurrency(investment.investmentAmount, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Current Value</p>\n <p className=\"font-semibold text-text-primary\">\n {formatCurrency(investment.currentValue, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">P&L</p>\n <p\n className={cn(\n 'font-semibold',\n investment.profitLoss >= 0\n ? 'text-green-600 dark:text-green-400'\n : 'text-red-600 dark:text-red-400'\n )}\n >\n {investment.profitLoss >= 0 ? '+' : ''}\n {formatCurrency(investment.profitLoss, { minimumFractionDigits: 0 })}\n </p>\n <p\n className={cn(\n 'text-xs',\n investment.profitLoss >= 0\n ? 'text-green-600 dark:text-green-400'\n : 'text-red-600 dark:text-red-400'\n )}\n >\n ({investment.profitLossPercentage >= 0 ? '+' : ''}\n {investment.profitLossPercentage}%)\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">ROI</p>\n <p className=\"font-semibold text-text-primary\">\n {investment.roiAnnual}% p.a.\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Invested on</p>\n <p className=\"font-semibold text-text-primary\">\n {formatDate(investment.investmentDate, {\n hour: undefined,\n minute: undefined,\n })}\n </p>\n </div>\n </div>\n </div>\n\n <div className=\"ml-6\">\n <button\n type=\"button\"\n onClick={() => navigateTo(`/investor/investments/${investment.id}`)}\n className=\"flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Eye className=\"h-4 w-4\" />\n View Details\n </button>\n </div>\n </div>\n </div>\n ))\n ) : (\n <EmptyState\n illustration=\"empty-data\"\n icon={<TrendingDown className=\"h-12 w-12\" />}\n title={`No ${filter !== 'all' ? filter : ''} investments found`}\n description={\n filter === 'all'\n ? \"You haven't made any investments yet. Start exploring opportunities to grow your wealth.\"\n : `You don't have any ${filter} investments at the moment.`\n }\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/opportunities')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n Explore Investment Opportunities\n </button>\n }\n />\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;AAmEA,IAAM,IAAgC;CACpC;EACE,IAAI;EACJ,UAAU;EACV,WAAW;EACX,kBAAkB;EAClB,cAAc;EACd,YAAY;EACZ,sBAAsB;EACtB,gBAAgB;EAChB,QAAQ;EACR,WAAW;EACX,UAAU;EACV,YAAY;EACZ,cAAc;EACf;CACD;EACE,IAAI;EACJ,UAAU;EACV,WAAW;EACX,kBAAkB;EAClB,cAAc;EACd,YAAY;EACZ,sBAAsB;EACtB,gBAAgB;EAChB,QAAQ;EACR,WAAW;EACX,UAAU;EACV,YAAY;EACZ,cAAc;EACf;CACD;EACE,IAAI;EACJ,UAAU;EACV,WAAW;EACX,kBAAkB;EAClB,cAAc;EACd,YAAY;EACZ,sBAAsB;EACtB,gBAAgB;EAChB,QAAQ;EACR,WAAW;EACX,UAAU;EACV,YAAY;EACZ,cAAc;EACf;CACD;EACE,IAAI;EACJ,UAAU;EACV,WAAW;EACX,kBAAkB;EAClB,cAAc;EACd,YAAY;EACZ,sBAAsB;EACtB,gBAAgB;EAChB,QAAQ;EACR,WAAW;EACX,UAAU;EACV,YAAY;EACZ,cAAc;EACf;CACD;EACE,IAAI;EACJ,UAAU;EACV,WAAW;EACX,kBAAkB;EAClB,cAAc;EACd,YAAY;EACZ,sBAAsB;EACtB,gBAAgB;EAChB,QAAQ;EACR,WAAW;EACX,UAAU;EACV,YAAY;EACZ,cAAc;EACf;CACF,EAEK,IAAiC;CACrC,eAAe;CACf,cAAc;CACd,cAAc;CACd,mBAAmB;CACnB,YAAY;CACZ,YAAY;CACZ,sBAAsB;CACvB;AAMD,SAAS,EAAe,GAAwB;AAC9C,SAAQ,GAAR;EACE,KAAK,SACH,QAAO;EACT,KAAK,UACH,QAAO;EACT,KAAK,UACH,QAAO;EACT,KAAK,YACH,QAAO;EACT,QACE,QAAO;;;AAIb,SAAS,EAAc,GAAgB;AACrC,SAAQ,GAAR;EACE,KAAK,SACH,QAAO,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA;EAC7C,KAAK,UACH,QAAO,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;EACtC,KAAK,UACH,QAAO,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA;EAC7C,QACE,QAAO,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA;;;AAQhD,SAAgB,IAA0B;CACxC,IAAM,EAAE,kBAAe,GAAkB,EACnC,CAAC,GAAW,KAAgB,EAAS,GAAK,EAC1C,CAAC,GAAQ,KAAa,EAAoB,MAAM;AAEtD,SAAgB;EACd,IAAM,IAAQ,iBAAiB,EAAa,GAAM,EAAE,IAAI;AACxD,eAAa,aAAa,EAAM;IAC/B,EAAE,CAAC;CAEN,IAAM,IAAsB,QACtB,MAAW,QAAc,IACtB,EAAgB,QAAQ,MAAQ,EAAI,WAAW,EAAO,EAC5D,CAAC,EAAO,CAAC,EAEN,IAAuD;EAC3D;GAAE,KAAK;GAAO,OAAO;GAAmB;EACxC;GAAE,KAAK;GAAU,OAAO;GAAU;EAClC;GAAE,KAAK;GAAW,OAAO;GAAW;EACpC;GAAE,KAAK;GAAW,OAAO;GAAW;EACrC;CAED,SAAS,EAAS,GAAwB;AAExC,SADI,MAAQ,QAAc,EAAgB,SACnC,EAAgB,QAAQ,MAAQ,EAAI,WAAW,EAAI,CAAC;;AAgB7D,QAbI,IAEA,kBAAC,GAAD;EAAY,OAAM;EAAiB,aAAY;YAC7C,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAK,WAAU,8EAA+E,CAAA,EAC9F,kBAAC,KAAD;KAAG,WAAU;eAA8B;KAA+B,CAAA,CACtE;;GACF,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,0BAA0B;GACpD,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,iBAErB;;YAXb;GAeE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;MACpC,OAAO,EAAe,EAAY,eAAe,EAAE,uBAAuB,GAAG,CAAC;MAC9E,OAAM;MACN,OAAM;MACN,YAAW;MACX,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA;MACzC,OAAO,EAAe,EAAY,cAAc,EAAE,uBAAuB,GAAG,CAAC;MAC7E,OAAM;MACN,OAAO,EAAY,aAAa,IAAI,OAAO;MAC3C,YAAY,GAAG,EAAY,uBAAuB,IAAI,MAAM,KAAK,EAAY,qBAAqB;MAClG,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;MACxC,OAAO,EAAe,EAAY,cAAc,EAAE,uBAAuB,GAAG,CAAC;MAC7E,OAAM;MACN,OAAM;MACN,YAAW;MACX,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA;MAC1C,OAAO,OAAO,EAAY,kBAAkB;MAC5C,OAAM;MACN,OAAM;MACN,YAAY,GAAG,EAAY,WAAW;MACtC,CAAA;KACE;;GAGN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAW,KAAK,MACf,kBAAC,UAAD;MAEE,MAAK;MACL,eAAe,EAAU,EAAI,IAAI;MACjC,WAAW,EACT,sFACA,MAAW,EAAI,MACX,kDACA,uDACL;gBATH,CAWG,EAAI,OACL,kBAAC,QAAD;OACE,WAAW,EACT,oCACA,MAAW,EAAI,MACX,sDACA,uCACL;iBAEA,EAAS,EAAI,IAAI;OACb,CAAA,CACA;QArBF,EAAI,IAqBF,CACT;KACE,CAAA;IACF,CAAA;GAGN,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAoB,SAAS,IAC5B,EAAoB,KAAK,MACvB,kBAAC,OAAD;KAEE,WAAU;eAFZ,CAKE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAW;SACT,CAAA,EACL,kBAAC,KAAD;SAAG,WAAU;mBAAb,CAA2C,OAAI,EAAW,UAAc;WACpE,EAAA,CAAA,EACN,kBAAC,QAAD;SACE,WAAW,EACT,sEACA,EAAe,EAAW,OAAO,CAClC;mBAJH,CAMG,EAAc,EAAW,OAAO,EACjC,kBAAC,QAAD;UAAM,WAAU;oBAAc,EAAW;UAAc,CAAA,CAClD;WACH;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B;UAAY,CAAA,EACvD,kBAAC,KAAD;UAAG,WAAU;oBACV,EAAe,EAAW,kBAAkB,EAAE,uBAAuB,GAAG,CAAC;UACxE,CAAA,CACA,EAAA,CAAA;SACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B;UAAiB,CAAA,EAC5D,kBAAC,KAAD;UAAG,WAAU;oBACV,EAAe,EAAW,cAAc,EAAE,uBAAuB,GAAG,CAAC;UACpE,CAAA,CACA,EAAA,CAAA;SACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B;UAAO,CAAA,EAClD,kBAAC,KAAD;UACE,WAAW,EACT,iBACA,EAAW,cAAc,IACrB,uCACA,iCACL;oBANH;WAQG,EAAW,cAAc,IAAI,MAAM;WACnC,EAAe,EAAW,YAAY,EAAE,uBAAuB,GAAG,CAAC;WAAC;WACpE,EAAW,wBAAwB,IAAI,MAAM;WAC7C,EAAW;WAAqB;WAC/B;YACA,EAAA,CAAA;SACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B;UAAO,CAAA,EAClD,kBAAC,KAAD;UAAG,WAAU;oBAAb,CAAgD,EAAW,WAAU,SAAU;YAC3E,EAAA,CAAA;SACF;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAA8B;SAAe,CAAA,EAC1D,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAW,EAAW,gBAAgB;UACrC,MAAM,KAAA;UACN,QAAQ,KAAA;UACT,CAAC;SACA,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAW,yBAAyB,EAAW,KAAK;SACnE,WAAU;mBAHZ,CAKE,kBAAC,GAAD,EAAK,WAAU,WAAY,CAAA,EAAA,eAEpB;WACL;;OACF;SAGN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAW;UACT,CAAA,EACL,kBAAC,QAAD;UACE,WAAW,EACT,sEACA,EAAe,EAAW,OAAO,CAClC;oBAJH,CAMG,EAAc,EAAW,OAAO,EACjC,kBAAC,QAAD;WAAM,WAAU;qBAAc,EAAW;WAAc,CAAA,CAClD;YACH;;QACN,kBAAC,KAAD;SAAG,WAAU;mBAAb,CAAgD,OAAI,EAAW,UAAc;;QAE7E,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAY,CAAA,EACvD,kBAAC,KAAD;WAAG,WAAU;qBACV,EAAe,EAAW,kBAAkB,EAAE,uBAAuB,GAAG,CAAC;WACxE,CAAA,CACA,EAAA,CAAA;UACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAiB,CAAA,EAC5D,kBAAC,KAAD;WAAG,WAAU;qBACV,EAAe,EAAW,cAAc,EAAE,uBAAuB,GAAG,CAAC;WACpE,CAAA,CACA,EAAA,CAAA;UACN,kBAAC,OAAD,EAAA,UAAA;WACE,kBAAC,KAAD;YAAG,WAAU;sBAA8B;YAAO,CAAA;WAClD,kBAAC,KAAD;YACE,WAAW,EACT,iBACA,EAAW,cAAc,IACrB,uCACA,iCACL;sBANH,CAQG,EAAW,cAAc,IAAI,MAAM,IACnC,EAAe,EAAW,YAAY,EAAE,uBAAuB,GAAG,CAAC,CAClE;;WACJ,kBAAC,KAAD;YACE,WAAW,EACT,WACA,EAAW,cAAc,IACrB,uCACA,iCACL;sBANH;aAOC;aACG,EAAW,wBAAwB,IAAI,MAAM;aAC9C,EAAW;aAAqB;aAC/B;;WACA,EAAA,CAAA;UACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAO,CAAA,EAClD,kBAAC,KAAD;WAAG,WAAU;qBAAb,CACG,EAAW,WAAU,SACpB;aACA,EAAA,CAAA;UACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAe,CAAA,EAC1D,kBAAC,KAAD;WAAG,WAAU;qBACV,EAAW,EAAW,gBAAgB;YACrC,MAAM,KAAA;YACN,QAAQ,KAAA;YACT,CAAC;WACA,CAAA,CACA,EAAA,CAAA;UACF;;QACF;UAEN,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAW,yBAAyB,EAAW,KAAK;QACnE,WAAU;kBAHZ,CAKE,kBAAC,GAAD,EAAK,WAAU,WAAY,CAAA,EAAA,eAEpB;;OACL,CAAA,CACF;QACF;OArKC,EAAW,GAqKZ,CACN,GAEF,kBAAC,GAAD;KACE,cAAa;KACb,MAAM,kBAAC,GAAD,EAAc,WAAU,aAAc,CAAA;KAC5C,OAAO,MAAM,MAAW,QAAiB,KAAT,EAAY;KAC5C,aACE,MAAW,QACP,6FACA,sBAAsB,EAAO;KAEnC,QACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAW,0BAA0B;MACpD,WAAU;gBACX;MAEQ,CAAA;KAEX,CAAA;IAEA,CAAA;GACK"}
|
|
@@ -142,6 +142,7 @@ function V() {
|
|
|
142
142
|
if (!w) return /* @__PURE__ */ F(n, {
|
|
143
143
|
title: "Task Not Found",
|
|
144
144
|
children: /* @__PURE__ */ F(i, {
|
|
145
|
+
illustration: "empty-generic",
|
|
145
146
|
icon: /* @__PURE__ */ F(y, { className: "h-12 w-12" }),
|
|
146
147
|
title: "Task not found",
|
|
147
148
|
description: `No task found with ID "${p}".`,
|