refactor: remove Category resource and related components for cleanup
This commit is contained in:
parent
70cf767111
commit
785e425dee
@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Master\Categories;
|
||||
|
||||
use App\Filament\Resources\Master\Categories\Pages\ManageCategories;
|
||||
use App\Filament\Resources\Master\Categories\Schemas\CategoryForm;
|
||||
use App\Filament\Resources\Master\Categories\Tables\CategoryTable;
|
||||
use App\Models\Category;
|
||||
use BackedEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use UnitEnum;
|
||||
|
||||
class CategoryResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Category::class;
|
||||
|
||||
protected static string|UnitEnum|null $navigationGroup = 'Master';
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedListBullet;
|
||||
|
||||
protected static ?string $navigationLabel = 'Kategori';
|
||||
|
||||
protected static ?int $navigationSort = 5;
|
||||
|
||||
protected static ?string $slug = 'master/categories';
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return CategoryForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return CategoryTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ManageCategories::route('/'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Master\Categories\Pages;
|
||||
|
||||
use App\Filament\Actions\Cheerful\CreateAction;
|
||||
use App\Filament\Resources\Master\Categories\CategoryResource;
|
||||
use App\Filament\Support\CheerfulNotification;
|
||||
use Filament\Resources\Pages\ManageRecords;
|
||||
use Filament\Support\Enums\Width;
|
||||
|
||||
class ManageCategories extends ManageRecords
|
||||
{
|
||||
protected static string $resource = CategoryResource::class;
|
||||
|
||||
protected static ?string $title = 'Kategori';
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make()
|
||||
->label('Tambah')
|
||||
->modalHeading(fn () => CheerfulNotification::getByKey('category.create_title'))
|
||||
->modalDescription(fn () => CheerfulNotification::getByKey('category.create_desc'))
|
||||
->modalSubmitActionLabel('Simpan')
|
||||
->modalCancelActionLabel('Batal')
|
||||
->extraModalFooterActions(fn (CreateAction $action): array => [
|
||||
$action->makeModalSubmitAction('createAknother', arguments: ['another' => true])
|
||||
->label('Simpan dan Tambah Lagi'),
|
||||
])
|
||||
->modalWidth(Width::Large),
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Master\Categories\Schemas;
|
||||
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class CategoryForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextInput::make('name')
|
||||
->label('Nama Kategori')
|
||||
->placeholder('Ekonomi')
|
||||
->autocomplete(false)
|
||||
->autofocus()
|
||||
->required()
|
||||
->maxLength(50),
|
||||
])
|
||||
->columns(1);
|
||||
}
|
||||
}
|
||||
@ -1,84 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Master\Categories\Tables;
|
||||
|
||||
use App\Enums\IsActive;
|
||||
use App\Enums\RoleEnum;
|
||||
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\RowIndexColumn;
|
||||
use App\Filament\Columns\TimestampColumns;
|
||||
use App\Filament\Support\CheerfulNotification;
|
||||
use App\Models\Category;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Support\Enums\Width;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Columns\ToggleColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class CategoryTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
...RowIndexColumn::make(),
|
||||
|
||||
TextColumn::make('name')
|
||||
->label('Nama')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
ToggleColumn::make('is_active')
|
||||
->label('Aktif?')
|
||||
->sortable()
|
||||
->getStateUsing(fn (Category $record): bool => $record->is_active === IsActive::ACTIVE)
|
||||
->updateStateUsing(function (Category $record, bool $state): void {
|
||||
$record->is_active = $state ? IsActive::ACTIVE : IsActive::INACTIVE;
|
||||
$record->save();
|
||||
|
||||
CheerfulNotification::statusUpdated()->send();
|
||||
}),
|
||||
|
||||
...TimestampColumns::make(),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('is_active')
|
||||
->label('Status')
|
||||
->options(IsActive::class)
|
||||
->native(false),
|
||||
|
||||
TrashedFilter::make()
|
||||
->native(false)
|
||||
->visible(fn () => auth()->user()?->hasRole(RoleEnum::DEVELOPER->value)),
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make()
|
||||
->modalWidth(Width::Large),
|
||||
|
||||
DeleteAction::make(),
|
||||
|
||||
ForceDeleteAction::make(),
|
||||
|
||||
RestoreAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
...DefaultBulkActions::make('kategori'),
|
||||
]),
|
||||
])
|
||||
->emptyStateIcon(Heroicon::OutlinedListBullet)
|
||||
->emptyStateHeading(fn () => CheerfulNotification::getByKey('category.empty_state_heading'))
|
||||
->emptyStateDescription(fn () => CheerfulNotification::getByKey('category.empty_state'))
|
||||
->defaultSort('created_at', 'desc')
|
||||
->deferFilters(false)
|
||||
->paginated([25, 50, 100, 'all'])
|
||||
->deferLoading();
|
||||
}
|
||||
}
|
||||
@ -9,14 +9,12 @@
|
||||
use Filament\Forms\Components\Hidden;
|
||||
use Filament\Forms\Components\Radio;
|
||||
use Filament\Forms\Components\RichEditor;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\SpatieMediaLibraryFileUpload;
|
||||
use Filament\Forms\Components\TagsInput;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\Utilities\Set;
|
||||
use Filament\Schemas\Schema;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class NewsForm
|
||||
{
|
||||
@ -52,8 +50,8 @@ public static function configure(Schema $schema): Schema
|
||||
->columnSpanFull(),
|
||||
])->columnSpan(2),
|
||||
|
||||
Section::make(CheerfulNotification::getByKey('news.content.category_title'))
|
||||
->description(CheerfulNotification::getByKey('news.content.category_desc'))
|
||||
Section::make(CheerfulNotification::getByKey('news.content.publication_title'))
|
||||
->description(CheerfulNotification::getByKey('news.content.publication_desc'))
|
||||
->icon(CheerfulNotification::getNotifStyle() === NotifStyle::CHEERFUL ? 'heroicon-o-tag' : null)
|
||||
->schema([
|
||||
TextInput::make('link')
|
||||
@ -64,16 +62,6 @@ public static function configure(Schema $schema): Schema
|
||||
->maxLength(255)
|
||||
->url(),
|
||||
|
||||
Select::make('categories')
|
||||
->label('Kategori')
|
||||
->relationship('categories', 'name', function (Builder $query): Builder {
|
||||
return $query->active();
|
||||
})
|
||||
->native(false)
|
||||
->multiple()
|
||||
->preload()
|
||||
->required(),
|
||||
|
||||
TagsInput::make('tags')
|
||||
->label('Tag Berita')
|
||||
->reactive()
|
||||
|
||||
@ -42,14 +42,6 @@ public static function configure(Table $table): Table
|
||||
->sortable()
|
||||
->placeholder('Tidak ada'),
|
||||
|
||||
TextColumn::make('categories.name')
|
||||
->label('Kategori')
|
||||
->listWithLineBreaks()
|
||||
->limitList(3)
|
||||
->expandableLimitedList()
|
||||
->badge()
|
||||
->placeholder('Tidak ada kategori'),
|
||||
|
||||
TextColumn::make('tags.name')
|
||||
->label('Tag')
|
||||
->listWithLineBreaks()
|
||||
@ -85,13 +77,6 @@ public static function configure(Table $table): Table
|
||||
->options(NewsStatus::class)
|
||||
->native(false),
|
||||
|
||||
SelectFilter::make('categories')
|
||||
->label('Kategori')
|
||||
->relationship('categories', 'name')
|
||||
->multiple()
|
||||
->preload()
|
||||
->native(false),
|
||||
|
||||
SelectFilter::make('tags')
|
||||
->label('Tag')
|
||||
->relationship('tags', 'name')
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Livewire\Home\News;
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Models\News;
|
||||
use Livewire\Attributes\Title;
|
||||
use Livewire\Attributes\Url;
|
||||
@ -18,9 +17,6 @@ class Index extends Component
|
||||
#[Url(as: 'q')]
|
||||
public $search = '';
|
||||
|
||||
#[Url(as: 'category')]
|
||||
public $category = '';
|
||||
|
||||
#[Url(as: 'tag')]
|
||||
public $tag = '';
|
||||
|
||||
@ -29,11 +25,6 @@ public function updatedSearch()
|
||||
$this->resetPage();
|
||||
}
|
||||
|
||||
public function updatedCategory()
|
||||
{
|
||||
$this->resetPage();
|
||||
}
|
||||
|
||||
public function updatedTag()
|
||||
{
|
||||
$this->resetPage();
|
||||
@ -42,16 +33,11 @@ public function updatedTag()
|
||||
public function render()
|
||||
{
|
||||
$news = News::published()
|
||||
->with(['categories', 'author'])
|
||||
->with('author')
|
||||
->when($this->search, function ($query) {
|
||||
$query->where('title', 'like', '%'.$this->search.'%')
|
||||
->orWhere('content', 'like', '%'.$this->search.'%');
|
||||
})
|
||||
->when($this->category, function ($query) {
|
||||
$query->whereHas('categories', function ($query) {
|
||||
$query->where('categories.id', $this->category);
|
||||
});
|
||||
})
|
||||
->when($this->tag, function ($query) {
|
||||
$query->withAnyTags([$this->tag]);
|
||||
})
|
||||
@ -67,13 +53,6 @@ public function render()
|
||||
return $news;
|
||||
});
|
||||
|
||||
$categories = Category::active()
|
||||
->withCount(['news' => function ($query) {
|
||||
$query->published();
|
||||
}])
|
||||
->orderBy('name')
|
||||
->get();
|
||||
|
||||
$popularPosts = News::published()
|
||||
->latest('views')
|
||||
->limit(3)
|
||||
@ -90,7 +69,6 @@ public function render()
|
||||
'pageDescription' => 'Jelajahi berita terbaru seputar purwakarta.',
|
||||
'news' => $news,
|
||||
'popularPosts' => $popularPosts,
|
||||
'categories' => $categories,
|
||||
'tags' => Tag::all(),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ public function mount(News $news)
|
||||
#[Title('Detail Berita')]
|
||||
public function render()
|
||||
{
|
||||
$this->news->load(['categories', 'author', 'tags']);
|
||||
$this->news->load(['author', 'tags']);
|
||||
|
||||
// Format main news
|
||||
$this->news->thumbnail = $this->news->getFirstMediaUrl('news') ?: 'https://images.pexels.com/photos/12199409/pexels-photo-12199409.jpeg';
|
||||
@ -35,26 +35,14 @@ public function render()
|
||||
|
||||
$relatedNews = News::published()
|
||||
->where('id', '!=', $this->news->id)
|
||||
->whereHas('categories', function ($query) {
|
||||
$query->whereIn('categories.id', $this->news->categories->pluck('id'));
|
||||
})
|
||||
->latest('published_at')
|
||||
->limit(4)
|
||||
->get();
|
||||
|
||||
if ($relatedNews->isEmpty()) {
|
||||
$relatedNews = News::published()
|
||||
->where('id', '!=', $this->news->id)
|
||||
->latest('published_at')
|
||||
->limit(4)
|
||||
->get();
|
||||
}
|
||||
|
||||
// Format related news
|
||||
$relatedNews = $relatedNews->map(function ($news) {
|
||||
$news->thumbnail = $news->getFirstMediaUrl('news') ?: 'https://images.pexels.com/photos/12199409/pexels-photo-12199409.jpeg';
|
||||
$news->formatted_date = $news->published_at?->translatedFormat('d F Y') ?: '-';
|
||||
$news->primary_category = $news->categories->first();
|
||||
|
||||
return $news;
|
||||
});
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\IsActive;
|
||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Swindon\FilamentHashids\Traits\HasHashid;
|
||||
|
||||
class Category extends Model
|
||||
{
|
||||
use HasFactory, HasHashid, SoftDeletes;
|
||||
|
||||
protected $guarded = ['id'];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'is_active' => IsActive::class,
|
||||
];
|
||||
}
|
||||
|
||||
#[Scope]
|
||||
protected function active(Builder $query): void
|
||||
{
|
||||
$query->where('is_active', IsActive::ACTIVE);
|
||||
}
|
||||
|
||||
#[Scope]
|
||||
protected function inactive(Builder $query): void
|
||||
{
|
||||
$query->where('is_active', IsActive::INACTIVE);
|
||||
}
|
||||
|
||||
public function news(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(News::class);
|
||||
}
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Swindon\FilamentHashids\Traits\HasHashid;
|
||||
|
||||
class CategoryNews extends Model
|
||||
{
|
||||
use HasFactory, HasHashid;
|
||||
|
||||
protected $guarded = ['id'];
|
||||
|
||||
public function category(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Category::class);
|
||||
}
|
||||
|
||||
public function news(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(News::class);
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,6 @@
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
@ -61,9 +60,4 @@ public function author(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'author_id');
|
||||
}
|
||||
|
||||
public function categories(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Category::class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Category;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
use Illuminate\Foundation\Auth\User as AuthUser;
|
||||
|
||||
class CategoryPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function viewAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ViewAny:Category');
|
||||
}
|
||||
|
||||
public function view(AuthUser $authUser, Category $category): bool
|
||||
{
|
||||
return $authUser->can('View:Category');
|
||||
}
|
||||
|
||||
public function create(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Create:Category');
|
||||
}
|
||||
|
||||
public function update(AuthUser $authUser, Category $category): bool
|
||||
{
|
||||
return $authUser->can('Update:Category');
|
||||
}
|
||||
|
||||
public function delete(AuthUser $authUser, Category $category): bool
|
||||
{
|
||||
return $authUser->can('Delete:Category');
|
||||
}
|
||||
|
||||
public function restore(AuthUser $authUser, Category $category): bool
|
||||
{
|
||||
return $authUser->can('Restore:Category');
|
||||
}
|
||||
|
||||
public function forceDelete(AuthUser $authUser, Category $category): bool
|
||||
{
|
||||
return $authUser->can('ForceDelete:Category');
|
||||
}
|
||||
|
||||
public function forceDeleteAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ForceDeleteAny:Category');
|
||||
}
|
||||
|
||||
public function restoreAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('RestoreAny:Category');
|
||||
}
|
||||
|
||||
public function replicate(AuthUser $authUser, Category $category): bool
|
||||
{
|
||||
return $authUser->can('Replicate:Category');
|
||||
}
|
||||
|
||||
public function reorder(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Reorder:Category');
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\IsActive;
|
||||
use App\Models\Category;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends Factory<Category>
|
||||
*/
|
||||
class CategoryFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->unique()->word(),
|
||||
'is_active' => IsActive::ACTIVE,
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Models\CategoryNews;
|
||||
use App\Models\News;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends Factory<CategoryNews>
|
||||
*/
|
||||
class CategoryNewsFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'category_id' => Category::factory(),
|
||||
'news_id' => News::factory(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\IsActive;
|
||||
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('categories', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name', 50);
|
||||
$table->enum('is_active', IsActive::values())->default(IsActive::ACTIVE->value)->comment(IsActive::comment());
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('categories');
|
||||
}
|
||||
};
|
||||
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Models\News;
|
||||
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('category_news', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Category::class);
|
||||
$table->foreignIdFor(News::class);
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('category_news');
|
||||
}
|
||||
};
|
||||
@ -36,17 +36,6 @@ public function run(): void
|
||||
|
||||
"View:BudgetRealizationChart",
|
||||
|
||||
"ViewAny:Category",
|
||||
"View:Category",
|
||||
"Create:Category",
|
||||
"Update:Category",
|
||||
"Delete:Category",
|
||||
"Restore:Category",
|
||||
"ForceDelete:Category",
|
||||
"ForceDeleteAny:Category",
|
||||
"RestoreAny:Category",
|
||||
"Replicate:Category",
|
||||
"Reorder:Category",
|
||||
|
||||
"View:CompanyStatusChart",
|
||||
|
||||
@ -307,17 +296,6 @@ public function run(): void
|
||||
|
||||
"View:BudgetRealizationChart",
|
||||
|
||||
"ViewAny:Category",
|
||||
"View:Category",
|
||||
"Create:Category",
|
||||
"Update:Category",
|
||||
"Delete:Category",
|
||||
"Restore:Category",
|
||||
"ForceDelete:Category",
|
||||
"ForceDeleteAny:Category",
|
||||
"RestoreAny:Category",
|
||||
"Replicate:Category",
|
||||
"Reorder:Category",
|
||||
|
||||
"View:CompanyStatusChart",
|
||||
|
||||
@ -559,7 +537,7 @@ public function run(): void
|
||||
"RestoreAny:Classification",
|
||||
"Replicate:Classification",
|
||||
"Reorder:Classification",
|
||||
|
||||
|
||||
"View:Dashboard",
|
||||
|
||||
"ViewAny:IssueManagement",
|
||||
@ -573,7 +551,7 @@ public function run(): void
|
||||
"RestoreAny:IssueManagement",
|
||||
"Replicate:IssueManagement",
|
||||
"Reorder:IssueManagement",
|
||||
|
||||
|
||||
"ViewAny:Location",
|
||||
"View:Location",
|
||||
"Create:Location",
|
||||
@ -653,19 +631,6 @@ public function run(): void
|
||||
"permissions": [
|
||||
"View:Analytic",
|
||||
|
||||
"ViewAny:Category",
|
||||
|
||||
"View:Category",
|
||||
"Create:Category",
|
||||
"Update:Category",
|
||||
"Delete:Category",
|
||||
"Restore:Category",
|
||||
"ForceDelete:Category",
|
||||
"ForceDeleteAny:Category",
|
||||
"RestoreAny:Category",
|
||||
"Replicate:Category",
|
||||
"Reorder:Category",
|
||||
|
||||
"ViewAny:Classification",
|
||||
"View:Classification",
|
||||
"Create:Classification",
|
||||
|
||||
@ -787,14 +787,6 @@
|
||||
'cheerful' => 'Masukkan informasi lengkap mengenai pemberitaan media biar makin lengkap! 📰✨',
|
||||
'formal' => 'Masukkan informasi lengkap mengenai pemberitaan media.',
|
||||
],
|
||||
'category_title' => [
|
||||
'cheerful' => 'Kategori & Metadata 🏷️',
|
||||
'formal' => 'Kategori & Metadata',
|
||||
],
|
||||
'category_desc' => [
|
||||
'cheerful' => 'Tentukan kategori berita dan informasi tambahan lainnya biar makin rapi! 🏷️✨',
|
||||
'formal' => 'Tentukan kategori berita dan informasi tambahan lainnya.',
|
||||
],
|
||||
'empty_state' => [
|
||||
'cheerful' => 'Belum ada data Monitoring Media nih! Mulai buat data pertama sekarang biar makin rame! 🚀✨',
|
||||
'formal' => 'Belum ada data Monitoring Media yang tersedia saat ini.',
|
||||
@ -812,13 +804,13 @@
|
||||
'cheerful' => 'Yuk, tuliskan judul, ringkasan, dan isi lengkap berita Anda biar makin menarik! 🚀😊',
|
||||
'formal' => 'Silakan tuliskan judul, ringkasan, dan isi lengkap berita Anda.',
|
||||
],
|
||||
'category_title' => [
|
||||
'cheerful' => 'Kategori & Publikasi 🏷️',
|
||||
'formal' => 'Kategori & Publikasi',
|
||||
'publication_title' => [
|
||||
'cheerful' => 'Publikasi & Metadata 🏷️',
|
||||
'formal' => 'Publikasi & Metadata',
|
||||
],
|
||||
'category_desc' => [
|
||||
'cheerful' => 'Tentukan kategori, tautan media, dan status publikasi biar berita kita gampang dicari! 🏷️✨',
|
||||
'formal' => 'Tentukan kategori, tautan media, dan status publikasi.',
|
||||
'publication_desc' => [
|
||||
'cheerful' => 'Tentukan tautan media, tag, dan status publikasi agar berita lebih mudah ditemukan! 🏷️✨',
|
||||
'formal' => 'Tentukan tautan media, tag, dan status publikasi.',
|
||||
],
|
||||
'empty_state' => [
|
||||
'cheerful' => 'Belum ada data Berita nih! Mulai buat data pertama sekarang biar makin rame! 🚀✨',
|
||||
@ -916,24 +908,6 @@
|
||||
'formal' => 'Tidak Ada Data Tema',
|
||||
],
|
||||
],
|
||||
'category' => [
|
||||
'create_title' => [
|
||||
'cheerful' => 'Tambah Kategori Baru 🏷️✨',
|
||||
'formal' => 'Tambah Kategori',
|
||||
],
|
||||
'create_desc' => [
|
||||
'cheerful' => 'Tambahkan kategori baru biar data makin teratur dan rapi! 📁😊',
|
||||
'formal' => 'Silakan masukkan detail kategori data di bawah ini.',
|
||||
],
|
||||
'empty_state' => [
|
||||
'cheerful' => 'Belum ada data Kategori nih! Mulai buat data pertama sekarang biar makin rame! 🚀✨',
|
||||
'formal' => 'Belum ada data Kategori yang tersedia saat ini.',
|
||||
],
|
||||
'empty_state_heading' => [
|
||||
'cheerful' => 'Belum Ada Data Kategori! 🏷️✨',
|
||||
'formal' => 'Tidak Ada Data Kategori',
|
||||
],
|
||||
],
|
||||
'classification' => [
|
||||
'create_title' => [
|
||||
'cheerful' => 'Tambah Klasifikasi Baru 📂✨',
|
||||
|
||||
@ -41,13 +41,6 @@ class="bi bi-megaphone text-white icon-small me-10px"></i>{{ $pageTitle }}</span
|
||||
<img src="{{ $item->thumbnail }}" alt="{{ $item->title }}"
|
||||
class="w-100" />
|
||||
</a>
|
||||
<div class="blog-categories">
|
||||
@foreach ($item->categories as $itemCategory)
|
||||
<a href="javascript:void(0)"
|
||||
wire:click="$set('category', '{{ $itemCategory->id }}')"
|
||||
class="categories-btn bg-white text-dark-gray text-dark-gray-hover text-uppercase alt-font fw-600">{{ $itemCategory->name }}</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="card-body p-9 bg-white">
|
||||
@ -121,28 +114,6 @@ class="d-inline-block fs-15">{{ $post->formatted_date }}</a>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="mb-15 md-mb-50px xs-mb-35px">
|
||||
<div
|
||||
class="fw-600 fs-19 lh-22 ls-minus-05px text-dark-gray border-bottom border-color-dark-gray border-2 d-block mb-30px pb-15px position-relative">
|
||||
Kategori</div>
|
||||
<ul class="category-list-sidebar position-relative list-unstyled">
|
||||
<li class="mb-10px">
|
||||
<a href="javascript:void(0)" wire:click="$set('category', '')"
|
||||
class="d-flex align-items-center {{ $this->category == '' ? 'text-base-color fw-600' : 'text-dark-gray' }}">
|
||||
<span>Semua Kategori</span>
|
||||
</a>
|
||||
</li>
|
||||
@foreach ($categories as $cat)
|
||||
<li class="mb-10px border-bottom border-color-extra-light-gray pb-10px">
|
||||
<a href="javascript:void(0)" wire:click="$set('category', '{{ $cat->id }}')"
|
||||
class="d-flex align-items-center justify-content-between {{ $this->category == $cat->id ? 'text-base-color fw-600' : 'text-dark-gray' }}">
|
||||
<span>{{ $cat->name }}</span>
|
||||
<span class="fs-14 text-medium-gray">({{ $cat->news_count }})</span>
|
||||
</a>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@if ($tags->count() > 0)
|
||||
<div class="mb-15 md-mb-50px xs-mb-35px">
|
||||
|
||||
@ -33,10 +33,6 @@ class="bi bi-megaphone text-white icon-small me-10px"></i>{{ $pageTitle }}</span
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-10 overlap-section text-center">
|
||||
<div class="p-10 box-shadow-extra-large border-radius-4px bg-white text-center">
|
||||
@foreach ($news->categories as $category)
|
||||
<a href="{{ route('news.index', ['category' => $category->id]) }}"
|
||||
class="bg-solitude-blue text-uppercase fs-13 ps-25px pe-25px alt-font fw-500 text-base-color lh-40 sm-lh-55 border-radius-100px d-inline-block mb-3 sm-mb-15px">{{ $category->name }}</a>
|
||||
@endforeach
|
||||
<h3 class="alt-font text-dark-gray fw-600 ls-minus-1px mb-15px">{{ $news->title }}</h3>
|
||||
<div class="lg-20px sm-mb-0">
|
||||
<span>{{ $news->author_name }}</span>
|
||||
@ -122,10 +118,6 @@ class="w-100" /></a>
|
||||
</div>
|
||||
<div class="card-body px-0 pb-30px pt-30px xs-pb-15px last-paragraph-no-margin">
|
||||
<span class="fs-13 text-uppercase mb-5px d-block">
|
||||
@if ($related->primary_category)
|
||||
<a href="{{ route('news.index', ['category' => $related->primary_category->id]) }}"
|
||||
class="text-dark-gray fw-500 categories-text">{{ $related->primary_category->name }}</a>
|
||||
@endif
|
||||
<a href="javascript:void(0)"
|
||||
class="blog-date">{{ $related->formatted_date }}</a>
|
||||
</span>
|
||||
|
||||
@ -1,167 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\IsActive;
|
||||
use App\Enums\RoleEnum;
|
||||
use App\Filament\Resources\Master\Categories\Pages\ManageCategories;
|
||||
use App\Models\Category;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$this->user = User::factory()->create(['is_active' => IsActive::ACTIVE]);
|
||||
|
||||
// Setup Permissions
|
||||
$permissions = [
|
||||
'ViewAny:Category',
|
||||
'Create:Category',
|
||||
'Update:Category',
|
||||
'Delete:Category',
|
||||
'Restore:Category',
|
||||
'ForceDelete:Category',
|
||||
];
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
Permission::firstOrCreate(['name' => $permission, 'guard_name' => 'web']);
|
||||
}
|
||||
|
||||
$this->user->givePermissionTo($permissions);
|
||||
});
|
||||
|
||||
test('can render category list page', function () {
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageCategories::class)
|
||||
->assertSuccessful();
|
||||
});
|
||||
|
||||
test('can list categories', function () {
|
||||
$categories = Category::factory()->count(5)->create();
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageCategories::class)
|
||||
->call('loadTable')
|
||||
->assertCanSeeTableRecords($categories);
|
||||
});
|
||||
|
||||
test('can create category', function () {
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageCategories::class)
|
||||
->mountAction('create')
|
||||
->setActionData([
|
||||
'name' => 'Kategori Baru',
|
||||
])
|
||||
->callMountedAction()
|
||||
->assertHasNoActionErrors();
|
||||
|
||||
$this->assertDatabaseHas('categories', [
|
||||
'name' => 'Kategori Baru',
|
||||
'is_active' => IsActive::ACTIVE->value,
|
||||
]);
|
||||
});
|
||||
|
||||
test('cannot create category with empty name', function () {
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageCategories::class)
|
||||
->mountAction('create')
|
||||
->setActionData(['name' => ''])
|
||||
->callMountedAction()
|
||||
->assertHasActionErrors(['name' => 'required']);
|
||||
});
|
||||
|
||||
test('cannot create category with name exceeding 50 characters', function () {
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageCategories::class)
|
||||
->mountAction('create')
|
||||
->setActionData(['name' => str_repeat('a', 51)])
|
||||
->callMountedAction()
|
||||
->assertHasActionErrors(['name' => 'max']);
|
||||
});
|
||||
|
||||
test('can edit category', function () {
|
||||
$category = Category::factory()->create();
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageCategories::class)
|
||||
->mountTableAction('edit', $category)
|
||||
->setActionData([
|
||||
'name' => 'Kategori Updated',
|
||||
])
|
||||
->callMountedTableAction()
|
||||
->assertHasNoActionErrors();
|
||||
|
||||
expect($category->refresh()->name)->toBe('Kategori Updated');
|
||||
});
|
||||
|
||||
test('can toggle is_active status', function () {
|
||||
$category = Category::factory()->create(['is_active' => IsActive::INACTIVE]);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageCategories::class)
|
||||
->call('updateTableColumnState', 'is_active', $category->getKey(), true);
|
||||
|
||||
expect($category->refresh()->is_active)->toBe(IsActive::ACTIVE);
|
||||
});
|
||||
|
||||
test('unauthorized user cannot render category page', function () {
|
||||
$unauthorizedUser = User::factory()->create(['is_active' => IsActive::ACTIVE]);
|
||||
|
||||
$this->actingAs($unauthorizedUser);
|
||||
|
||||
Livewire::test(ManageCategories::class)
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
test('can delete category', function () {
|
||||
$category = Category::factory()->create();
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageCategories::class)
|
||||
->callTableAction('delete', $category);
|
||||
|
||||
$this->assertSoftDeleted($category);
|
||||
});
|
||||
|
||||
test('can restore deleted category', function () {
|
||||
$roleDev = Role::firstOrCreate(['name' => RoleEnum::DEVELOPER->value, 'guard_name' => 'web']);
|
||||
$this->user->assignRole($roleDev);
|
||||
|
||||
$category = Category::factory()->create(['deleted_at' => now()]);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageCategories::class)
|
||||
->filterTable('trashed', 'with')
|
||||
->callTableAction('restore', $category);
|
||||
|
||||
$this->assertDatabaseHas('categories', [
|
||||
'id' => $category->id,
|
||||
'deleted_at' => null,
|
||||
]);
|
||||
});
|
||||
|
||||
test('can force delete category', function () {
|
||||
$roleDev = Role::firstOrCreate(['name' => RoleEnum::DEVELOPER->value, 'guard_name' => 'web']);
|
||||
$this->user->assignRole($roleDev);
|
||||
|
||||
$category = Category::factory()->create(['deleted_at' => now()]);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageCategories::class)
|
||||
->filterTable('trashed', 'only')
|
||||
->callTableAction('forceDelete', $category);
|
||||
|
||||
$this->assertDatabaseMissing('categories', ['id' => $category->id]);
|
||||
});
|
||||
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Models\CategoryNews;
|
||||
use App\Models\News;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('category news relation works', function () {
|
||||
$news = News::factory()->create();
|
||||
$category = Category::factory()->create();
|
||||
|
||||
$categoryNews = CategoryNews::factory()->create([
|
||||
'news_id' => $news->id,
|
||||
'category_id' => $category->id,
|
||||
]);
|
||||
|
||||
expect($categoryNews->news->id)->toBe($news->id);
|
||||
expect($categoryNews->category->id)->toBe($category->id);
|
||||
});
|
||||
@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\IsActive;
|
||||
use App\Models\Category;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('category can be created using factory', function () {
|
||||
$category = Category::factory()->create(['name' => 'Politik']);
|
||||
expect($category->name)->toBe('Politik');
|
||||
expect($category->is_active)->toBe(IsActive::ACTIVE);
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user