feat(category): crud
-membuat tabel, form, skema db -membuat factory untuk kebutuhan test -membuat test untuk memastikan semuanya berjalan lancar -membuat seeder untuk data awal -membuat action datatable baru yaitu sort-button
This commit is contained in:
parent
52e0758419
commit
c60bb2b09d
89
app/Livewire/Datatable/CategoriesTable.php
Normal file
89
app/Livewire/Datatable/CategoriesTable.php
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Datatable;
|
||||||
|
|
||||||
|
use App\Models\Category;
|
||||||
|
use App\Traits\Datatable\WithConfiguration;
|
||||||
|
use App\Traits\Datatable\WithPrependColumn;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Rappasoft\LaravelLivewireTables\DataTableComponent;
|
||||||
|
use Rappasoft\LaravelLivewireTables\Views\Column;
|
||||||
|
|
||||||
|
class CategoriesTable extends DataTableComponent
|
||||||
|
{
|
||||||
|
use WithConfiguration, WithPrependColumn;
|
||||||
|
|
||||||
|
protected $model = Category::class;
|
||||||
|
|
||||||
|
public function columns(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Column::make('Nama', 'name')->searchable(),
|
||||||
|
|
||||||
|
Column::make('Urutan', 'sort_order')
|
||||||
|
->sortable()
|
||||||
|
->hideIf(false),
|
||||||
|
|
||||||
|
Column::make('Aksi')
|
||||||
|
->label(function ($row) {
|
||||||
|
$actions = '';
|
||||||
|
$maxSortOrder = Category::max('sort_order');
|
||||||
|
|
||||||
|
if ($row->sort_order > 1) {
|
||||||
|
$actions .= view('components.datatables.sort-button', [
|
||||||
|
'id' => $row->id,
|
||||||
|
'direction' => 'up',
|
||||||
|
'tooltip' => 'Naik',
|
||||||
|
'color' => 'cyan',
|
||||||
|
'icon' => 'arrow-up',
|
||||||
|
])->render();
|
||||||
|
|
||||||
|
$actions .= view('components.datatables.sort-button', [
|
||||||
|
'id' => $row->id,
|
||||||
|
'direction' => 'first',
|
||||||
|
'tooltip' => 'Pertama',
|
||||||
|
'color' => 'emerald',
|
||||||
|
'icon' => 'bars-arrow-up',
|
||||||
|
])->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($row->sort_order < $maxSortOrder) {
|
||||||
|
$actions .= view('components.datatables.sort-button', [
|
||||||
|
'id' => $row->id,
|
||||||
|
'direction' => 'down',
|
||||||
|
'tooltip' => 'Turun',
|
||||||
|
'color' => 'orange',
|
||||||
|
'icon' => 'arrow-down',
|
||||||
|
])->render();
|
||||||
|
|
||||||
|
$actions .= view('components.datatables.sort-button', [
|
||||||
|
'id' => $row->id,
|
||||||
|
'direction' => 'last',
|
||||||
|
'tooltip' => 'Terakhir',
|
||||||
|
'color' => 'rose',
|
||||||
|
'icon' => 'bars-arrow-down',
|
||||||
|
])->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
$actions .= view('components.datatables.edit-modal', [
|
||||||
|
'id' => $row->id,
|
||||||
|
'method' => 'update',
|
||||||
|
'modalTitle' => 'Ubah Kategori',
|
||||||
|
])->render();
|
||||||
|
|
||||||
|
$actions .= view('components.datatables.delete', [
|
||||||
|
'id' => $row->id,
|
||||||
|
'deleteRoute' => route('studio.catalog.category.delete', $row->id),
|
||||||
|
])->render();
|
||||||
|
|
||||||
|
return $actions;
|
||||||
|
})
|
||||||
|
->html(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function builder(): Builder
|
||||||
|
{
|
||||||
|
return Category::select('id', 'name', 'sort_order')->orderBy('sort_order');
|
||||||
|
}
|
||||||
|
}
|
||||||
110
app/Livewire/Forms/CategoryForm.php
Normal file
110
app/Livewire/Forms/CategoryForm.php
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Forms;
|
||||||
|
|
||||||
|
use App\Models\Category;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use Livewire\Form;
|
||||||
|
|
||||||
|
class CategoryForm extends Form
|
||||||
|
{
|
||||||
|
public ?Category $category = null;
|
||||||
|
|
||||||
|
public string $name = '';
|
||||||
|
|
||||||
|
public ?string $description = null;
|
||||||
|
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => ['required', 'string', 'max:20', Rule::unique('categories', 'name')->whereNull('deleted_at')->ignore($this->category)],
|
||||||
|
'description' => ['nullable', 'string'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validationAttributes(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'nama',
|
||||||
|
'description' => 'syarat dan ketentuan',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCategory(Category $category)
|
||||||
|
{
|
||||||
|
$this->category = $category;
|
||||||
|
|
||||||
|
$this->name = $category->name;
|
||||||
|
$this->description = $category->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store()
|
||||||
|
{
|
||||||
|
$this->validate();
|
||||||
|
|
||||||
|
Category::create([
|
||||||
|
'name' => $this->name,
|
||||||
|
'description' => $this->description,
|
||||||
|
'sort_order' => Category::count() + 1,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$this->validate();
|
||||||
|
|
||||||
|
$this->category->update([
|
||||||
|
'name' => $this->name,
|
||||||
|
'description' => $this->description,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$this->category->delete();
|
||||||
|
|
||||||
|
Category::where('sort_order', '>', $this->category->sort_order)
|
||||||
|
->orderBy('sort_order')
|
||||||
|
->get()
|
||||||
|
->each(function ($cat) {
|
||||||
|
$cat->update(['sort_order' => $cat->sort_order - 1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sortOrder(string $direction)
|
||||||
|
{
|
||||||
|
if (in_array($direction, ['up', 'down'])) {
|
||||||
|
$swap = null;
|
||||||
|
|
||||||
|
if ($direction === 'up') {
|
||||||
|
$swap = Category::where('sort_order', '<', $this->category->sort_order)
|
||||||
|
->orderByDesc('sort_order')
|
||||||
|
->first();
|
||||||
|
} else {
|
||||||
|
$swap = Category::where('sort_order', '>', $this->category->sort_order)
|
||||||
|
->orderBy('sort_order')
|
||||||
|
->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($swap) {
|
||||||
|
$temp = $this->category->sort_order;
|
||||||
|
$this->category->update(['sort_order' => $swap->sort_order]);
|
||||||
|
$swap->update(['sort_order' => $temp]);
|
||||||
|
}
|
||||||
|
} elseif ($direction === 'first') {
|
||||||
|
$this->category->update(['sort_order' => Category::min('sort_order') - 1]);
|
||||||
|
$this->normalizeSortOrder();
|
||||||
|
} elseif ($direction === 'last') {
|
||||||
|
$this->category->update(['sort_order' => Category::max('sort_order') + 1]);
|
||||||
|
$this->normalizeSortOrder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function normalizeSortOrder()
|
||||||
|
{
|
||||||
|
$categories = Category::orderBy('sort_order')->get();
|
||||||
|
foreach ($categories as $index => $category) {
|
||||||
|
$category->update(['sort_order' => $index + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
105
app/Livewire/Studio/Catalog/Category.php
Normal file
105
app/Livewire/Studio/Catalog/Category.php
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Studio\Catalog;
|
||||||
|
|
||||||
|
use App\Livewire\Forms\CategoryForm;
|
||||||
|
use App\Models\Category as CategoryModel;
|
||||||
|
use App\Traits\WithCloseModal;
|
||||||
|
use App\Traits\WithConfirmation;
|
||||||
|
use App\Traits\WithUpdatedData;
|
||||||
|
use Flux\Flux;
|
||||||
|
use Livewire\Attributes\On;
|
||||||
|
use Livewire\Attributes\Title;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
#[Title('Kategori')]
|
||||||
|
class Category extends Component
|
||||||
|
{
|
||||||
|
use WithCloseModal, WithConfirmation, WithUpdatedData;
|
||||||
|
|
||||||
|
public CategoryForm $form;
|
||||||
|
|
||||||
|
public string $method = 'create';
|
||||||
|
|
||||||
|
public string $modalTitle = '';
|
||||||
|
|
||||||
|
#[On('modal:open')]
|
||||||
|
public function openModal(string $method, string $modalTitle, ?string $id = null)
|
||||||
|
{
|
||||||
|
$this->resetValidation();
|
||||||
|
$this->resetErrorBag();
|
||||||
|
|
||||||
|
$this->method = $method;
|
||||||
|
$this->modalTitle = $modalTitle;
|
||||||
|
|
||||||
|
if ($id) {
|
||||||
|
$this->form->setCategory(CategoryModel::findOrFail($id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$this->form->store();
|
||||||
|
|
||||||
|
$this->dispatch('refreshDatatable');
|
||||||
|
|
||||||
|
Flux::toast(
|
||||||
|
heading: 'Berhasil',
|
||||||
|
text: 'Kategori berhasil ditambahkan.',
|
||||||
|
variant: 'success',
|
||||||
|
duration: 3000
|
||||||
|
);
|
||||||
|
|
||||||
|
Flux::modals()->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$this->form->update();
|
||||||
|
|
||||||
|
$this->dispatch('refreshDatatable');
|
||||||
|
|
||||||
|
Flux::toast(
|
||||||
|
heading: 'Berhasil',
|
||||||
|
text: 'Kategori berhasil diperbarui.',
|
||||||
|
variant: 'success',
|
||||||
|
duration: 3000
|
||||||
|
);
|
||||||
|
|
||||||
|
Flux::modals()->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(CategoryModel $category)
|
||||||
|
{
|
||||||
|
$this->form->category = $category;
|
||||||
|
|
||||||
|
$this->form->delete();
|
||||||
|
|
||||||
|
$this->dispatch('refreshDatatable');
|
||||||
|
|
||||||
|
Flux::toast(
|
||||||
|
heading: 'Berhasil',
|
||||||
|
text: 'Kategori berhasil dihapus.',
|
||||||
|
variant: 'success',
|
||||||
|
);
|
||||||
|
|
||||||
|
Flux::modals()->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[On('fn:sortOrder')]
|
||||||
|
public function sortOrder(CategoryModel $category, string $direction)
|
||||||
|
{
|
||||||
|
$this->form->category = $category;
|
||||||
|
|
||||||
|
$this->form->sortOrder($direction);
|
||||||
|
|
||||||
|
$this->dispatch('refreshDatatable');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.studio.catalog.categories', [
|
||||||
|
'pageTitle' => 'Kategori',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
app/Models/Category.php
Normal file
30
app/Models/Category.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Spatie\Sluggable\HasSlug;
|
||||||
|
use Spatie\Sluggable\SlugOptions;
|
||||||
|
|
||||||
|
class Category extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, HasSlug, SoftDeletes;
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
|
||||||
|
protected function casts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'sort_order' => 'int',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSlugOptions(): SlugOptions
|
||||||
|
{
|
||||||
|
return SlugOptions::create()
|
||||||
|
->generateSlugsFrom('name')
|
||||||
|
->saveSlugsTo('slug');
|
||||||
|
}
|
||||||
|
}
|
||||||
23
database/factories/CategoryFactory.php
Normal file
23
database/factories/CategoryFactory.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Models\Category;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
|
class CategoryFactory extends Factory
|
||||||
|
{
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => $this->faker->unique()->name(),
|
||||||
|
'slug' => $this->faker->slug(),
|
||||||
|
'description' => $this->faker->optional()->text(),
|
||||||
|
'sort_order' => function () {
|
||||||
|
$max = Category::max('sort_order') ?? 0;
|
||||||
|
|
||||||
|
return $max + 1;
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
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', 20);
|
||||||
|
$table->string('slug', 30);
|
||||||
|
$table->text('description')->nullable();
|
||||||
|
$table->unsignedInteger('sort_order');
|
||||||
|
$table->timestamps();
|
||||||
|
$table->softDeletes();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('categories');
|
||||||
|
}
|
||||||
|
};
|
||||||
33
database/seeders/CategorySeeder.php
Normal file
33
database/seeders/CategorySeeder.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\Category;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class CategorySeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$categories = [
|
||||||
|
['name' => 'Floral', 'description' => 'Perfume with floral scents', 'sort_order' => 1],
|
||||||
|
['name' => 'Citrus', 'description' => 'Fresh citrus fragrances', 'sort_order' => 2],
|
||||||
|
['name' => 'Woody', 'description' => 'Warm woody notes', 'sort_order' => 3],
|
||||||
|
['name' => 'Oriental', 'description' => 'Spicy and exotic oriental scents', 'sort_order' => 4],
|
||||||
|
['name' => 'Fruity', 'description' => 'Sweet and fresh fruity fragrances', 'sort_order' => 5],
|
||||||
|
['name' => 'Aquatic', 'description' => 'Light, oceanic, and fresh scents', 'sort_order' => 6],
|
||||||
|
['name' => 'Gourmand', 'description' => 'Edible, sweet and dessert-like scents', 'sort_order' => 7],
|
||||||
|
['name' => 'Green', 'description' => 'Fresh, leafy, and herbal notes', 'sort_order' => 8],
|
||||||
|
['name' => 'Chypre', 'description' => 'Classic blend of citrus, oakmoss, and labdanum', 'sort_order' => 9],
|
||||||
|
['name' => 'Musk', 'description' => 'Warm, sensual musky fragrances', 'sort_order' => 10],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($categories as $category) {
|
||||||
|
Category::create([
|
||||||
|
'name' => $category['name'],
|
||||||
|
'description' => $category['description'],
|
||||||
|
'sort_order' => $category['sort_order'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,6 +12,7 @@ public function run(): void
|
|||||||
UserSeeder::class,
|
UserSeeder::class,
|
||||||
MembershipSeeder::class,
|
MembershipSeeder::class,
|
||||||
VoucherSeeder::class,
|
VoucherSeeder::class,
|
||||||
|
CategorySeeder::class,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
<flux:tooltip content="{{ $tooltip }}">
|
||||||
|
<flux:button wire:navigate.hover variant="primary" color="{{ $color }}" icon="{{ $icon }}" size="sm"
|
||||||
|
wire:click="$dispatch('fn:sortOrder', {category: '{{ $id }}', direction: '{{ $direction }}'})">
|
||||||
|
</flux:button>
|
||||||
|
</flux:tooltip>
|
||||||
@ -35,5 +35,14 @@ class="px-2 hidden dark:flex" />
|
|||||||
</flux:navlist.item>
|
</flux:navlist.item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3 mb-1">
|
||||||
|
<div class="text-zinc-500 dark:text-gray-300 text-sm/6">Katalog</div>
|
||||||
|
<div class="grid gap-2">
|
||||||
|
<flux:navlist.item icon="list-bullet" href="{{ route('studio.catalog.category.index') }}"
|
||||||
|
:current="request()->routeIs('studio.catalog.category.*')" wire:navigate.hover>Kategori
|
||||||
|
</flux:navlist.item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</flux:navlist>
|
</flux:navlist>
|
||||||
</flux:sidebar>
|
</flux:sidebar>
|
||||||
|
|||||||
39
resources/views/livewire/studio/catalog/categories.blade.php
Normal file
39
resources/views/livewire/studio/catalog/categories.blade.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<flux:main>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div>
|
||||||
|
<flux:heading size="xl">{{ $pageTitle }}</flux:heading>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<flux:modal.trigger name="form-modal">
|
||||||
|
<flux:button href="javascript:void(0)" variant="primary" class="text-sm"
|
||||||
|
wire:click="$dispatch('modal:open', {method: 'create', 'modalTitle': 'Tambah Kategori'})">Tambah
|
||||||
|
</flux:button>
|
||||||
|
</flux:modal.trigger>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-6">
|
||||||
|
<livewire:datatable.categories-table />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@include('components.confirmation.delete')
|
||||||
|
<flux:modal name="form-modal" class="w-[95%] max-w-sm md:max-w-xl mx-auto" @close="closeModal('form-modal')">
|
||||||
|
<div class="p-4 space-y-6">
|
||||||
|
<flux:heading size="lg">{{ $modalTitle }}</flux:heading>
|
||||||
|
|
||||||
|
<flux:input label="Nama" placeholder="Masukkan nama kategori" wire:model.live.debounce.500ms="form.name"
|
||||||
|
autofocus autocomplete="off" clearable />
|
||||||
|
|
||||||
|
<flux:editor label="Keterangan" wire:model="form.description" placeholder="Masukkan keterangan"
|
||||||
|
auotocomplete="off" class="**:data-[slot=content]:min-h-[100px]!" />
|
||||||
|
|
||||||
|
<div class="flex">
|
||||||
|
<flux:spacer />
|
||||||
|
<flux:button variant="primary" class="sm:w-auto cursor-pointer" wire:click="{{ $method }}">
|
||||||
|
Simpan
|
||||||
|
</flux:button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</flux:modal>
|
||||||
|
|
||||||
|
</flux:main>
|
||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use App\Livewire\Auth\Login;
|
use App\Livewire\Auth\Login;
|
||||||
use App\Livewire\Auth\Logout;
|
use App\Livewire\Auth\Logout;
|
||||||
|
use App\Livewire\Studio\Catalog\Category as CategoryComponent;
|
||||||
use App\Livewire\Studio\Dashboard\Overview;
|
use App\Livewire\Studio\Dashboard\Overview;
|
||||||
use App\Livewire\Studio\Loyalty\Membership as MembershipComponent;
|
use App\Livewire\Studio\Loyalty\Membership as MembershipComponent;
|
||||||
use App\Livewire\Studio\Loyalty\Voucher\Create as VoucherCreate;
|
use App\Livewire\Studio\Loyalty\Voucher\Create as VoucherCreate;
|
||||||
@ -68,4 +69,11 @@
|
|||||||
Route::get('vouchers/{voucher}/edit', VoucherEdit::class)->name('edit');
|
Route::get('vouchers/{voucher}/edit', VoucherEdit::class)->name('edit');
|
||||||
Route::get('vouchers/{voucher}/delete', VoucherCreate::class)->name('delete');
|
Route::get('vouchers/{voucher}/delete', VoucherCreate::class)->name('delete');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::prefix('catalog')
|
||||||
|
->as('studio.catalog.category.')
|
||||||
|
->group(function () {
|
||||||
|
Route::get('categories', CategoryComponent::class)->name('index');
|
||||||
|
Route::delete('categories/{category}/delete', CategoryComponent::class)->name('delete');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
67
tests/Feature/Livewire/Studio/Catalog/CategoryTest.php
Normal file
67
tests/Feature/Livewire/Studio/Catalog/CategoryTest.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Livewire\Studio\Catalog\Category;
|
||||||
|
use App\Models\Category as CategoryModel;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
uses(RefreshDatabase::class);
|
||||||
|
|
||||||
|
it('renders successfully', function () {
|
||||||
|
Livewire::test(Category::class)
|
||||||
|
->assertViewIs('livewire.studio.catalog.categories')
|
||||||
|
->assertViewHas('pageTitle', 'Kategori');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays all categories', function () {
|
||||||
|
CategoryModel::factory()->count(10)->create();
|
||||||
|
|
||||||
|
$category = CategoryModel::first();
|
||||||
|
|
||||||
|
Livewire::test(Category::class)->assertSee($category->name);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can create a category', function () {
|
||||||
|
$data = CategoryModel::factory()->raw();
|
||||||
|
|
||||||
|
Livewire::test(Category::class)
|
||||||
|
->call('openModal', 'create', 'Tambah Kategori')
|
||||||
|
->set('form.name', $data['name'])
|
||||||
|
->set('form.slug', $data['slug'])
|
||||||
|
->set('form.description', $data['description'])
|
||||||
|
->set('form.sort_order', $data['sort_order'])
|
||||||
|
->call('create')
|
||||||
|
->assertDispatched('refreshDatatable');
|
||||||
|
|
||||||
|
expect(CategoryModel::count())->toBe(1);
|
||||||
|
expect(CategoryModel::first()->name)->toBe($data['name']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can update a category', function () {
|
||||||
|
$category = CategoryModel::factory()->create();
|
||||||
|
|
||||||
|
$data = CategoryModel::factory()->raw();
|
||||||
|
|
||||||
|
Livewire::test(Category::class)
|
||||||
|
->call('openModal', 'update', 'Edit Kategori', $category->id)
|
||||||
|
->set('form.name', $data['name'])
|
||||||
|
->set('form.description', $data['description'])
|
||||||
|
->set('form.sort_order', $data['sort_order'])
|
||||||
|
->call('update')
|
||||||
|
->assertDispatched('refreshDatatable');
|
||||||
|
|
||||||
|
$category->refresh();
|
||||||
|
|
||||||
|
expect($category->name)->toBe($data['name']);
|
||||||
|
expect($category->description)->toBe($data['description']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can delete an category', function () {
|
||||||
|
$category = CategoryModel::factory()->create();
|
||||||
|
|
||||||
|
Livewire::test(Category::class)
|
||||||
|
->call('delete', $category)
|
||||||
|
->assertDispatched('refreshDatatable');
|
||||||
|
|
||||||
|
expect(CategoryModel::count())->toBe(0);
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user