simedkom/app/Filament/Widgets/Charts/SentimentTrendChart.php

124 lines
3.6 KiB
PHP

<?php
namespace App\Filament\Widgets\Charts;
use App\Enums\IssueSentiment;
use App\Models\IssueManagement;
use BezhanSalleh\FilamentShield\Traits\HasWidgetShield;
use Filament\Widgets\ChartWidget;
use Filament\Widgets\Concerns\InteractsWithPageFilters;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
class SentimentTrendChart extends ChartWidget
{
use HasWidgetShield, InteractsWithPageFilters;
protected ?string $heading = 'Dinamika Sentimen Isu (Area)';
protected static ?int $sort = 18;
protected int|string|array $columnSpan = 1;
protected ?string $pollingInterval = null;
protected function getData(): array
{
$startDate = $this->filters['startDate'] ?? Carbon::now()->subDays(30);
$endDate = $this->filters['endDate'] ?? Carbon::now();
$startDate = Carbon::parse($startDate)->startOfDay();
$endDate = Carbon::parse($endDate)->endOfDay();
$query = IssueManagement::query()
->select(
DB::raw('DATE(created_at) as date'),
'issue',
DB::raw('count(*) as total')
)
->whereBetween('created_at', [$startDate, $endDate])
->groupBy('date', 'issue')
->orderBy('date')
->get();
$labels = [];
$current = clone $startDate;
while ($current <= $endDate) {
$labels[] = $current->translatedFormat('d M');
$current->addDay();
}
$datasets = [];
foreach (IssueSentiment::cases() as $sentiment) {
$data = [];
$current = clone $startDate;
while ($current <= $endDate) {
$dateStr = $current->toDateString();
$count = $query->where('date', $dateStr)
->where('issue', $sentiment->value)
->first();
$data[] = $count ? $count->total : 0;
$current->addDay();
}
$datasets[] = [
'label' => $sentiment->getLabel(),
'data' => $data,
'fill' => 'origin',
'backgroundColor' => $this->getHexColorRGBA($sentiment, 0.2),
'borderColor' => $this->getHexColor($sentiment),
'tension' => 0.4,
];
}
return [
'datasets' => $datasets,
'labels' => $labels,
];
}
private function getHexColor(IssueSentiment $sentiment): string
{
return match ($sentiment) {
IssueSentiment::POSITIVE => '#10B981',
IssueSentiment::NEGATIVE => '#EF4444',
IssueSentiment::NEUTRAL => '#6B7280',
IssueSentiment::CRISIS => '#F97316',
};
}
private function getHexColorRGBA(IssueSentiment $sentiment, float $opacity): string
{
return match ($sentiment) {
IssueSentiment::POSITIVE => "rgba(16, 185, 129, {$opacity})",
IssueSentiment::NEGATIVE => "rgba(239, 68, 68, {$opacity})",
IssueSentiment::NEUTRAL => "rgba(107, 114, 128, {$opacity})",
IssueSentiment::CRISIS => "rgba(249, 115, 22, {$opacity})",
};
}
protected function getType(): string
{
return 'line';
}
protected function getOptions(): array
{
return [
'plugins' => [
'legend' => [
'display' => true,
],
],
'scales' => [
'y' => [
'beginAtZero' => true,
'ticks' => [
'stepSize' => 1,
],
],
],
];
}
}