@burdenoff/microfe-kadaikodi 2026.704.4 → 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 +30 -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 +18 -10
- 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/CartManagementPage.js +558 -718
- package/dist/kadaikodi/pages/admin/CartManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/UserManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/AnalyticsDashboard.js +142 -55
- package/dist/kadaikodi/pages/cart-owner/AnalyticsDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/CartOwnerDashboard.js +129 -164
- package/dist/kadaikodi/pages/cart-owner/CartOwnerDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/InventoryManagementPage.js +379 -361
- package/dist/kadaikodi/pages/cart-owner/InventoryManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/InvestmentListingPage.js +266 -166
- package/dist/kadaikodi/pages/cart-owner/InvestmentListingPage.js.map +1 -1
- 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 +288 -161
- 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.map +1 -1
- package/dist/kadaikodi/pages/common/SettingsPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/BookingDetailsPage.js +17 -34
- 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/DirectServiceBookingPage.js +270 -230
- package/dist/kadaikodi/pages/customer/DirectServiceBookingPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/FavoritesPage.js +149 -412
- 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 +176 -175
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/ReviewsPage.js +295 -438
- package/dist/kadaikodi/pages/customer/ReviewsPage.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.map +1 -1
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.js +424 -448
- 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 +300 -296
- package/dist/kadaikodi/pages/worker/WorkerProfilePage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/WorkerSchedulePage.js +284 -309
- package/dist/kadaikodi/pages/worker/WorkerSchedulePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InvestorAnalyticsPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/investor/InvestorAnalyticsPage.tsx"],"sourcesContent":["/**\n * Investor Analytics Page\n * @module kadaikodi/pages/investor\n *\n * Portfolio performance metrics, best/worst performer, and per-cart performance\n * ranking. Every figure is derived from the investor's real holdings\n * (useInvestments) — no fabricated analytics, trends or recommendations.\n */\n\nimport { useMemo } from 'react';\nimport {\n TrendingUp,\n PieChart,\n BarChart3,\n Target,\n Wallet,\n IndianRupee,\n ArrowUp,\n ArrowDown,\n} from 'lucide-react';\nimport { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { EmptyState } from '../../components/EmptyState';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport { useInvestments } from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency } from '../../utils/formatters';\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function InvestorAnalyticsPage() {\n const { navigateTo, currentUser } = useKadaikodi();\n const { data: investments = [], isLoading } = useInvestments(currentUser?.id || '');\n\n const analytics = useMemo(() => {\n const totalInvested = investments.reduce((s, i) => s + i.investedAmount, 0);\n const totalValue = investments.reduce((s, i) => s + i.currentValue, 0);\n const totalReturns = totalValue - totalInvested;\n const portfolioGrowth = totalInvested > 0 ? (totalReturns / totalInvested) * 100 : 0;\n\n const performanceByCart = investments.map((inv) => {\n const returns = inv.currentValue - inv.investedAmount;\n const roi = inv.investedAmount > 0 ? (returns / inv.investedAmount) * 100 : 0;\n return {\n id: inv.id,\n cartName: inv.cartName,\n investedAmount: inv.investedAmount,\n currentValue: inv.currentValue,\n returns,\n roi,\n };\n });\n\n const averageRoi = performanceByCart.length\n ? performanceByCart.reduce((s, c) => s + c.roi, 0) / performanceByCart.length\n : 0;\n\n const sortedByRoi = [...performanceByCart].sort((a, b) => b.roi - a.roi);\n const bestPerforming = sortedByRoi[0]?.cartName ?? '';\n const worstPerforming = sortedByRoi[sortedByRoi.length - 1]?.cartName ?? '';\n\n return {\n totalInvested,\n totalValue,\n totalReturns,\n portfolioGrowth,\n averageRoi,\n performanceByCart: sortedByRoi,\n bestPerforming,\n worstPerforming,\n };\n }, [investments]);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Investment Analytics\" description=\"Loading analytics...\">\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 analytics data...</p>\n </div>\n </div>\n </PageLayout>\n );\n }\n\n if (investments.length === 0) {\n return (\n <PageLayout\n title=\"Investment Analytics\"\n description=\"Comprehensive analysis of your portfolio performance\"\n >\n <EmptyState\n illustration=\"empty-data\"\n title=\"No analytics yet\"\n description=\"Once you back a cart, your portfolio performance and per-cart analytics will appear here.\"\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 Browse Opportunities\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Investment Analytics\"\n description=\"Comprehensive analysis of your portfolio performance\"\n >\n <PagePurpose className=\"mb-6\">\n The analytical lens on your whole portfolio. Use this page to judge how well your money is\n working — overall value and returns, average ROI — then see your best and worst performers\n so you can rebalance, double down, or trim exposure.\n </PagePurpose>\n\n {/* Key Metrics — the one emphasis zone for this page */}\n <EmphasisPanel>\n <h2 className=\"mb-4 text-base font-semibold text-text-primary\">Portfolio Performance</h2>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <MetricsCard\n featured\n icon={<Wallet className=\"h-5 w-5\" />}\n value={formatCurrency(analytics.totalValue, { minimumFractionDigits: 0 })}\n label=\"Portfolio Value\"\n trend={analytics.portfolioGrowth >= 0 ? 'up' : 'down'}\n trendValue={`${analytics.portfolioGrowth >= 0 ? '+' : ''}${analytics.portfolioGrowth.toFixed(1)}%`}\n />\n <MetricsCard\n icon={<IndianRupee className=\"h-5 w-5\" />}\n value={formatCurrency(analytics.totalInvested, { minimumFractionDigits: 0 })}\n label=\"Total Invested\"\n />\n <MetricsCard\n icon={<TrendingUp className=\"h-5 w-5\" />}\n value={formatCurrency(analytics.totalReturns, { minimumFractionDigits: 0 })}\n label=\"Total Returns\"\n trend={analytics.totalReturns >= 0 ? 'up' : 'down'}\n />\n <MetricsCard\n icon={<Target className=\"h-5 w-5\" />}\n value={`${analytics.averageRoi.toFixed(1)}%`}\n label=\"Average ROI\"\n />\n </div>\n </EmphasisPanel>\n\n {/* Best / Worst Performers */}\n {analytics.performanceByCart.length > 1 && (\n <div className=\"mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div className=\"flex items-center gap-3 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-status-success-bg-subtle\">\n <ArrowUp className=\"h-5 w-5 text-status-success-text\" />\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Best Performing</p>\n <p className=\"text-sm font-semibold text-status-success-text\">\n {analytics.bestPerforming}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-3 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-status-error-bg-subtle\">\n <ArrowDown className=\"h-5 w-5 text-status-error-text\" />\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Worst Performing</p>\n <p className=\"text-sm font-semibold text-text-primary\">{analytics.worstPerforming}</p>\n </div>\n </div>\n </div>\n )}\n\n {/* Performance by Cart */}\n <section className=\"mt-6\">\n <div className=\"mb-4 flex items-center gap-2\">\n <BarChart3 className=\"h-5 w-5 text-text-secondary\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">Performance by Cart</h2>\n </div>\n\n <div className=\"space-y-3\">\n {analytics.performanceByCart.map((cart, index) => (\n <div\n key={cart.id}\n className=\"flex items-center justify-between rounded-lg border border-border-subtle bg-bg-surface p-3\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-action-primary-bg text-xs font-bold text-action-primary-text\">\n {index + 1}\n </div>\n <div>\n <p className=\"text-sm font-medium text-text-primary\">{cart.cartName}</p>\n <p className=\"text-xs text-text-secondary\">\n {formatCurrency(cart.investedAmount, { minimumFractionDigits: 0 })} invested\n </p>\n </div>\n </div>\n <div className=\"text-right\">\n <p\n className={cn(\n 'text-sm font-semibold',\n cart.returns >= 0 ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n {cart.returns >= 0 ? '+' : ''}\n {formatCurrency(cart.returns, { minimumFractionDigits: 0 })}\n </p>\n <p\n className={cn(\n 'text-xs',\n cart.roi >= 0 ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n {cart.roi >= 0 ? '+' : ''}\n {cart.roi.toFixed(1)}% ROI\n </p>\n </div>\n </div>\n ))}\n </div>\n </section>\n\n {/* Quick Navigation */}\n <div className=\"mt-8 flex flex-wrap gap-3\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/portfolio')}\n className=\"flex items-center gap-2 rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <PieChart className=\"h-4 w-4\" />\n View Portfolio\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/opportunities')}\n className=\"flex items-center gap-2 rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Target className=\"h-4 w-4\" />\n Browse Opportunities\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/investments')}\n className=\"flex items-center gap-2 rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Wallet className=\"h-4 w-4\" />\n My Investments\n </button>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InvestorAnalyticsPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/investor/InvestorAnalyticsPage.tsx"],"sourcesContent":["/**\n * Investor Analytics Page\n * @module kadaikodi/pages/investor\n *\n * Portfolio performance analytics rendered with the viz kit — a value-trend\n * area chart, an allocation donut, a value-by-cart bar chart, and a ranked\n * performance list. Every figure is derived from the investor's real holdings\n * (useInvestments) — no fabricated analytics, trends or recommendations.\n */\n\nimport { useMemo } from 'react';\nimport {\n TrendingUp,\n PieChart,\n BarChart3,\n Target,\n Wallet,\n IndianRupee,\n ArrowUp,\n ArrowDown,\n} from 'lucide-react';\nimport { EmphasisPanel, GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { EmptyState } from '../../components/EmptyState';\nimport { AreaChart, BarChart, DonutChart } from '../../components/viz';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport { useInvestments } from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatDate } from '../../utils/formatters';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatRupeeCompact(value: number): string {\n return formatCurrency(value, { minimumFractionDigits: 0, notation: 'compact' });\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function InvestorAnalyticsPage() {\n const { navigateTo, currentUser } = useKadaikodi();\n const { data: investments = [], isLoading } = useInvestments(currentUser?.id || '');\n\n const analytics = useMemo(() => {\n const totalInvested = investments.reduce((s, i) => s + i.investedAmount, 0);\n const totalValue = investments.reduce((s, i) => s + i.currentValue, 0);\n const totalReturns = totalValue - totalInvested;\n const portfolioGrowth = totalInvested > 0 ? (totalReturns / totalInvested) * 100 : 0;\n\n const performanceByCart = investments.map((inv) => {\n const returns = inv.currentValue - inv.investedAmount;\n const roi = inv.investedAmount > 0 ? (returns / inv.investedAmount) * 100 : 0;\n return {\n id: inv.id,\n cartName: inv.cartName,\n investedAmount: inv.investedAmount,\n currentValue: inv.currentValue,\n returns,\n roi,\n };\n });\n\n const averageRoi = performanceByCart.length\n ? performanceByCart.reduce((s, c) => s + c.roi, 0) / performanceByCart.length\n : 0;\n\n const sortedByRoi = [...performanceByCart].sort((a, b) => b.roi - a.roi);\n\n // Value-by-cart (always positive) for the bar chart + allocation donut.\n const valueByCart = [...performanceByCart]\n .sort((a, b) => b.currentValue - a.currentValue)\n .map((c) => ({ label: c.cartName, value: c.currentValue }));\n\n // Portfolio value trend — running total by holding date (real, derived).\n const sortedByDate = [...investments].sort(\n (a, b) => new Date(a.investmentDate).getTime() - new Date(b.investmentDate).getTime()\n );\n let running = 0;\n const valueTrendRaw = sortedByDate.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 const valueTrend =\n valueTrendRaw.length === 1 ? [{ label: 'Start', value: 0 }, ...valueTrendRaw] : valueTrendRaw;\n\n return {\n totalInvested,\n totalValue,\n totalReturns,\n portfolioGrowth,\n averageRoi,\n performanceByCart: sortedByRoi,\n valueByCart,\n valueTrend,\n bestPerforming: sortedByRoi[0]?.cartName ?? '',\n worstPerforming: sortedByRoi[sortedByRoi.length - 1]?.cartName ?? '',\n };\n }, [investments]);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Investment Analytics\" description=\"Loading analytics...\">\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div\n key={i}\n className=\"h-28 animate-pulse rounded-[var(--radius-card)] bg-bg-sunken\"\n />\n ))}\n </div>\n <div className=\"h-72 animate-pulse rounded-[var(--radius-card)] bg-bg-sunken\" />\n </div>\n </PageLayout>\n );\n }\n\n if (investments.length === 0) {\n return (\n <PageLayout\n title=\"Investment Analytics\"\n description=\"Comprehensive analysis of your portfolio performance\"\n >\n <EmptyState\n illustration=\"empty-data\"\n title=\"No analytics yet\"\n description=\"Once you back a cart, your portfolio performance and per-cart analytics will appear here.\"\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-hover transition-colors\"\n >\n Browse Opportunities\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Investment Analytics\"\n description=\"Comprehensive analysis of your portfolio performance\"\n >\n <PagePurpose className=\"mb-6\">\n The analytical lens on your whole portfolio. Judge how well your money is working — overall\n value and returns, average ROI, how value has grown, and where it's concentrated — then\n see your best and worst performers so you can rebalance, double down, or trim exposure.\n </PagePurpose>\n\n {/* Key Metrics — the one emphasis zone for this page */}\n <EmphasisPanel>\n <h2 className=\"mb-4 text-base font-semibold text-text-primary\">Portfolio Performance</h2>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <MetricsCard\n featured\n icon={<Wallet className=\"h-5 w-5\" />}\n value={formatCurrency(analytics.totalValue, { minimumFractionDigits: 0 })}\n label=\"Portfolio Value\"\n trend={analytics.portfolioGrowth >= 0 ? 'up' : 'down'}\n trendValue={`${analytics.portfolioGrowth >= 0 ? '+' : ''}${analytics.portfolioGrowth.toFixed(1)}%`}\n />\n <MetricsCard\n icon={<IndianRupee className=\"h-5 w-5\" />}\n value={formatCurrency(analytics.totalInvested, { minimumFractionDigits: 0 })}\n label=\"Total Invested\"\n />\n <MetricsCard\n icon={<TrendingUp className=\"h-5 w-5\" />}\n value={formatCurrency(analytics.totalReturns, { minimumFractionDigits: 0 })}\n label=\"Total Returns\"\n trend={analytics.totalReturns >= 0 ? 'up' : 'down'}\n />\n <MetricsCard\n icon={<Target className=\"h-5 w-5\" />}\n value={`${analytics.averageRoi.toFixed(1)}%`}\n label=\"Average ROI\"\n />\n </div>\n </EmphasisPanel>\n\n {/* Value trend + allocation */}\n <div className=\"mt-6 grid gap-6 lg:grid-cols-3\">\n <GlassCard treatment=\"plain\" className=\"p-5 sm:p-6 lg:col-span-2\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Portfolio Value Trend</h2>\n <AreaChart\n series={analytics.valueTrend}\n height={240}\n valueFormatter={formatRupeeCompact}\n title=\"Cumulative portfolio value by holding date\"\n />\n </GlassCard>\n <GlassCard treatment=\"plain\" className=\"p-5 sm:p-6\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Allocation</h2>\n <div className=\"flex justify-center\">\n <DonutChart\n segments={analytics.valueByCart}\n size={180}\n centerLabel={formatRupeeCompact(analytics.totalValue)}\n centerCaption=\"total value\"\n valueFormatter={formatRupeeCompact}\n />\n </div>\n </GlassCard>\n </div>\n\n {/* Value by cart bar chart */}\n {analytics.valueByCart.length > 1 && (\n <GlassCard treatment=\"plain\" className=\"mt-6 p-5 sm:p-6\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Value by Cart</h2>\n <BarChart\n series={analytics.valueByCart}\n height={240}\n colorful\n valueFormatter={formatRupeeCompact}\n title=\"Current value held per cart\"\n />\n </GlassCard>\n )}\n\n {/* Best / Worst Performers */}\n {analytics.performanceByCart.length > 1 && (\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div className=\"flex items-center gap-3 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-status-success-bg-subtle\">\n <ArrowUp className=\"h-5 w-5 text-status-success-text\" />\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Best Performing</p>\n <p className=\"text-sm font-semibold text-status-success-text\">\n {analytics.bestPerforming}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-3 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-status-error-bg-subtle\">\n <ArrowDown className=\"h-5 w-5 text-status-error-text\" />\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Worst Performing</p>\n <p className=\"text-sm font-semibold text-text-primary\">{analytics.worstPerforming}</p>\n </div>\n </div>\n </div>\n )}\n\n {/* Performance by Cart */}\n <section className=\"mt-6\">\n <div className=\"mb-4 flex items-center gap-2\">\n <BarChart3 className=\"h-5 w-5 text-text-secondary\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">Performance Ranking</h2>\n </div>\n\n <div className=\"space-y-3\">\n {analytics.performanceByCart.map((cart, index) => (\n <div\n key={cart.id}\n className=\"flex items-center justify-between rounded-lg border border-border-subtle bg-bg-surface p-3\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-action-primary-bg text-xs font-bold text-action-primary-text\">\n {index + 1}\n </div>\n <div>\n <p className=\"text-sm font-medium text-text-primary\">{cart.cartName}</p>\n <p className=\"text-xs text-text-secondary\">\n {formatCurrency(cart.investedAmount, { minimumFractionDigits: 0 })} invested\n </p>\n </div>\n </div>\n <div className=\"text-right\">\n <p\n className={cn(\n 'text-sm font-semibold',\n cart.returns >= 0 ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n {cart.returns >= 0 ? '+' : ''}\n {formatCurrency(cart.returns, { minimumFractionDigits: 0 })}\n </p>\n <p\n className={cn(\n 'text-xs',\n cart.roi >= 0 ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n {cart.roi >= 0 ? '+' : ''}\n {cart.roi.toFixed(1)}% ROI\n </p>\n </div>\n </div>\n ))}\n </div>\n </section>\n\n {/* Quick Navigation */}\n <div className=\"mt-8 flex flex-wrap gap-3\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/portfolio')}\n className=\"flex items-center gap-2 rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <PieChart className=\"h-4 w-4\" />\n View Portfolio\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/opportunities')}\n className=\"flex items-center gap-2 rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Target className=\"h-4 w-4\" />\n Browse Opportunities\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/investments')}\n className=\"flex items-center gap-2 rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Wallet className=\"h-4 w-4\" />\n My Investments\n </button>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,17 +1,19 @@
|
|
|
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 {
|
|
12
|
-
import {
|
|
4
|
+
import { EmptyState as r } from "../../components/EmptyState.js";
|
|
5
|
+
import { useInvestmentOpportunities as i, useInvestments as a } from "../../hooks/useKadaikodiApi.js";
|
|
6
|
+
import { formatCurrency as o, formatDate as s } from "../../utils/formatters.js";
|
|
7
|
+
import { MetricsCard as c } from "../../components/MetricsCard.js";
|
|
8
|
+
import { AreaChart as l } from "../../components/viz/AreaChart.js";
|
|
9
|
+
import "../../components/viz/index.js";
|
|
10
|
+
import { InvestmentCard as u } from "../../components/InvestmentCard.js";
|
|
11
|
+
import { useMemo as d, useState as f } from "react";
|
|
12
|
+
import { Award as p, BarChart3 as m, Eye as h, Filter as g, IndianRupee as _, PieChart as v, Plus as y, Target as b, Wallet as x } from "lucide-react";
|
|
13
|
+
import { jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
14
|
+
import { EmphasisPanel as w, GlassCard as T, NextSteps as E, PagePurpose as D } from "@burdenoff/fe-libs/ui";
|
|
13
15
|
//#region src/kadaikodi/pages/investor/InvestorDashboard.tsx
|
|
14
|
-
function
|
|
16
|
+
function O(e) {
|
|
15
17
|
switch (e) {
|
|
16
18
|
case "active": return "bg-status-success-bg-subtle text-status-success-text";
|
|
17
19
|
case "completed": return "bg-[var(--color-accent-soft)] text-text-primary";
|
|
@@ -19,38 +21,51 @@ function T(e) {
|
|
|
19
21
|
default: return "bg-bg-sunken text-text-secondary";
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
|
-
function
|
|
23
|
-
let { navigateTo:
|
|
24
|
-
let e =
|
|
24
|
+
function k() {
|
|
25
|
+
let { navigateTo: k, currentUser: A } = e(), [j, M] = f("portfolio"), { data: N = [], isLoading: P } = i(), { data: F = [], isLoading: I } = a(A?.id || ""), L = A?.firstName ?? A?.name ?? "Investor", R = N.filter((e) => e.status === "active"), z = d(() => {
|
|
26
|
+
let e = F.reduce((e, t) => e + t.investedAmount, 0), t = F.reduce((e, t) => e + t.currentValue, 0);
|
|
25
27
|
return {
|
|
26
28
|
totalInvested: e,
|
|
27
29
|
currentValue: t,
|
|
28
|
-
totalReturns:
|
|
30
|
+
totalReturns: F.reduce((e, t) => e + t.returns, 0),
|
|
29
31
|
roi: e > 0 ? (t - e) / e * 100 : 0
|
|
30
32
|
};
|
|
31
|
-
}, [
|
|
32
|
-
|
|
33
|
+
}, [F]), B = d(() => {
|
|
34
|
+
let e = [...F].sort((e, t) => new Date(e.investmentDate).getTime() - new Date(t.investmentDate).getTime()), t = 0, n = e.map((e) => (t += e.currentValue, {
|
|
35
|
+
label: s(e.investmentDate, {
|
|
36
|
+
day: void 0,
|
|
37
|
+
hour: void 0,
|
|
38
|
+
minute: void 0
|
|
39
|
+
}),
|
|
40
|
+
value: t
|
|
41
|
+
}));
|
|
42
|
+
return n.length === 1 ? [{
|
|
43
|
+
label: "Start",
|
|
44
|
+
value: 0
|
|
45
|
+
}, ...n] : n;
|
|
46
|
+
}, [F]);
|
|
47
|
+
return P || I ? /* @__PURE__ */ S(n, {
|
|
33
48
|
title: "Investment Dashboard",
|
|
34
49
|
description: "Loading your portfolio...",
|
|
35
|
-
children: /* @__PURE__ */
|
|
50
|
+
children: /* @__PURE__ */ S("div", {
|
|
36
51
|
className: "flex items-center justify-center py-20",
|
|
37
|
-
children: /* @__PURE__ */
|
|
52
|
+
children: /* @__PURE__ */ C("div", {
|
|
38
53
|
className: "text-center",
|
|
39
|
-
children: [/* @__PURE__ */
|
|
54
|
+
children: [/* @__PURE__ */ S("div", { className: "mx-auto mb-4 h-12 w-12 animate-spin rounded-full border-b-2 border-primary" }), /* @__PURE__ */ S("p", {
|
|
40
55
|
className: "text-sm text-text-secondary",
|
|
41
56
|
children: "Loading your portfolio..."
|
|
42
57
|
})]
|
|
43
58
|
})
|
|
44
59
|
})
|
|
45
|
-
}) : /* @__PURE__ */
|
|
46
|
-
title: `Welcome back, ${
|
|
60
|
+
}) : /* @__PURE__ */ C(n, {
|
|
61
|
+
title: `Welcome back, ${L}!`,
|
|
47
62
|
description: "Here's your investment portfolio overview.",
|
|
48
63
|
children: [
|
|
49
|
-
/* @__PURE__ */
|
|
64
|
+
/* @__PURE__ */ S(D, {
|
|
50
65
|
className: "mb-6",
|
|
51
66
|
children: "Track how your money is working across the mobile carts you've backed — see what you've invested, what it's worth today, and the returns flowing in. Review your active investments below or browse new opportunities to diversify."
|
|
52
67
|
}),
|
|
53
|
-
/* @__PURE__ */
|
|
68
|
+
/* @__PURE__ */ S(E, {
|
|
54
69
|
storageKey: "kadaikodi-investor-dashboard",
|
|
55
70
|
className: "mb-6",
|
|
56
71
|
steps: [
|
|
@@ -58,142 +73,142 @@ function E() {
|
|
|
58
73
|
id: "opportunities",
|
|
59
74
|
label: "Explore new opportunities",
|
|
60
75
|
description: "Discover carts seeking funding and their projected returns.",
|
|
61
|
-
onClick: () =>
|
|
76
|
+
onClick: () => k("/investor/opportunities")
|
|
62
77
|
},
|
|
63
78
|
{
|
|
64
79
|
id: "portfolio",
|
|
65
80
|
label: "Review your portfolio",
|
|
66
81
|
description: "Dig into each active investment and its performance.",
|
|
67
|
-
onClick: () =>
|
|
82
|
+
onClick: () => k("/investor/portfolio")
|
|
68
83
|
},
|
|
69
84
|
{
|
|
70
85
|
id: "analytics",
|
|
71
86
|
label: "Analyse your returns",
|
|
72
87
|
description: "See trends and projections across your whole portfolio.",
|
|
73
|
-
onClick: () =>
|
|
88
|
+
onClick: () => k("/investor/analytics")
|
|
74
89
|
}
|
|
75
90
|
]
|
|
76
91
|
}),
|
|
77
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ C(w, { children: [/* @__PURE__ */ S("h2", {
|
|
78
93
|
className: "mb-4 text-lg font-semibold text-text-primary",
|
|
79
94
|
children: "Portfolio Overview"
|
|
80
|
-
}), /* @__PURE__ */
|
|
95
|
+
}), /* @__PURE__ */ C("div", {
|
|
81
96
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-3",
|
|
82
97
|
children: [
|
|
83
|
-
/* @__PURE__ */
|
|
98
|
+
/* @__PURE__ */ S(c, {
|
|
84
99
|
featured: !0,
|
|
85
|
-
icon: /* @__PURE__ */
|
|
86
|
-
value:
|
|
100
|
+
icon: /* @__PURE__ */ S(x, { className: "h-5 w-5" }),
|
|
101
|
+
value: o(z.totalInvested, { minimumFractionDigits: 0 }),
|
|
87
102
|
label: "Total Invested",
|
|
88
103
|
trend: "up",
|
|
89
104
|
trendValue: "Across all businesses"
|
|
90
105
|
}),
|
|
91
|
-
/* @__PURE__ */
|
|
92
|
-
icon: /* @__PURE__ */
|
|
93
|
-
value:
|
|
106
|
+
/* @__PURE__ */ S(c, {
|
|
107
|
+
icon: /* @__PURE__ */ S(_, { className: "h-5 w-5" }),
|
|
108
|
+
value: o(z.currentValue, { minimumFractionDigits: 0 }),
|
|
94
109
|
label: "Current Value",
|
|
95
|
-
trend:
|
|
96
|
-
trendValue: `${
|
|
110
|
+
trend: z.roi >= 0 ? "up" : "down",
|
|
111
|
+
trendValue: `${z.roi >= 0 ? "+" : ""}${z.roi.toFixed(1)}%`
|
|
97
112
|
}),
|
|
98
|
-
/* @__PURE__ */
|
|
99
|
-
icon: /* @__PURE__ */ b
|
|
100
|
-
value:
|
|
113
|
+
/* @__PURE__ */ S(c, {
|
|
114
|
+
icon: /* @__PURE__ */ S(b, { className: "h-5 w-5" }),
|
|
115
|
+
value: o(z.totalReturns, { minimumFractionDigits: 0 }),
|
|
101
116
|
label: "Total Returns"
|
|
102
117
|
})
|
|
103
118
|
]
|
|
104
119
|
})] }),
|
|
105
|
-
/* @__PURE__ */
|
|
120
|
+
/* @__PURE__ */ C("div", {
|
|
106
121
|
className: "mt-8 grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
107
|
-
children: [/* @__PURE__ */
|
|
122
|
+
children: [/* @__PURE__ */ C("div", {
|
|
108
123
|
className: "lg:col-span-2",
|
|
109
124
|
children: [
|
|
110
|
-
/* @__PURE__ */
|
|
125
|
+
/* @__PURE__ */ C("div", {
|
|
111
126
|
className: "mb-6 flex rounded-lg bg-bg-sunken p-1",
|
|
112
|
-
children: [/* @__PURE__ */
|
|
127
|
+
children: [/* @__PURE__ */ S("button", {
|
|
113
128
|
type: "button",
|
|
114
|
-
onClick: () =>
|
|
115
|
-
className: t("flex-1 rounded-md px-4 py-2 text-sm font-medium transition-colors",
|
|
129
|
+
onClick: () => M("portfolio"),
|
|
130
|
+
className: t("flex-1 rounded-md px-4 py-2 text-sm font-medium transition-colors", j === "portfolio" ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-secondary hover:text-text-primary"),
|
|
116
131
|
children: "My Investments"
|
|
117
|
-
}), /* @__PURE__ */
|
|
132
|
+
}), /* @__PURE__ */ S("button", {
|
|
118
133
|
type: "button",
|
|
119
|
-
onClick: () =>
|
|
120
|
-
className: t("flex-1 rounded-md px-4 py-2 text-sm font-medium transition-colors",
|
|
134
|
+
onClick: () => M("opportunities"),
|
|
135
|
+
className: t("flex-1 rounded-md px-4 py-2 text-sm font-medium transition-colors", j === "opportunities" ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-secondary hover:text-text-primary"),
|
|
121
136
|
children: "New Opportunities"
|
|
122
137
|
})]
|
|
123
138
|
}),
|
|
124
|
-
|
|
139
|
+
j === "portfolio" && /* @__PURE__ */ C("div", {
|
|
125
140
|
className: "space-y-4",
|
|
126
|
-
children: [/* @__PURE__ */
|
|
141
|
+
children: [/* @__PURE__ */ C("div", {
|
|
127
142
|
className: "flex items-center justify-between",
|
|
128
|
-
children: [/* @__PURE__ */
|
|
143
|
+
children: [/* @__PURE__ */ S("h3", {
|
|
129
144
|
className: "text-base font-semibold text-text-primary",
|
|
130
145
|
children: "Active Investments"
|
|
131
|
-
}), /* @__PURE__ */
|
|
146
|
+
}), /* @__PURE__ */ C("button", {
|
|
132
147
|
type: "button",
|
|
133
|
-
onClick: () =>
|
|
148
|
+
onClick: () => k("/investor/investments"),
|
|
134
149
|
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",
|
|
135
|
-
children: [/* @__PURE__ */
|
|
150
|
+
children: [/* @__PURE__ */ S(g, { className: "h-4 w-4" }), "View all"]
|
|
136
151
|
})]
|
|
137
|
-
}),
|
|
152
|
+
}), F.length === 0 ? /* @__PURE__ */ S(r, {
|
|
138
153
|
illustration: "empty-data",
|
|
139
154
|
title: "No active investments yet",
|
|
140
155
|
description: "Once you back a cart, your investments will appear here. Browse open opportunities to get started.",
|
|
141
|
-
action: /* @__PURE__ */
|
|
156
|
+
action: /* @__PURE__ */ S("button", {
|
|
142
157
|
type: "button",
|
|
143
|
-
onClick: () =>
|
|
158
|
+
onClick: () => M("opportunities"),
|
|
144
159
|
className: "rounded-lg bg-foreground px-4 py-2 text-sm font-medium text-background hover:opacity-90 transition-opacity",
|
|
145
160
|
children: "Browse opportunities"
|
|
146
161
|
})
|
|
147
|
-
}) :
|
|
162
|
+
}) : F.map((e) => /* @__PURE__ */ C("div", {
|
|
148
163
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-4 shadow-sm hover:shadow-md transition-shadow",
|
|
149
|
-
children: [/* @__PURE__ */
|
|
164
|
+
children: [/* @__PURE__ */ C("div", {
|
|
150
165
|
className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between",
|
|
151
|
-
children: [/* @__PURE__ */
|
|
166
|
+
children: [/* @__PURE__ */ S("div", {
|
|
152
167
|
className: "flex-1",
|
|
153
|
-
children: /* @__PURE__ */
|
|
168
|
+
children: /* @__PURE__ */ C("div", {
|
|
154
169
|
className: "mb-2 flex flex-wrap items-center gap-2",
|
|
155
|
-
children: [/* @__PURE__ */
|
|
170
|
+
children: [/* @__PURE__ */ S("h4", {
|
|
156
171
|
className: "text-base font-semibold text-text-primary",
|
|
157
172
|
children: e.cartName
|
|
158
|
-
}), /* @__PURE__ */
|
|
159
|
-
className: t("rounded-full px-2 py-0.5 text-xs font-medium",
|
|
173
|
+
}), /* @__PURE__ */ S("span", {
|
|
174
|
+
className: t("rounded-full px-2 py-0.5 text-xs font-medium", O(e.status)),
|
|
160
175
|
children: e.status
|
|
161
176
|
})]
|
|
162
177
|
})
|
|
163
|
-
}), /* @__PURE__ */
|
|
178
|
+
}), /* @__PURE__ */ C("button", {
|
|
164
179
|
type: "button",
|
|
165
|
-
onClick: () =>
|
|
180
|
+
onClick: () => k(`/investor/investments/${e.id}`),
|
|
166
181
|
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",
|
|
167
|
-
children: [/* @__PURE__ */
|
|
182
|
+
children: [/* @__PURE__ */ S(h, { className: "h-4 w-4" }), "View Details"]
|
|
168
183
|
})]
|
|
169
|
-
}), /* @__PURE__ */
|
|
184
|
+
}), /* @__PURE__ */ C("div", {
|
|
170
185
|
className: "mt-3 grid grid-cols-2 gap-3 sm:grid-cols-4",
|
|
171
186
|
children: [
|
|
172
|
-
/* @__PURE__ */
|
|
187
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
173
188
|
className: "text-xs text-text-secondary",
|
|
174
189
|
children: "Invested"
|
|
175
|
-
}), /* @__PURE__ */
|
|
190
|
+
}), /* @__PURE__ */ S("p", {
|
|
176
191
|
className: "text-sm font-semibold text-text-primary",
|
|
177
|
-
children:
|
|
192
|
+
children: o(e.investedAmount, { minimumFractionDigits: 0 })
|
|
178
193
|
})] }),
|
|
179
|
-
/* @__PURE__ */
|
|
194
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
180
195
|
className: "text-xs text-text-secondary",
|
|
181
196
|
children: "Current Value"
|
|
182
|
-
}), /* @__PURE__ */
|
|
197
|
+
}), /* @__PURE__ */ S("p", {
|
|
183
198
|
className: "text-sm font-semibold text-status-success-text",
|
|
184
|
-
children:
|
|
199
|
+
children: o(e.currentValue, { minimumFractionDigits: 0 })
|
|
185
200
|
})] }),
|
|
186
|
-
/* @__PURE__ */
|
|
201
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
187
202
|
className: "text-xs text-text-secondary",
|
|
188
203
|
children: "Returns"
|
|
189
|
-
}), /* @__PURE__ */
|
|
204
|
+
}), /* @__PURE__ */ S("p", {
|
|
190
205
|
className: "text-sm font-semibold text-text-primary",
|
|
191
|
-
children:
|
|
206
|
+
children: o(e.returns, { minimumFractionDigits: 0 })
|
|
192
207
|
})] }),
|
|
193
|
-
/* @__PURE__ */
|
|
208
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
194
209
|
className: "text-xs text-text-secondary",
|
|
195
210
|
children: "Expected Return"
|
|
196
|
-
}), /* @__PURE__ */
|
|
211
|
+
}), /* @__PURE__ */ C("p", {
|
|
197
212
|
className: "text-sm font-semibold text-status-success-text",
|
|
198
213
|
children: [e.returnsPercentage, "%"]
|
|
199
214
|
})] })
|
|
@@ -201,26 +216,26 @@ function E() {
|
|
|
201
216
|
})]
|
|
202
217
|
}, e.id))]
|
|
203
218
|
}),
|
|
204
|
-
|
|
219
|
+
j === "opportunities" && /* @__PURE__ */ C("div", {
|
|
205
220
|
className: "space-y-4",
|
|
206
|
-
children: [/* @__PURE__ */
|
|
221
|
+
children: [/* @__PURE__ */ C("div", {
|
|
207
222
|
className: "flex items-center justify-between",
|
|
208
|
-
children: [/* @__PURE__ */
|
|
223
|
+
children: [/* @__PURE__ */ S("h3", {
|
|
209
224
|
className: "text-base font-semibold text-text-primary",
|
|
210
225
|
children: "Investment Opportunities"
|
|
211
|
-
}), /* @__PURE__ */
|
|
226
|
+
}), /* @__PURE__ */ C("button", {
|
|
212
227
|
type: "button",
|
|
213
|
-
onClick: () =>
|
|
228
|
+
onClick: () => k("/investor/opportunities"),
|
|
214
229
|
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",
|
|
215
|
-
children: [/* @__PURE__ */
|
|
230
|
+
children: [/* @__PURE__ */ S(y, { className: "h-4 w-4" }), "Browse All"]
|
|
216
231
|
})]
|
|
217
|
-
}),
|
|
232
|
+
}), R.length === 0 ? /* @__PURE__ */ S(r, {
|
|
218
233
|
illustration: "empty-data",
|
|
219
234
|
title: "No open opportunities right now",
|
|
220
235
|
description: "New carts seeking funding will show up here. Check back soon."
|
|
221
|
-
}) : /* @__PURE__ */
|
|
236
|
+
}) : /* @__PURE__ */ S("div", {
|
|
222
237
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
|
|
223
|
-
children:
|
|
238
|
+
children: R.slice(0, 4).map((e) => /* @__PURE__ */ S(u, {
|
|
224
239
|
id: e.id,
|
|
225
240
|
cartName: e.cartName,
|
|
226
241
|
targetAmount: e.targetAmount,
|
|
@@ -228,54 +243,69 @@ function E() {
|
|
|
228
243
|
expectedReturns: `${e.expectedReturns}%`,
|
|
229
244
|
riskLevel: e.riskLevel,
|
|
230
245
|
status: e.status,
|
|
231
|
-
onClick: (e) =>
|
|
246
|
+
onClick: (e) => k(`/investor/opportunity/${e}`)
|
|
232
247
|
}, e.id))
|
|
233
248
|
})]
|
|
234
249
|
})
|
|
235
250
|
]
|
|
236
|
-
}), /* @__PURE__ */
|
|
251
|
+
}), /* @__PURE__ */ C("div", {
|
|
237
252
|
className: "space-y-6",
|
|
238
|
-
children: /* @__PURE__ */
|
|
253
|
+
children: [F.length > 0 && /* @__PURE__ */ C(T, {
|
|
254
|
+
treatment: "plain",
|
|
255
|
+
className: "p-4 sm:p-5",
|
|
256
|
+
children: [/* @__PURE__ */ S("h3", {
|
|
257
|
+
className: "mb-3 text-base font-semibold text-text-primary",
|
|
258
|
+
children: "Portfolio Value Trend"
|
|
259
|
+
}), /* @__PURE__ */ S(l, {
|
|
260
|
+
series: B,
|
|
261
|
+
height: 160,
|
|
262
|
+
valueFormatter: (e) => o(e, {
|
|
263
|
+
minimumFractionDigits: 0,
|
|
264
|
+
notation: "compact"
|
|
265
|
+
}),
|
|
266
|
+
title: "Cumulative portfolio value by holding date"
|
|
267
|
+
})]
|
|
268
|
+
}), /* @__PURE__ */ C("div", {
|
|
239
269
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
|
|
240
|
-
children: [/* @__PURE__ */
|
|
270
|
+
children: [/* @__PURE__ */ S("h3", {
|
|
241
271
|
className: "mb-3 text-base font-semibold text-text-primary",
|
|
242
272
|
children: "Quick Actions"
|
|
243
|
-
}), /* @__PURE__ */
|
|
273
|
+
}), /* @__PURE__ */ C("div", {
|
|
244
274
|
className: "space-y-2",
|
|
245
275
|
children: [
|
|
246
|
-
/* @__PURE__ */
|
|
276
|
+
/* @__PURE__ */ C("button", {
|
|
247
277
|
type: "button",
|
|
248
|
-
onClick: () =>
|
|
278
|
+
onClick: () => k("/investor/portfolio"),
|
|
249
279
|
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",
|
|
250
|
-
children: [/* @__PURE__ */
|
|
280
|
+
children: [/* @__PURE__ */ S(v, { className: "h-4 w-4 text-text-secondary" }), "View Full Portfolio"]
|
|
251
281
|
}),
|
|
252
|
-
/* @__PURE__ */
|
|
282
|
+
/* @__PURE__ */ C("button", {
|
|
253
283
|
type: "button",
|
|
254
|
-
onClick: () =>
|
|
284
|
+
onClick: () => k("/investor/opportunities"),
|
|
255
285
|
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",
|
|
256
|
-
children: [/* @__PURE__ */ b
|
|
286
|
+
children: [/* @__PURE__ */ S(b, { className: "h-4 w-4 text-text-secondary" }), "Browse Opportunities"]
|
|
257
287
|
}),
|
|
258
|
-
/* @__PURE__ */
|
|
288
|
+
/* @__PURE__ */ C("button", {
|
|
259
289
|
type: "button",
|
|
260
|
-
onClick: () =>
|
|
290
|
+
onClick: () => k("/investor/analytics"),
|
|
261
291
|
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",
|
|
262
|
-
children: [/* @__PURE__ */
|
|
292
|
+
children: [/* @__PURE__ */ S(m, { className: "h-4 w-4 text-text-secondary" }), "Investment Analytics"]
|
|
263
293
|
}),
|
|
264
|
-
/* @__PURE__ */
|
|
294
|
+
/* @__PURE__ */ C("button", {
|
|
265
295
|
type: "button",
|
|
266
|
-
onClick: () =>
|
|
296
|
+
onClick: () => k("/investor/profile"),
|
|
267
297
|
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",
|
|
268
|
-
children: [/* @__PURE__ */
|
|
298
|
+
children: [/* @__PURE__ */ S(p, { className: "h-4 w-4 text-text-secondary" }), "View Profile"]
|
|
269
299
|
})
|
|
270
300
|
]
|
|
271
301
|
})]
|
|
272
|
-
})
|
|
302
|
+
})]
|
|
273
303
|
})]
|
|
274
304
|
})
|
|
275
305
|
]
|
|
276
306
|
});
|
|
277
307
|
}
|
|
278
308
|
//#endregion
|
|
279
|
-
export {
|
|
309
|
+
export { k as InvestorDashboard };
|
|
280
310
|
|
|
281
311
|
//# sourceMappingURL=InvestorDashboard.js.map
|