diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php
index 6250ae5..df6c765 100644
--- a/app/Http/Controllers/DashboardController.php
+++ b/app/Http/Controllers/DashboardController.php
@@ -2,6 +2,9 @@
namespace App\Http\Controllers;
+use App\Enums\OrderChannel;
+use App\Enums\OrderStatus;
+use App\Enums\PaymentMethod;
use App\Models\Expense;
use App\Models\Order;
use App\Models\OrderItem;
@@ -63,9 +66,48 @@ public function __invoke()
];
});
+ $paymentMethods = DB::table('orders')
+ ->select('payment_method as name', DB::raw('COUNT(*) as total'))
+ ->groupBy('payment_method')
+ ->get()
+ ->map(function ($item) {
+ if ($item->name) {
+ $item->name = PaymentMethod::tryFrom($item->name)?->label() ?? $item->name;
+ }
+
+ return $item;
+ });
+
+ $orderStatuses = DB::table('orders')
+ ->select('order_status as name', DB::raw('COUNT(*) as total'))
+ ->groupBy('order_status')
+ ->get()
+ ->map(function ($item) {
+ if ($item->name) {
+ $item->name = OrderStatus::tryFrom($item->name)?->label() ?? $item->name;
+ }
+
+ return $item;
+ });
+
+ $orderChannels = DB::table('orders')
+ ->select('order_channel as name', DB::raw('COUNT(*) as total'))
+ ->groupBy('order_channel')
+ ->get()
+ ->map(function ($item) {
+ if ($item->name) {
+ $item->name = OrderChannel::tryFrom($item->name)?->label() ?? $item->name;
+ }
+
+ return $item;
+ });
+
return Inertia::render('dashboard', [
'stats' => $stats,
'salesByHour' => $salesByHour,
+ 'paymentMethods' => $paymentMethods,
+ 'orderStatuses' => $orderStatuses,
+ 'orderChannels' => $orderChannels,
]);
}
diff --git a/resources/js/components/charts/pie-chart.tsx b/resources/js/components/charts/pie-chart.tsx
new file mode 100644
index 0000000..b4980d7
--- /dev/null
+++ b/resources/js/components/charts/pie-chart.tsx
@@ -0,0 +1,80 @@
+"use client"
+
+import React, { useMemo } from "react"
+import { Pie, PieChart } from "recharts"
+
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from "@/components/ui/card"
+import {
+ ChartContainer,
+ ChartTooltip,
+ ChartTooltipContent,
+ type ChartConfig,
+} from "@/components/ui/chart"
+
+export const CustomPieChart = React.memo(function CustomPieChart({
+ title,
+ description,
+ data,
+ colorOffset = 0,
+}: {
+ title: string
+ description: string
+ data: any[]
+ colorOffset?: number
+}) {
+ const { config, chartData } = useMemo(() => {
+ const cfg: ChartConfig = {
+ total: { label: "Total" },
+ }
+
+ const formattedData = data.map((item, index) => {
+ const key = String(item.name).toLowerCase().replace(/[^a-z0-9]/g, '_')
+
+ // Generate distinct HSL color based on index and chart-level offset
+ // 137.5 is the golden angle, which distributes colors nicely
+ const hue = Math.floor((index * 137.5 + colorOffset) % 360)
+
+ cfg[key] = {
+ label: String(item.name),
+ color: `hsl(${hue}, 70%, 50%)`,
+ }
+ return {
+ ...item,
+ fill: `var(--color-${key})`,
+ name: String(item.name),
+ }
+ })
+ return { config: cfg, chartData: formattedData }
+ }, [data, colorOffset])
+
+ return (
+
+
+ {title}
+ {description}
+
+
+
+
+ } />
+
+
+
+
+
+ )
+})
diff --git a/resources/js/pages/dashboard.tsx b/resources/js/pages/dashboard.tsx
index 1797a55..2a9a561 100644
--- a/resources/js/pages/dashboard.tsx
+++ b/resources/js/pages/dashboard.tsx
@@ -5,9 +5,10 @@ import { DashboardPageProps } from '@/types';
import { StatCard } from '@/components/cards/stat-card';
import { WelcomeCard } from '@/components/cards/welcome-card';
import { SalesByHourChart } from '../components/charts/sales-by-hour-chart';
+import { CustomPieChart } from '../components/charts/pie-chart';
export default function Dashboard() {
- const { auth, stats, salesByHour } = usePage().props;
+ const { auth, stats, salesByHour, paymentMethods, orderStatuses, orderChannels } = usePage().props;
const [time, setTime] = useState(new Date());
useEffect(() => {
@@ -101,6 +102,27 @@ export default function Dashboard() {
+
+
+
+
+
+
>
);