@burdenoff/microfe-kadaikodi 2026.704.2 → 2026.704.4
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/hooks/useKadaikodiApi.js +76 -6
- package/dist/kadaikodi/hooks/useKadaikodiApi.js.map +1 -1
- 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/AdminProfilePage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminSettingsPage.js +332 -276
- package/dist/kadaikodi/pages/admin/AdminSettingsPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/CartManagementPage.js +278 -283
- package/dist/kadaikodi/pages/admin/CartManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/UserManagementPage.js +310 -366
- package/dist/kadaikodi/pages/admin/UserManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/AnalyticsDashboard.js +105 -111
- package/dist/kadaikodi/pages/cart-owner/AnalyticsDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/BusinessSettingsPage.js +290 -257
- package/dist/kadaikodi/pages/cart-owner/BusinessSettingsPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/CartOwnerDashboard.js +84 -70
- package/dist/kadaikodi/pages/cart-owner/CartOwnerDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/CartOwnerProfilePage.js +270 -228
- package/dist/kadaikodi/pages/cart-owner/CartOwnerProfilePage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/CartServiceConfigPage.js +194 -173
- package/dist/kadaikodi/pages/cart-owner/CartServiceConfigPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/InventoryManagementPage.js +202 -139
- package/dist/kadaikodi/pages/cart-owner/InventoryManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/InvestmentListingPage.js +232 -0
- package/dist/kadaikodi/pages/cart-owner/InvestmentListingPage.js.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/OrderManagementPage.js +84 -79
- package/dist/kadaikodi/pages/cart-owner/OrderManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/common/HelpSupportPage.js +310 -317
- package/dist/kadaikodi/pages/common/HelpSupportPage.js.map +1 -1
- package/dist/kadaikodi/pages/common/NotificationCenterPage.js.map +1 -1
- package/dist/kadaikodi/pages/common/SettingsPage.js +502 -586
- package/dist/kadaikodi/pages/common/SettingsPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/BookingDetailsPage.js +243 -143
- package/dist/kadaikodi/pages/customer/BookingDetailsPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDetailPage.js +4 -4
- package/dist/kadaikodi/pages/customer/CartDetailPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.js +2 -2
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CheckoutPage.js +4 -4
- package/dist/kadaikodi/pages/customer/CheckoutPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CustomerDashboard.js +6 -6
- package/dist/kadaikodi/pages/customer/CustomerDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CustomerProfilePage.js +189 -199
- package/dist/kadaikodi/pages/customer/CustomerProfilePage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/DirectServiceBookingPage.js +6 -4
- package/dist/kadaikodi/pages/customer/DirectServiceBookingPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/FavoritesPage.js +6 -6
- package/dist/kadaikodi/pages/customer/FavoritesPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/OrderHistoryPage.js +4 -4
- package/dist/kadaikodi/pages/customer/OrderHistoryPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.js +409 -304
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/ReviewsPage.js +209 -162
- package/dist/kadaikodi/pages/customer/ReviewsPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/SavedAddressesPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestmentDetailsPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestmentOpportunitiesPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestorAnalyticsPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestorProfilePage.js +441 -514
- package/dist/kadaikodi/pages/investor/InvestorProfilePage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.js +207 -186
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/WorkerOrdersPage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/WorkerProfilePage.js +340 -272
- package/dist/kadaikodi/pages/worker/WorkerProfilePage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/WorkerSchedulePage.js +122 -75
- package/dist/kadaikodi/pages/worker/WorkerSchedulePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminFinancialPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/admin/AdminFinancialPage.tsx"],"sourcesContent":["/**\n * Admin Financial Page\n * @module kadaikodi/pages/admin\n *\n * Financial reporting wired to the live backend (useDashboardStats +\n * useAdminAnalytics). Revenue, top carts, category breakdown and order\n * trends are all real; the export produces a CSV of the real figures.\n * Metrics with no honest backend source (commission, payouts) are omitted\n * rather than fabricated.\n */\n\nimport { useMemo } from 'react';\nimport {\n IndianRupee,\n TrendingUp,\n Download,\n Calendar,\n BarChart3,\n ShoppingCart,\n ArrowLeft,\n Loader2,\n Award,\n Store,\n ShoppingBag,\n Clock,\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 { useDashboardStats, useAdminAnalytics } from '../../hooks/useKadaikodiApi';\nimport { formatCurrency } from '../../utils/formatters';\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport function AdminFinancialPage() {\n const { navigateTo } = useKadaikodi();\n const { data: stats, isLoading: statsLoading } = useDashboardStats();\n const { data: analytics, isLoading: analyticsLoading } = useAdminAnalytics();\n\n const loading = statsLoading || analyticsLoading;\n\n const fmtCur = (amount: number) => formatCurrency(amount, { minimumFractionDigits: 0 });\n\n const averageOrderValue = useMemo(() => {\n if (stats && stats.totalOrders > 0) return stats.totalRevenue / stats.totalOrders;\n return 0;\n }, [stats]);\n\n // Category rows with a real, derived share-of-revenue percentage.\n const categoryRows = useMemo(() => {\n const rows = analytics?.revenueByCategory ?? [];\n const total = rows.reduce((sum, r) => sum + r.revenue, 0);\n return rows.map((r) => ({\n ...r,\n percentage: total > 0 ? (r.revenue / total) * 100 : 0,\n }));\n }, [analytics]);\n\n const topCarts = analytics?.topProviders ?? [];\n const orderTrends = analytics?.orderTrends ?? [];\n\n const handleExportReport = () => {\n const lines: string[] = [];\n lines.push('Kadaikodi Financial Report');\n lines.push('');\n lines.push('Metric,Value');\n lines.push(`Total Revenue,${stats?.totalRevenue ?? 0}`);\n lines.push(`Total Orders,${stats?.totalOrders ?? 0}`);\n lines.push(`Average Order Value,${Math.round(averageOrderValue)}`);\n lines.push(`Pending Orders,${stats?.pendingOrders ?? 0}`);\n lines.push('');\n lines.push('Revenue by Category');\n lines.push('Category,Revenue,Orders,Share %');\n categoryRows.forEach((r) => {\n lines.push(`${r.category},${r.revenue},${r.orders},${r.percentage.toFixed(1)}`);\n });\n lines.push('');\n lines.push('Top Performing Carts');\n lines.push('Cart,Revenue,Orders,Rating');\n topCarts.forEach((c) => {\n lines.push(`${c.name},${c.revenue},${c.orders},${c.rating}`);\n });\n\n const blob = new Blob([lines.join('\\n')], { type: 'text/csv;charset=utf-8;' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `kadaikodi-financial-report-${new Date().toISOString().slice(0, 10)}.csv`;\n a.click();\n URL.revokeObjectURL(url);\n };\n\n const medalIcon = (index: number) => {\n if (index < 3) return <Award className=\"h-5 w-5 text-status-warning-text\" />;\n return (\n <span className=\"flex h-5 w-5 items-center justify-center rounded-full bg-bg-sunken text-xs font-bold text-text-secondary\">\n {index + 1}\n </span>\n );\n };\n\n if (loading) {\n return (\n <PageLayout title=\"Financial Reports\" description=\"Loading financial data...\">\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 financial data...</p>\n </div>\n </PageLayout>\n );\n }\n\n if (!stats) {\n return (\n <PageLayout title=\"Financial Reports\" description=\"Unable to load financial data\">\n <EmptyState\n illustration=\"empty-data\"\n title=\"No financial data available\"\n description=\"We couldn't load the financial figures right now. Please check back shortly.\"\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Financial Reports\"\n description=\"Revenue, top carts and financial trends\"\n actions={\n <div className=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/admin')}\n 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\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n <button\n type=\"button\"\n onClick={handleExportReport}\n 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\"\n >\n <Download className=\"h-4 w-4\" /> Export Report\n </button>\n </div>\n }\n >\n <PagePurpose className=\"mb-6\">\n The money view of Kadaikodi. Track total revenue and order volume, see which carts and\n categories drive the most business, and watch how orders trend over time — then export a\n CSV for accounting or investor updates.\n </PagePurpose>\n\n {/* Key Metrics — the one emphasis zone for this page */}\n <EmphasisPanel className=\"mb-8\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Financial Summary</h2>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\n <MetricsCard\n featured\n icon={<IndianRupee className=\"h-5 w-5\" />}\n value={fmtCur(stats.totalRevenue)}\n label=\"Total Revenue\"\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 icon={<TrendingUp className=\"h-5 w-5\" />}\n value={fmtCur(averageOrderValue)}\n label=\"Avg Order Value\"\n />\n <MetricsCard\n icon={<Clock className=\"h-5 w-5\" />}\n value={stats.pendingOrders.toLocaleString('en-IN')}\n label=\"Pending Orders\"\n />\n </div>\n </EmphasisPanel>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8\">\n {/* Top Performing Carts */}\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 <ShoppingCart className=\"h-5 w-5 text-text-secondary\" />\n <h3 className=\"text-lg font-semibold text-text-primary\">Top Performing Carts</h3>\n </div>\n {topCarts.length > 0 ? (\n <div className=\"space-y-3\">\n {topCarts.map((cart, index) => (\n <div\n key={cart.id}\n className=\"flex items-center justify-between rounded-lg bg-bg-sunken/50 p-3\"\n >\n <div className=\"flex items-center gap-3\">\n {medalIcon(index)}\n <div>\n <p className=\"text-sm font-medium text-text-primary\">{cart.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {cart.orders.toLocaleString('en-IN')} orders\n </p>\n </div>\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\n {/* Revenue by Category */}\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 {categoryRows.length > 0 ? (\n <div className=\"space-y-3\">\n {categoryRows.map((category) => (\n <div key={category.category}>\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"text-sm font-medium text-text-primary capitalize\">\n {category.category}\n </span>\n <span className=\"text-sm text-text-secondary\">\n {category.percentage.toFixed(1)}%\n </span>\n </div>\n <div className=\"w-full bg-bg-sunken rounded-full h-2\">\n <div\n className=\"bg-action-primary-bg h-2 rounded-full transition-all duration-300\"\n style={{ width: `${category.percentage}%` }}\n />\n </div>\n <div className=\"text-right mt-1\">\n <span className=\"text-sm font-semibold text-text-primary\">\n {fmtCur(category.revenue)}\n </span>\n </div>\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 </div>\n\n {/* Order Trends Table */}\n {orderTrends.length > 0 && (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-6 mb-8\">\n <div className=\"flex items-center gap-2 mb-4\">\n <Calendar className=\"h-5 w-5 text-text-secondary\" />\n <h3 className=\"text-lg font-semibold text-text-primary\">Order Trends</h3>\n </div>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"border-b border-border-subtle bg-bg-sunken/50\">\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Date\n </th>\n <th className=\"px-4 py-3 text-right text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Orders\n </th>\n <th className=\"px-4 py-3 text-right text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Revenue\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {orderTrends.map((trend) => (\n <tr key={trend.date} className=\"hover:bg-accent/50 transition-colors\">\n <td className=\"px-4 py-3 text-sm font-medium text-text-primary\">\n {trend.date}\n </td>\n <td className=\"px-4 py-3 text-sm text-right text-text-primary\">\n {trend.orders.toLocaleString('en-IN')}\n </td>\n <td className=\"px-4 py-3 text-sm text-right text-text-primary\">\n {fmtCur(trend.revenue)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n )}\n\n {/* 3 Additional Cards — all real */}\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-6 text-center\">\n <ShoppingBag className=\"h-8 w-8 text-primary mx-auto mb-3\" />\n <h4 className=\"text-lg font-semibold text-text-primary mb-2\">Total Orders</h4>\n <p className=\"text-2xl font-bold text-primary\">\n {stats.totalOrders.toLocaleString('en-IN')}\n </p>\n <p className=\"text-sm text-text-secondary mt-1\">All-time orders</p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-6 text-center\">\n <BarChart3 className=\"h-8 w-8 text-status-success-text mx-auto mb-3\" />\n <h4 className=\"text-lg font-semibold text-text-primary mb-2\">Average Order Value</h4>\n <p className=\"text-2xl font-bold text-status-success-text\">{fmtCur(averageOrderValue)}</p>\n <p className=\"text-sm text-text-secondary mt-1\">Per order average</p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-6 text-center\">\n <Store className=\"h-8 w-8 text-text-primary mx-auto mb-3\" />\n <h4 className=\"text-lg font-semibold text-text-primary mb-2\">Active Carts</h4>\n <p className=\"text-2xl font-bold text-text-primary\">\n {stats.activeProviders.toLocaleString('en-IN')}\n </p>\n <p className=\"text-sm text-text-secondary mt-1\">Currently live on the platform</p>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AdminFinancialPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/admin/AdminFinancialPage.tsx"],"sourcesContent":["/**\n * Admin Financial Page\n * @module kadaikodi/pages/admin\n *\n * Financial reporting wired to the live backend (useDashboardStats +\n * useAdminAnalytics). Revenue, top carts, category breakdown and order\n * trends are all real; the export produces a CSV of the real figures.\n * Metrics with no honest backend source (commission, payouts) are omitted\n * rather than fabricated.\n */\n\nimport { useMemo } from 'react';\nimport {\n IndianRupee,\n TrendingUp,\n Download,\n Calendar,\n BarChart3,\n ShoppingCart,\n ArrowLeft,\n Loader2,\n Award,\n Store,\n ShoppingBag,\n Clock,\n Star,\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 { useDashboardStats, useAdminAnalytics } from '../../hooks/useKadaikodiApi';\nimport { formatCurrency } from '../../utils/formatters';\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport function AdminFinancialPage() {\n const { navigateTo } = useKadaikodi();\n const { data: stats, isLoading: statsLoading } = useDashboardStats();\n const { data: analytics, isLoading: analyticsLoading } = useAdminAnalytics();\n\n const loading = statsLoading || analyticsLoading;\n\n const fmtCur = (amount: number) => formatCurrency(amount, { minimumFractionDigits: 0 });\n\n const averageOrderValue = useMemo(() => {\n if (stats && stats.totalOrders > 0) return stats.totalRevenue / stats.totalOrders;\n return 0;\n }, [stats]);\n\n // Cart distribution per category with a real, derived share percentage.\n // The backend exposes counts per category, not revenue per category.\n const categoryRows = useMemo(() => {\n const entries = Object.entries(analytics?.categoryDistribution ?? {});\n const total = entries.reduce((sum, [, count]) => sum + count, 0);\n return entries\n .map(([category, count]) => ({\n category,\n count,\n percentage: total > 0 ? (count / total) * 100 : 0,\n }))\n .sort((a, b) => b.count - a.count);\n }, [analytics]);\n\n const topCarts = analytics?.topProviders ?? [];\n const orderTrends = analytics?.orderTrends ?? [];\n\n const prettyCategory = (c: string) => c.replace(/_/g, ' ').toLowerCase();\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 const handleExportReport = () => {\n const lines: string[] = [];\n lines.push('Kadaikodi Financial Report');\n lines.push('');\n lines.push('Metric,Value');\n lines.push(`Total Revenue,${stats?.totalRevenue ?? 0}`);\n lines.push(`Total Orders,${stats?.totalOrders ?? 0}`);\n lines.push(`Average Order Value,${Math.round(averageOrderValue)}`);\n lines.push(`Pending Orders,${stats?.pendingOrders ?? 0}`);\n lines.push('');\n lines.push('Cart Category Distribution');\n lines.push('Category,Carts,Share %');\n categoryRows.forEach((r) => {\n lines.push(`${r.category},${r.count},${(r.percentage ?? 0).toFixed(1)}`);\n });\n lines.push('');\n lines.push('Top Performing Carts');\n lines.push('Cart,Category,Rating');\n topCarts.forEach((c) => {\n lines.push(`${c.name},${c.category},${c.rating ?? 0}`);\n });\n lines.push('');\n lines.push('Recent Orders');\n lines.push('Date,Status,Amount');\n orderTrends.forEach((o) => {\n lines.push(`${new Date(o.createdAt).toISOString().slice(0, 10)},${o.status},${o.total ?? 0}`);\n });\n\n const blob = new Blob([lines.join('\\n')], { type: 'text/csv;charset=utf-8;' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `kadaikodi-financial-report-${new Date().toISOString().slice(0, 10)}.csv`;\n a.click();\n URL.revokeObjectURL(url);\n };\n\n const medalIcon = (index: number) => {\n if (index < 3) return <Award className=\"h-5 w-5 text-status-warning-text\" />;\n return (\n <span className=\"flex h-5 w-5 items-center justify-center rounded-full bg-bg-sunken text-xs font-bold text-text-secondary\">\n {index + 1}\n </span>\n );\n };\n\n if (loading) {\n return (\n <PageLayout title=\"Financial Reports\" description=\"Loading financial data...\">\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 financial data...</p>\n </div>\n </PageLayout>\n );\n }\n\n if (!stats) {\n return (\n <PageLayout title=\"Financial Reports\" description=\"Unable to load financial data\">\n <EmptyState\n illustration=\"empty-data\"\n title=\"No financial data available\"\n description=\"We couldn't load the financial figures right now. Please check back shortly.\"\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Financial Reports\"\n description=\"Revenue, top carts and financial trends\"\n actions={\n <div className=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/admin')}\n 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\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n <button\n type=\"button\"\n onClick={handleExportReport}\n 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\"\n >\n <Download className=\"h-4 w-4\" /> Export Report\n </button>\n </div>\n }\n >\n <PagePurpose className=\"mb-6\">\n The money view of Kadaikodi. Track total revenue and order volume, see which carts and\n categories drive the most business, and watch how orders trend over time — then export a CSV\n for accounting or investor updates.\n </PagePurpose>\n\n {/* Key Metrics — the one emphasis zone for this page */}\n <EmphasisPanel className=\"mb-8\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Financial Summary</h2>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\n <MetricsCard\n featured\n icon={<IndianRupee className=\"h-5 w-5\" />}\n value={fmtCur(stats.totalRevenue)}\n label=\"Total Revenue\"\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 icon={<TrendingUp className=\"h-5 w-5\" />}\n value={fmtCur(averageOrderValue)}\n label=\"Avg Order Value\"\n />\n <MetricsCard\n icon={<Clock className=\"h-5 w-5\" />}\n value={(stats.pendingOrders ?? 0).toLocaleString('en-IN')}\n label=\"Pending Orders\"\n />\n </div>\n </EmphasisPanel>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8\">\n {/* Top Performing Carts */}\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 <ShoppingCart className=\"h-5 w-5 text-text-secondary\" />\n <h3 className=\"text-lg font-semibold text-text-primary\">Top Performing Carts</h3>\n </div>\n {topCarts.length > 0 ? (\n <div className=\"space-y-3\">\n {topCarts.map((cart, index) => (\n <div\n key={cart.id}\n className=\"flex items-center justify-between rounded-lg bg-bg-sunken/50 p-3\"\n >\n <div className=\"flex items-center gap-3\">\n {medalIcon(index)}\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 </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\n {/* Cart Category Distribution */}\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\">Cart Category Distribution</h3>\n </div>\n {categoryRows.length > 0 ? (\n <div className=\"space-y-3\">\n {categoryRows.map((category) => (\n <div key={category.category}>\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"text-sm font-medium text-text-primary capitalize\">\n {prettyCategory(category.category)}\n </span>\n <span className=\"text-sm text-text-secondary\">\n {(category.percentage ?? 0).toFixed(1)}%\n </span>\n </div>\n <div className=\"w-full bg-bg-sunken rounded-full h-2\">\n <div\n className=\"bg-action-primary-bg h-2 rounded-full transition-all duration-300\"\n style={{ width: `${category.percentage}%` }}\n />\n </div>\n <div className=\"text-right mt-1\">\n <span className=\"text-sm font-semibold text-text-primary\">\n {(category.count ?? 0).toLocaleString('en-IN')}{' '}\n <span className=\"text-xs font-normal text-text-secondary\">\n {category.count === 1 ? 'cart' : 'carts'}\n </span>\n </span>\n </div>\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 </div>\n\n {/* Recent Orders Table */}\n {orderTrends.length > 0 && (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-6 mb-8\">\n <div className=\"flex items-center gap-2 mb-4\">\n <Calendar className=\"h-5 w-5 text-text-secondary\" />\n <h3 className=\"text-lg font-semibold text-text-primary\">Recent Orders</h3>\n </div>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"border-b border-border-subtle bg-bg-sunken/50\">\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Date\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Status\n </th>\n <th className=\"px-4 py-3 text-right text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Amount\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {orderTrends.map((order) => (\n <tr key={order.id} className=\"hover:bg-accent/50 transition-colors\">\n <td className=\"px-4 py-3 text-sm font-medium text-text-primary\">\n {new Date(order.createdAt).toLocaleDateString('en-IN', {\n day: '2-digit',\n month: 'short',\n year: 'numeric',\n })}\n </td>\n <td className=\"px-4 py-3 text-sm\">\n <span\n className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize ${orderStatusBadge(\n order.status\n )}`}\n >\n {order.status.replace(/_/g, ' ')}\n </span>\n </td>\n <td className=\"px-4 py-3 text-sm text-right text-text-primary\">\n {fmtCur(order.total ?? 0)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n )}\n\n {/* 3 Additional Cards — all real */}\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-6 text-center\">\n <ShoppingBag className=\"h-8 w-8 text-primary mx-auto mb-3\" />\n <h4 className=\"text-lg font-semibold text-text-primary mb-2\">Total Orders</h4>\n <p className=\"text-2xl font-bold text-primary\">\n {(stats.totalOrders ?? 0).toLocaleString('en-IN')}\n </p>\n <p className=\"text-sm text-text-secondary mt-1\">All-time orders</p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-6 text-center\">\n <BarChart3 className=\"h-8 w-8 text-status-success-text mx-auto mb-3\" />\n <h4 className=\"text-lg font-semibold text-text-primary mb-2\">Average Order Value</h4>\n <p className=\"text-2xl font-bold text-status-success-text\">{fmtCur(averageOrderValue)}</p>\n <p className=\"text-sm text-text-secondary mt-1\">Per order average</p>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-6 text-center\">\n <Store className=\"h-8 w-8 text-text-primary mx-auto mb-3\" />\n <h4 className=\"text-lg font-semibold text-text-primary mb-2\">Active Carts</h4>\n <p className=\"text-2xl font-bold text-text-primary\">\n {(stats.activeProviders ?? 0).toLocaleString('en-IN')}\n </p>\n <p className=\"text-sm text-text-secondary mt-1\">Currently live on the platform</p>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -94,7 +94,7 @@ function k() {
|
|
|
94
94
|
children: [
|
|
95
95
|
/* @__PURE__ */ w(n, {
|
|
96
96
|
icon: /* @__PURE__ */ w(y, { className: "h-5 w-5" }),
|
|
97
|
-
value: j.totalOrders.toLocaleString("en-IN"),
|
|
97
|
+
value: (j.totalOrders ?? 0).toLocaleString("en-IN"),
|
|
98
98
|
label: "Total Orders"
|
|
99
99
|
}),
|
|
100
100
|
/* @__PURE__ */ w(n, {
|
|
@@ -109,7 +109,7 @@ function k() {
|
|
|
109
109
|
}),
|
|
110
110
|
/* @__PURE__ */ w(n, {
|
|
111
111
|
icon: /* @__PURE__ */ w(f, { className: "h-5 w-5" }),
|
|
112
|
-
value: j.pendingOrders.toLocaleString("en-IN"),
|
|
112
|
+
value: (j.pendingOrders ?? 0).toLocaleString("en-IN"),
|
|
113
113
|
label: "Pending Orders",
|
|
114
114
|
trendValue: "Awaiting action"
|
|
115
115
|
})
|