214 lines
6.8 KiB
PHP
214 lines
6.8 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Pages\System\Changelog;
|
|
|
|
use App\Enums\ChangelogType;
|
|
use App\Filament\Pages\System\Changelog\Actions\CreateChangelogAction;
|
|
use App\Filament\Pages\System\Changelog\Actions\DeleteChangelogAction;
|
|
use App\Filament\Pages\System\Changelog\Actions\EditChangelogAction;
|
|
use App\Filament\Pages\System\Changelog\Actions\MarkAsReadAction;
|
|
use App\Filament\Support\SystemNotification;
|
|
use App\Models\Changelog;
|
|
use App\Models\Student;
|
|
use BackedEnum;
|
|
use BezhanSalleh\FilamentShield\Traits\HasPageShield;
|
|
use Carbon\Carbon;
|
|
use Filament\Actions\Action;
|
|
use Filament\Actions\Concerns\InteractsWithActions;
|
|
use Filament\Actions\Contracts\HasActions;
|
|
use Filament\Forms\Components\DatePicker;
|
|
use Filament\Forms\Components\RichEditor;
|
|
use Filament\Forms\Components\Select;
|
|
use Filament\Forms\Components\TagsInput;
|
|
use Filament\Forms\Components\TextInput;
|
|
use Filament\Forms\Concerns\InteractsWithForms;
|
|
use Filament\Forms\Contracts\HasForms;
|
|
use Filament\Pages\Page;
|
|
use Filament\Schemas\Components\Grid;
|
|
use Filament\Support\Enums\Width;
|
|
use Illuminate\Support\Collection;
|
|
use Livewire\Attributes\Computed;
|
|
use UnitEnum;
|
|
|
|
class Index extends Page implements HasActions, HasForms
|
|
{
|
|
use HasPageShield, InteractsWithActions, InteractsWithForms;
|
|
|
|
protected static string|UnitEnum|null $navigationGroup = 'Sistem';
|
|
|
|
protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-information-circle';
|
|
|
|
protected static ?string $title = 'Changelog';
|
|
|
|
protected static ?string $navigationLabel = 'Changelog';
|
|
|
|
protected static ?string $slug = 'system/changelog';
|
|
|
|
protected static ?int $navigationSort = 10;
|
|
|
|
protected string $view = 'filament.pages.system.changelog.index';
|
|
|
|
public static function getNavigationBadge(): ?string
|
|
{
|
|
$unreadCount = Changelog::whereDoesntHave('users', fn ($query) => $query->where('user_id', auth()->id()))->count();
|
|
|
|
return $unreadCount > 0 ? (string) $unreadCount : null;
|
|
}
|
|
|
|
public static function getPagePermission(): string
|
|
{
|
|
return 'View:Changelog';
|
|
}
|
|
|
|
#[Computed]
|
|
public function techStack(): array
|
|
{
|
|
$latestUpdate = Changelog::latest('release_date')->first();
|
|
|
|
return [
|
|
'name' => config('app.name'),
|
|
'version' => $latestUpdate?->version ?? 'v1.0.0',
|
|
'stack' => [
|
|
'PHP' => PHP_VERSION,
|
|
'Laravel' => app()->version(),
|
|
'Filament' => 'v5.x',
|
|
'Database' => config('database.default'),
|
|
],
|
|
];
|
|
}
|
|
|
|
#[Computed]
|
|
public function changelogs(): Collection
|
|
{
|
|
return Changelog::with([
|
|
'users' => fn ($query) => $query->where('user_id', auth()->id()),
|
|
])
|
|
->orderBy('version', 'desc')
|
|
->get()
|
|
->sortBy([
|
|
fn ($a, $b) => $a->is_read <=> $b->is_read,
|
|
])
|
|
->values();
|
|
}
|
|
|
|
protected function getHeaderActions(): array
|
|
{
|
|
return [
|
|
CreateChangelogAction::make()
|
|
->visible(fn () => auth()->user()?->can('Create:Changelog')),
|
|
];
|
|
}
|
|
|
|
public function editChangelogAction(): Action
|
|
{
|
|
return EditChangelogAction::make()
|
|
->visible(fn () => auth()->user()?->can('Update:Changelog'));
|
|
}
|
|
|
|
public function deleteChangelogAction(): Action
|
|
{
|
|
return DeleteChangelogAction::make()
|
|
->visible(fn () => auth()->user()?->can('Delete:Changelog'));
|
|
}
|
|
|
|
public function markAsReadAction(): Action
|
|
{
|
|
return MarkAsReadAction::make();
|
|
}
|
|
|
|
public function viewReadersAction(): Action
|
|
{
|
|
return Action::make('viewReaders')
|
|
->label('Lihat')
|
|
->icon('heroicon-o-eye')
|
|
->color('info')
|
|
->link()
|
|
->tooltip('Daftar Mahasiswa')
|
|
->modalHeading('Daftar Mahasiswa yang Melihat')
|
|
->modalWidth(Width::TwoExtraLarge)
|
|
->modalSubmitAction(false)
|
|
->modalCancelActionLabel('Tutup')
|
|
->visible(fn () => auth()->user()?->can('Update:Changelog'))
|
|
->modalContent(function (array $arguments) {
|
|
$record = Changelog::find($arguments['record'] ?? null);
|
|
|
|
if (! $record) {
|
|
return null;
|
|
}
|
|
|
|
$students = Student::with('user')->get();
|
|
$readUsersMap = $record->users()->withPivot('read_at')->get()->keyBy('id');
|
|
|
|
$records = $students->map(fn ($student) => (object) [
|
|
'student' => $student,
|
|
'is_read' => $readUsersMap->has($student->user_id),
|
|
'read_at' => $readUsersMap->get($student->user_id)?->pivot?->read_at
|
|
? Carbon::parse($readUsersMap->get($student->user_id)->pivot->read_at)->translatedFormat('d F Y H:i')
|
|
: null,
|
|
]);
|
|
|
|
return view('filament.pages.system.changelog.view-readers', [
|
|
'records' => $records,
|
|
'readCount' => $readUsersMap->count(),
|
|
]);
|
|
});
|
|
}
|
|
|
|
#[Computed]
|
|
public function emptyHeading(): string
|
|
{
|
|
return SystemNotification::getByKey('labels.empty_changelog.title');
|
|
}
|
|
|
|
#[Computed]
|
|
public function emptyDescription(): string
|
|
{
|
|
return SystemNotification::getByKey('labels.empty_changelog.description');
|
|
}
|
|
|
|
public function changelogFormSchema(): array
|
|
{
|
|
return [
|
|
Grid::make(3)
|
|
->schema([
|
|
TextInput::make('version')
|
|
->label('Versi')
|
|
->placeholder('v1.0.0')
|
|
->required()
|
|
->unique(ignoreRecord: true)
|
|
->autocomplete(false),
|
|
|
|
DatePicker::make('release_date')
|
|
->label('Tanggal Rilis')
|
|
->required()
|
|
->native(false)
|
|
->default(now())
|
|
->displayFormat('d F Y'),
|
|
|
|
Select::make('type')
|
|
->label('Tipe Update')
|
|
->options(ChangelogType::class)
|
|
->required()
|
|
->native(false),
|
|
]),
|
|
|
|
TextInput::make('title')
|
|
->label('Judul Update')
|
|
->placeholder('Sistem Notifikasi & Estetika Baru')
|
|
->required()
|
|
->maxLength(100)
|
|
->autocomplete(false),
|
|
|
|
TagsInput::make('changes')
|
|
->label('Daftar Perubahan')
|
|
->placeholder('Tambah perubahan...')
|
|
->required(),
|
|
|
|
RichEditor::make('description')
|
|
->label('Deskripsi')
|
|
->placeholder('...')
|
|
->required(),
|
|
];
|
|
}
|
|
}
|