A friend told me how to fix this, I have created 6 widgets for each single stats overview and gave each one columnspan = 1; but he told me to do it like in the photo. I must put each 3 widgets or each row in the same stats overview widget and give it columnspan = 'full'; let me share my code with you
<?php
namespace App\Filament\Widgets;
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
use Filament\Widgets\StatsOverviewWidget\Stat;
use App\Models\Order;
use App\Models\PlaceOrder;
use Filament\Widgets\Concerns\InteractsWithPageFilters;
use Carbon\Carbon;
class OrderDeliveredWidget extends BaseWidget
{
use InteractsWithPageFilters;
protected int | string | array $columnSpan = 'full';
protected function getStats(): array
{
$statuses = [
['model' => Order::class, 'status' => 'to_customer', 'label' => 'On Delivery Orders'],
['model' => Order::class, 'status' => 'delivered', 'label' => 'Delivered Orders'],
['model' => PlaceOrder::class, 'status' => 'pending', 'label' => 'Pending Orders'],
];
$stats = [];
foreach ($statuses as $statusInfo) {
$query = $statusInfo['model']::query();
if ($this->filters['Date']) {
$query->where('created_at', '>=', $this->getFilterDate($this->filters['Date']));
}
$currentCount = $query->where('status', $statusInfo['status'])->count();
$previousPeriodStart = $this->getPreviousPeriodStart($this->filters['Date']);
$previousCount = $statusInfo['model']::where('status', $statusInfo['status'])
->where('created_at', '>=', $previousPeriodStart)
->where('created_at', '<', $this->getFilterDate($this->filters['Date']))
->count();
$percentageChange = $this->calculatePercentageChange($previousCount, $currentCount);
$description = $this->getDescription($percentageChange);
$icon = $this->getDescriptionIcon($percentageChange);
$color = $this->getColor($percentageChange);
$stats[] = Stat::make($statusInfo['label'], $currentCount)
->description($description)
->descriptionIcon($icon)
->color($color);
}
return $stats;
}
private function getFilterDate(?string $filter): Carbon
{
return match($filter) {
'today' => now()->startOfDay(),
'week' => now()->startOfWeek(),
'month' => now()->startOfMonth(),
'year' => now()->startOfYear(),
default => Carbon::createFromTimestamp(0),
};
}
protected function getFilters(): ?array
{
return [
'today' => 'Today',
'week' => 'This week',
'month' => 'This month',
'year' => 'This year',
];
}
private function calculatePercentageChange($oldValue, $newValue): float
{
if ($oldValue == 0) {
return $newValue > 0 ? 100 : 0;
}
return (($newValue - $oldValue) / $oldValue) * 100;
}
private function getDescription(float $percentageChange): string
{
$formattedChange = number_format(abs($percentageChange), 1);
$direction = $percentageChange >= 0 ? 'increase' : 'decrease';
return "{$formattedChange}% {$direction}";
}
private function getDescriptionIcon(float $percentageChange): string
{
return $percentageChange >= 0
? 'heroicon-m-arrow-trending-up'
: 'heroicon-m-arrow-trending-down';
}
private function getColor(float $percentageChange): string
{
if ($percentageChange > 10) {
return 'success';
} elseif ($percentageChange < -10) {
return 'danger';
} else {
return 'warning';
}
}
private function getPreviousPeriodStart(?string $filter): Carbon
{
return match($filter) {
'today' => now()->subDay()->startOfDay(),
'week' => now()->subWeek()->startOfWeek(),
'month' => now()->subMonth()->startOfMonth(),
'year' => now()->subYear()->startOfYear(),
default => Carbon::createFromTimestamp(0),
};
}
}