Add all files
This commit is contained in:
36
app/Admin/Widgets/ActiveUsers.php
Normal file
36
app/Admin/Widgets/ActiveUsers.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Widgets;
|
||||
|
||||
use Filament\Widgets\Widget;
|
||||
|
||||
class ActiveUsers extends Widget
|
||||
{
|
||||
protected static string $view = 'admin.widgets.active-users';
|
||||
|
||||
protected static ?int $sort = 2;
|
||||
|
||||
protected static string $title = 'Active Users';
|
||||
|
||||
public function render(): \Illuminate\View\View
|
||||
{
|
||||
$baseQuery = \App\Models\Session::query()
|
||||
->where('last_activity', '>=', now()->subMinutes(5))
|
||||
->whereNotNull('user_id')
|
||||
->orderBy('last_activity', 'desc')
|
||||
->with('user');
|
||||
|
||||
$sessions = (clone $baseQuery)->limit(5)->get();
|
||||
$onlineCount = (clone $baseQuery)->count();
|
||||
|
||||
return view(static::$view, [
|
||||
'sessions' => $sessions,
|
||||
'onlineCount' => $onlineCount,
|
||||
]);
|
||||
}
|
||||
|
||||
public static function canView(): bool
|
||||
{
|
||||
return auth()->user()->hasPermission('admin.widgets.active_users');
|
||||
}
|
||||
}
|
||||
71
app/Admin/Widgets/Overview.php
Normal file
71
app/Admin/Widgets/Overview.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Widgets;
|
||||
|
||||
use App\Models\InvoiceTransaction;
|
||||
use App\Models\Service;
|
||||
use App\Models\Ticket;
|
||||
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
|
||||
use Filament\Widgets\StatsOverviewWidget\Stat;
|
||||
use Flowframe\Trend\Trend;
|
||||
use Flowframe\Trend\TrendValue;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Overview extends BaseWidget
|
||||
{
|
||||
// Poll every 5 minutes (5m doesn't work somehow)
|
||||
protected static ?string $pollingInterval = '600s';
|
||||
|
||||
protected function getStats(): array
|
||||
{
|
||||
return [
|
||||
$this->getData(InvoiceTransaction::class, 'Revenue', 'amount'),
|
||||
$this->getData(Ticket::class, 'Tickets'),
|
||||
$this->getData(Service::class, 'Services'),
|
||||
];
|
||||
}
|
||||
|
||||
private function getData($model, $name, $sum = false)
|
||||
{
|
||||
$model = $model instanceof Model ? get_class($model) : $model;
|
||||
|
||||
$chart = Trend::model($model)
|
||||
->between(
|
||||
start: now()->subMonth(),
|
||||
end: now(),
|
||||
)
|
||||
->perDay();
|
||||
|
||||
if ($sum) {
|
||||
$chart = $chart->sum($sum);
|
||||
} else {
|
||||
$chart = $chart->count();
|
||||
}
|
||||
|
||||
$thisMonth = $chart->sum('aggregate');
|
||||
|
||||
$lastMonth = $model::query()
|
||||
->whereBetween('created_at', [now()->subMonths(2), now()->subMonth()]);
|
||||
|
||||
if ($sum) {
|
||||
$lastMonth = $lastMonth->sum($sum);
|
||||
} else {
|
||||
$lastMonth = $lastMonth->count();
|
||||
}
|
||||
|
||||
$increase = $thisMonth - $lastMonth;
|
||||
|
||||
$percentageIncrease = $lastMonth > 0 ? (($thisMonth - $lastMonth) / $lastMonth) * 100 : 0;
|
||||
|
||||
return Stat::make($name, $thisMonth)
|
||||
->description($increase >= 0 ? 'Increased by ' . number_format($percentageIncrease, 2) . '% (this month)' : 'Decreased by ' . number_format($percentageIncrease, 2) . '% (this month)')
|
||||
->descriptionIcon($increase >= 0 ? 'heroicon-m-arrow-trending-up' : 'heroicon-m-arrow-trending-down')
|
||||
->chart($chart->map(fn (TrendValue $value) => $value->aggregate)->toArray())
|
||||
->color($increase >= 0 ? 'success' : 'danger');
|
||||
}
|
||||
|
||||
public static function canView(): bool
|
||||
{
|
||||
return auth()->user()->hasPermission('admin.widgets.overview');
|
||||
}
|
||||
}
|
||||
118
app/Admin/Widgets/Revenue.php
Normal file
118
app/Admin/Widgets/Revenue.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Widgets;
|
||||
|
||||
use App\Models\InvoiceTransaction;
|
||||
use App\Models\Order;
|
||||
use Carbon\Carbon;
|
||||
use Filament\Support\RawJs;
|
||||
use Filament\Widgets\ChartWidget;
|
||||
use Flowframe\Trend\Trend;
|
||||
use Flowframe\Trend\TrendValue;
|
||||
|
||||
class Revenue extends ChartWidget
|
||||
{
|
||||
protected static ?string $heading = 'Revenue';
|
||||
|
||||
public ?string $filter = 'week';
|
||||
|
||||
protected static ?string $pollingInterval = null;
|
||||
|
||||
protected function getFilters(): ?array
|
||||
{
|
||||
return [
|
||||
'today' => 'Last 24 hours',
|
||||
'week' => 'Last 7 days',
|
||||
'month' => 'Last 30 days',
|
||||
'year' => 'Last 365 days',
|
||||
];
|
||||
}
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$start = match ($this->filter) {
|
||||
'today' => now()->subDay(),
|
||||
'week' => now()->subWeek(),
|
||||
'month' => now()->subMonth(),
|
||||
'year' => now()->subYear(),
|
||||
};
|
||||
|
||||
$end = now();
|
||||
|
||||
$per = match ($this->filter) {
|
||||
'today' => 'hour',
|
||||
'week' => 'day',
|
||||
'month' => 'day',
|
||||
'year' => 'month',
|
||||
};
|
||||
|
||||
$revenue = Trend::model(InvoiceTransaction::class)
|
||||
->between(
|
||||
start: $start,
|
||||
end: $end,
|
||||
)
|
||||
->{'per' . ucfirst($per)}()
|
||||
->sum('amount');
|
||||
|
||||
$netRevenue = Trend::model(InvoiceTransaction::class)
|
||||
->between(
|
||||
start: $start,
|
||||
end: $end,
|
||||
)
|
||||
->{'per' . ucfirst($per)}()
|
||||
->sum('amount - fee');
|
||||
|
||||
$newOrders = Trend::model(Order::class)
|
||||
->between(
|
||||
start: $start,
|
||||
end: $end,
|
||||
)
|
||||
->{'per' . ucfirst($per)}()
|
||||
->count();
|
||||
|
||||
return [
|
||||
'datasets' => [
|
||||
[
|
||||
'label' => 'Revenue',
|
||||
'data' => $revenue->map(fn (TrendValue $value) => $value->aggregate)->toArray(),
|
||||
'backgroundColor' => '#3490dc',
|
||||
'borderColor' => '#3490dc',
|
||||
],
|
||||
[
|
||||
'label' => 'Net Revenue',
|
||||
'data' => $netRevenue->map(fn (TrendValue $value) => $value->aggregate)->toArray(),
|
||||
'backgroundColor' => '#38c172',
|
||||
'borderColor' => '#38c172',
|
||||
],
|
||||
[
|
||||
'label' => 'New Orders',
|
||||
'data' => $newOrders->map(fn (TrendValue $value) => $value->aggregate)->toArray(),
|
||||
'backgroundColor' => '#e3342f',
|
||||
'borderColor' => '#e3342f',
|
||||
],
|
||||
],
|
||||
'labels' => $revenue->map(fn (TrendValue $value) => $this->filter === 'today' ? Carbon::parse($value->date)->format('H:i') : Carbon::parse($value->date)->format('M d'))->toArray(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function getOptions(): array|RawJs|null
|
||||
{
|
||||
return [
|
||||
'scales' => [
|
||||
'y' => [
|
||||
'beginAtZero' => true,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
protected function getType(): string
|
||||
{
|
||||
return 'line';
|
||||
}
|
||||
|
||||
public static function canView(): bool
|
||||
{
|
||||
return auth()->user()->hasPermission('admin.widgets.revenue');
|
||||
}
|
||||
}
|
||||
51
app/Admin/Widgets/Support.php
Normal file
51
app/Admin/Widgets/Support.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Widgets;
|
||||
|
||||
use App\Admin\Resources\TicketResource;
|
||||
use App\Models\Ticket;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Filament\Widgets\TableWidget as BaseWidget;
|
||||
|
||||
class Support extends BaseWidget
|
||||
{
|
||||
protected static ?string $pollingInterval = '30s';
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->query(
|
||||
Ticket::query()
|
||||
->where('status', '!=', 'closed')
|
||||
->with('user')
|
||||
->withMax('messages', 'created_at')
|
||||
->orderByDesc('messages_max_created_at')
|
||||
->limit(5)
|
||||
)
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('subject')
|
||||
->label('Subject'),
|
||||
Tables\Columns\TextColumn::make('status')
|
||||
->label('Status')
|
||||
->badge()
|
||||
->color(fn (Ticket $record) => match ($record->status) {
|
||||
'open' => 'success',
|
||||
'closed' => 'danger',
|
||||
'replied' => 'warning',
|
||||
})
|
||||
->formatStateUsing(fn (string $state) => ucfirst($state)),
|
||||
Tables\Columns\TextColumn::make('user.name')
|
||||
->label('User'),
|
||||
Tables\Columns\TextColumn::make('created_at')
|
||||
->label('Created At'),
|
||||
])
|
||||
->recordUrl(fn (Ticket $record) => TicketResource::getUrl('edit', ['record' => $record]))
|
||||
->paginated(false);
|
||||
}
|
||||
|
||||
public static function canView(): bool
|
||||
{
|
||||
return auth()->user()->hasPermission('admin.widgets.support');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user