@burdenoff/microfe-kadaikodi 2026.704.2 → 2026.704.3
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/pages/admin/AdminAnalyticsPage.js +45 -107
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminDashboard.js +30 -32
- package/dist/kadaikodi/pages/admin/AdminDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminFinancialPage.js +137 -120
- package/dist/kadaikodi/pages/admin/AdminFinancialPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminOrdersPage.js +2 -2
- package/dist/kadaikodi/pages/admin/AdminOrdersPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/UserManagementPage.js +5 -5
- package/dist/kadaikodi/pages/admin/UserManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/AnalyticsDashboard.js +2 -2
- package/dist/kadaikodi/pages/cart-owner/AnalyticsDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CustomerDashboard.js +1 -1
- package/dist/kadaikodi/pages/customer/CustomerDashboard.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminDashboard.js","names":[],"sources":["../../../../src/kadaikodi/pages/admin/AdminDashboard.tsx"],"sourcesContent":["/**\n * Admin Dashboard Page\n * @module kadaikodi/pages/admin\n *\n * Platform control room wired to the live Kadaikodi backend. Every stat,\n * activity row and breakdown is derived from real hook data\n * (useDashboardStats + useProviders + useOrders + useAdminAnalytics).\n * Where a metric has no honest backend source it is omitted rather than faked.\n */\n\nimport { useMemo } from 'react';\nimport {\n Users,\n Store,\n ShoppingBag,\n IndianRupee,\n Activity,\n ArrowRight,\n Star,\n Settings,\n BarChart3,\n Award,\n FileText,\n AlertTriangle,\n Loader2,\n} from 'lucide-react';\nimport { CTAOverflowMenu, EmphasisPanel, PagePurpose, NextSteps } 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 {\n useDashboardStats,\n useProviders,\n useOrders,\n useAdminAnalytics,\n} from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatRelativeTime } from '../../utils/formatters';\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport function AdminDashboard() {\n const { navigateTo, currentUser } = useKadaikodi();\n const firstName = currentUser?.firstName ?? currentUser?.name ?? 'Admin';\n\n const { data: stats, isLoading: statsLoading } = useDashboardStats();\n const { data: providers = [], isLoading: providersLoading } = useProviders();\n const { data: orders = [], isLoading: ordersLoading } = useOrders({});\n const { data: analytics } = useAdminAnalytics();\n\n const isLoading = statsLoading || providersLoading || ordersLoading;\n\n const fmtCur = (amount: number) => formatCurrency(amount, { minimumFractionDigits: 0 });\n\n // Carts awaiting activation/verification — real derivation from provider status.\n const pendingCarts = useMemo(() => providers.filter((p) => !p.isOpen).length, [providers]);\n\n // Most recent orders across the platform → honest \"recent activity\" feed.\n const recentOrders = useMemo(\n () =>\n [...orders]\n .sort((a, b) => new Date(b.orderDate).getTime() - new Date(a.orderDate).getTime())\n .slice(0, 6),\n [orders]\n );\n\n const orderStatusBadge = (status: string) => {\n if (status === 'delivered') return 'bg-status-success-bg-subtle text-status-success-text';\n if (status === 'cancelled') return 'bg-status-error-bg-subtle text-status-error-text';\n return 'bg-status-warning-bg-subtle text-status-warning-text';\n };\n\n /* ---- Loading state ---- */\n if (isLoading) {\n return (\n <PageLayout title=\"Admin Dashboard\" description=\"Loading...\">\n <div className=\"flex flex-col items-center justify-center py-20\">\n <Loader2 className=\"h-10 w-10 animate-spin text-text-secondary mb-4\" />\n <p className=\"text-text-secondary\">Loading admin dashboard...</p>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Admin Dashboard\"\n description={`Welcome, ${firstName}! Monitor and manage the platform.`}\n actions={\n pendingCarts > 0 ? (\n <div className=\"flex items-center gap-2 rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-3 py-2\">\n <AlertTriangle className=\"h-4 w-4 text-status-error-text\" />\n <span className=\"text-sm font-medium text-status-error-text\">\n {pendingCarts} carts awaiting review\n </span>\n </div>\n ) : undefined\n }\n >\n <PagePurpose className=\"mb-6\">\n The control room for the whole Kadaikodi marketplace — approve new carts, keep an eye on\n users, orders and platform revenue, and act on anything that needs attention. Clear pending\n approvals first, then review platform health below.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"kadaikodi-admin-dashboard\"\n className=\"mb-6\"\n steps={[\n {\n id: 'approvals',\n label: 'Review pending cart approvals',\n description: 'Vet and approve new carts waiting to go live.',\n onClick: () => navigateTo('/admin/carts'),\n done: pendingCarts === 0,\n },\n {\n id: 'users',\n label: 'Manage users',\n description: 'Review accounts, roles and access across the platform.',\n onClick: () => navigateTo('/admin/users'),\n },\n {\n id: 'financial',\n label: 'Check financial health',\n description: 'Track revenue, commission and payouts.',\n onClick: () => navigateTo('/admin/financial'),\n },\n ]}\n />\n\n {/* Hero — the one emphasis zone: pending approvals + primary action + overflow */}\n <EmphasisPanel className=\"mb-8\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Quick Actions</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {pendingCarts > 0\n ? `${pendingCarts} carts awaiting your review.`\n : 'All caught up — nothing pending review.'}\n </p>\n </div>\n <CTAOverflowMenu\n primary={{\n label: `Review Carts${pendingCarts > 0 ? ` (${pendingCarts})` : ''}`,\n icon: <Store className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/carts'),\n }}\n actions={[\n {\n label: 'Manage Carts',\n icon: <Store className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/carts'),\n },\n {\n label: 'User Management',\n icon: <Users className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/users'),\n },\n {\n label: 'Order Management',\n icon: <ShoppingBag className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/orders'),\n },\n {\n label: 'Financial Analytics',\n icon: <IndianRupee className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/financial'),\n },\n {\n label: 'Analytics',\n icon: <BarChart3 className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/analytics'),\n },\n {\n label: 'Settings',\n icon: <Settings className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/settings'),\n },\n {\n label: 'Reports',\n icon: <FileText className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/analytics'),\n },\n ]}\n />\n </div>\n </EmphasisPanel>\n\n {/* Platform Overview — real dashboard stats */}\n {stats && (\n <div className=\"mb-8\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-4\">Platform Overview</h2>\n <div className=\"grid grid-cols-2 lg:grid-cols-4 gap-4\">\n <MetricsCard\n icon={<Users className=\"h-5 w-5\" />}\n value={stats.activeCustomers.toLocaleString('en-IN')}\n label=\"Active Customers\"\n />\n <MetricsCard\n icon={<Store className=\"h-5 w-5\" />}\n value={stats.activeProviders.toLocaleString('en-IN')}\n label=\"Active Carts\"\n />\n <MetricsCard\n icon={<ShoppingBag className=\"h-5 w-5\" />}\n value={stats.totalOrders.toLocaleString('en-IN')}\n label=\"Total Orders\"\n />\n <MetricsCard\n featured\n icon={<IndianRupee className=\"h-5 w-5\" />}\n value={fmtCur(stats.totalRevenue)}\n label=\"Total Revenue\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 lg:grid-cols-4 gap-4 mt-4\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <p className=\"text-xs text-text-secondary\">Total Carts</p>\n <p className=\"text-xl font-bold text-text-primary\">\n {providers.length.toLocaleString('en-IN')}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <p className=\"text-xs text-text-secondary\">Pending Cart Approvals</p>\n <p className=\"text-xl font-bold text-status-error-text\">\n {pendingCarts.toLocaleString('en-IN')}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <p className=\"text-xs text-text-secondary\">Pending Orders</p>\n <p className=\"text-xl font-bold text-status-warning-text\">\n {stats.pendingOrders.toLocaleString('en-IN')}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <p className=\"text-xs text-text-secondary\">Average Rating</p>\n <p className=\"text-xl font-bold text-text-primary flex items-center gap-1\">\n <Star className=\"h-4 w-4 fill-status-warning-text text-status-warning-text\" />\n {stats.avgRating > 0 ? stats.avgRating.toFixed(1) : '—'}\n </p>\n </div>\n </div>\n </div>\n )}\n\n {/* Recent Activity — real recent orders */}\n <div className=\"mb-8\">\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Recent Orders</h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('/admin/orders')}\n className=\"flex items-center gap-1 text-sm font-medium text-text-secondary hover:text-text-primary transition-colors\"\n >\n View all orders\n <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n {recentOrders.length > 0 ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface divide-y divide-border\">\n {recentOrders.map((order) => (\n <div key={order.id} className=\"flex items-start gap-3 px-4 py-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-bg-sunken mt-0.5 text-text-secondary\">\n <ShoppingBag className=\"h-4 w-4\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex flex-col sm:flex-row sm:items-center justify-between gap-2\">\n <p className=\"text-sm font-medium text-text-primary\">\n Order from {order.cartName}\n </p>\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize w-fit',\n orderStatusBadge(order.status)\n )}\n >\n {order.status.replace(/_/g, ' ')}\n </span>\n </div>\n <div className=\"flex flex-wrap items-center mt-1 text-xs text-text-secondary gap-3\">\n <span>{formatRelativeTime(order.orderDate)}</span>\n <span className=\"flex items-center gap-1\">\n <IndianRupee className=\"h-3 w-3\" />\n {order.total.toLocaleString('en-IN')}\n </span>\n </div>\n </div>\n </div>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No orders yet\"\n description=\"Orders placed across the platform will appear here as they come in.\"\n />\n )}\n </div>\n\n {/* Revenue by Category & Top Carts — real admin analytics */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-6\">\n <div className=\"flex items-center gap-2 mb-4\">\n <BarChart3 className=\"h-5 w-5 text-text-secondary\" />\n <h3 className=\"text-lg font-semibold text-text-primary\">Revenue by Category</h3>\n </div>\n {analytics && analytics.revenueByCategory.length > 0 ? (\n <div className=\"space-y-3\">\n {analytics.revenueByCategory.map((row) => (\n <div\n key={row.category}\n className=\"flex items-center justify-between rounded-lg bg-bg-sunken/50 p-3\"\n >\n <div>\n <p className=\"text-sm font-medium text-text-primary capitalize\">\n {row.category}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {row.orders.toLocaleString('en-IN')} orders\n </p>\n </div>\n <p className=\"text-sm font-semibold text-text-primary\">{fmtCur(row.revenue)}</p>\n </div>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n Category revenue will appear here once orders are recorded.\n </p>\n )}\n </div>\n\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-6\">\n <div className=\"flex items-center gap-2 mb-4\">\n <Award className=\"h-5 w-5 text-text-secondary\" />\n <h3 className=\"text-lg font-semibold text-text-primary\">Top Carts</h3>\n </div>\n {analytics && analytics.topProviders.length > 0 ? (\n <div className=\"space-y-3\">\n {analytics.topProviders.map((cart) => (\n <div\n key={cart.id}\n className=\"flex items-center justify-between rounded-lg bg-bg-sunken/50 p-3\"\n >\n <div>\n <p className=\"text-sm font-medium text-text-primary\">{cart.name}</p>\n <p className=\"text-xs text-text-secondary flex items-center gap-1\">\n <Star className=\"h-3 w-3 fill-status-warning-text text-status-warning-text\" />\n {cart.rating.toFixed(1)} · {cart.orders.toLocaleString('en-IN')} orders\n </p>\n </div>\n <p className=\"text-sm font-semibold text-text-primary\">{fmtCur(cart.revenue)}</p>\n </div>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n Top-performing carts will be ranked here once orders start flowing.\n </p>\n )}\n </div>\n </div>\n\n {/* Management Links */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {[\n {\n icon: Store,\n label: 'Cart Management',\n desc: 'Approve, manage, and monitor carts',\n path: '/admin/carts',\n },\n {\n icon: Users,\n label: 'User Management',\n desc: 'Manage users and permissions',\n path: '/admin/users',\n },\n {\n icon: BarChart3,\n label: 'Analytics & Reports',\n desc: 'View detailed platform analytics',\n path: '/admin/analytics',\n },\n {\n icon: IndianRupee,\n label: 'Financial Analytics',\n desc: 'View revenue, investments, and financial metrics',\n path: '/admin/financial',\n },\n {\n icon: Activity,\n label: 'Order Management',\n desc: 'Handle orders and customer issues',\n path: '/admin/orders',\n },\n {\n icon: Settings,\n label: 'Platform Settings',\n desc: 'Configure platform-wide settings',\n path: '/admin/settings',\n },\n ].map((link) => {\n const LinkIcon = link.icon;\n return (\n <button\n key={link.label}\n type=\"button\"\n onClick={() => navigateTo(link.path)}\n className={cn(\n 'flex items-center gap-4 rounded-lg border border-border-subtle bg-bg-surface p-4 sm:p-6 text-left shadow-sm transition-all',\n 'hover:bg-accent hover:shadow-md'\n )}\n >\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-text-secondary\">\n <LinkIcon className=\"h-5 w-5\" />\n </div>\n <div className=\"min-w-0\">\n <h3 className=\"font-semibold text-text-primary text-sm sm:text-base\">\n {link.label}\n </h3>\n <p className=\"text-xs sm:text-sm text-text-secondary\">{link.desc}</p>\n </div>\n </button>\n );\n })}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AdminDashboard.js","names":[],"sources":["../../../../src/kadaikodi/pages/admin/AdminDashboard.tsx"],"sourcesContent":["/**\n * Admin Dashboard Page\n * @module kadaikodi/pages/admin\n *\n * Platform control room wired to the live Kadaikodi backend. Every stat,\n * activity row and breakdown is derived from real hook data\n * (useDashboardStats + useProviders + useOrders + useAdminAnalytics).\n * Where a metric has no honest backend source it is omitted rather than faked.\n */\n\nimport { useMemo } from 'react';\nimport {\n Users,\n Store,\n ShoppingBag,\n IndianRupee,\n Activity,\n ArrowRight,\n Star,\n Settings,\n BarChart3,\n Award,\n FileText,\n AlertTriangle,\n Loader2,\n} from 'lucide-react';\nimport { CTAOverflowMenu, EmphasisPanel, PagePurpose, NextSteps } 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 {\n useDashboardStats,\n useProviders,\n useOrders,\n useAdminAnalytics,\n} from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatRelativeTime } from '../../utils/formatters';\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport function AdminDashboard() {\n const { navigateTo, currentUser } = useKadaikodi();\n const firstName = currentUser?.firstName ?? currentUser?.name ?? 'Admin';\n\n const { data: stats, isLoading: statsLoading } = useDashboardStats();\n const { data: providers = [], isLoading: providersLoading } = useProviders();\n const { data: orders = [], isLoading: ordersLoading } = useOrders({});\n const { data: analytics } = useAdminAnalytics();\n\n const isLoading = statsLoading || providersLoading || ordersLoading;\n\n const fmtCur = (amount: number) => formatCurrency(amount, { minimumFractionDigits: 0 });\n\n // Carts awaiting activation/verification — real derivation from provider status.\n const pendingCarts = useMemo(() => providers.filter((p) => !p.isOpen).length, [providers]);\n\n // Most recent orders across the platform → honest \"recent activity\" feed.\n const recentOrders = useMemo(\n () =>\n [...orders]\n .sort((a, b) => new Date(b.orderDate).getTime() - new Date(a.orderDate).getTime())\n .slice(0, 6),\n [orders]\n );\n\n // Admin analytics — only fields the backend actually returns.\n const prettyCategory = (c: string) => c.replace(/_/g, ' ').toLowerCase();\n const topProviders = analytics?.topProviders ?? [];\n const categoryRows = Object.entries(analytics?.categoryDistribution ?? {}).sort(\n (a, b) => b[1] - a[1]\n );\n\n const orderStatusBadge = (status: string) => {\n if (status === 'delivered') return 'bg-status-success-bg-subtle text-status-success-text';\n if (status === 'cancelled') return 'bg-status-error-bg-subtle text-status-error-text';\n return 'bg-status-warning-bg-subtle text-status-warning-text';\n };\n\n /* ---- Loading state ---- */\n if (isLoading) {\n return (\n <PageLayout title=\"Admin Dashboard\" description=\"Loading...\">\n <div className=\"flex flex-col items-center justify-center py-20\">\n <Loader2 className=\"h-10 w-10 animate-spin text-text-secondary mb-4\" />\n <p className=\"text-text-secondary\">Loading admin dashboard...</p>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Admin Dashboard\"\n description={`Welcome, ${firstName}! Monitor and manage the platform.`}\n actions={\n pendingCarts > 0 ? (\n <div className=\"flex items-center gap-2 rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-3 py-2\">\n <AlertTriangle className=\"h-4 w-4 text-status-error-text\" />\n <span className=\"text-sm font-medium text-status-error-text\">\n {pendingCarts} carts awaiting review\n </span>\n </div>\n ) : undefined\n }\n >\n <PagePurpose className=\"mb-6\">\n The control room for the whole Kadaikodi marketplace — approve new carts, keep an eye on\n users, orders and platform revenue, and act on anything that needs attention. Clear pending\n approvals first, then review platform health below.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"kadaikodi-admin-dashboard\"\n className=\"mb-6\"\n steps={[\n {\n id: 'approvals',\n label: 'Review pending cart approvals',\n description: 'Vet and approve new carts waiting to go live.',\n onClick: () => navigateTo('/admin/carts'),\n done: pendingCarts === 0,\n },\n {\n id: 'users',\n label: 'Manage users',\n description: 'Review accounts, roles and access across the platform.',\n onClick: () => navigateTo('/admin/users'),\n },\n {\n id: 'financial',\n label: 'Check financial health',\n description: 'Track revenue, commission and payouts.',\n onClick: () => navigateTo('/admin/financial'),\n },\n ]}\n />\n\n {/* Hero — the one emphasis zone: pending approvals + primary action + overflow */}\n <EmphasisPanel className=\"mb-8\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Quick Actions</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {pendingCarts > 0\n ? `${pendingCarts} carts awaiting your review.`\n : 'All caught up — nothing pending review.'}\n </p>\n </div>\n <CTAOverflowMenu\n primary={{\n label: `Review Carts${pendingCarts > 0 ? ` (${pendingCarts})` : ''}`,\n icon: <Store className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/carts'),\n }}\n actions={[\n {\n label: 'Manage Carts',\n icon: <Store className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/carts'),\n },\n {\n label: 'User Management',\n icon: <Users className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/users'),\n },\n {\n label: 'Order Management',\n icon: <ShoppingBag className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/orders'),\n },\n {\n label: 'Financial Analytics',\n icon: <IndianRupee className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/financial'),\n },\n {\n label: 'Analytics',\n icon: <BarChart3 className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/analytics'),\n },\n {\n label: 'Settings',\n icon: <Settings className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/settings'),\n },\n {\n label: 'Reports',\n icon: <FileText className=\"h-4 w-4\" />,\n onSelect: () => navigateTo('/admin/analytics'),\n },\n ]}\n />\n </div>\n </EmphasisPanel>\n\n {/* Platform Overview — real dashboard stats */}\n {stats && (\n <div className=\"mb-8\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-4\">Platform Overview</h2>\n <div className=\"grid grid-cols-2 lg:grid-cols-4 gap-4\">\n <MetricsCard\n icon={<Users className=\"h-5 w-5\" />}\n value={(stats.activeCustomers ?? 0).toLocaleString('en-IN')}\n label=\"Active Customers\"\n />\n <MetricsCard\n icon={<Store className=\"h-5 w-5\" />}\n value={(stats.activeProviders ?? 0).toLocaleString('en-IN')}\n label=\"Active Carts\"\n />\n <MetricsCard\n icon={<ShoppingBag className=\"h-5 w-5\" />}\n value={(stats.totalOrders ?? 0).toLocaleString('en-IN')}\n label=\"Total Orders\"\n />\n <MetricsCard\n featured\n icon={<IndianRupee className=\"h-5 w-5\" />}\n value={fmtCur(stats.totalRevenue)}\n label=\"Total Revenue\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 lg:grid-cols-4 gap-4 mt-4\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <p className=\"text-xs text-text-secondary\">Total Carts</p>\n <p className=\"text-xl font-bold text-text-primary\">\n {providers.length.toLocaleString('en-IN')}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <p className=\"text-xs text-text-secondary\">Pending Cart Approvals</p>\n <p className=\"text-xl font-bold text-status-error-text\">\n {pendingCarts.toLocaleString('en-IN')}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <p className=\"text-xs text-text-secondary\">Pending Orders</p>\n <p className=\"text-xl font-bold text-status-warning-text\">\n {(stats.pendingOrders ?? 0).toLocaleString('en-IN')}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <p className=\"text-xs text-text-secondary\">Average Rating</p>\n <p className=\"text-xl font-bold text-text-primary flex items-center gap-1\">\n <Star className=\"h-4 w-4 fill-status-warning-text text-status-warning-text\" />\n {stats.avgRating > 0 ? stats.avgRating.toFixed(1) : '—'}\n </p>\n </div>\n </div>\n </div>\n )}\n\n {/* Recent Activity — real recent orders */}\n <div className=\"mb-8\">\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Recent Orders</h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('/admin/orders')}\n className=\"flex items-center gap-1 text-sm font-medium text-text-secondary hover:text-text-primary transition-colors\"\n >\n View all orders\n <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n {recentOrders.length > 0 ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface divide-y divide-border\">\n {recentOrders.map((order) => (\n <div key={order.id} className=\"flex items-start gap-3 px-4 py-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-bg-sunken mt-0.5 text-text-secondary\">\n <ShoppingBag className=\"h-4 w-4\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex flex-col sm:flex-row sm:items-center justify-between gap-2\">\n <p className=\"text-sm font-medium text-text-primary\">\n Order from {order.cartName}\n </p>\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize w-fit',\n orderStatusBadge(order.status)\n )}\n >\n {order.status.replace(/_/g, ' ')}\n </span>\n </div>\n <div className=\"flex flex-wrap items-center mt-1 text-xs text-text-secondary gap-3\">\n <span>{formatRelativeTime(order.orderDate)}</span>\n <span className=\"flex items-center gap-1\">\n <IndianRupee className=\"h-3 w-3\" />\n {(order.total ?? 0).toLocaleString('en-IN')}\n </span>\n </div>\n </div>\n </div>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No orders yet\"\n description=\"Orders placed across the platform will appear here as they come in.\"\n />\n )}\n </div>\n\n {/* Carts by Category & Top Carts — real admin analytics */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-6\">\n <div className=\"flex items-center gap-2 mb-4\">\n <BarChart3 className=\"h-5 w-5 text-text-secondary\" />\n <h3 className=\"text-lg font-semibold text-text-primary\">Carts by Category</h3>\n </div>\n {categoryRows.length > 0 ? (\n <div className=\"space-y-3\">\n {categoryRows.map(([category, count]) => (\n <div\n key={category}\n className=\"flex items-center justify-between rounded-lg bg-bg-sunken/50 p-3\"\n >\n <p className=\"text-sm font-medium text-text-primary capitalize\">\n {prettyCategory(category)}\n </p>\n <p className=\"text-sm font-semibold text-text-primary\">\n {(count ?? 0).toLocaleString('en-IN')}{' '}\n <span className=\"text-xs font-normal text-text-secondary\">\n {count === 1 ? 'cart' : 'carts'}\n </span>\n </p>\n </div>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n Cart categories will appear here as carts are onboarded.\n </p>\n )}\n </div>\n\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-6\">\n <div className=\"flex items-center gap-2 mb-4\">\n <Award className=\"h-5 w-5 text-text-secondary\" />\n <h3 className=\"text-lg font-semibold text-text-primary\">Top Carts</h3>\n </div>\n {topProviders.length > 0 ? (\n <div className=\"space-y-3\">\n {topProviders.map((cart) => (\n <div\n key={cart.id}\n className=\"flex items-center justify-between rounded-lg bg-bg-sunken/50 p-3\"\n >\n <div>\n <p className=\"text-sm font-medium text-text-primary\">{cart.name}</p>\n <p className=\"text-xs text-text-secondary capitalize\">\n {prettyCategory(cart.category)}\n </p>\n </div>\n <p className=\"text-sm font-semibold text-text-primary flex items-center gap-1\">\n <Star className=\"h-3.5 w-3.5 fill-status-warning-text text-status-warning-text\" />\n {(cart.rating ?? 0).toFixed(1)}\n </p>\n </div>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n Top-performing carts will be ranked here once orders start flowing.\n </p>\n )}\n </div>\n </div>\n\n {/* Management Links */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {[\n {\n icon: Store,\n label: 'Cart Management',\n desc: 'Approve, manage, and monitor carts',\n path: '/admin/carts',\n },\n {\n icon: Users,\n label: 'User Management',\n desc: 'Manage users and permissions',\n path: '/admin/users',\n },\n {\n icon: BarChart3,\n label: 'Analytics & Reports',\n desc: 'View detailed platform analytics',\n path: '/admin/analytics',\n },\n {\n icon: IndianRupee,\n label: 'Financial Analytics',\n desc: 'View revenue, investments, and financial metrics',\n path: '/admin/financial',\n },\n {\n icon: Activity,\n label: 'Order Management',\n desc: 'Handle orders and customer issues',\n path: '/admin/orders',\n },\n {\n icon: Settings,\n label: 'Platform Settings',\n desc: 'Configure platform-wide settings',\n path: '/admin/settings',\n },\n ].map((link) => {\n const LinkIcon = link.icon;\n return (\n <button\n key={link.label}\n type=\"button\"\n onClick={() => navigateTo(link.path)}\n className={cn(\n 'flex items-center gap-4 rounded-lg border border-border-subtle bg-bg-surface p-4 sm:p-6 text-left shadow-sm transition-all',\n 'hover:bg-accent hover:shadow-md'\n )}\n >\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-text-secondary\">\n <LinkIcon className=\"h-5 w-5\" />\n </div>\n <div className=\"min-w-0\">\n <h3 className=\"font-semibold text-text-primary text-sm sm:text-base\">\n {link.label}\n </h3>\n <p className=\"text-xs sm:text-sm text-text-secondary\">{link.desc}</p>\n </div>\n </button>\n );\n })}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -5,271 +5,288 @@ import { EmptyState as r } from "../../components/EmptyState.js";
|
|
|
5
5
|
import { useAdminAnalytics as i, useDashboardStats as a } from "../../hooks/useKadaikodiApi.js";
|
|
6
6
|
import { formatCurrency as o } from "../../utils/formatters.js";
|
|
7
7
|
import { useMemo as s } from "react";
|
|
8
|
-
import { ArrowLeft as c, Award as l, BarChart3 as u, Calendar as d, Clock as f, Download as p, IndianRupee as m, Loader2 as h, ShoppingBag as g, ShoppingCart as _,
|
|
9
|
-
import { jsx as
|
|
10
|
-
import { EmphasisPanel as
|
|
8
|
+
import { ArrowLeft as c, Award as l, BarChart3 as u, Calendar as d, Clock as f, Download as p, IndianRupee as m, Loader2 as h, ShoppingBag as g, ShoppingCart as _, Star as v, Store as y, TrendingUp as b } from "lucide-react";
|
|
9
|
+
import { jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
10
|
+
import { EmphasisPanel as C, PagePurpose as w } from "@burdenoff/fe-libs/ui";
|
|
11
11
|
//#region src/kadaikodi/pages/admin/AdminFinancialPage.tsx
|
|
12
|
-
function
|
|
13
|
-
let { navigateTo:
|
|
14
|
-
let e =
|
|
15
|
-
return e.map((e) => ({
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
function T() {
|
|
13
|
+
let { navigateTo: T } = e(), { data: E, isLoading: D } = a(), { data: O, isLoading: k } = i(), A = D || k, j = (e) => o(e, { minimumFractionDigits: 0 }), M = s(() => E && E.totalOrders > 0 ? E.totalRevenue / E.totalOrders : 0, [E]), N = s(() => {
|
|
14
|
+
let e = Object.entries(O?.categoryDistribution ?? {}), t = e.reduce((e, [, t]) => e + t, 0);
|
|
15
|
+
return e.map(([e, n]) => ({
|
|
16
|
+
category: e,
|
|
17
|
+
count: n,
|
|
18
|
+
percentage: t > 0 ? n / t * 100 : 0
|
|
19
|
+
})).sort((e, t) => t.count - e.count);
|
|
20
|
+
}, [O]), P = O?.topProviders ?? [], F = O?.orderTrends ?? [], I = (e) => e.replace(/_/g, " ").toLowerCase(), L = (e) => e === "delivered" ? "bg-status-success-bg-subtle text-status-success-text" : e === "cancelled" ? "bg-status-error-bg-subtle text-status-error-text" : "bg-status-warning-bg-subtle text-status-warning-text", R = () => {
|
|
20
21
|
let e = [];
|
|
21
|
-
e.push("Kadaikodi Financial Report"), e.push(""), e.push("Metric,Value"), e.push(`Total Revenue,${
|
|
22
|
-
e.push(`${t.category},${t.
|
|
23
|
-
}), e.push(""), e.push("Top Performing Carts"), e.push("Cart,
|
|
24
|
-
e.push(`${t.name},${t.
|
|
22
|
+
e.push("Kadaikodi Financial Report"), e.push(""), e.push("Metric,Value"), e.push(`Total Revenue,${E?.totalRevenue ?? 0}`), e.push(`Total Orders,${E?.totalOrders ?? 0}`), e.push(`Average Order Value,${Math.round(M)}`), e.push(`Pending Orders,${E?.pendingOrders ?? 0}`), e.push(""), e.push("Cart Category Distribution"), e.push("Category,Carts,Share %"), N.forEach((t) => {
|
|
23
|
+
e.push(`${t.category},${t.count},${(t.percentage ?? 0).toFixed(1)}`);
|
|
24
|
+
}), e.push(""), e.push("Top Performing Carts"), e.push("Cart,Category,Rating"), P.forEach((t) => {
|
|
25
|
+
e.push(`${t.name},${t.category},${t.rating ?? 0}`);
|
|
26
|
+
}), e.push(""), e.push("Recent Orders"), e.push("Date,Status,Amount"), F.forEach((t) => {
|
|
27
|
+
e.push(`${new Date(t.createdAt).toISOString().slice(0, 10)},${t.status},${t.total ?? 0}`);
|
|
25
28
|
});
|
|
26
29
|
let t = new Blob([e.join("\n")], { type: "text/csv;charset=utf-8;" }), n = URL.createObjectURL(t), r = document.createElement("a");
|
|
27
30
|
r.href = n, r.download = `kadaikodi-financial-report-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.csv`, r.click(), URL.revokeObjectURL(n);
|
|
28
|
-
},
|
|
31
|
+
}, z = (e) => e < 3 ? /* @__PURE__ */ x(l, { className: "h-5 w-5 text-status-warning-text" }) : /* @__PURE__ */ x("span", {
|
|
29
32
|
className: "flex h-5 w-5 items-center justify-center rounded-full bg-bg-sunken text-xs font-bold text-text-secondary",
|
|
30
33
|
children: e + 1
|
|
31
34
|
});
|
|
32
|
-
return
|
|
35
|
+
return A ? /* @__PURE__ */ x(t, {
|
|
33
36
|
title: "Financial Reports",
|
|
34
37
|
description: "Loading financial data...",
|
|
35
|
-
children: /* @__PURE__ */
|
|
38
|
+
children: /* @__PURE__ */ S("div", {
|
|
36
39
|
className: "flex flex-col items-center justify-center py-20",
|
|
37
|
-
children: [/* @__PURE__ */
|
|
40
|
+
children: [/* @__PURE__ */ x(h, { className: "h-10 w-10 animate-spin text-text-secondary mb-4" }), /* @__PURE__ */ x("p", {
|
|
38
41
|
className: "text-text-secondary",
|
|
39
42
|
children: "Loading financial data..."
|
|
40
43
|
})]
|
|
41
44
|
})
|
|
42
|
-
}) :
|
|
45
|
+
}) : E ? /* @__PURE__ */ S(t, {
|
|
43
46
|
title: "Financial Reports",
|
|
44
47
|
description: "Revenue, top carts and financial trends",
|
|
45
|
-
actions: /* @__PURE__ */
|
|
48
|
+
actions: /* @__PURE__ */ S("div", {
|
|
46
49
|
className: "flex flex-col sm:flex-row items-stretch sm:items-center gap-3",
|
|
47
|
-
children: [/* @__PURE__ */
|
|
50
|
+
children: [/* @__PURE__ */ S("button", {
|
|
48
51
|
type: "button",
|
|
49
|
-
onClick: () =>
|
|
52
|
+
onClick: () => T("/admin"),
|
|
50
53
|
className: "flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors",
|
|
51
|
-
children: [/* @__PURE__ */
|
|
52
|
-
}), /* @__PURE__ */
|
|
54
|
+
children: [/* @__PURE__ */ x(c, { className: "h-4 w-4" }), " Back"]
|
|
55
|
+
}), /* @__PURE__ */ S("button", {
|
|
53
56
|
type: "button",
|
|
54
|
-
onClick:
|
|
57
|
+
onClick: R,
|
|
55
58
|
className: "flex items-center gap-1.5 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",
|
|
56
|
-
children: [/* @__PURE__ */
|
|
59
|
+
children: [/* @__PURE__ */ x(p, { className: "h-4 w-4" }), " Export Report"]
|
|
57
60
|
})]
|
|
58
61
|
}),
|
|
59
62
|
children: [
|
|
60
|
-
/* @__PURE__ */
|
|
63
|
+
/* @__PURE__ */ x(w, {
|
|
61
64
|
className: "mb-6",
|
|
62
65
|
children: "The money view of Kadaikodi. Track total revenue and order volume, see which carts and categories drive the most business, and watch how orders trend over time — then export a CSV for accounting or investor updates."
|
|
63
66
|
}),
|
|
64
|
-
/* @__PURE__ */
|
|
67
|
+
/* @__PURE__ */ S(C, {
|
|
65
68
|
className: "mb-8",
|
|
66
|
-
children: [/* @__PURE__ */
|
|
69
|
+
children: [/* @__PURE__ */ x("h2", {
|
|
67
70
|
className: "mb-4 text-lg font-semibold text-text-primary",
|
|
68
71
|
children: "Financial Summary"
|
|
69
|
-
}), /* @__PURE__ */
|
|
72
|
+
}), /* @__PURE__ */ S("div", {
|
|
70
73
|
className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4",
|
|
71
74
|
children: [
|
|
72
|
-
/* @__PURE__ */
|
|
75
|
+
/* @__PURE__ */ x(n, {
|
|
73
76
|
featured: !0,
|
|
74
|
-
icon: /* @__PURE__ */
|
|
75
|
-
value:
|
|
77
|
+
icon: /* @__PURE__ */ x(m, { className: "h-5 w-5" }),
|
|
78
|
+
value: j(E.totalRevenue),
|
|
76
79
|
label: "Total Revenue"
|
|
77
80
|
}),
|
|
78
|
-
/* @__PURE__ */
|
|
79
|
-
icon: /* @__PURE__ */
|
|
80
|
-
value:
|
|
81
|
+
/* @__PURE__ */ x(n, {
|
|
82
|
+
icon: /* @__PURE__ */ x(g, { className: "h-5 w-5" }),
|
|
83
|
+
value: (E.totalOrders ?? 0).toLocaleString("en-IN"),
|
|
81
84
|
label: "Total Orders"
|
|
82
85
|
}),
|
|
83
|
-
/* @__PURE__ */
|
|
84
|
-
icon: /* @__PURE__ */ b
|
|
85
|
-
value:
|
|
86
|
+
/* @__PURE__ */ x(n, {
|
|
87
|
+
icon: /* @__PURE__ */ x(b, { className: "h-5 w-5" }),
|
|
88
|
+
value: j(M),
|
|
86
89
|
label: "Avg Order Value"
|
|
87
90
|
}),
|
|
88
|
-
/* @__PURE__ */
|
|
89
|
-
icon: /* @__PURE__ */
|
|
90
|
-
value:
|
|
91
|
+
/* @__PURE__ */ x(n, {
|
|
92
|
+
icon: /* @__PURE__ */ x(f, { className: "h-5 w-5" }),
|
|
93
|
+
value: (E.pendingOrders ?? 0).toLocaleString("en-IN"),
|
|
91
94
|
label: "Pending Orders"
|
|
92
95
|
})
|
|
93
96
|
]
|
|
94
97
|
})]
|
|
95
98
|
}),
|
|
96
|
-
/* @__PURE__ */
|
|
99
|
+
/* @__PURE__ */ S("div", {
|
|
97
100
|
className: "grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8",
|
|
98
|
-
children: [/* @__PURE__ */
|
|
101
|
+
children: [/* @__PURE__ */ S("div", {
|
|
99
102
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-6",
|
|
100
|
-
children: [/* @__PURE__ */
|
|
103
|
+
children: [/* @__PURE__ */ S("div", {
|
|
101
104
|
className: "flex items-center gap-2 mb-4",
|
|
102
|
-
children: [/* @__PURE__ */
|
|
105
|
+
children: [/* @__PURE__ */ x(_, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ x("h3", {
|
|
103
106
|
className: "text-lg font-semibold text-text-primary",
|
|
104
107
|
children: "Top Performing Carts"
|
|
105
108
|
})]
|
|
106
|
-
}),
|
|
109
|
+
}), P.length > 0 ? /* @__PURE__ */ x("div", {
|
|
107
110
|
className: "space-y-3",
|
|
108
|
-
children:
|
|
111
|
+
children: P.map((e, t) => /* @__PURE__ */ S("div", {
|
|
109
112
|
className: "flex items-center justify-between rounded-lg bg-bg-sunken/50 p-3",
|
|
110
|
-
children: [/* @__PURE__ */
|
|
113
|
+
children: [/* @__PURE__ */ S("div", {
|
|
111
114
|
className: "flex items-center gap-3",
|
|
112
|
-
children: [
|
|
115
|
+
children: [z(t), /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
113
116
|
className: "text-sm font-medium text-text-primary",
|
|
114
117
|
children: e.name
|
|
115
118
|
}), /* @__PURE__ */ x("p", {
|
|
116
|
-
className: "text-xs text-text-secondary",
|
|
117
|
-
children:
|
|
119
|
+
className: "text-xs text-text-secondary capitalize",
|
|
120
|
+
children: I(e.category)
|
|
118
121
|
})] })]
|
|
119
|
-
}), /* @__PURE__ */
|
|
120
|
-
className: "text-sm font-semibold text-text-primary",
|
|
121
|
-
children:
|
|
122
|
+
}), /* @__PURE__ */ S("p", {
|
|
123
|
+
className: "text-sm font-semibold text-text-primary flex items-center gap-1",
|
|
124
|
+
children: [/* @__PURE__ */ x(v, { className: "h-3.5 w-3.5 fill-status-warning-text text-status-warning-text" }), (e.rating ?? 0).toFixed(1)]
|
|
122
125
|
})]
|
|
123
126
|
}, e.id))
|
|
124
|
-
}) : /* @__PURE__ */
|
|
127
|
+
}) : /* @__PURE__ */ x("p", {
|
|
125
128
|
className: "text-sm text-text-secondary",
|
|
126
129
|
children: "Top-performing carts will be ranked here once orders start flowing."
|
|
127
130
|
})]
|
|
128
|
-
}), /* @__PURE__ */
|
|
131
|
+
}), /* @__PURE__ */ S("div", {
|
|
129
132
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-6",
|
|
130
|
-
children: [/* @__PURE__ */
|
|
133
|
+
children: [/* @__PURE__ */ S("div", {
|
|
131
134
|
className: "flex items-center gap-2 mb-4",
|
|
132
|
-
children: [/* @__PURE__ */
|
|
135
|
+
children: [/* @__PURE__ */ x(u, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ x("h3", {
|
|
133
136
|
className: "text-lg font-semibold text-text-primary",
|
|
134
|
-
children: "
|
|
137
|
+
children: "Cart Category Distribution"
|
|
135
138
|
})]
|
|
136
|
-
}),
|
|
139
|
+
}), N.length > 0 ? /* @__PURE__ */ x("div", {
|
|
137
140
|
className: "space-y-3",
|
|
138
|
-
children:
|
|
139
|
-
/* @__PURE__ */
|
|
141
|
+
children: N.map((e) => /* @__PURE__ */ S("div", { children: [
|
|
142
|
+
/* @__PURE__ */ S("div", {
|
|
140
143
|
className: "flex items-center justify-between mb-1",
|
|
141
|
-
children: [/* @__PURE__ */
|
|
144
|
+
children: [/* @__PURE__ */ x("span", {
|
|
142
145
|
className: "text-sm font-medium text-text-primary capitalize",
|
|
143
|
-
children: e.category
|
|
144
|
-
}), /* @__PURE__ */
|
|
146
|
+
children: I(e.category)
|
|
147
|
+
}), /* @__PURE__ */ S("span", {
|
|
145
148
|
className: "text-sm text-text-secondary",
|
|
146
|
-
children: [e.percentage.toFixed(1), "%"]
|
|
149
|
+
children: [(e.percentage ?? 0).toFixed(1), "%"]
|
|
147
150
|
})]
|
|
148
151
|
}),
|
|
149
|
-
/* @__PURE__ */
|
|
152
|
+
/* @__PURE__ */ x("div", {
|
|
150
153
|
className: "w-full bg-bg-sunken rounded-full h-2",
|
|
151
|
-
children: /* @__PURE__ */
|
|
154
|
+
children: /* @__PURE__ */ x("div", {
|
|
152
155
|
className: "bg-action-primary-bg h-2 rounded-full transition-all duration-300",
|
|
153
156
|
style: { width: `${e.percentage}%` }
|
|
154
157
|
})
|
|
155
158
|
}),
|
|
156
|
-
/* @__PURE__ */
|
|
159
|
+
/* @__PURE__ */ x("div", {
|
|
157
160
|
className: "text-right mt-1",
|
|
158
|
-
children: /* @__PURE__ */
|
|
161
|
+
children: /* @__PURE__ */ S("span", {
|
|
159
162
|
className: "text-sm font-semibold text-text-primary",
|
|
160
|
-
children:
|
|
163
|
+
children: [
|
|
164
|
+
(e.count ?? 0).toLocaleString("en-IN"),
|
|
165
|
+
" ",
|
|
166
|
+
/* @__PURE__ */ x("span", {
|
|
167
|
+
className: "text-xs font-normal text-text-secondary",
|
|
168
|
+
children: e.count === 1 ? "cart" : "carts"
|
|
169
|
+
})
|
|
170
|
+
]
|
|
161
171
|
})
|
|
162
172
|
})
|
|
163
173
|
] }, e.category))
|
|
164
|
-
}) : /* @__PURE__ */
|
|
174
|
+
}) : /* @__PURE__ */ x("p", {
|
|
165
175
|
className: "text-sm text-text-secondary",
|
|
166
|
-
children: "
|
|
176
|
+
children: "Cart categories will appear here as carts are onboarded."
|
|
167
177
|
})]
|
|
168
178
|
})]
|
|
169
179
|
}),
|
|
170
|
-
|
|
180
|
+
F.length > 0 && /* @__PURE__ */ S("div", {
|
|
171
181
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-6 mb-8",
|
|
172
|
-
children: [/* @__PURE__ */
|
|
182
|
+
children: [/* @__PURE__ */ S("div", {
|
|
173
183
|
className: "flex items-center gap-2 mb-4",
|
|
174
|
-
children: [/* @__PURE__ */
|
|
184
|
+
children: [/* @__PURE__ */ x(d, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ x("h3", {
|
|
175
185
|
className: "text-lg font-semibold text-text-primary",
|
|
176
|
-
children: "
|
|
186
|
+
children: "Recent Orders"
|
|
177
187
|
})]
|
|
178
|
-
}), /* @__PURE__ */
|
|
188
|
+
}), /* @__PURE__ */ x("div", {
|
|
179
189
|
className: "overflow-x-auto",
|
|
180
|
-
children: /* @__PURE__ */
|
|
190
|
+
children: /* @__PURE__ */ S("table", {
|
|
181
191
|
className: "w-full",
|
|
182
|
-
children: [/* @__PURE__ */
|
|
192
|
+
children: [/* @__PURE__ */ x("thead", { children: /* @__PURE__ */ S("tr", {
|
|
183
193
|
className: "border-b border-border-subtle bg-bg-sunken/50",
|
|
184
194
|
children: [
|
|
185
|
-
/* @__PURE__ */
|
|
195
|
+
/* @__PURE__ */ x("th", {
|
|
186
196
|
className: "px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
|
|
187
197
|
children: "Date"
|
|
188
198
|
}),
|
|
189
|
-
/* @__PURE__ */
|
|
190
|
-
className: "px-4 py-3 text-
|
|
191
|
-
children: "
|
|
199
|
+
/* @__PURE__ */ x("th", {
|
|
200
|
+
className: "px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
|
|
201
|
+
children: "Status"
|
|
192
202
|
}),
|
|
193
|
-
/* @__PURE__ */
|
|
203
|
+
/* @__PURE__ */ x("th", {
|
|
194
204
|
className: "px-4 py-3 text-right text-xs font-medium text-text-secondary uppercase tracking-wider",
|
|
195
|
-
children: "
|
|
205
|
+
children: "Amount"
|
|
196
206
|
})
|
|
197
207
|
]
|
|
198
|
-
}) }), /* @__PURE__ */
|
|
208
|
+
}) }), /* @__PURE__ */ x("tbody", {
|
|
199
209
|
className: "divide-y divide-border",
|
|
200
|
-
children:
|
|
210
|
+
children: F.map((e) => /* @__PURE__ */ S("tr", {
|
|
201
211
|
className: "hover:bg-accent/50 transition-colors",
|
|
202
212
|
children: [
|
|
203
|
-
/* @__PURE__ */
|
|
213
|
+
/* @__PURE__ */ x("td", {
|
|
204
214
|
className: "px-4 py-3 text-sm font-medium text-text-primary",
|
|
205
|
-
children: e.
|
|
215
|
+
children: new Date(e.createdAt).toLocaleDateString("en-IN", {
|
|
216
|
+
day: "2-digit",
|
|
217
|
+
month: "short",
|
|
218
|
+
year: "numeric"
|
|
219
|
+
})
|
|
206
220
|
}),
|
|
207
|
-
/* @__PURE__ */
|
|
208
|
-
className: "px-4 py-3 text-sm
|
|
209
|
-
children:
|
|
221
|
+
/* @__PURE__ */ x("td", {
|
|
222
|
+
className: "px-4 py-3 text-sm",
|
|
223
|
+
children: /* @__PURE__ */ x("span", {
|
|
224
|
+
className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize ${L(e.status)}`,
|
|
225
|
+
children: e.status.replace(/_/g, " ")
|
|
226
|
+
})
|
|
210
227
|
}),
|
|
211
|
-
/* @__PURE__ */
|
|
228
|
+
/* @__PURE__ */ x("td", {
|
|
212
229
|
className: "px-4 py-3 text-sm text-right text-text-primary",
|
|
213
|
-
children:
|
|
230
|
+
children: j(e.total ?? 0)
|
|
214
231
|
})
|
|
215
232
|
]
|
|
216
|
-
}, e.
|
|
233
|
+
}, e.id))
|
|
217
234
|
})]
|
|
218
235
|
})
|
|
219
236
|
})]
|
|
220
237
|
}),
|
|
221
|
-
/* @__PURE__ */
|
|
238
|
+
/* @__PURE__ */ S("div", {
|
|
222
239
|
className: "grid grid-cols-1 md:grid-cols-3 gap-6",
|
|
223
240
|
children: [
|
|
224
|
-
/* @__PURE__ */
|
|
241
|
+
/* @__PURE__ */ S("div", {
|
|
225
242
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-6 text-center",
|
|
226
243
|
children: [
|
|
227
|
-
/* @__PURE__ */
|
|
228
|
-
/* @__PURE__ */
|
|
244
|
+
/* @__PURE__ */ x(g, { className: "h-8 w-8 text-primary mx-auto mb-3" }),
|
|
245
|
+
/* @__PURE__ */ x("h4", {
|
|
229
246
|
className: "text-lg font-semibold text-text-primary mb-2",
|
|
230
247
|
children: "Total Orders"
|
|
231
248
|
}),
|
|
232
|
-
/* @__PURE__ */
|
|
249
|
+
/* @__PURE__ */ x("p", {
|
|
233
250
|
className: "text-2xl font-bold text-primary",
|
|
234
|
-
children:
|
|
251
|
+
children: (E.totalOrders ?? 0).toLocaleString("en-IN")
|
|
235
252
|
}),
|
|
236
|
-
/* @__PURE__ */
|
|
253
|
+
/* @__PURE__ */ x("p", {
|
|
237
254
|
className: "text-sm text-text-secondary mt-1",
|
|
238
255
|
children: "All-time orders"
|
|
239
256
|
})
|
|
240
257
|
]
|
|
241
258
|
}),
|
|
242
|
-
/* @__PURE__ */
|
|
259
|
+
/* @__PURE__ */ S("div", {
|
|
243
260
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-6 text-center",
|
|
244
261
|
children: [
|
|
245
|
-
/* @__PURE__ */
|
|
246
|
-
/* @__PURE__ */
|
|
262
|
+
/* @__PURE__ */ x(u, { className: "h-8 w-8 text-status-success-text mx-auto mb-3" }),
|
|
263
|
+
/* @__PURE__ */ x("h4", {
|
|
247
264
|
className: "text-lg font-semibold text-text-primary mb-2",
|
|
248
265
|
children: "Average Order Value"
|
|
249
266
|
}),
|
|
250
|
-
/* @__PURE__ */
|
|
267
|
+
/* @__PURE__ */ x("p", {
|
|
251
268
|
className: "text-2xl font-bold text-status-success-text",
|
|
252
|
-
children:
|
|
269
|
+
children: j(M)
|
|
253
270
|
}),
|
|
254
|
-
/* @__PURE__ */
|
|
271
|
+
/* @__PURE__ */ x("p", {
|
|
255
272
|
className: "text-sm text-text-secondary mt-1",
|
|
256
273
|
children: "Per order average"
|
|
257
274
|
})
|
|
258
275
|
]
|
|
259
276
|
}),
|
|
260
|
-
/* @__PURE__ */
|
|
277
|
+
/* @__PURE__ */ S("div", {
|
|
261
278
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-6 text-center",
|
|
262
279
|
children: [
|
|
263
|
-
/* @__PURE__ */
|
|
264
|
-
/* @__PURE__ */
|
|
280
|
+
/* @__PURE__ */ x(y, { className: "h-8 w-8 text-text-primary mx-auto mb-3" }),
|
|
281
|
+
/* @__PURE__ */ x("h4", {
|
|
265
282
|
className: "text-lg font-semibold text-text-primary mb-2",
|
|
266
283
|
children: "Active Carts"
|
|
267
284
|
}),
|
|
268
|
-
/* @__PURE__ */
|
|
285
|
+
/* @__PURE__ */ x("p", {
|
|
269
286
|
className: "text-2xl font-bold text-text-primary",
|
|
270
|
-
children:
|
|
287
|
+
children: (E.activeProviders ?? 0).toLocaleString("en-IN")
|
|
271
288
|
}),
|
|
272
|
-
/* @__PURE__ */
|
|
289
|
+
/* @__PURE__ */ x("p", {
|
|
273
290
|
className: "text-sm text-text-secondary mt-1",
|
|
274
291
|
children: "Currently live on the platform"
|
|
275
292
|
})
|
|
@@ -278,10 +295,10 @@ function w() {
|
|
|
278
295
|
]
|
|
279
296
|
})
|
|
280
297
|
]
|
|
281
|
-
}) : /* @__PURE__ */
|
|
298
|
+
}) : /* @__PURE__ */ x(t, {
|
|
282
299
|
title: "Financial Reports",
|
|
283
300
|
description: "Unable to load financial data",
|
|
284
|
-
children: /* @__PURE__ */
|
|
301
|
+
children: /* @__PURE__ */ x(r, {
|
|
285
302
|
illustration: "empty-data",
|
|
286
303
|
title: "No financial data available",
|
|
287
304
|
description: "We couldn't load the financial figures right now. Please check back shortly."
|
|
@@ -289,6 +306,6 @@ function w() {
|
|
|
289
306
|
});
|
|
290
307
|
}
|
|
291
308
|
//#endregion
|
|
292
|
-
export {
|
|
309
|
+
export { T as AdminFinancialPage };
|
|
293
310
|
|
|
294
311
|
//# sourceMappingURL=AdminFinancialPage.js.map
|