feat(bottle): crud botol
-menambahkan skema model dan migrsai -menyesuaikan relasi
This commit is contained in:
parent
aee349093d
commit
4c43729299
86
app/Livewire/Datatable/BottlesTable.php
Normal file
86
app/Livewire/Datatable/BottlesTable.php
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Datatable;
|
||||||
|
|
||||||
|
use App\Models\Bottle;
|
||||||
|
use App\Traits\Datatable\WithConfiguration;
|
||||||
|
use App\Traits\Datatable\WithPrependColumn;
|
||||||
|
use App\Traits\WithMediaHandler;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Support\Facades\Blade;
|
||||||
|
use Rappasoft\LaravelLivewireTables\DataTableComponent;
|
||||||
|
use Rappasoft\LaravelLivewireTables\Views\Column;
|
||||||
|
use Rappasoft\LaravelLivewireTables\Views\Columns\ArrayColumn;
|
||||||
|
use Rappasoft\LaravelLivewireTables\Views\Columns\ImageColumn;
|
||||||
|
|
||||||
|
class BottlesTable extends DataTableComponent
|
||||||
|
{
|
||||||
|
use WithConfiguration, WithMediaHandler, WithPrependColumn;
|
||||||
|
|
||||||
|
protected $model = Bottle::class;
|
||||||
|
|
||||||
|
public function columns(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Column::make('Nama')
|
||||||
|
->label(function ($row) {
|
||||||
|
return <<<HTML
|
||||||
|
<div>
|
||||||
|
<div>{$row->name}</div>
|
||||||
|
<span class="text-xs text-gray-400">{$row->size} ml</span>
|
||||||
|
</div>
|
||||||
|
HTML;
|
||||||
|
})
|
||||||
|
->searchable(function ($query, $searchTerm) {
|
||||||
|
$query->where('name', 'like', "%{$searchTerm}%")
|
||||||
|
->orWhere('size', 'like', "%{$searchTerm}%");
|
||||||
|
})
|
||||||
|
->html(),
|
||||||
|
|
||||||
|
Column::make('Harga Beli', 'cost_price')
|
||||||
|
->label(fn ($row, $column) => currency($row->cost_price, 'Rp'))
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
|
||||||
|
Column::make('Harga Jual', 'sale_price')
|
||||||
|
->label(fn ($row, $column) => currency($row->sale_price, 'Rp'))
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
|
||||||
|
ImageColumn::make('Gambar')
|
||||||
|
->location(fn ($row) => optional($row->getMedia('image')->first())->getUrl() ?? asset('assets/images/logo.png'))
|
||||||
|
->attributes(fn ($row) => [
|
||||||
|
'style' => 'width: 50px; height: 50px;',
|
||||||
|
'alt' => $row->name,
|
||||||
|
]),
|
||||||
|
|
||||||
|
ArrayColumn::make('Outlet')
|
||||||
|
->data(fn ($value, $row) => $row->outlets->pluck('name')->toArray())
|
||||||
|
->outputFormat(fn ($index, $value) => Blade::render('<span class="text-xs text-gray-400 border border-gray-400 rounded px-1">'.$value.'</span>'))
|
||||||
|
->flexRow(['class' => 'gap-2 flex-wrap']),
|
||||||
|
|
||||||
|
Column::make('Aksi')
|
||||||
|
->label(function ($row) {
|
||||||
|
$actions = '';
|
||||||
|
|
||||||
|
$actions .= view('components.datatables.edit', [
|
||||||
|
'id' => $row->id,
|
||||||
|
'editRoute' => route('studio.catalog.bottle.edit', $row->id),
|
||||||
|
])->render();
|
||||||
|
|
||||||
|
$actions .= view('components.datatables.delete', [
|
||||||
|
'id' => $row->id,
|
||||||
|
'deleteRoute' => route('studio.catalog.bottle.delete', $row->id),
|
||||||
|
])->render();
|
||||||
|
|
||||||
|
return $actions;
|
||||||
|
})
|
||||||
|
->html(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function builder(): Builder
|
||||||
|
{
|
||||||
|
return Bottle::select('id', 'name', 'size', 'cost_price', 'sale_price')->with('outlets');
|
||||||
|
}
|
||||||
|
}
|
||||||
100
app/Livewire/Forms/BottleForm.php
Normal file
100
app/Livewire/Forms/BottleForm.php
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Forms;
|
||||||
|
|
||||||
|
use App\Models\Bottle;
|
||||||
|
use App\Rules\UnsignedInteger;
|
||||||
|
use App\Traits\WithMediaHandler;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Livewire\Form;
|
||||||
|
|
||||||
|
class BottleForm extends Form
|
||||||
|
{
|
||||||
|
use WithMediaHandler;
|
||||||
|
|
||||||
|
public ?Bottle $bottle = null;
|
||||||
|
|
||||||
|
public string $name = '';
|
||||||
|
|
||||||
|
public string $size = '';
|
||||||
|
|
||||||
|
public string $cost_price = '';
|
||||||
|
|
||||||
|
public string $sale_price = '';
|
||||||
|
|
||||||
|
public ?string $description = null;
|
||||||
|
|
||||||
|
public array $image = [];
|
||||||
|
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => ['required', 'string', 'max:50'],
|
||||||
|
'size' => ['required', 'numeric', new UnsignedInteger],
|
||||||
|
'cost_price' => ['required', 'numeric', new UnsignedInteger],
|
||||||
|
'sale_price' => ['required', 'numeric', new UnsignedInteger],
|
||||||
|
'description' => ['nullable', 'string'],
|
||||||
|
'image' => ['nullable', 'array'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validationAttributes(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'nama',
|
||||||
|
'size' => 'ukuran',
|
||||||
|
'cost_price' => 'harga beli',
|
||||||
|
'sale_price' => 'harga jual',
|
||||||
|
'description' => 'deskripsi',
|
||||||
|
'image' => 'gambar',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBottle(Bottle $bottle)
|
||||||
|
{
|
||||||
|
$this->bottle = $bottle;
|
||||||
|
|
||||||
|
$this->name = $bottle->name;
|
||||||
|
$this->size = $bottle->size;
|
||||||
|
$this->cost_price = $bottle->cost_price;
|
||||||
|
$this->sale_price = $bottle->sale_price;
|
||||||
|
$this->description = $bottle->description;
|
||||||
|
|
||||||
|
$this->image = $this->mapMediaCollection($bottle->getMedia('image'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store()
|
||||||
|
{
|
||||||
|
$this->validate();
|
||||||
|
|
||||||
|
DB::transaction(function () {
|
||||||
|
$bottle = Bottle::create([
|
||||||
|
'name' => $this->name,
|
||||||
|
'size' => $this->size,
|
||||||
|
'cost_price' => $this->cost_price,
|
||||||
|
'sale_price' => $this->sale_price,
|
||||||
|
'description' => $this->description,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->uploadMedia($this->image, $bottle, 'image');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$this->validate();
|
||||||
|
|
||||||
|
DB::transaction(function () {
|
||||||
|
$this->bottle->update([
|
||||||
|
'name' => $this->name,
|
||||||
|
'size' => $this->size,
|
||||||
|
'cost_price' => $this->cost_price,
|
||||||
|
'sale_price' => $this->sale_price,
|
||||||
|
'description' => $this->description,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->syncMedia($this->image, $this->bottle, 'image');
|
||||||
|
$this->uploadMedia($this->image, $this->bottle, 'image');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
49
app/Livewire/Studio/Catalog/Bottle/Create.php
Normal file
49
app/Livewire/Studio/Catalog/Bottle/Create.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Studio\Catalog\Bottle;
|
||||||
|
|
||||||
|
use App\Livewire\Forms\BottleForm;
|
||||||
|
use App\Models\Outlet;
|
||||||
|
use App\Traits\WithOutletSelector;
|
||||||
|
use App\Traits\WithUpdatedData;
|
||||||
|
use Flux\Flux;
|
||||||
|
use Livewire\Attributes\Title;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
#[Title('Tambah Botol')]
|
||||||
|
class Create extends Component
|
||||||
|
{
|
||||||
|
use WithOutletSelector, WithUpdatedData;
|
||||||
|
|
||||||
|
public BottleForm $form;
|
||||||
|
|
||||||
|
public array $outlets = [];
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->outlets = Outlet::pluck('name', 'id')->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$this->form->store();
|
||||||
|
|
||||||
|
$this->dispatch('refreshDatatable');
|
||||||
|
|
||||||
|
Flux::toast(
|
||||||
|
heading: 'Berhasil',
|
||||||
|
text: 'Botol berhasil ditambahkan.',
|
||||||
|
variant: 'success',
|
||||||
|
duration: 3000
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->redirectRoute('studio.catalog.bottle.index', navigate: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.studio.catalog.bottle.form', [
|
||||||
|
'pageTitle' => 'Tambah Botol',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
52
app/Livewire/Studio/Catalog/Bottle/Edit.php
Normal file
52
app/Livewire/Studio/Catalog/Bottle/Edit.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Studio\Catalog\Bottle;
|
||||||
|
|
||||||
|
use App\Livewire\Forms\BottleForm;
|
||||||
|
use App\Models\Bottle;
|
||||||
|
use App\Models\Outlet;
|
||||||
|
use App\Traits\WithOutletSelector;
|
||||||
|
use App\Traits\WithUpdatedData;
|
||||||
|
use Flux\Flux;
|
||||||
|
use Livewire\Attributes\Title;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
#[Title('Ubah Botol')]
|
||||||
|
class Edit extends Component
|
||||||
|
{
|
||||||
|
use WithOutletSelector, WithUpdatedData;
|
||||||
|
|
||||||
|
public BottleForm $form;
|
||||||
|
|
||||||
|
public array $outlets = [];
|
||||||
|
|
||||||
|
public function mount(Bottle $bottle)
|
||||||
|
{
|
||||||
|
$this->form->setBottle($bottle);
|
||||||
|
|
||||||
|
$this->outlets = Outlet::pluck('name', 'id')->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$this->form->update();
|
||||||
|
|
||||||
|
$this->dispatch('refreshDatatable');
|
||||||
|
|
||||||
|
Flux::toast(
|
||||||
|
heading: 'Berhasil',
|
||||||
|
text: 'Botol berhasil diperbarui.',
|
||||||
|
variant: 'success',
|
||||||
|
duration: 3000
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->redirectRoute('studio.catalog.bottle.index', navigate: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.studio.catalog.bottle.form', [
|
||||||
|
'pageTitle' => 'Ubah Botol',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
app/Livewire/Studio/Catalog/Bottle/Index.php
Normal file
37
app/Livewire/Studio/Catalog/Bottle/Index.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Studio\Catalog\Bottle;
|
||||||
|
|
||||||
|
use App\Models\Bottle;
|
||||||
|
use App\Traits\WithConfirmation;
|
||||||
|
use Flux\Flux;
|
||||||
|
use Livewire\Attributes\Title;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
#[Title('Botol')]
|
||||||
|
class Index extends Component
|
||||||
|
{
|
||||||
|
use WithConfirmation;
|
||||||
|
|
||||||
|
public function delete(Bottle $bottle)
|
||||||
|
{
|
||||||
|
$bottle->delete();
|
||||||
|
|
||||||
|
$this->dispatch('refreshDatatable');
|
||||||
|
|
||||||
|
Flux::toast(
|
||||||
|
heading: 'Berhasil',
|
||||||
|
text: 'Botol berhasil dihapus.',
|
||||||
|
variant: 'success',
|
||||||
|
);
|
||||||
|
|
||||||
|
Flux::modals()->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.studio.catalog.bottle.index', [
|
||||||
|
'pageTitle' => 'Botol',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
app/Models/Bottle.php
Normal file
39
app/Models/Bottle.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
|
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||||
|
use Spatie\Sluggable\HasSlug;
|
||||||
|
use Spatie\Sluggable\SlugOptions;
|
||||||
|
|
||||||
|
class Bottle extends Model implements HasMedia
|
||||||
|
{
|
||||||
|
use HasFactory, HasSlug, InteractsWithMedia, SoftDeletes;
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
|
||||||
|
protected function casts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'cost_price' => 'int',
|
||||||
|
'sale_price' => 'int',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSlugOptions(): SlugOptions
|
||||||
|
{
|
||||||
|
return SlugOptions::create()
|
||||||
|
->generateSlugsFrom('name')
|
||||||
|
->saveSlugsTo('slug');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function outlets(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Outlet::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
app/Models/BottleOutlet.php
Normal file
12
app/Models/BottleOutlet.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class BottleOutlet extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'bottle_outlet';
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
}
|
||||||
@ -62,4 +62,9 @@ public function products(): BelongsToMany
|
|||||||
{
|
{
|
||||||
return $this->belongsToMany(Product::class);
|
return $this->belongsToMany(Product::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function bottles(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Bottle::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,34 @@
|
|||||||
|
<?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('bottles', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('name', 50);
|
||||||
|
$table->string('slug', 70)->unique();
|
||||||
|
$table->unsignedInteger('size');
|
||||||
|
$table->unsignedInteger('cost_price')->default(0);
|
||||||
|
$table->unsignedInteger('sale_price')->default(0);
|
||||||
|
$table->text('description')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
$table->softDeletes();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('bottles');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
<?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('bottle_outlet', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('bottle_id')->constrained()->cascadeOnDelete();
|
||||||
|
$table->foreignId('outlet_id')->constrained()->cascadeOnDelete();
|
||||||
|
$table->unsignedInteger('stock')->default(0);
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('bottle_outlet');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -56,6 +56,10 @@ class="bg-zinc-50 dark:bg-zinc-900 border-r rtl:border-r-0 rtl:border-l border-z
|
|||||||
<flux:navlist.item icon="boxes" href="{{ route('studio.catalog.product.index') }}"
|
<flux:navlist.item icon="boxes" href="{{ route('studio.catalog.product.index') }}"
|
||||||
:current="request()->routeIs('studio.catalog.product.*')" wire:navigate.hover>Produk
|
:current="request()->routeIs('studio.catalog.product.*')" wire:navigate.hover>Produk
|
||||||
</flux:navlist.item>
|
</flux:navlist.item>
|
||||||
|
|
||||||
|
<flux:navlist.item icon="beaker" href="{{ route('studio.catalog.bottle.index') }}"
|
||||||
|
:current="request()->routeIs('studio.catalog.bottle.*')" wire:navigate.hover>Botol
|
||||||
|
</flux:navlist.item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</flux:navlist>
|
</flux:navlist>
|
||||||
|
|||||||
107
resources/views/livewire/studio/catalog/bottle/form.blade.php
Normal file
107
resources/views/livewire/studio/catalog/bottle/form.blade.php
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<flux:main>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div>
|
||||||
|
<flux:heading size="xl">{{ $pageTitle }}</flux:heading>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<flux:button href="{{ route('studio.catalog.bottle.index') }}" wire:navigate.hover class="text-sm">
|
||||||
|
Kembali
|
||||||
|
</flux:button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-6">
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div class="flex flex-col lg:flex-row gap-4">
|
||||||
|
<div class="w-full lg:w-3/4 space-y-4">
|
||||||
|
<div class="grid grid-cols-1 gap-4 lg:grid-cols-2 items-start">
|
||||||
|
<div class="col-span-1 lg:col-span-2">
|
||||||
|
<flux:card class="space-y-6 p-6">
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
|
<flux:input label="Nama" placeholder="Masukkan nama produk"
|
||||||
|
wire:model.live.debounce.500ms="form.name" autofocus autocomplete="off" />
|
||||||
|
|
||||||
|
<flux:input label="Ukuran" placeholder="Masukkan ukuran"
|
||||||
|
wire:model.live.debounce.500ms="form.size" autocomplete="off" />
|
||||||
|
|
||||||
|
<flux:field>
|
||||||
|
<flux:label>Harga Beli</flux:label>
|
||||||
|
<flux:input.group>
|
||||||
|
<flux:input.group.prefix>Rp</flux:input.group.prefix>
|
||||||
|
<flux:input placeholder="Masukkan harga beli"
|
||||||
|
x-mask:dynamic="$money($input, ',')"
|
||||||
|
wire:model.live.debounce.500ms="form.cost_price" autocomplete="off" />
|
||||||
|
</flux:input.group>
|
||||||
|
<flux:error name="form.cost_price" />
|
||||||
|
</flux:field>
|
||||||
|
|
||||||
|
<flux:field>
|
||||||
|
<flux:label>Harga Jual</flux:label>
|
||||||
|
<flux:input.group>
|
||||||
|
<flux:input.group.prefix>Rp</flux:input.group.prefix>
|
||||||
|
<flux:input placeholder="Masukkan harga jual"
|
||||||
|
x-mask:dynamic="$money($input, ',')"
|
||||||
|
wire:model.live.debounce.500ms="form.sale_price" autocomplete="off" />
|
||||||
|
</flux:input.group>
|
||||||
|
<flux:error name="form.sale_price" />
|
||||||
|
</flux:field>
|
||||||
|
|
||||||
|
<div class="md:col-span-2">
|
||||||
|
<flux:editor label="Deskripsi" wire:model="form.description"
|
||||||
|
placeholder="Masukkan deskripsi" auotocomplete="off"
|
||||||
|
class="**:data-[slot=content]:min-h-[100px]!" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</flux:card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full lg:w-1/3 space-y-4">
|
||||||
|
<flux:card class="space-y-6 p-6">
|
||||||
|
<flux:select variant="listbox" multiple searchable placeholder="Pilih Outlet" label="Outlet"
|
||||||
|
wire:model.live.debounce.500ms="form.outlet_ids">
|
||||||
|
<flux:select.option wire:click="selectAllOutlets" wire:ignore>Pilih Semua
|
||||||
|
</flux:select.option>
|
||||||
|
<flux:select.option wire:click="deselectAllOutlets" wire:ignore>Hapus Semua
|
||||||
|
</flux:select.option>
|
||||||
|
@foreach ($outlets as $key => $value)
|
||||||
|
<flux:select.option value="{{ $key }}">{{ $value }}
|
||||||
|
</flux:select.option>
|
||||||
|
@endforeach
|
||||||
|
</flux:select>
|
||||||
|
</flux:card>
|
||||||
|
|
||||||
|
<flux:card class="space-y-6 p-6">
|
||||||
|
<div class="space-y-3">
|
||||||
|
<h3 class="text-sm font-medium">Gambar</h3>
|
||||||
|
<div class="dropzone-wrapper">
|
||||||
|
<livewire:dropzone wire:model="form.image" :rules="['image', 'mimes:png,jpeg', 'max:10420']" :max-files="1"
|
||||||
|
:key="'image'" :files="$form->image" />
|
||||||
|
@error('form.image')
|
||||||
|
<div role="alert" aria-live="polite" aria-atomic="true"
|
||||||
|
class="mt-3 text-sm font-medium text-red-500 dark:text-red-400">
|
||||||
|
<svg class="shrink-0 [:where(&)]:size-5 inline" data-flux-icon=""
|
||||||
|
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"
|
||||||
|
aria-hidden="true" data-slot="icon">
|
||||||
|
<path fill-rule="evenodd"
|
||||||
|
d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495ZM10 5a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 10 5Zm0 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"
|
||||||
|
clip-rule="evenodd"></path>
|
||||||
|
</svg>
|
||||||
|
{{ $message }}
|
||||||
|
</div>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</flux:card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-start">
|
||||||
|
<flux:button variant="primary" class="sm:w-auto cursor-pointer" wire:click="save">
|
||||||
|
Simpan
|
||||||
|
</flux:button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</flux:main>
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
<flux:main>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div>
|
||||||
|
<flux:heading size="xl">{{ $pageTitle }}</flux:heading>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<flux:button href="{{ route('studio.catalog.bottle.create') }}" variant="primary" wire:navigate.hover
|
||||||
|
class="text-sm">
|
||||||
|
Tambah
|
||||||
|
</flux:button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-6">
|
||||||
|
<livewire:datatable.bottles-table />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@include('components.confirmation.delete')
|
||||||
|
</flux:main>
|
||||||
@ -3,6 +3,9 @@
|
|||||||
use App\Livewire\Auth\Login;
|
use App\Livewire\Auth\Login;
|
||||||
use App\Livewire\Auth\Logout;
|
use App\Livewire\Auth\Logout;
|
||||||
use App\Livewire\Auth\Register;
|
use App\Livewire\Auth\Register;
|
||||||
|
use App\Livewire\Studio\Catalog\Bottle\Create as BottleCreate;
|
||||||
|
use App\Livewire\Studio\Catalog\Bottle\Edit as BottleEdit;
|
||||||
|
use App\Livewire\Studio\Catalog\Bottle\Index as BottleIndex;
|
||||||
use App\Livewire\Studio\Catalog\Brand as BrandComponent;
|
use App\Livewire\Studio\Catalog\Brand as BrandComponent;
|
||||||
use App\Livewire\Studio\Catalog\Category as CategoryComponent;
|
use App\Livewire\Studio\Catalog\Category as CategoryComponent;
|
||||||
use App\Livewire\Studio\Catalog\Perfume\Create as PerfumeCreate;
|
use App\Livewire\Studio\Catalog\Perfume\Create as PerfumeCreate;
|
||||||
@ -139,4 +142,13 @@
|
|||||||
Route::get('products/{product}/edit', ProductEdit::class)->name('edit');
|
Route::get('products/{product}/edit', ProductEdit::class)->name('edit');
|
||||||
Route::get('products/{product}/delete', ProductCreate::class)->name('delete');
|
Route::get('products/{product}/delete', ProductCreate::class)->name('delete');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::prefix('catalog')
|
||||||
|
->as('studio.catalog.bottle.')
|
||||||
|
->group(function () {
|
||||||
|
Route::get('bottles', BottleIndex::class)->name('index');
|
||||||
|
Route::get('bottles/create', BottleCreate::class)->name('create');
|
||||||
|
Route::get('bottles/{bottle}/edit', BottleEdit::class)->name('edit');
|
||||||
|
Route::get('bottles/{bottle}/delete', BottleCreate::class)->name('delete');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user