@burdenoff/microfe-kadaikodi 2026.704.3 → 2026.704.5
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/kadaikodi/KadaikodiRoutes.js +34 -26
- package/dist/kadaikodi/KadaikodiRoutes.js.map +1 -1
- package/dist/kadaikodi/components/viz/AllocationBar.js +68 -0
- package/dist/kadaikodi/components/viz/AllocationBar.js.map +1 -0
- package/dist/kadaikodi/components/viz/AreaChart.js +102 -0
- package/dist/kadaikodi/components/viz/AreaChart.js.map +1 -0
- package/dist/kadaikodi/components/viz/AvatarStack.js +36 -0
- package/dist/kadaikodi/components/viz/AvatarStack.js.map +1 -0
- package/dist/kadaikodi/components/viz/BarChart.js +83 -0
- package/dist/kadaikodi/components/viz/BarChart.js.map +1 -0
- package/dist/kadaikodi/components/viz/CertificateCard.js +4 -0
- package/dist/kadaikodi/components/viz/DonutChart.js +109 -0
- package/dist/kadaikodi/components/viz/DonutChart.js.map +1 -0
- package/dist/kadaikodi/components/viz/HBarFunnel.js +54 -0
- package/dist/kadaikodi/components/viz/HBarFunnel.js.map +1 -0
- package/dist/kadaikodi/components/viz/Heatmap.js +3 -0
- package/dist/kadaikodi/components/viz/KanbanBoard.js +50 -0
- package/dist/kadaikodi/components/viz/KanbanBoard.js.map +1 -0
- package/dist/kadaikodi/components/viz/LineChart.js +4 -0
- package/dist/kadaikodi/components/viz/OrgTree.js +2 -0
- package/dist/kadaikodi/components/viz/PathSteps.js +3 -0
- package/dist/kadaikodi/components/viz/ProgressRing.js +68 -0
- package/dist/kadaikodi/components/viz/ProgressRing.js.map +1 -0
- package/dist/kadaikodi/components/viz/RatingStars.js +51 -0
- package/dist/kadaikodi/components/viz/RatingStars.js.map +1 -0
- package/dist/kadaikodi/components/viz/SegmentedTabs.js +69 -0
- package/dist/kadaikodi/components/viz/SegmentedTabs.js.map +1 -0
- package/dist/kadaikodi/components/viz/SkillBar.js +3 -0
- package/dist/kadaikodi/components/viz/Sparkline.js +74 -0
- package/dist/kadaikodi/components/viz/Sparkline.js.map +1 -0
- package/dist/kadaikodi/components/viz/StatCard.js +60 -0
- package/dist/kadaikodi/components/viz/StatCard.js.map +1 -0
- package/dist/kadaikodi/components/viz/StepProgress.js +64 -0
- package/dist/kadaikodi/components/viz/StepProgress.js.map +1 -0
- package/dist/kadaikodi/components/viz/Timeline.js +66 -0
- package/dist/kadaikodi/components/viz/Timeline.js.map +1 -0
- package/dist/kadaikodi/components/viz/index.js +23 -0
- package/dist/kadaikodi/components/viz/lib/Avatar.js +30 -0
- package/dist/kadaikodi/components/viz/lib/Avatar.js.map +1 -0
- package/dist/kadaikodi/components/viz/lib/CartesianFrame.js +119 -0
- package/dist/kadaikodi/components/viz/lib/CartesianFrame.js.map +1 -0
- package/dist/kadaikodi/components/viz/lib/ResponsiveSvg.js +35 -0
- package/dist/kadaikodi/components/viz/lib/ResponsiveSvg.js.map +1 -0
- package/dist/kadaikodi/components/viz/lib/format.js +21 -0
- package/dist/kadaikodi/components/viz/lib/format.js.map +1 -0
- package/dist/kadaikodi/components/viz/lib/geometry.js +61 -0
- package/dist/kadaikodi/components/viz/lib/geometry.js.map +1 -0
- package/dist/kadaikodi/components/viz/lib/hooks.js +39 -0
- package/dist/kadaikodi/components/viz/lib/hooks.js.map +1 -0
- package/dist/kadaikodi/components/viz/lib/palette.js +27 -0
- package/dist/kadaikodi/components/viz/lib/palette.js.map +1 -0
- package/dist/kadaikodi/hooks/useKadaikodiApi.js +84 -6
- package/dist/kadaikodi/hooks/useKadaikodiApi.js.map +1 -1
- package/dist/kadaikodi/pages/HomePage.js +373 -631
- package/dist/kadaikodi/pages/HomePage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.js +304 -169
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminDashboard.js +255 -271
- package/dist/kadaikodi/pages/admin/AdminDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminFinancialPage.js +185 -125
- package/dist/kadaikodi/pages/admin/AdminFinancialPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminOrdersPage.js +141 -102
- package/dist/kadaikodi/pages/admin/AdminOrdersPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminProfilePage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminSettingsPage.js +332 -276
- package/dist/kadaikodi/pages/admin/AdminSettingsPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/CartManagementPage.js +564 -729
- package/dist/kadaikodi/pages/admin/CartManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/UserManagementPage.js +310 -366
- package/dist/kadaikodi/pages/admin/UserManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/AnalyticsDashboard.js +201 -120
- package/dist/kadaikodi/pages/cart-owner/AnalyticsDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/BusinessSettingsPage.js +290 -257
- package/dist/kadaikodi/pages/cart-owner/BusinessSettingsPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/CartOwnerDashboard.js +173 -194
- package/dist/kadaikodi/pages/cart-owner/CartOwnerDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/CartOwnerProfilePage.js +270 -228
- package/dist/kadaikodi/pages/cart-owner/CartOwnerProfilePage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/CartServiceConfigPage.js +194 -173
- package/dist/kadaikodi/pages/cart-owner/CartServiceConfigPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/InventoryManagementPage.js +428 -347
- package/dist/kadaikodi/pages/cart-owner/InventoryManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/InvestmentListingPage.js +332 -0
- package/dist/kadaikodi/pages/cart-owner/InvestmentListingPage.js.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/MerchantOnboardingPage.js +373 -0
- package/dist/kadaikodi/pages/cart-owner/MerchantOnboardingPage.js.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/OrderManagementPage.js +294 -162
- package/dist/kadaikodi/pages/cart-owner/OrderManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.js +180 -181
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/common/HelpSupportPage.js +310 -317
- package/dist/kadaikodi/pages/common/HelpSupportPage.js.map +1 -1
- package/dist/kadaikodi/pages/common/NotificationCenterPage.js.map +1 -1
- package/dist/kadaikodi/pages/common/SettingsPage.js +502 -586
- package/dist/kadaikodi/pages/common/SettingsPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/BookingDetailsPage.js +239 -156
- package/dist/kadaikodi/pages/customer/BookingDetailsPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDetailPage.js +405 -248
- package/dist/kadaikodi/pages/customer/CartDetailPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.js +258 -232
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CheckoutPage.js +254 -205
- package/dist/kadaikodi/pages/customer/CheckoutPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CustomerDashboard.js +5 -5
- package/dist/kadaikodi/pages/customer/CustomerDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CustomerProfilePage.js +189 -199
- package/dist/kadaikodi/pages/customer/CustomerProfilePage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/DirectServiceBookingPage.js +272 -230
- package/dist/kadaikodi/pages/customer/DirectServiceBookingPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/FavoritesPage.js +150 -413
- package/dist/kadaikodi/pages/customer/FavoritesPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/OrderHistoryPage.js +173 -134
- package/dist/kadaikodi/pages/customer/OrderHistoryPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.js +411 -305
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/ReviewsPage.js +310 -406
- package/dist/kadaikodi/pages/customer/ReviewsPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/SavedAddressesPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/shared.js +181 -0
- package/dist/kadaikodi/pages/customer/shared.js.map +1 -0
- package/dist/kadaikodi/pages/investor/InvestmentDetailsPage.js +438 -311
- package/dist/kadaikodi/pages/investor/InvestmentDetailsPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestmentOpportunitiesPage.js +320 -293
- package/dist/kadaikodi/pages/investor/InvestmentOpportunitiesPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestorAnalyticsPage.js +159 -91
- package/dist/kadaikodi/pages/investor/InvestorAnalyticsPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestorDashboard.js +137 -107
- package/dist/kadaikodi/pages/investor/InvestorDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestorInvestmentsPage.js +157 -135
- package/dist/kadaikodi/pages/investor/InvestorInvestmentsPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestorPortfolioPage.js +280 -206
- package/dist/kadaikodi/pages/investor/InvestorPortfolioPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestorProfilePage.js +441 -514
- package/dist/kadaikodi/pages/investor/InvestorProfilePage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.js +428 -431
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/WorkerDashboard.js +328 -445
- package/dist/kadaikodi/pages/worker/WorkerDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/worker/WorkerOrdersPage.js +141 -164
- package/dist/kadaikodi/pages/worker/WorkerOrdersPage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/WorkerProfilePage.js +360 -288
- package/dist/kadaikodi/pages/worker/WorkerProfilePage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/WorkerSchedulePage.js +303 -281
- package/dist/kadaikodi/pages/worker/WorkerSchedulePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InvestorDashboard.js","names":[],"sources":["../../../../src/kadaikodi/pages/investor/InvestorDashboard.tsx"],"sourcesContent":["/**\n * Investor Dashboard Page\n * @module kadaikodi/pages/investor\n *\n * Portfolio overview with real metrics derived from the investor's holdings,\n * tab navigation (my investments / new opportunities), and quick actions.\n * All data comes from the live backend — no fabricated insights or activity.\n */\n\nimport { useState, useMemo } from 'react';\nimport {\n Wallet,\n PieChart,\n IndianRupee,\n Target,\n Award,\n Filter,\n Eye,\n Plus,\n BarChart3,\n} from 'lucide-react';\nimport { EmphasisPanel, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\nimport { EmptyState } from '../../components/EmptyState';\nimport { PageLayout } from '../../components/PageLayout';\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { InvestmentCard } from '../../components/InvestmentCard';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport { useInvestmentOpportunities, useInvestments } from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency } from '../../utils/formatters';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getStatusBadgeColor(status: string): string {\n switch (status) {\n case 'active':\n return 'bg-status-success-bg-subtle text-status-success-text';\n case 'completed':\n return 'bg-[var(--color-accent-soft)] text-text-primary';\n case 'exited':\n return 'bg-bg-sunken text-text-secondary';\n default:\n return 'bg-bg-sunken text-text-secondary';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function InvestorDashboard() {\n const { navigateTo, currentUser } = useKadaikodi();\n const [activeTab, setActiveTab] = useState<'portfolio' | 'opportunities'>('portfolio');\n\n const { data: opportunities = [], isLoading: opportunitiesLoading } =\n useInvestmentOpportunities();\n const { data: investments = [], isLoading: investmentsLoading } = useInvestments(\n currentUser?.id || ''\n );\n\n const firstName = currentUser?.firstName ?? currentUser?.name ?? 'Investor';\n\n const activeOpportunities = opportunities.filter((inv) => inv.status === 'active');\n\n const portfolioSummary = useMemo(() => {\n const totalInvested = investments.reduce((sum, inv) => sum + inv.investedAmount, 0);\n const currentValue = investments.reduce((sum, inv) => sum + inv.currentValue, 0);\n const totalReturns = investments.reduce((sum, inv) => sum + inv.returns, 0);\n const roi = totalInvested > 0 ? ((currentValue - totalInvested) / totalInvested) * 100 : 0;\n\n return {\n totalInvested,\n currentValue,\n totalReturns,\n roi,\n };\n }, [investments]);\n\n if (opportunitiesLoading || investmentsLoading) {\n return (\n <PageLayout title=\"Investment Dashboard\" description=\"Loading your portfolio...\">\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 portfolio...</p>\n </div>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={`Welcome back, ${firstName}!`}\n description=\"Here's your investment portfolio overview.\"\n >\n <PagePurpose className=\"mb-6\">\n Track how your money is working across the mobile carts you've backed — see what you've\n invested, what it's worth today, and the returns flowing in. Review your active investments\n below or browse new opportunities to diversify.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"kadaikodi-investor-dashboard\"\n className=\"mb-6\"\n steps={[\n {\n id: 'opportunities',\n label: 'Explore new opportunities',\n description: 'Discover carts seeking funding and their projected returns.',\n onClick: () => navigateTo('/investor/opportunities'),\n },\n {\n id: 'portfolio',\n label: 'Review your portfolio',\n description: 'Dig into each active investment and its performance.',\n onClick: () => navigateTo('/investor/portfolio'),\n },\n {\n id: 'analytics',\n label: 'Analyse your returns',\n description: 'See trends and projections across your whole portfolio.',\n onClick: () => navigateTo('/investor/analytics'),\n },\n ]}\n />\n\n {/* Portfolio Summary Metrics — the one emphasis zone */}\n <EmphasisPanel>\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Portfolio Overview</h2>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n featured\n icon={<Wallet className=\"h-5 w-5\" />}\n value={formatCurrency(portfolioSummary.totalInvested, { minimumFractionDigits: 0 })}\n label=\"Total Invested\"\n trend=\"up\"\n trendValue=\"Across all businesses\"\n />\n <MetricsCard\n icon={<IndianRupee className=\"h-5 w-5\" />}\n value={formatCurrency(portfolioSummary.currentValue, { minimumFractionDigits: 0 })}\n label=\"Current Value\"\n trend={portfolioSummary.roi >= 0 ? 'up' : 'down'}\n trendValue={`${portfolioSummary.roi >= 0 ? '+' : ''}${portfolioSummary.roi.toFixed(1)}%`}\n />\n <MetricsCard\n icon={<Target className=\"h-5 w-5\" />}\n value={formatCurrency(portfolioSummary.totalReturns, { minimumFractionDigits: 0 })}\n label=\"Total Returns\"\n />\n </div>\n </EmphasisPanel>\n\n {/* Main Content + Sidebar */}\n <div className=\"mt-8 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Main Content */}\n <div className=\"lg:col-span-2\">\n {/* Tab Navigation */}\n <div className=\"mb-6 flex rounded-lg bg-bg-sunken p-1\">\n <button\n type=\"button\"\n onClick={() => setActiveTab('portfolio')}\n className={cn(\n 'flex-1 rounded-md px-4 py-2 text-sm font-medium transition-colors',\n activeTab === 'portfolio'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\n )}\n >\n My Investments\n </button>\n <button\n type=\"button\"\n onClick={() => setActiveTab('opportunities')}\n className={cn(\n 'flex-1 rounded-md px-4 py-2 text-sm font-medium transition-colors',\n activeTab === 'opportunities'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\n )}\n >\n New Opportunities\n </button>\n </div>\n\n {/* Portfolio Tab */}\n {activeTab === 'portfolio' && (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-base font-semibold text-text-primary\">Active Investments</h3>\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/investments')}\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 <Filter className=\"h-4 w-4\" />\n View all\n </button>\n </div>\n\n {investments.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No active investments yet\"\n description=\"Once you back a cart, your investments will appear here. Browse open opportunities to get started.\"\n action={\n <button\n type=\"button\"\n onClick={() => setActiveTab('opportunities')}\n className=\"rounded-lg bg-foreground px-4 py-2 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n Browse opportunities\n </button>\n }\n />\n ) : (\n investments.map((investment) => (\n <div\n key={investment.id}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 shadow-sm hover:shadow-md transition-shadow\"\n >\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex-1\">\n <div className=\"mb-2 flex flex-wrap items-center gap-2\">\n <h4 className=\"text-base font-semibold text-text-primary\">\n {investment.cartName}\n </h4>\n <span\n className={cn(\n 'rounded-full px-2 py-0.5 text-xs font-medium',\n getStatusBadgeColor(investment.status)\n )}\n >\n {investment.status}\n </span>\n </div>\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\n <div className=\"mt-3 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <div>\n <p className=\"text-xs text-text-secondary\">Invested</p>\n <p className=\"text-sm font-semibold text-text-primary\">\n {formatCurrency(investment.investedAmount, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Current Value</p>\n <p className=\"text-sm font-semibold text-status-success-text\">\n {formatCurrency(investment.currentValue, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Returns</p>\n <p className=\"text-sm font-semibold text-text-primary\">\n {formatCurrency(investment.returns, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Expected Return</p>\n <p className=\"text-sm font-semibold text-status-success-text\">\n {investment.returnsPercentage}%\n </p>\n </div>\n </div>\n </div>\n ))\n )}\n </div>\n )}\n\n {/* Opportunities Tab */}\n {activeTab === 'opportunities' && (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n Investment Opportunities\n </h3>\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 Browse All\n </button>\n </div>\n\n {activeOpportunities.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No open opportunities right now\"\n description=\"New carts seeking funding will show up here. Check back soon.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n {activeOpportunities.slice(0, 4).map((opp) => (\n <InvestmentCard\n key={opp.id}\n id={opp.id}\n cartName={opp.cartName}\n targetAmount={opp.targetAmount}\n raisedAmount={opp.raisedAmount}\n expectedReturns={`${opp.expectedReturns}%`}\n riskLevel={opp.riskLevel}\n status={opp.status}\n onClick={(id) => navigateTo(`/investor/opportunity/${id}`)}\n />\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-6\">\n {/* Quick Actions */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h3 className=\"mb-3 text-base font-semibold text-text-primary\">Quick Actions</h3>\n <div className=\"space-y-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/portfolio')}\n className=\"flex w-full items-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-left text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <PieChart className=\"h-4 w-4 text-text-secondary\" />\n View Full Portfolio\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/opportunities')}\n className=\"flex w-full items-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-left text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Target className=\"h-4 w-4 text-text-secondary\" />\n Browse Opportunities\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/analytics')}\n className=\"flex w-full items-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-left text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <BarChart3 className=\"h-4 w-4 text-text-secondary\" />\n Investment Analytics\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/profile')}\n className=\"flex w-full items-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-left text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Award className=\"h-4 w-4 text-text-secondary\" />\n View Profile\n </button>\n </div>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InvestorDashboard.js","names":[],"sources":["../../../../src/kadaikodi/pages/investor/InvestorDashboard.tsx"],"sourcesContent":["/**\n * Investor Dashboard Page\n * @module kadaikodi/pages/investor\n *\n * Portfolio overview with real metrics derived from the investor's holdings,\n * tab navigation (my investments / new opportunities), and quick actions.\n * All data comes from the live backend — no fabricated insights or activity.\n */\n\nimport { useState, useMemo } from 'react';\nimport {\n Wallet,\n PieChart,\n IndianRupee,\n Target,\n Award,\n Filter,\n Eye,\n Plus,\n BarChart3,\n} from 'lucide-react';\nimport { EmphasisPanel, GlassCard, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\nimport { EmptyState } from '../../components/EmptyState';\nimport { PageLayout } from '../../components/PageLayout';\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { InvestmentCard } from '../../components/InvestmentCard';\nimport { AreaChart } from '../../components/viz';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport { useInvestmentOpportunities, useInvestments } from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatDate } from '../../utils/formatters';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getStatusBadgeColor(status: string): string {\n switch (status) {\n case 'active':\n return 'bg-status-success-bg-subtle text-status-success-text';\n case 'completed':\n return 'bg-[var(--color-accent-soft)] text-text-primary';\n case 'exited':\n return 'bg-bg-sunken text-text-secondary';\n default:\n return 'bg-bg-sunken text-text-secondary';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function InvestorDashboard() {\n const { navigateTo, currentUser } = useKadaikodi();\n const [activeTab, setActiveTab] = useState<'portfolio' | 'opportunities'>('portfolio');\n\n const { data: opportunities = [], isLoading: opportunitiesLoading } =\n useInvestmentOpportunities();\n const { data: investments = [], isLoading: investmentsLoading } = useInvestments(\n currentUser?.id || ''\n );\n\n const firstName = currentUser?.firstName ?? currentUser?.name ?? 'Investor';\n\n const activeOpportunities = opportunities.filter((inv) => inv.status === 'active');\n\n const portfolioSummary = useMemo(() => {\n const totalInvested = investments.reduce((sum, inv) => sum + inv.investedAmount, 0);\n const currentValue = investments.reduce((sum, inv) => sum + inv.currentValue, 0);\n const totalReturns = investments.reduce((sum, inv) => sum + inv.returns, 0);\n const roi = totalInvested > 0 ? ((currentValue - totalInvested) / totalInvested) * 100 : 0;\n\n return {\n totalInvested,\n currentValue,\n totalReturns,\n roi,\n };\n }, [investments]);\n\n // Portfolio value trend — running total of holding value by date (real).\n const valueTrend = useMemo(() => {\n const sorted = [...investments].sort(\n (a, b) => new Date(a.investmentDate).getTime() - new Date(b.investmentDate).getTime()\n );\n let running = 0;\n const points = sorted.map((inv) => {\n running += inv.currentValue;\n return {\n label: formatDate(inv.investmentDate, {\n day: undefined,\n hour: undefined,\n minute: undefined,\n }),\n value: running,\n };\n });\n return points.length === 1 ? [{ label: 'Start', value: 0 }, ...points] : points;\n }, [investments]);\n\n if (opportunitiesLoading || investmentsLoading) {\n return (\n <PageLayout title=\"Investment Dashboard\" description=\"Loading your portfolio...\">\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 portfolio...</p>\n </div>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={`Welcome back, ${firstName}!`}\n description=\"Here's your investment portfolio overview.\"\n >\n <PagePurpose className=\"mb-6\">\n Track how your money is working across the mobile carts you've backed — see what you've\n invested, what it's worth today, and the returns flowing in. Review your active investments\n below or browse new opportunities to diversify.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"kadaikodi-investor-dashboard\"\n className=\"mb-6\"\n steps={[\n {\n id: 'opportunities',\n label: 'Explore new opportunities',\n description: 'Discover carts seeking funding and their projected returns.',\n onClick: () => navigateTo('/investor/opportunities'),\n },\n {\n id: 'portfolio',\n label: 'Review your portfolio',\n description: 'Dig into each active investment and its performance.',\n onClick: () => navigateTo('/investor/portfolio'),\n },\n {\n id: 'analytics',\n label: 'Analyse your returns',\n description: 'See trends and projections across your whole portfolio.',\n onClick: () => navigateTo('/investor/analytics'),\n },\n ]}\n />\n\n {/* Portfolio Summary Metrics — the one emphasis zone */}\n <EmphasisPanel>\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Portfolio Overview</h2>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n featured\n icon={<Wallet className=\"h-5 w-5\" />}\n value={formatCurrency(portfolioSummary.totalInvested, { minimumFractionDigits: 0 })}\n label=\"Total Invested\"\n trend=\"up\"\n trendValue=\"Across all businesses\"\n />\n <MetricsCard\n icon={<IndianRupee className=\"h-5 w-5\" />}\n value={formatCurrency(portfolioSummary.currentValue, { minimumFractionDigits: 0 })}\n label=\"Current Value\"\n trend={portfolioSummary.roi >= 0 ? 'up' : 'down'}\n trendValue={`${portfolioSummary.roi >= 0 ? '+' : ''}${portfolioSummary.roi.toFixed(1)}%`}\n />\n <MetricsCard\n icon={<Target className=\"h-5 w-5\" />}\n value={formatCurrency(portfolioSummary.totalReturns, { minimumFractionDigits: 0 })}\n label=\"Total Returns\"\n />\n </div>\n </EmphasisPanel>\n\n {/* Main Content + Sidebar */}\n <div className=\"mt-8 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Main Content */}\n <div className=\"lg:col-span-2\">\n {/* Tab Navigation */}\n <div className=\"mb-6 flex rounded-lg bg-bg-sunken p-1\">\n <button\n type=\"button\"\n onClick={() => setActiveTab('portfolio')}\n className={cn(\n 'flex-1 rounded-md px-4 py-2 text-sm font-medium transition-colors',\n activeTab === 'portfolio'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\n )}\n >\n My Investments\n </button>\n <button\n type=\"button\"\n onClick={() => setActiveTab('opportunities')}\n className={cn(\n 'flex-1 rounded-md px-4 py-2 text-sm font-medium transition-colors',\n activeTab === 'opportunities'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\n )}\n >\n New Opportunities\n </button>\n </div>\n\n {/* Portfolio Tab */}\n {activeTab === 'portfolio' && (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-base font-semibold text-text-primary\">Active Investments</h3>\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/investments')}\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 <Filter className=\"h-4 w-4\" />\n View all\n </button>\n </div>\n\n {investments.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No active investments yet\"\n description=\"Once you back a cart, your investments will appear here. Browse open opportunities to get started.\"\n action={\n <button\n type=\"button\"\n onClick={() => setActiveTab('opportunities')}\n className=\"rounded-lg bg-foreground px-4 py-2 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n Browse opportunities\n </button>\n }\n />\n ) : (\n investments.map((investment) => (\n <div\n key={investment.id}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 shadow-sm hover:shadow-md transition-shadow\"\n >\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex-1\">\n <div className=\"mb-2 flex flex-wrap items-center gap-2\">\n <h4 className=\"text-base font-semibold text-text-primary\">\n {investment.cartName}\n </h4>\n <span\n className={cn(\n 'rounded-full px-2 py-0.5 text-xs font-medium',\n getStatusBadgeColor(investment.status)\n )}\n >\n {investment.status}\n </span>\n </div>\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\n <div className=\"mt-3 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <div>\n <p className=\"text-xs text-text-secondary\">Invested</p>\n <p className=\"text-sm font-semibold text-text-primary\">\n {formatCurrency(investment.investedAmount, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Current Value</p>\n <p className=\"text-sm font-semibold text-status-success-text\">\n {formatCurrency(investment.currentValue, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Returns</p>\n <p className=\"text-sm font-semibold text-text-primary\">\n {formatCurrency(investment.returns, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Expected Return</p>\n <p className=\"text-sm font-semibold text-status-success-text\">\n {investment.returnsPercentage}%\n </p>\n </div>\n </div>\n </div>\n ))\n )}\n </div>\n )}\n\n {/* Opportunities Tab */}\n {activeTab === 'opportunities' && (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n Investment Opportunities\n </h3>\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 Browse All\n </button>\n </div>\n\n {activeOpportunities.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No open opportunities right now\"\n description=\"New carts seeking funding will show up here. Check back soon.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n {activeOpportunities.slice(0, 4).map((opp) => (\n <InvestmentCard\n key={opp.id}\n id={opp.id}\n cartName={opp.cartName}\n targetAmount={opp.targetAmount}\n raisedAmount={opp.raisedAmount}\n expectedReturns={`${opp.expectedReturns}%`}\n riskLevel={opp.riskLevel}\n status={opp.status}\n onClick={(id) => navigateTo(`/investor/opportunity/${id}`)}\n />\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-6\">\n {/* Portfolio value trend */}\n {investments.length > 0 && (\n <GlassCard treatment=\"plain\" className=\"p-4 sm:p-5\">\n <h3 className=\"mb-3 text-base font-semibold text-text-primary\">\n Portfolio Value Trend\n </h3>\n <AreaChart\n series={valueTrend}\n height={160}\n valueFormatter={(v) =>\n formatCurrency(v, { minimumFractionDigits: 0, notation: 'compact' })\n }\n title=\"Cumulative portfolio value by holding date\"\n />\n </GlassCard>\n )}\n\n {/* Quick Actions */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h3 className=\"mb-3 text-base font-semibold text-text-primary\">Quick Actions</h3>\n <div className=\"space-y-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/portfolio')}\n className=\"flex w-full items-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-left text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <PieChart className=\"h-4 w-4 text-text-secondary\" />\n View Full Portfolio\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/opportunities')}\n className=\"flex w-full items-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-left text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Target className=\"h-4 w-4 text-text-secondary\" />\n Browse Opportunities\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/analytics')}\n className=\"flex w-full items-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-left text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <BarChart3 className=\"h-4 w-4 text-text-secondary\" />\n Investment Analytics\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/profile')}\n className=\"flex w-full items-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-left text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Award className=\"h-4 w-4 text-text-secondary\" />\n View Profile\n </button>\n </div>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { useKadaikodi as e } from "../../context/KadaikodiContext.js";
|
|
2
2
|
import { cn as t } from "../../utils/cn.js";
|
|
3
3
|
import { PageLayout as n } from "../../components/PageLayout.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
4
|
+
import { EmptyState as r } from "../../components/EmptyState.js";
|
|
5
|
+
import { useInvestments as i } from "../../hooks/useKadaikodiApi.js";
|
|
6
|
+
import { formatCurrency as a, formatDate as o } from "../../utils/formatters.js";
|
|
7
|
+
import { MetricsCard as s } from "../../components/MetricsCard.js";
|
|
8
|
+
import { AllocationBar as c } from "../../components/viz/AllocationBar.js";
|
|
9
|
+
import "../../components/viz/index.js";
|
|
10
|
+
import { useMemo as l, useState as u } from "react";
|
|
11
|
+
import { CheckCircle2 as d, Clock as f, Eye as p, IndianRupee as m, Plus as h, TrendingDown as g, TrendingUp as _, Wallet as v } from "lucide-react";
|
|
12
|
+
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
13
|
+
import { EmphasisPanel as x, PagePurpose as S } from "@burdenoff/fe-libs/ui";
|
|
12
14
|
//#region src/kadaikodi/pages/investor/InvestorInvestmentsPage.tsx
|
|
13
|
-
var
|
|
15
|
+
var C = [
|
|
14
16
|
{
|
|
15
17
|
key: "all",
|
|
16
18
|
label: "All Investments"
|
|
@@ -28,7 +30,7 @@ var S = [
|
|
|
28
30
|
label: "Exited"
|
|
29
31
|
}
|
|
30
32
|
];
|
|
31
|
-
function
|
|
33
|
+
function w(e) {
|
|
32
34
|
switch (e) {
|
|
33
35
|
case "active": return "bg-status-success-bg-subtle text-status-success-text";
|
|
34
36
|
case "completed": return "bg-[var(--color-accent-soft)] text-text-primary";
|
|
@@ -36,231 +38,251 @@ function C(e) {
|
|
|
36
38
|
default: return "bg-bg-sunken text-text-secondary";
|
|
37
39
|
}
|
|
38
40
|
}
|
|
39
|
-
function
|
|
41
|
+
function T(e) {
|
|
40
42
|
switch (e) {
|
|
41
|
-
case "active": return /* @__PURE__ */
|
|
42
|
-
case "completed": return /* @__PURE__ */
|
|
43
|
-
default: return /* @__PURE__ */
|
|
43
|
+
case "active": return /* @__PURE__ */ y(d, { className: "h-4 w-4" });
|
|
44
|
+
case "completed": return /* @__PURE__ */ y(d, { className: "h-4 w-4" });
|
|
45
|
+
default: return /* @__PURE__ */ y(f, { className: "h-4 w-4" });
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
|
-
function
|
|
48
|
+
function E(e) {
|
|
47
49
|
return e.currentValue - e.investedAmount;
|
|
48
50
|
}
|
|
49
|
-
function
|
|
50
|
-
return e.investedAmount > 0 ?
|
|
51
|
+
function D(e) {
|
|
52
|
+
return e.investedAmount > 0 ? E(e) / e.investedAmount * 100 : 0;
|
|
51
53
|
}
|
|
52
|
-
function
|
|
53
|
-
let { navigateTo:
|
|
54
|
-
let e =
|
|
54
|
+
function O() {
|
|
55
|
+
let { navigateTo: f, currentUser: O } = e(), { data: k = [], isLoading: A } = i(O?.id || ""), [j, M] = u("all"), N = l(() => j === "all" ? k : k.filter((e) => e.status === j), [j, k]), P = l(() => {
|
|
56
|
+
let e = k.reduce((e, t) => e + t.investedAmount, 0), t = k.reduce((e, t) => e + t.currentValue, 0), n = k.reduce((e, t) => e + t.returns, 0), r = t - e;
|
|
55
57
|
return {
|
|
56
58
|
totalInvested: e,
|
|
57
59
|
currentValue: t,
|
|
58
60
|
totalReturns: n,
|
|
59
61
|
pl: r,
|
|
60
62
|
plPct: e > 0 ? r / e * 100 : 0,
|
|
61
|
-
activeInvestments:
|
|
63
|
+
activeInvestments: k.filter((e) => e.status === "active").length
|
|
62
64
|
};
|
|
63
|
-
}, [
|
|
64
|
-
|
|
65
|
-
return e
|
|
65
|
+
}, [k]), F = l(() => {
|
|
66
|
+
let e = k.reduce((e, t) => (e[t.cartName] = (e[t.cartName] || 0) + t.currentValue, e), {});
|
|
67
|
+
return Object.entries(e).map(([e, t]) => ({
|
|
68
|
+
label: e,
|
|
69
|
+
value: t
|
|
70
|
+
})).sort((e, t) => t.value - e.value);
|
|
71
|
+
}, [k]);
|
|
72
|
+
function I(e) {
|
|
73
|
+
return e === "all" ? k.length : k.filter((t) => t.status === e).length;
|
|
66
74
|
}
|
|
67
|
-
return
|
|
75
|
+
return A ? /* @__PURE__ */ y(n, {
|
|
68
76
|
title: "My Investments",
|
|
69
77
|
description: "Loading your investments...",
|
|
70
|
-
children: /* @__PURE__ */
|
|
78
|
+
children: /* @__PURE__ */ y("div", {
|
|
71
79
|
className: "flex items-center justify-center py-20",
|
|
72
|
-
children: /* @__PURE__ */
|
|
80
|
+
children: /* @__PURE__ */ b("div", {
|
|
73
81
|
className: "text-center",
|
|
74
|
-
children: [/* @__PURE__ */
|
|
82
|
+
children: [/* @__PURE__ */ y("div", { className: "mx-auto mb-4 h-12 w-12 animate-spin rounded-full border-b-2 border-primary" }), /* @__PURE__ */ y("p", {
|
|
75
83
|
className: "text-sm text-text-secondary",
|
|
76
84
|
children: "Loading your investments..."
|
|
77
85
|
})]
|
|
78
86
|
})
|
|
79
87
|
})
|
|
80
|
-
}) : /* @__PURE__ */
|
|
88
|
+
}) : /* @__PURE__ */ b(n, {
|
|
81
89
|
title: "My Investments",
|
|
82
90
|
description: "Track and manage your investment portfolio",
|
|
83
|
-
actions: /* @__PURE__ */
|
|
91
|
+
actions: /* @__PURE__ */ b("button", {
|
|
84
92
|
type: "button",
|
|
85
|
-
onClick: () =>
|
|
93
|
+
onClick: () => f("/investor/opportunities"),
|
|
86
94
|
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",
|
|
87
|
-
children: [/* @__PURE__ */
|
|
95
|
+
children: [/* @__PURE__ */ y(h, { className: "h-4 w-4" }), "New Investment"]
|
|
88
96
|
}),
|
|
89
97
|
children: [
|
|
90
|
-
/* @__PURE__ */
|
|
98
|
+
/* @__PURE__ */ y(S, {
|
|
91
99
|
className: "mb-6",
|
|
92
100
|
children: "Your active holdings in one place. Use this page to track every cart you've backed — what you put in, what it's worth now, the returns you've earned, and which investments are still active. Filter by status to focus, open any investment for the full picture, or start a New Investment when you're ready to grow your portfolio."
|
|
93
101
|
}),
|
|
94
|
-
/* @__PURE__ */
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
102
|
+
/* @__PURE__ */ b(x, { children: [
|
|
103
|
+
/* @__PURE__ */ y("h2", {
|
|
104
|
+
className: "mb-4 text-base font-semibold text-text-primary",
|
|
105
|
+
children: "Portfolio Summary"
|
|
106
|
+
}),
|
|
107
|
+
/* @__PURE__ */ b("div", {
|
|
108
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
109
|
+
children: [
|
|
110
|
+
/* @__PURE__ */ y(s, {
|
|
111
|
+
icon: /* @__PURE__ */ y(v, { className: "h-5 w-5" }),
|
|
112
|
+
value: a(P.totalInvested, { minimumFractionDigits: 0 }),
|
|
113
|
+
label: "Total Invested"
|
|
114
|
+
}),
|
|
115
|
+
/* @__PURE__ */ y(s, {
|
|
116
|
+
icon: /* @__PURE__ */ y(m, { className: "h-5 w-5" }),
|
|
117
|
+
value: a(P.currentValue, { minimumFractionDigits: 0 }),
|
|
118
|
+
label: "Current Value",
|
|
119
|
+
trend: P.pl >= 0 ? "up" : "down",
|
|
120
|
+
trendValue: `${P.plPct >= 0 ? "+" : ""}${P.plPct.toFixed(1)}%`
|
|
121
|
+
}),
|
|
122
|
+
/* @__PURE__ */ y(s, {
|
|
123
|
+
icon: /* @__PURE__ */ y(_, { className: "h-5 w-5" }),
|
|
124
|
+
value: a(P.totalReturns, { minimumFractionDigits: 0 }),
|
|
125
|
+
label: "Total Returns"
|
|
126
|
+
}),
|
|
127
|
+
/* @__PURE__ */ y(s, {
|
|
128
|
+
icon: /* @__PURE__ */ y(d, { className: "h-5 w-5" }),
|
|
129
|
+
value: String(P.activeInvestments),
|
|
130
|
+
label: "Active Investments",
|
|
131
|
+
trend: "neutral"
|
|
132
|
+
})
|
|
133
|
+
]
|
|
134
|
+
}),
|
|
135
|
+
F.length > 1 && /* @__PURE__ */ y("div", {
|
|
136
|
+
className: "mt-4 rounded-lg border border-border-subtle bg-bg-surface p-4",
|
|
137
|
+
children: /* @__PURE__ */ y(c, {
|
|
138
|
+
segments: F,
|
|
139
|
+
label: "Allocation by cart",
|
|
140
|
+
rightLabel: a(P.currentValue, {
|
|
141
|
+
minimumFractionDigits: 0,
|
|
142
|
+
notation: "compact"
|
|
143
|
+
})
|
|
122
144
|
})
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
/* @__PURE__ */
|
|
145
|
+
})
|
|
146
|
+
] }),
|
|
147
|
+
/* @__PURE__ */ y("div", {
|
|
126
148
|
className: "mt-6 rounded-lg border border-border-subtle bg-bg-surface p-4",
|
|
127
|
-
children: /* @__PURE__ */
|
|
149
|
+
children: /* @__PURE__ */ y("div", {
|
|
128
150
|
className: "flex flex-wrap gap-2",
|
|
129
|
-
children:
|
|
151
|
+
children: C.map((e) => /* @__PURE__ */ b("button", {
|
|
130
152
|
type: "button",
|
|
131
|
-
onClick: () =>
|
|
132
|
-
className: t("flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-colors",
|
|
133
|
-
children: [e.label, /* @__PURE__ */
|
|
134
|
-
className: t("rounded-full px-2 py-0.5 text-xs",
|
|
135
|
-
children:
|
|
153
|
+
onClick: () => M(e.key),
|
|
154
|
+
className: t("flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-colors", j === e.key ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-primary hover:bg-bg-sunken/80"),
|
|
155
|
+
children: [e.label, /* @__PURE__ */ y("span", {
|
|
156
|
+
className: t("rounded-full px-2 py-0.5 text-xs", j === e.key ? "bg-primary-foreground/20 text-action-primary-text" : "bg-action-primary-bg/10 text-primary"),
|
|
157
|
+
children: I(e.key)
|
|
136
158
|
})]
|
|
137
159
|
}, e.key))
|
|
138
160
|
})
|
|
139
161
|
}),
|
|
140
|
-
/* @__PURE__ */
|
|
162
|
+
/* @__PURE__ */ y("div", {
|
|
141
163
|
className: "mt-6 space-y-4",
|
|
142
|
-
children:
|
|
143
|
-
let n =
|
|
144
|
-
return /* @__PURE__ */
|
|
164
|
+
children: N.length > 0 ? N.map((e) => {
|
|
165
|
+
let n = E(e), r = D(e);
|
|
166
|
+
return /* @__PURE__ */ b("div", {
|
|
145
167
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-4 sm:p-6",
|
|
146
|
-
children: [/* @__PURE__ */
|
|
168
|
+
children: [/* @__PURE__ */ b("div", {
|
|
147
169
|
className: "block space-y-4 lg:hidden",
|
|
148
170
|
children: [
|
|
149
|
-
/* @__PURE__ */
|
|
171
|
+
/* @__PURE__ */ b("div", {
|
|
150
172
|
className: "flex items-start justify-between",
|
|
151
|
-
children: [/* @__PURE__ */
|
|
173
|
+
children: [/* @__PURE__ */ y("h3", {
|
|
152
174
|
className: "text-lg font-semibold text-text-primary",
|
|
153
175
|
children: e.cartName
|
|
154
|
-
}), /* @__PURE__ */
|
|
155
|
-
className: t("flex items-center gap-1 rounded-full px-3 py-1 text-sm font-medium",
|
|
156
|
-
children: [
|
|
176
|
+
}), /* @__PURE__ */ b("span", {
|
|
177
|
+
className: t("flex items-center gap-1 rounded-full px-3 py-1 text-sm font-medium", w(e.status)),
|
|
178
|
+
children: [T(e.status), /* @__PURE__ */ y("span", {
|
|
157
179
|
className: "capitalize",
|
|
158
180
|
children: e.status
|
|
159
181
|
})]
|
|
160
182
|
})]
|
|
161
183
|
}),
|
|
162
|
-
/* @__PURE__ */
|
|
184
|
+
/* @__PURE__ */ b("div", {
|
|
163
185
|
className: "grid grid-cols-2 gap-4",
|
|
164
186
|
children: [
|
|
165
|
-
/* @__PURE__ */
|
|
187
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
166
188
|
className: "text-sm text-text-secondary",
|
|
167
189
|
children: "Invested"
|
|
168
|
-
}), /* @__PURE__ */
|
|
190
|
+
}), /* @__PURE__ */ y("p", {
|
|
169
191
|
className: "font-semibold text-text-primary",
|
|
170
|
-
children:
|
|
192
|
+
children: a(e.investedAmount, { minimumFractionDigits: 0 })
|
|
171
193
|
})] }),
|
|
172
|
-
/* @__PURE__ */
|
|
194
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
173
195
|
className: "text-sm text-text-secondary",
|
|
174
196
|
children: "Current Value"
|
|
175
|
-
}), /* @__PURE__ */
|
|
197
|
+
}), /* @__PURE__ */ y("p", {
|
|
176
198
|
className: "font-semibold text-text-primary",
|
|
177
|
-
children:
|
|
199
|
+
children: a(e.currentValue, { minimumFractionDigits: 0 })
|
|
178
200
|
})] }),
|
|
179
|
-
/* @__PURE__ */
|
|
201
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
180
202
|
className: "text-sm text-text-secondary",
|
|
181
203
|
children: "P&L"
|
|
182
|
-
}), /* @__PURE__ */
|
|
204
|
+
}), /* @__PURE__ */ b("p", {
|
|
183
205
|
className: t("font-semibold", n >= 0 ? "text-status-success-text" : "text-status-error-text"),
|
|
184
206
|
children: [
|
|
185
207
|
n >= 0 ? "+" : "",
|
|
186
|
-
|
|
208
|
+
a(n, { minimumFractionDigits: 0 }),
|
|
187
209
|
" (",
|
|
188
210
|
r >= 0 ? "+" : "",
|
|
189
211
|
r.toFixed(1),
|
|
190
212
|
"%)"
|
|
191
213
|
]
|
|
192
214
|
})] }),
|
|
193
|
-
/* @__PURE__ */
|
|
215
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
194
216
|
className: "text-sm text-text-secondary",
|
|
195
217
|
children: "Expected Return"
|
|
196
|
-
}), /* @__PURE__ */
|
|
218
|
+
}), /* @__PURE__ */ b("p", {
|
|
197
219
|
className: "font-semibold text-text-primary",
|
|
198
220
|
children: [e.returnsPercentage, "%"]
|
|
199
221
|
})] })
|
|
200
222
|
]
|
|
201
223
|
}),
|
|
202
|
-
/* @__PURE__ */
|
|
224
|
+
/* @__PURE__ */ b("div", {
|
|
203
225
|
className: "flex items-center justify-between border-t border-border-subtle pt-2",
|
|
204
|
-
children: [/* @__PURE__ */
|
|
226
|
+
children: [/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
205
227
|
className: "text-xs text-text-secondary",
|
|
206
228
|
children: "Invested on"
|
|
207
|
-
}), /* @__PURE__ */
|
|
229
|
+
}), /* @__PURE__ */ y("p", {
|
|
208
230
|
className: "text-sm font-medium text-text-primary",
|
|
209
|
-
children:
|
|
231
|
+
children: o(e.investmentDate, {
|
|
210
232
|
hour: void 0,
|
|
211
233
|
minute: void 0
|
|
212
234
|
})
|
|
213
|
-
})] }), /* @__PURE__ */
|
|
235
|
+
})] }), /* @__PURE__ */ b("button", {
|
|
214
236
|
type: "button",
|
|
215
|
-
onClick: () =>
|
|
237
|
+
onClick: () => f(`/investor/investments/${e.id}`),
|
|
216
238
|
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",
|
|
217
|
-
children: [/* @__PURE__ */
|
|
239
|
+
children: [/* @__PURE__ */ y(p, { className: "h-4 w-4" }), "View Details"]
|
|
218
240
|
})]
|
|
219
241
|
})
|
|
220
242
|
]
|
|
221
|
-
}), /* @__PURE__ */
|
|
243
|
+
}), /* @__PURE__ */ b("div", {
|
|
222
244
|
className: "hidden lg:flex lg:items-center lg:justify-between",
|
|
223
|
-
children: [/* @__PURE__ */
|
|
245
|
+
children: [/* @__PURE__ */ b("div", {
|
|
224
246
|
className: "min-w-0 flex-1",
|
|
225
|
-
children: [/* @__PURE__ */
|
|
247
|
+
children: [/* @__PURE__ */ b("div", {
|
|
226
248
|
className: "mb-4 flex items-center justify-between",
|
|
227
|
-
children: [/* @__PURE__ */
|
|
249
|
+
children: [/* @__PURE__ */ y("h3", {
|
|
228
250
|
className: "text-lg font-semibold text-text-primary",
|
|
229
251
|
children: e.cartName
|
|
230
|
-
}), /* @__PURE__ */
|
|
231
|
-
className: t("flex items-center gap-1 rounded-full px-3 py-1 text-sm font-medium",
|
|
232
|
-
children: [
|
|
252
|
+
}), /* @__PURE__ */ b("span", {
|
|
253
|
+
className: t("flex items-center gap-1 rounded-full px-3 py-1 text-sm font-medium", w(e.status)),
|
|
254
|
+
children: [T(e.status), /* @__PURE__ */ y("span", {
|
|
233
255
|
className: "capitalize",
|
|
234
256
|
children: e.status
|
|
235
257
|
})]
|
|
236
258
|
})]
|
|
237
|
-
}), /* @__PURE__ */
|
|
259
|
+
}), /* @__PURE__ */ b("div", {
|
|
238
260
|
className: "grid grid-cols-5 gap-6",
|
|
239
261
|
children: [
|
|
240
|
-
/* @__PURE__ */
|
|
262
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
241
263
|
className: "text-sm text-text-secondary",
|
|
242
264
|
children: "Invested"
|
|
243
|
-
}), /* @__PURE__ */
|
|
265
|
+
}), /* @__PURE__ */ y("p", {
|
|
244
266
|
className: "font-semibold text-text-primary",
|
|
245
|
-
children:
|
|
267
|
+
children: a(e.investedAmount, { minimumFractionDigits: 0 })
|
|
246
268
|
})] }),
|
|
247
|
-
/* @__PURE__ */
|
|
269
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
248
270
|
className: "text-sm text-text-secondary",
|
|
249
271
|
children: "Current Value"
|
|
250
|
-
}), /* @__PURE__ */
|
|
272
|
+
}), /* @__PURE__ */ y("p", {
|
|
251
273
|
className: "font-semibold text-text-primary",
|
|
252
|
-
children:
|
|
274
|
+
children: a(e.currentValue, { minimumFractionDigits: 0 })
|
|
253
275
|
})] }),
|
|
254
|
-
/* @__PURE__ */
|
|
255
|
-
/* @__PURE__ */
|
|
276
|
+
/* @__PURE__ */ b("div", { children: [
|
|
277
|
+
/* @__PURE__ */ y("p", {
|
|
256
278
|
className: "text-sm text-text-secondary",
|
|
257
279
|
children: "P&L"
|
|
258
280
|
}),
|
|
259
|
-
/* @__PURE__ */
|
|
281
|
+
/* @__PURE__ */ b("p", {
|
|
260
282
|
className: t("font-semibold", n >= 0 ? "text-status-success-text" : "text-status-error-text"),
|
|
261
|
-
children: [n >= 0 ? "+" : "",
|
|
283
|
+
children: [n >= 0 ? "+" : "", a(n, { minimumFractionDigits: 0 })]
|
|
262
284
|
}),
|
|
263
|
-
/* @__PURE__ */
|
|
285
|
+
/* @__PURE__ */ b("p", {
|
|
264
286
|
className: t("text-xs", n >= 0 ? "text-status-success-text" : "text-status-error-text"),
|
|
265
287
|
children: [
|
|
266
288
|
"(",
|
|
@@ -270,43 +292,43 @@ function D() {
|
|
|
270
292
|
]
|
|
271
293
|
})
|
|
272
294
|
] }),
|
|
273
|
-
/* @__PURE__ */
|
|
295
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
274
296
|
className: "text-sm text-text-secondary",
|
|
275
297
|
children: "Expected Return"
|
|
276
|
-
}), /* @__PURE__ */
|
|
298
|
+
}), /* @__PURE__ */ b("p", {
|
|
277
299
|
className: "font-semibold text-text-primary",
|
|
278
300
|
children: [e.returnsPercentage, "%"]
|
|
279
301
|
})] }),
|
|
280
|
-
/* @__PURE__ */
|
|
302
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
281
303
|
className: "text-sm text-text-secondary",
|
|
282
304
|
children: "Invested on"
|
|
283
|
-
}), /* @__PURE__ */
|
|
305
|
+
}), /* @__PURE__ */ y("p", {
|
|
284
306
|
className: "font-semibold text-text-primary",
|
|
285
|
-
children:
|
|
307
|
+
children: o(e.investmentDate, {
|
|
286
308
|
hour: void 0,
|
|
287
309
|
minute: void 0
|
|
288
310
|
})
|
|
289
311
|
})] })
|
|
290
312
|
]
|
|
291
313
|
})]
|
|
292
|
-
}), /* @__PURE__ */
|
|
314
|
+
}), /* @__PURE__ */ y("div", {
|
|
293
315
|
className: "ml-6",
|
|
294
|
-
children: /* @__PURE__ */
|
|
316
|
+
children: /* @__PURE__ */ b("button", {
|
|
295
317
|
type: "button",
|
|
296
|
-
onClick: () =>
|
|
318
|
+
onClick: () => f(`/investor/investments/${e.id}`),
|
|
297
319
|
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",
|
|
298
|
-
children: [/* @__PURE__ */
|
|
320
|
+
children: [/* @__PURE__ */ y(p, { className: "h-4 w-4" }), "View Details"]
|
|
299
321
|
})
|
|
300
322
|
})]
|
|
301
323
|
})]
|
|
302
324
|
}, e.id);
|
|
303
|
-
}) : /* @__PURE__ */
|
|
304
|
-
icon: /* @__PURE__ */
|
|
305
|
-
title: `No ${
|
|
306
|
-
description:
|
|
307
|
-
action: /* @__PURE__ */
|
|
325
|
+
}) : /* @__PURE__ */ y(r, {
|
|
326
|
+
icon: /* @__PURE__ */ y(g, { className: "h-12 w-12" }),
|
|
327
|
+
title: `No ${j === "all" ? "" : j} investments found`,
|
|
328
|
+
description: j === "all" ? "You haven't made any investments yet. Start exploring opportunities to grow your wealth." : `You don't have any ${j} investments at the moment.`,
|
|
329
|
+
action: /* @__PURE__ */ y("button", {
|
|
308
330
|
type: "button",
|
|
309
|
-
onClick: () =>
|
|
331
|
+
onClick: () => f("/investor/opportunities"),
|
|
310
332
|
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",
|
|
311
333
|
children: "Explore Investment Opportunities"
|
|
312
334
|
})
|
|
@@ -316,6 +338,6 @@ function D() {
|
|
|
316
338
|
});
|
|
317
339
|
}
|
|
318
340
|
//#endregion
|
|
319
|
-
export {
|
|
341
|
+
export { O as InvestorInvestmentsPage };
|
|
320
342
|
|
|
321
343
|
//# sourceMappingURL=InvestorInvestmentsPage.js.map
|