Phase 7 dashboard widgets, Gitea CI, and branded landing page (T7.1)

- BookingsTodayWidget, RecentBookingsTableWidget (Booking module) and
  RevenueChartWidget, PaymentFailureRateWidget (Payment module) dashboard
  widgets, auto-registered via each plugin's existing discoverWidgets().
- .gitea/workflows/tests.yml: Postgres-backed Pest run on push/PR.
- Landing page (resources/views/welcome.blade.php) now shows the Famous
  Linnyone4 EV logo with a single admin login link, and the Filament admin
  panel uses the same logo as its brand logo.
This commit is contained in:
Nyan Lin Paing
2026-08-10 00:15:19 +07:00
parent d528cf16ec
commit 60413bdebf
12 changed files with 375 additions and 259 deletions
@@ -0,0 +1,36 @@
<?php
namespace Modules\Booking\Filament\Widgets;
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
use Filament\Widgets\StatsOverviewWidget\Stat;
use Modules\Booking\Enums\BookingStatus;
use Modules\Booking\Models\Booking;
/**
* Dispatch-facing snapshot of today's trips "today" means travel_date, not
* created_at, since this is what staff care about when assigning
* drivers/vehicles (domain.md §5a), not how many bookings were made today.
*/
class BookingsTodayWidget extends BaseWidget
{
protected function getStats(): array
{
$today = Booking::query()->whereDate('travel_date', today());
$confirmedToday = (clone $today)->where('status', BookingStatus::Confirmed)->count();
$pendingToday = (clone $today)->where('status', BookingStatus::PendingPayment)->count();
return [
Stat::make('Trips Today', (clone $today)->count())
->description('Bookings scheduled for today')
->color('primary'),
Stat::make('Confirmed', $confirmedToday)
->description('Paid & ready for driver assignment')
->color('success'),
Stat::make('Awaiting Payment', $pendingToday)
->description('Still pending_payment')
->color($pendingToday > 0 ? 'warning' : 'gray'),
];
}
}
@@ -0,0 +1,52 @@
<?php
namespace Modules\Booking\Filament\Widgets;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Filament\Widgets\TableWidget as BaseWidget;
use Modules\Booking\Enums\BookingStatus;
use Modules\Booking\Models\Booking;
class RecentBookingsTableWidget extends BaseWidget
{
protected static ?int $sort = 2;
protected int|string|array $columnSpan = 'full';
public function table(Table $table): Table
{
return $table
->heading('Recent Bookings')
->query(
Booking::query()
->with(['route.fromDestination', 'route.toDestination'])
->latest('created_at')
->limit(10),
)
->columns([
TextColumn::make('booking_ref')
->label('Ref'),
TextColumn::make('status')
->badge()
->color(fn (BookingStatus $state) => match ($state) {
BookingStatus::PendingPayment => 'warning',
BookingStatus::Confirmed => 'success',
BookingStatus::Cancelled => 'gray',
BookingStatus::Expired => 'danger',
}),
TextColumn::make('route.fromDestination.name')
->label('From'),
TextColumn::make('route.toDestination.name')
->label('To'),
TextColumn::make('travel_date')
->date(),
TextColumn::make('price')
->numeric(2),
TextColumn::make('created_at')
->dateTime()
->since(),
])
->paginated(false);
}
}