feat(content recap): implement crud
- create model and migration - relation to classification - create resource - create enum for support option
This commit is contained in:
parent
2f2de29dd5
commit
f9f1e60b2e
23
app/Enums/ContentType.php
Normal file
23
app/Enums/ContentType.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use App\Traits\Enum\WithValue;
|
||||
|
||||
enum ContentType: string
|
||||
{
|
||||
use WithValue;
|
||||
|
||||
case FOTO = 'Foto';
|
||||
case TEXT = 'Teks';
|
||||
case GRAPHIC = 'Grafis';
|
||||
case VIDEO = 'Video';
|
||||
|
||||
public static function options(): array
|
||||
{
|
||||
return array_combine(
|
||||
array_map(fn ($status) => $status->value, self::cases()),
|
||||
array_map(fn ($status) => $status->value, self::cases())
|
||||
);
|
||||
}
|
||||
}
|
||||
22
app/Enums/SocialMedia.php
Normal file
22
app/Enums/SocialMedia.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use App\Traits\Enum\WithValue;
|
||||
|
||||
enum SocialMedia: string
|
||||
{
|
||||
use WithValue;
|
||||
|
||||
case PPID_DISKOMINFO_PURWAKARTA = 'PPID Diskominfo Purwakarta';
|
||||
case DISKOMINFO_PURWAKARTA = 'Diskominfo Purwakarta';
|
||||
case PURWAKARTA_SABER_HOAKS = 'Purwakarta Saber Hoaks';
|
||||
|
||||
public static function options(): array
|
||||
{
|
||||
return array_combine(
|
||||
array_map(fn ($status) => $status->value, self::cases()),
|
||||
array_map(fn ($status) => $status->value, self::cases())
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Monitoring\ContentRecaps;
|
||||
|
||||
use App\Filament\Resources\Monitoring\ContentRecaps\Pages\CreateContentRecap;
|
||||
use App\Filament\Resources\Monitoring\ContentRecaps\Pages\EditContentRecap;
|
||||
use App\Filament\Resources\Monitoring\ContentRecaps\Pages\ListContentRecaps;
|
||||
use App\Filament\Resources\Monitoring\ContentRecaps\Schemas\ContentRecapForm;
|
||||
use App\Filament\Resources\Monitoring\ContentRecaps\Tables\ContentRecapsTable;
|
||||
use App\Models\ContentRecap;
|
||||
use BackedEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
use UnitEnum;
|
||||
|
||||
class ContentRecapResource extends Resource
|
||||
{
|
||||
protected static ?string $model = ContentRecap::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::ClipboardDocumentList;
|
||||
|
||||
protected static ?string $navigationLabel = 'Rekap Konten';
|
||||
|
||||
protected static string|UnitEnum|null $navigationGroup = 'Monitoring';
|
||||
|
||||
protected static ?string $slug = 'monitoring/content-recaps';
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'title';
|
||||
|
||||
protected static ?int $navigationSort = 13;
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return ContentRecapForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return ContentRecapsTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListContentRecaps::route('/'),
|
||||
'create' => CreateContentRecap::route('/create'),
|
||||
'edit' => EditContentRecap::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getRecordRouteBindingEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getRecordRouteBindingEloquentQuery()
|
||||
->withoutGlobalScopes([
|
||||
SoftDeletingScope::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Monitoring\ContentRecaps\Pages;
|
||||
|
||||
use App\Filament\Resources\Monitoring\ContentRecaps\ContentRecapResource;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateContentRecap extends CreateRecord
|
||||
{
|
||||
protected static string $resource = ContentRecapResource::class;
|
||||
|
||||
protected static ?string $title = 'Tambah Rekap Konten';
|
||||
|
||||
protected function getRedirectUrl(): string
|
||||
{
|
||||
return $this->getResource()::getUrl('index');
|
||||
}
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Action::make('back')
|
||||
->label('Kembali')
|
||||
->url(fn (): string => route('filament.dashboard.resources.monitoring.content-recaps.index'))
|
||||
->outlined()
|
||||
->color('secondary'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Monitoring\ContentRecaps\Pages;
|
||||
|
||||
use App\Filament\Resources\Monitoring\ContentRecaps\ContentRecapResource;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditContentRecap extends EditRecord
|
||||
{
|
||||
protected static string $resource = ContentRecapResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Action::make('back')
|
||||
->label('Kembali')
|
||||
->url(fn (): string => route('filament.dashboard.resources.monitoring.media-monitorings.index'))
|
||||
->outlined()
|
||||
->color('secondary'),
|
||||
];
|
||||
}
|
||||
|
||||
protected function getRedirectUrl(): string
|
||||
{
|
||||
return $this->getResource()::getUrl('index');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Monitoring\ContentRecaps\Pages;
|
||||
|
||||
use App\Filament\Resources\Monitoring\ContentRecaps\ContentRecapResource;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListContentRecaps extends ListRecords
|
||||
{
|
||||
protected static string $resource = ContentRecapResource::class;
|
||||
|
||||
protected static ?string $title = 'Rekap Konten';
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make()
|
||||
->label('Tambah'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Monitoring\ContentRecaps\Schemas;
|
||||
|
||||
use App\Enums\Channel;
|
||||
use App\Enums\ContentType;
|
||||
use App\Enums\SocialMedia;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\SpatieMediaLibraryFileUpload;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Schemas\Components\Grid;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class ContentRecapForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Section::make([
|
||||
TextInput::make('title')
|
||||
->label('Judul')
|
||||
->placeholder('Reels Kerja Sama DPMPTSP')
|
||||
->autocomplete(false)
|
||||
->autofocus()
|
||||
->required()
|
||||
->maxLength(255),
|
||||
|
||||
TextInput::make('link')
|
||||
->label('Tautan')
|
||||
->placeholder('https://www.pwknews.com')
|
||||
->autocomplete(false)
|
||||
->nullable()
|
||||
->maxLength(50)
|
||||
->url(),
|
||||
|
||||
Grid::make(2)
|
||||
->schema([
|
||||
Select::make('type')
|
||||
->label('Tipe')
|
||||
->options(ContentType::options())
|
||||
->native(false)
|
||||
->required()
|
||||
->in(implode(',', array_column(ContentType::cases(), 'value'))),
|
||||
|
||||
Select::make('channel')
|
||||
->label('Kanal')
|
||||
->options(Channel::options())
|
||||
->native(false)
|
||||
->required()
|
||||
->in(implode(',', array_column(Channel::cases(), 'value'))),
|
||||
|
||||
Select::make('social_media')
|
||||
->label('Media Sosial')
|
||||
->options(SocialMedia::options())
|
||||
->native(false)
|
||||
->required()
|
||||
->in(implode(',', array_column(SocialMedia::cases(), 'value'))),
|
||||
|
||||
DatePicker::make('posting_date')
|
||||
->label('Tanggal Posting')
|
||||
->placeholder(fn () => now()->format('Y-m-d'))
|
||||
->native(false)
|
||||
->displayFormat('l, d F Y')
|
||||
->required(),
|
||||
]),
|
||||
])->columnSpan(2),
|
||||
|
||||
Section::make([
|
||||
Select::make('classification_id')
|
||||
->label('Klasifikasi')
|
||||
->relationship('classification', 'name')
|
||||
->native(false)
|
||||
->preload()
|
||||
->required(),
|
||||
|
||||
SpatieMediaLibraryFileUpload::make('image')
|
||||
->label('Gambar')
|
||||
->disk(config('filesystems.default'))
|
||||
->acceptedFileTypes(['images/*'])
|
||||
->maxSize(1024 * 3)
|
||||
->collection('content-recpaps')
|
||||
->image()
|
||||
->required(),
|
||||
]),
|
||||
])
|
||||
->columns(3);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Monitoring\ContentRecaps\Tables;
|
||||
|
||||
use App\Filament\Actions\DefaultBulkActions;
|
||||
use App\Filament\Columns\TimestampColumns;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class ContentRecapsTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('title')
|
||||
->label('Judul')
|
||||
->searchable()
|
||||
->sortable()
|
||||
->wrap(),
|
||||
|
||||
TextColumn::make('type')
|
||||
->label('Tipe')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('channel')
|
||||
->label('Kanal')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('social_media')
|
||||
->label('Media Sosial')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('classification.name')
|
||||
->label('Klasifikasi')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('link')
|
||||
->label('Tautan')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('posting_date')
|
||||
->label('Tgl Posting')
|
||||
->searchable()
|
||||
->sortable()
|
||||
->date('l, d F Y'),
|
||||
|
||||
...TimestampColumns::make(),
|
||||
])
|
||||
->filters([
|
||||
TrashedFilter::make()->native(false),
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make(),
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
...DefaultBulkActions::make('Rekap Konten'),
|
||||
]),
|
||||
])
|
||||
->emptyStateIcon('heroicon-o-bookmark')
|
||||
->emptyStateDescription('Setelah Anda membubat data pertama, maka akan muncul disini.')
|
||||
->defaultSort('created_at', 'desc')
|
||||
->deferFilters(false);
|
||||
}
|
||||
}
|
||||
@ -25,4 +25,9 @@ public function subClassifications(): HasMany
|
||||
{
|
||||
return $this->hasMany(SubClassification::class);
|
||||
}
|
||||
|
||||
public function contentRecaps(): HasMany
|
||||
{
|
||||
return $this->hasMany(ContentRecap::class);
|
||||
}
|
||||
}
|
||||
|
||||
21
app/Models/ContentRecap.php
Normal file
21
app/Models/ContentRecap.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
|
||||
class ContentRecap extends Model implements HasMedia
|
||||
{
|
||||
use InteractsWithMedia, SoftDeletes;
|
||||
|
||||
protected $guarded = ['id'];
|
||||
|
||||
public function classification(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Classification::class);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\ContentType;
|
||||
use App\Models\Classification;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('content_recaps', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Classification::class)->constrained();
|
||||
$table->string('title', 255);
|
||||
$table->text('link', 50)->nullable();
|
||||
$table->date('posting_date');
|
||||
$table->enum('type', [ContentType::values()])->default(ContentType::FOTO);
|
||||
$table->string('channel', 20);
|
||||
$table->string('social_media', 50);
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('content_recaps');
|
||||
}
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user