feat: Implement advanced filtering and Excel export functionality for Cooperation, Issue Management, Media Monitoring, and Content Recap tables.

This commit is contained in:
Yoga Pangestu 2026-01-29 13:22:57 +07:00
parent c67faf3e4e
commit 2e80c19c19
12 changed files with 1413 additions and 5 deletions

View File

@ -0,0 +1,95 @@
<?php
namespace App\Filament\Exports;
use App\Enums\Channel;
use App\Enums\SocialMedia;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithStyles;
use Maatwebsite\Excel\Events\AfterSheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use pxlrbt\FilamentExcel\Columns\Column;
use pxlrbt\FilamentExcel\Exports\ExcelExport;
class ContentRecapExcelExport extends ExcelExport implements WithEvents, WithStyles
{
public function setUp()
{
$this->withFilename(fn ($resource) => $resource::getModelLabel().'-'.date('Y-m-d'));
$this->withColumns([
Column::make('title')
->heading('Judul'),
Column::make('type')
->heading('Tipe')
->formatStateUsing(fn ($state) => $state?->getLabel()),
Column::make('channel')
->heading('Kanal')
->formatStateUsing(fn ($state) => Channel::tryFrom($state)?->getLabel() ?? $state),
Column::make('social_media')
->heading('Media Sosial')
->formatStateUsing(fn ($state) => SocialMedia::tryFrom($state)?->getLabel() ?? $state),
Column::make('classification.name')
->heading('Klasifikasi'),
Column::make('link')
->heading('Tautan'),
Column::make('posting_date')
->heading('Tgl Posting')
->formatStateUsing(fn ($state) => $state?->translatedFormat('l, d F Y')),
]);
}
public function headings(): array
{
return [
['Data Rekap Konten'],
$this->getHeadings(),
];
}
public function styles(Worksheet $sheet)
{
return [
1 => [
'font' => ['bold' => true, 'size' => 14],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
],
2 => [
'font' => ['bold' => true],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER],
],
];
}
public function registerEvents(): array
{
return [
AfterSheet::class => function (AfterSheet $event) {
$sheet = $event->sheet->getDelegate();
$lastColumn = 'G'; // A-G
$sheet->mergeCells("A1:{$lastColumn}1");
$sheet->getStyle("A2:{$lastColumn}".$sheet->getHighestRow())
->getAlignment()
->setVertical(Alignment::VERTICAL_TOP)
->setWrapText(true);
for ($i = 3; $i <= $sheet->getHighestRow(); $i++) {
$sheet->getRowDimension($i)->setRowHeight(-1);
}
foreach (range('A', $lastColumn) as $columnID) {
$sheet->getColumnDimension($columnID)->setAutoSize(true);
}
},
];
}
}

View File

@ -0,0 +1,98 @@
<?php
namespace App\Filament\Exports;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithStyles;
use Maatwebsite\Excel\Events\AfterSheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use pxlrbt\FilamentExcel\Columns\Column;
use pxlrbt\FilamentExcel\Exports\ExcelExport;
class CooperationExcelExport extends ExcelExport implements WithEvents, WithStyles
{
public function setUp()
{
$this->withFilename(fn ($resource) => $resource::getModelLabel().'-'.date('Y-m-d'));
$this->withColumns([
Column::make('title')
->heading('Judul'),
Column::make('partnerMedia.name')
->heading('Media')
->getStateUsing(fn ($record) => $record->partnerMedia->pluck('name')->join(', ')),
Column::make('initial_submission_date')
->heading('Tgl Pengajuan Awal')
->formatStateUsing(fn ($state) => $state?->translatedFormat('l, d F Y')),
Column::make('final_submission_date')
->heading('Tgl Pengajuan Akhir')
->formatStateUsing(fn ($state) => $state?->translatedFormat('l, d F Y')),
Column::make('status')
->heading('Status')
->formatStateUsing(fn ($state) => $state?->getLabel()),
Column::make('payment_amount')
->heading('Jumlah Pembayaran')
->formatStateUsing(fn ($state) => 'Rp '.number_format($state, 0, ',', '.')),
Column::make('payment_date')
->heading('Tanggal Pembayaran')
->formatStateUsing(fn ($state) => $state?->translatedFormat('l, d F Y')),
Column::make('description')
->heading('Deskripsi'),
]);
}
public function headings(): array
{
return [
['Data Kerja Sama'],
$this->getHeadings(),
];
}
public function styles(Worksheet $sheet)
{
return [
1 => [
'font' => ['bold' => true, 'size' => 14],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
],
2 => [
'font' => ['bold' => true],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER],
],
];
}
public function registerEvents(): array
{
return [
AfterSheet::class => function (AfterSheet $event) {
$sheet = $event->sheet->getDelegate();
$lastColumn = 'H'; // A-H
$sheet->mergeCells("A1:{$lastColumn}1");
$sheet->getStyle("A2:{$lastColumn}".$sheet->getHighestRow())
->getAlignment()
->setVertical(Alignment::VERTICAL_TOP)
->setWrapText(true);
for ($i = 3; $i <= $sheet->getHighestRow(); $i++) {
$sheet->getRowDimension($i)->setRowHeight(-1);
}
foreach (range('A', $lastColumn) as $columnID) {
$sheet->getColumnDimension($columnID)->setAutoSize(true);
}
},
];
}
}

View File

@ -0,0 +1,98 @@
<?php
namespace App\Filament\Exports;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithStyles;
use Maatwebsite\Excel\Events\AfterSheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use pxlrbt\FilamentExcel\Columns\Column;
use pxlrbt\FilamentExcel\Exports\ExcelExport;
class IssueManagementExcelExport extends ExcelExport implements WithEvents, WithStyles
{
public function setUp()
{
$this->withFilename(fn ($resource) => $resource::getModelLabel().'-'.date('Y-m-d'));
$this->withColumns([
Column::make('mediaMonitoring.title')
->heading('Judul Berita'),
Column::make('issue')
->heading('Isu')
->formatStateUsing(fn ($state) => $state?->getLabel()),
Column::make('response')
->heading('Respon')
->formatStateUsing(fn ($state) => $state?->getLabel()),
Column::make('location.name')
->heading('Lokus'),
Column::make('subLocation.name')
->heading('Sub Lokus'),
Column::make('classification.name')
->heading('Klasifikasi'),
Column::make('subClassification.name')
->heading('Sub Klasifikasi'),
Column::make('description')
->heading('Keterangan'),
Column::make('mediaMonitoring.release_date')
->heading('Tgl Rilis')
->formatStateUsing(fn ($state) => $state?->translatedFormat('l, d F Y')),
]);
}
public function headings(): array
{
return [
['Data Manajemen Isu'],
$this->getHeadings(),
];
}
public function styles(Worksheet $sheet)
{
return [
1 => [
'font' => ['bold' => true, 'size' => 14],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
],
2 => [
'font' => ['bold' => true],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER],
],
];
}
public function registerEvents(): array
{
return [
AfterSheet::class => function (AfterSheet $event) {
$sheet = $event->sheet->getDelegate();
$lastColumn = 'I'; // A-I
$sheet->mergeCells("A1:{$lastColumn}1");
$sheet->getStyle("A2:{$lastColumn}".$sheet->getHighestRow())
->getAlignment()
->setVertical(Alignment::VERTICAL_TOP)
->setWrapText(true);
for ($i = 3; $i <= $sheet->getHighestRow(); $i++) {
$sheet->getRowDimension($i)->setRowHeight(-1);
}
foreach (range('A', $lastColumn) as $columnID) {
$sheet->getColumnDimension($columnID)->setAutoSize(true);
}
},
];
}
}

View File

@ -0,0 +1,109 @@
<?php
namespace App\Filament\Exports;
use App\Enums\Channel;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithStyles;
use Maatwebsite\Excel\Events\AfterSheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use pxlrbt\FilamentExcel\Columns\Column;
use pxlrbt\FilamentExcel\Exports\ExcelExport;
class MediaMonitoringExcelExport extends ExcelExport implements WithEvents, WithStyles
{
public function setUp()
{
$this->withFilename(fn ($resource) => $resource::getModelLabel().'-'.date('Y-m-d'));
$this->withColumns([
Column::make('code')
->heading('Kode'),
Column::make('media_name')
->heading('Nama Media'),
Column::make('title')
->heading('Judul'),
Column::make('channel')
->heading('Kanal')
->formatStateUsing(fn ($state) => Channel::tryFrom($state)?->getLabel() ?? $state),
Column::make('writter')
->heading('Penulis'),
Column::make('link')
->heading('Tautan'),
Column::make('news_page')
->heading('Halaman Berita'),
Column::make('influencer')
->heading('Influencer'),
Column::make('keyword')
->heading('Kata Kunci'),
Column::make('themes')
->heading('Tema')
->getStateUsing(fn ($record) => $record->themes->pluck('name')->join(', ')),
Column::make('release_date')
->heading('Tgl Rilis'),
]);
}
public function headings(): array
{
return [
['Data Monitoring Media'],
$this->getHeadings(),
];
}
public function styles(Worksheet $sheet)
{
return [
1 => [
'font' => ['bold' => true, 'size' => 14],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
],
2 => [
'font' => ['bold' => true],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER],
],
];
}
public function registerEvents(): array
{
return [
AfterSheet::class => function (AfterSheet $event) {
$sheet = $event->sheet->getDelegate();
$lastColumn = 'K'; // Based on column count (A-K)
// Merge Title Row
// Merge Title Row
$sheet->mergeCells("A1:{$lastColumn}1");
// Alignment and Wrap Text
$sheet->getStyle("A2:{$lastColumn}".$sheet->getHighestRow())
->getAlignment()
->setVertical(Alignment::VERTICAL_TOP)
->setWrapText(true);
// Ensure data rows auto-expand to fit wrapped text ("jadi 2 row")
// We start from row 3 (after Title and Header)
for ($i = 3; $i <= $sheet->getHighestRow(); $i++) {
$sheet->getRowDimension($i)->setRowHeight(-1);
}
foreach (range('A', $lastColumn) as $columnID) {
$sheet->getColumnDimension($columnID)->setAutoSize(true);
}
},
];
}
}

View File

@ -3,11 +3,13 @@
namespace App\Filament\Resources\Manage\Cooperations\Tables;
use App\Enums\ApprovalStatus;
use App\Enums\CooperationStatus;
use App\Enums\RoleEnum;
use App\Filament\Actions\Cheerful\DeleteAction;
use App\Filament\Actions\Cheerful\EditAction;
use App\Filament\Actions\DefaultBulkActions;
use App\Filament\Columns\TimestampColumns;
use App\Filament\Exports\CooperationExcelExport;
use App\Filament\Resources\Manage\Cooperations\Actions\Cooperation\AcceptAction;
use App\Filament\Resources\Manage\Cooperations\Actions\Cooperation\CompleteCooperationAction;
use App\Filament\Resources\Manage\Cooperations\Actions\Cooperation\CreateTaskAssignmentAction;
@ -18,11 +20,18 @@
use Carbon\CarbonInterface;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\ViewAction;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use pxlrbt\FilamentExcel\Actions\Tables\ExportAction;
class CooperationsTable
{
@ -133,6 +142,102 @@ public static function configure(Table $table): Table
])
->filters([
TrashedFilter::make()->native(false),
SelectFilter::make('status')
->label('Status')
->options(CooperationStatus::class),
SelectFilter::make('partnerMedia')
->label('Media')
->relationship('partnerMedia', 'name')
->searchable()
->preload(),
Filter::make('title')
->schema([
TextInput::make('title')
->label('Nama Kegiatan')
->placeholder('Cari nama kegiatan...'),
])
->query(function (Builder $query, array $data): Builder {
return $query->when(
$data['title'],
fn (Builder $query, $title): Builder => $query->where('title', 'like', "%{$title}%"),
);
}),
Filter::make('date_filter')
->schema([
Select::make('date_type')
->label('Jenis Filter Tanggal')
->options([
'date' => 'Tanggal Penyerahan Awal',
'month' => 'Bulan & Tahun',
'year' => 'Tahun',
'range' => 'Rentang Tanggal',
])
->default('date')
->live(),
DatePicker::make('specific_date')
->label('Tanggal')
->visible(fn (Get $get) => $get('date_type') === 'date'),
Select::make('month')
->label('Bulan')
->options([
1 => 'Januari',
2 => 'Februari',
3 => 'Maret',
4 => 'April',
5 => 'Mei',
6 => 'Juni',
7 => 'Juli',
8 => 'Agustus',
9 => 'September',
10 => 'Oktober',
11 => 'November',
12 => 'Desember',
])
->visible(fn (Get $get) => $get('date_type') === 'month'),
Select::make('year')
->label('Tahun')
->options(function () {
$years = range(date('Y'), 2020);
return array_combine($years, $years);
})
->visible(fn (Get $get) => in_array($get('date_type'), ['month', 'year'])),
DatePicker::make('start_date')
->label('Mulai Tanggal')
->visible(fn (Get $get) => $get('date_type') === 'range'),
DatePicker::make('end_date')
->label('Sampai Tanggal')
->visible(fn (Get $get) => $get('date_type') === 'range'),
])
->query(function (Builder $query, array $data): Builder {
$type = $data['date_type'] ?? null;
$column = 'initial_submission_date';
if ($type === 'date' && ! empty($data['specific_date'])) {
return $query->whereDate($column, $data['specific_date']);
}
if ($type === 'month' && ! empty($data['month']) && ! empty($data['year'])) {
return $query->whereMonth($column, $data['month'])
->whereYear($column, $data['year']);
}
if ($type === 'year' && ! empty($data['year'])) {
return $query->whereYear($column, $data['year']);
}
if ($type === 'range' && ! empty($data['start_date']) && ! empty($data['end_date'])) {
return $query->whereBetween($column, [$data['start_date'], $data['end_date']]);
}
return $query;
}),
])
->recordActions([
ViewAction::make(),
@ -155,6 +260,14 @@ public static function configure(Table $table): Table
DeleteAction::make()
->visible(fn (): bool => ! auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value)),
])
->headerActions([
ExportAction::make()
->exports([
CooperationExcelExport::make(),
])
->color('success'),
])
->toolbarActions([
BulkActionGroup::make([
...DefaultBulkActions::make('Kerja Sama'),

View File

@ -2,17 +2,29 @@
namespace App\Filament\Resources\Monitoring\ContentRecaps\Tables;
use App\Enums\Channel;
use App\Enums\ContentType;
use App\Enums\SocialMedia;
use App\Filament\Actions\Cheerful\DeleteAction;
use App\Filament\Actions\Cheerful\EditAction;
use App\Filament\Actions\Cheerful\ForceDeleteAction;
use App\Filament\Actions\Cheerful\RestoreAction;
use App\Filament\Actions\DefaultBulkActions;
use App\Filament\Columns\TimestampColumns;
use App\Filament\Exports\ContentRecapExcelExport;
use Filament\Actions\BulkActionGroup;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use pxlrbt\FilamentExcel\Actions\Tables\ExportAction;
class ContentRecapsTable
{
@ -61,7 +73,114 @@ public static function configure(Table $table): Table
])
->filters([
TrashedFilter::make()->native(false),
SelectFilter::make('social_media')
->label('Media Sosial')
->options(SocialMedia::class)
->native(false),
SelectFilter::make('classification')
->label('Klasifikasi')
->relationship('classification', 'name')
->searchable()
->preload()
->native(false),
SelectFilter::make('type')
->label('Jenis Konten')
->options(ContentType::class)
->native(false),
SelectFilter::make('channel')
->label('Kanal')
->options(Channel::class)
->native(false),
Filter::make('date_filter')
->schema([
Select::make('date_type')
->label('Jenis Filter Tanggal')
->options([
'date' => 'Tanggal Posting',
'month' => 'Bulan & Tahun',
'year' => 'Tahun',
'range' => 'Rentang Tanggal',
])
->default('date')
->live()
->native(false),
DatePicker::make('specific_date')
->label('Tanggal')
->placeholder('Pilih tanggal')
->visible(fn (Get $get) => $get('date_type') === 'date')
->native(false),
Select::make('month')
->label('Bulan')
->options([
1 => 'Januari',
2 => 'Februari',
3 => 'Maret',
4 => 'April',
5 => 'Mei',
6 => 'Juni',
7 => 'Juli',
8 => 'Agustus',
9 => 'September',
10 => 'Oktober',
11 => 'November',
12 => 'Desember',
])
->visible(fn (Get $get) => $get('date_type') === 'month')
->native(false),
Select::make('year')
->label('Tahun')
->options(function () {
$years = range(date('Y'), 2020);
return array_combine($years, $years);
})
->visible(fn (Get $get) => in_array($get('date_type'), ['month', 'year']))
->native(false),
DatePicker::make('start_date')
->label('Tanggal Mulai')
->placeholder('Pilih tanggal mulai')
->visible(fn (Get $get) => $get('date_type') === 'range')
->native(false)
->displayFormat('l, d F Y'),
DatePicker::make('end_date')
->label('Tanggal Selesai')
->placeholder('Pilih tanggal selesai')
->visible(fn (Get $get) => $get('date_type') === 'range')
->native(false)
->displayFormat('l, d F Y'),
])
->query(function (Builder $query, array $data): Builder {
$type = $data['date_type'] ?? null;
$column = 'posting_date';
if ($type === 'date' && ! empty($data['specific_date'])) {
return $query->whereDate($column, $data['specific_date']);
}
if ($type === 'month' && ! empty($data['month']) && ! empty($data['year'])) {
return $query->whereMonth($column, $data['month'])
->whereYear($column, $data['year']);
}
if ($type === 'year' && ! empty($data['year'])) {
return $query->whereYear($column, $data['year']);
}
if ($type === 'range' && ! empty($data['start_date']) && ! empty($data['end_date'])) {
return $query->whereBetween($column, [$data['start_date'], $data['end_date']]);
}
return $query;
}),
], FiltersLayout::AboveContentCollapsible)
->filtersFormColumns(3)
->recordActions([
EditAction::make(),
@ -71,6 +190,15 @@ public static function configure(Table $table): Table
RestoreAction::make(),
])
->headerActions([
ExportAction::make()
->exports([
ContentRecapExcelExport::make()
->fromTable(),
])
->color('success'),
])
->toolbarActions([
BulkActionGroup::make([
...DefaultBulkActions::make('Rekap Konten'),

View File

@ -9,12 +9,20 @@
use App\Filament\Actions\Cheerful\RestoreAction;
use App\Filament\Actions\DefaultBulkActions;
use App\Filament\Columns\TimestampColumns;
use App\Filament\Exports\IssueManagementExcelExport;
use Filament\Actions\BulkActionGroup;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use pxlrbt\FilamentExcel\Actions\Tables\ExportAction;
class IssueManagementTable
{
@ -76,7 +84,121 @@ public static function configure(Table $table): Table
->label('Filter Respon')
->options(IssueSentiment::class)
->native(false),
SelectFilter::make('location')
->label('Lokus')
->relationship('location', 'name')
->searchable()
->preload()
->native(false),
SelectFilter::make('subLocation')
->label('Sub Lokus')
->relationship('subLocation', 'name')
->searchable()
->preload()
->native(false),
SelectFilter::make('classification')
->label('Klasifikasi')
->relationship('classification', 'name')
->searchable()
->preload()
->native(false),
SelectFilter::make('subClassification')
->label('Sub Klasifikasi')
->relationship('subClassification', 'name')
->searchable()
->preload()
->native(false),
Filter::make('date_filter')
->schema([
Select::make('date_type')
->label('Jenis Filter Tanggal')
->options([
'date' => 'Tanggal Rilis Berita',
'month' => 'Bulan & Tahun',
'year' => 'Tahun',
'range' => 'Rentang Tanggal',
])
->default('date')
->live()
->native(false),
DatePicker::make('specific_date')
->label('Tanggal')
->placeholder('Pilih tanggal')
->visible(fn (Get $get) => $get('date_type') === 'date')
->native(false),
Select::make('month')
->label('Bulan')
->options([
1 => 'Januari',
2 => 'Februari',
3 => 'Maret',
4 => 'April',
5 => 'Mei',
6 => 'Juni',
7 => 'Juli',
8 => 'Agustus',
9 => 'September',
10 => 'Oktober',
11 => 'November',
12 => 'Desember',
])
->visible(fn (Get $get) => $get('date_type') === 'month')
->native(false),
Select::make('year')
->label('Tahun')
->options(function () {
$years = range(date('Y'), 2020);
return array_combine($years, $years);
})
->visible(fn (Get $get) => in_array($get('date_type'), ['month', 'year']))
->native(false),
DatePicker::make('start_date')
->label('Tanggal Mulai')
->placeholder('Pilih tanggal mulai')
->visible(fn (Get $get) => $get('date_type') === 'range')
->native(false)
->displayFormat('l, d F Y'),
DatePicker::make('end_date')
->label('Tanggal Selesai')
->placeholder('Pilih tanggal selesai')
->visible(fn (Get $get) => $get('date_type') === 'range')
->native(false)
->displayFormat('l, d F Y'),
])
->query(function (Builder $query, array $data): Builder {
$type = $data['date_type'] ?? null;
// Filtering based on mediaMonitoring.release_date relationship
$query->whereHas('mediaMonitoring', function (Builder $query) use ($type, $data) {
$column = 'release_date';
if ($type === 'date' && ! empty($data['specific_date'])) {
$query->whereDate($column, $data['specific_date']);
} elseif ($type === 'month' && ! empty($data['month']) && ! empty($data['year'])) {
$query->whereMonth($column, $data['month'])
->whereYear($column, $data['year']);
} elseif ($type === 'year' && ! empty($data['year'])) {
$query->whereYear($column, $data['year']);
} elseif ($type === 'range' && ! empty($data['start_date']) && ! empty($data['end_date'])) {
$query->whereBetween($column, [$data['start_date'], $data['end_date']]);
}
});
return $query;
}),
], FiltersLayout::AboveContentCollapsible)
->filtersFormColumns(3)
->recordActions([
EditAction::make(),
@ -86,6 +208,13 @@ public static function configure(Table $table): Table
ForceDeleteAction::make(),
])
->headerActions([
ExportAction::make()
->exports([
IssueManagementExcelExport::make(),
])
->color('success'),
])
->toolbarActions([
BulkActionGroup::make([
...DefaultBulkActions::make('Manajemen Isu'),

View File

@ -19,7 +19,7 @@ protected function setUp(): void
$this->label('Crawl Berita')
->icon(Heroicon::MagnifyingGlass)
->color('info')
->color('slate')
->schema([
TextInput::make('keyword')
->label('Kata Kunci')

View File

@ -2,18 +2,29 @@
namespace App\Filament\Resources\Monitoring\MediaMonitorings\Tables;
use App\Enums\Channel;
use App\Filament\Actions\Cheerful\DeleteAction;
use App\Filament\Actions\Cheerful\EditAction;
use App\Filament\Actions\Cheerful\ForceDeleteAction;
use App\Filament\Actions\Cheerful\RestoreAction;
use App\Filament\Actions\DefaultBulkActions;
use App\Filament\Columns\TimestampColumns;
use App\Filament\Exports\MediaMonitoringExcelExport;
use App\Filament\Resources\Monitoring\MediaMonitorings\Actions\CrawlNewsAction;
use Filament\Actions\BulkActionGroup;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use pxlrbt\FilamentExcel\Actions\Tables\ExportAction;
class MediaMonitoringsTable
{
@ -86,7 +97,117 @@ public static function configure(Table $table): Table
])
->filters([
TrashedFilter::make()->native(false),
SelectFilter::make('themes')
->label('Tema')
->relationship('themes', 'name')
->searchable()
->preload()
->native(false),
SelectFilter::make('channel')
->label('Kanal')
->options(Channel::class)
->native(false),
Filter::make('writter')
->form([
TextInput::make('writter')
->label('Penulis')
->placeholder('Cari penulis...'),
])
->query(function (Builder $query, array $data): Builder {
return $query->when(
$data['writter'],
fn (Builder $query, $term): Builder => $query->where('writter', 'like', "%{$term}%"),
);
}),
Filter::make('date_filter')
->schema([
Select::make('date_type')
->label('Jenis Filter Tanggal')
->options([
'date' => 'Tanggal Rilis',
'month' => 'Bulan & Tahun',
'year' => 'Tahun',
'range' => 'Rentang Tanggal',
])
->default('date')
->live()
->native(false),
DatePicker::make('specific_date')
->label('Tanggal')
->placeholder('Pilih tanggal')
->visible(fn (Get $get) => $get('date_type') === 'date')
->native(false),
Select::make('month')
->label('Bulan')
->options([
1 => 'Januari',
2 => 'Februari',
3 => 'Maret',
4 => 'April',
5 => 'Mei',
6 => 'Juni',
7 => 'Juli',
8 => 'Agustus',
9 => 'September',
10 => 'Oktober',
11 => 'November',
12 => 'Desember',
])
->visible(fn (Get $get) => $get('date_type') === 'month')
->native(false),
Select::make('year')
->label('Tahun')
->options(function () {
$years = range(date('Y'), 2020);
return array_combine($years, $years);
})
->visible(fn (Get $get) => in_array($get('date_type'), ['month', 'year']))
->native(false),
DatePicker::make('start_date')
->label('Tanggal Mulai')
->placeholder('Pilih tanggal mulai')
->visible(fn (Get $get) => $get('date_type') === 'range')
->native(false)
->displayFormat('l, d F Y'),
DatePicker::make('end_date')
->label('Tanggal Selesai')
->placeholder('Pilih tanggal selesai')
->visible(fn (Get $get) => $get('date_type') === 'range')
->native(false)
->displayFormat('l, d F Y'),
])
->query(function (Builder $query, array $data): Builder {
$type = $data['date_type'] ?? null;
$column = 'release_date';
if ($type === 'date' && ! empty($data['specific_date'])) {
return $query->whereDate($column, $data['specific_date']);
}
if ($type === 'month' && ! empty($data['month']) && ! empty($data['year'])) {
return $query->whereMonth($column, $data['month'])
->whereYear($column, $data['year']);
}
if ($type === 'year' && ! empty($data['year'])) {
return $query->whereYear($column, $data['year']);
}
if ($type === 'range' && ! empty($data['start_date']) && ! empty($data['end_date'])) {
return $query->whereBetween($column, [$data['start_date'], $data['end_date']]);
}
return $query;
}),
], FiltersLayout::AboveContentCollapsible)
->filtersFormColumns(3)
->recordActions([
EditAction::make(),
@ -98,6 +219,12 @@ public static function configure(Table $table): Table
])
->headerActions([
CrawlNewsAction::make('crawlNews'),
ExportAction::make()
->exports([
MediaMonitoringExcelExport::make(),
])
->color('success'),
])
->toolbarActions([
BulkActionGroup::make([

View File

@ -18,6 +18,13 @@ class MediaMonitoring extends Model implements HasMedia
protected $guarded = ['id'];
protected function casts(): array
{
return [
'release_date' => 'date',
];
}
public function issueManagement(): HasOne
{
return $this->hasOne(IssueManagement::class);

View File

@ -20,6 +20,7 @@
"laravel/framework": "^12.0",
"laravel/tinker": "^2.10.1",
"livewire/livewire": "^3.7",
"pxlrbt/filament-excel": "^3.4",
"spatie/laravel-settings": "^3.6",
"spatie/laravel-sluggable": "^3.7",
"spatie/laravel-tags": "^4.10",

505
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "90e78103def2be6a7e1905f567c53f06",
"content-hash": "4f6cfc9fed7cb0e122dae7b27fc317b1",
"packages": [
{
"name": "anourvalar/eloquent-serialize",
@ -938,6 +938,85 @@
],
"time": "2024-07-16T11:13:48+00:00"
},
{
"name": "composer/pcre",
"version": "3.3.2",
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
"shasum": ""
},
"require": {
"php": "^7.4 || ^8.0"
},
"conflict": {
"phpstan/phpstan": "<1.11.10"
},
"require-dev": {
"phpstan/phpstan": "^1.12 || ^2",
"phpstan/phpstan-strict-rules": "^1 || ^2",
"phpunit/phpunit": "^8 || ^9"
},
"type": "library",
"extra": {
"phpstan": {
"includes": [
"extension.neon"
]
},
"branch-alias": {
"dev-main": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Pcre\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "PCRE wrapping library that offers type-safe preg_* replacements.",
"keywords": [
"PCRE",
"preg",
"regex",
"regular expression"
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
"source": "https://github.com/composer/pcre/tree/3.3.2"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
],
"time": "2024-11-12T16:29:46+00:00"
},
{
"name": "composer/semver",
"version": "3.4.4",
@ -1541,6 +1620,67 @@
],
"time": "2025-03-06T22:45:56+00:00"
},
{
"name": "ezyang/htmlpurifier",
"version": "v4.19.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "b287d2a16aceffbf6e0295559b39662612b77fcf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/b287d2a16aceffbf6e0295559b39662612b77fcf",
"reference": "b287d2a16aceffbf6e0295559b39662612b77fcf",
"shasum": ""
},
"require": {
"php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
},
"require-dev": {
"cerdic/css-tidy": "^1.7 || ^2.0",
"simpletest/simpletest": "dev-master"
},
"suggest": {
"cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.",
"ext-bcmath": "Used for unit conversion and imagecrash protection",
"ext-iconv": "Converts text to and from non-UTF-8 encodings",
"ext-tidy": "Used for pretty-printing HTML"
},
"type": "library",
"autoload": {
"files": [
"library/HTMLPurifier.composer.php"
],
"psr-0": {
"HTMLPurifier": "library/"
},
"exclude-from-classmap": [
"/library/HTMLPurifier/Language/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-or-later"
],
"authors": [
{
"name": "Edward Z. Yang",
"email": "admin@htmlpurifier.org",
"homepage": "http://ezyang.com"
}
],
"description": "Standards compliant HTML filter written in PHP",
"homepage": "http://htmlpurifier.org/",
"keywords": [
"html"
],
"support": {
"issues": "https://github.com/ezyang/htmlpurifier/issues",
"source": "https://github.com/ezyang/htmlpurifier/tree/v4.19.0"
},
"time": "2025-10-17T16:34:55+00:00"
},
{
"name": "filament/actions",
"version": "v4.4.0",
@ -4144,6 +4284,87 @@
],
"time": "2025-12-19T02:00:29+00:00"
},
{
"name": "maatwebsite/excel",
"version": "3.1.67",
"source": {
"type": "git",
"url": "https://github.com/SpartnerNL/Laravel-Excel.git",
"reference": "e508e34a502a3acc3329b464dad257378a7edb4d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/e508e34a502a3acc3329b464dad257378a7edb4d",
"reference": "e508e34a502a3acc3329b464dad257378a7edb4d",
"shasum": ""
},
"require": {
"composer/semver": "^3.3",
"ext-json": "*",
"illuminate/support": "5.8.*||^6.0||^7.0||^8.0||^9.0||^10.0||^11.0||^12.0",
"php": "^7.0||^8.0",
"phpoffice/phpspreadsheet": "^1.30.0",
"psr/simple-cache": "^1.0||^2.0||^3.0"
},
"require-dev": {
"laravel/scout": "^7.0||^8.0||^9.0||^10.0",
"orchestra/testbench": "^6.0||^7.0||^8.0||^9.0||^10.0",
"predis/predis": "^1.1"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Excel": "Maatwebsite\\Excel\\Facades\\Excel"
},
"providers": [
"Maatwebsite\\Excel\\ExcelServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Maatwebsite\\Excel\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Patrick Brouwers",
"email": "patrick@spartner.nl"
}
],
"description": "Supercharged Excel exports and imports in Laravel",
"keywords": [
"PHPExcel",
"batch",
"csv",
"excel",
"export",
"import",
"laravel",
"php",
"phpspreadsheet"
],
"support": {
"issues": "https://github.com/SpartnerNL/Laravel-Excel/issues",
"source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.67"
},
"funding": [
{
"url": "https://laravel-excel.com/commercial-support",
"type": "custom"
},
{
"url": "https://github.com/patrickbrouwers",
"type": "github"
}
],
"time": "2025-08-26T09:13:16+00:00"
},
{
"name": "maennchen/zipstream-php",
"version": "3.1.2",
@ -4222,6 +4443,113 @@
],
"time": "2025-01-27T12:07:53+00:00"
},
{
"name": "markbaker/complex",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPComplex.git",
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
"phpcompatibility/php-compatibility": "^9.3",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"squizlabs/php_codesniffer": "^3.7"
},
"type": "library",
"autoload": {
"psr-4": {
"Complex\\": "classes/src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Baker",
"email": "mark@lange.demon.co.uk"
}
],
"description": "PHP Class for working with complex numbers",
"homepage": "https://github.com/MarkBaker/PHPComplex",
"keywords": [
"complex",
"mathematics"
],
"support": {
"issues": "https://github.com/MarkBaker/PHPComplex/issues",
"source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2"
},
"time": "2022-12-06T16:21:08+00:00"
},
{
"name": "markbaker/matrix",
"version": "3.0.1",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPMatrix.git",
"reference": "728434227fe21be27ff6d86621a1b13107a2562c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c",
"reference": "728434227fe21be27ff6d86621a1b13107a2562c",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
"phpcompatibility/php-compatibility": "^9.3",
"phpdocumentor/phpdocumentor": "2.*",
"phploc/phploc": "^4.0",
"phpmd/phpmd": "2.*",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"sebastian/phpcpd": "^4.0",
"squizlabs/php_codesniffer": "^3.7"
},
"type": "library",
"autoload": {
"psr-4": {
"Matrix\\": "classes/src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Baker",
"email": "mark@demon-angel.eu"
}
],
"description": "PHP Class for working with matrices",
"homepage": "https://github.com/MarkBaker/PHPMatrix",
"keywords": [
"mathematics",
"matrix",
"vector"
],
"support": {
"issues": "https://github.com/MarkBaker/PHPMatrix/issues",
"source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1"
},
"time": "2022-12-02T22:17:43+00:00"
},
{
"name": "masterminds/html5",
"version": "2.10.0",
@ -5141,6 +5469,114 @@
},
"time": "2025-11-21T15:09:14+00:00"
},
{
"name": "phpoffice/phpspreadsheet",
"version": "1.30.2",
"source": {
"type": "git",
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
"reference": "09cdde5e2f078b9a3358dd217e2c8cb4dac84be2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/09cdde5e2f078b9a3358dd217e2c8cb4dac84be2",
"reference": "09cdde5e2f078b9a3358dd217e2c8cb4dac84be2",
"shasum": ""
},
"require": {
"composer/pcre": "^1||^2||^3",
"ext-ctype": "*",
"ext-dom": "*",
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-iconv": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-simplexml": "*",
"ext-xml": "*",
"ext-xmlreader": "*",
"ext-xmlwriter": "*",
"ext-zip": "*",
"ext-zlib": "*",
"ezyang/htmlpurifier": "^4.15",
"maennchen/zipstream-php": "^2.1 || ^3.0",
"markbaker/complex": "^3.0",
"markbaker/matrix": "^3.0",
"php": ">=7.4.0 <8.5.0",
"psr/simple-cache": "^1.0 || ^2.0 || ^3.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "dev-main",
"doctrine/instantiator": "^1.5",
"dompdf/dompdf": "^1.0 || ^2.0 || ^3.0",
"friendsofphp/php-cs-fixer": "^3.2",
"mitoteam/jpgraph": "^10.3",
"mpdf/mpdf": "^8.1.1",
"phpcompatibility/php-compatibility": "^9.3",
"phpstan/phpstan": "^1.1",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^8.5 || ^9.0",
"squizlabs/php_codesniffer": "^3.7",
"tecnickcom/tcpdf": "^6.5"
},
"suggest": {
"dompdf/dompdf": "Option for rendering PDF with PDF Writer",
"ext-intl": "PHP Internationalization Functions",
"mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer"
},
"type": "library",
"autoload": {
"psr-4": {
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Maarten Balliauw",
"homepage": "https://blog.maartenballiauw.be"
},
{
"name": "Mark Baker",
"homepage": "https://markbakeruk.net"
},
{
"name": "Franck Lefevre",
"homepage": "https://rootslabs.net"
},
{
"name": "Erik Tilt"
},
{
"name": "Adrien Crivelli"
},
{
"name": "Owen Leibman"
}
],
"description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
"keywords": [
"OpenXML",
"excel",
"gnumeric",
"ods",
"php",
"spreadsheet",
"xls",
"xlsx"
],
"support": {
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.30.2"
},
"time": "2026-01-11T05:58:24+00:00"
},
{
"name": "phpoption/phpoption",
"version": "1.9.5",
@ -5873,6 +6309,73 @@
},
"time": "2025-12-17T14:35:46+00:00"
},
{
"name": "pxlrbt/filament-excel",
"version": "v3.4.0",
"source": {
"type": "git",
"url": "https://github.com/pxlrbt/filament-excel.git",
"reference": "1f4c958a8c4aa8386c5e5c96eba956ac307b6e19"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pxlrbt/filament-excel/zipball/1f4c958a8c4aa8386c5e5c96eba956ac307b6e19",
"reference": "1f4c958a8c4aa8386c5e5c96eba956ac307b6e19",
"shasum": ""
},
"require": {
"anourvalar/eloquent-serialize": "^1.2",
"filament/filament": "^4.0|^5.0",
"maatwebsite/excel": "^3.1",
"php": "^8.1"
},
"require-dev": {
"laravel/pint": "^1.10"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"pxlrbt\\FilamentExcel\\FilamentExcelServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"pxlrbt\\FilamentExcel\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Dennis Koch",
"email": "info@pixelarbeit.de"
}
],
"description": "Supercharged Excel exports for Filament Resources",
"keywords": [
"PHPExcel",
"actions",
"filament",
"laravel",
"laravel-filament",
"phpspreadsheet"
],
"support": {
"issues": "https://github.com/pxlrbt/filament-excel/issues",
"source": "https://github.com/pxlrbt/filament-excel/tree/v3.4.0"
},
"funding": [
{
"url": "https://github.com/pxlrbt",
"type": "github"
}
],
"time": "2026-01-16T17:09:19+00:00"
},
{
"name": "ralouphie/getallheaders",
"version": "3.0.3",