diff --git a/app/Livewire/Datatable/Information/TestimonialsTable.php b/app/Livewire/Datatable/Information/TestimonialsTable.php
new file mode 100644
index 0000000..f78f3df
--- /dev/null
+++ b/app/Livewire/Datatable/Information/TestimonialsTable.php
@@ -0,0 +1,51 @@
+searchable(),
+
+ Column::make('Konten', 'content')
+ ->searchable()
+ ->format(fn ($value) => Str::limit($value, 50)),
+
+ Column::make('Rating', 'rating')
+ ->sortable(),
+
+ Column::make('Visibilitas', 'is_show')
+ ->label(fn ($row, $column) => Blade::render('', ['checked' => $row->is_show === IsShow::SHOW]))
+ ->html(),
+ ];
+ }
+
+ public function toggleShow(Testimonial $testimonial): void
+ {
+ $testimonial->update([
+ 'is_show' => $testimonial->is_show === IsShow::SHOW ? IsShow::HIDDEN : IsShow::SHOW,
+ ]);
+ }
+
+ public function builder(): Builder
+ {
+ return Testimonial::select('testimonials.id', 'rating', 'content', 'is_show', 'testimonials.created_at')->with(['user', 'user.customer']);
+ }
+}
diff --git a/app/Livewire/Studio/Information/Testimonial.php b/app/Livewire/Studio/Information/Testimonial.php
new file mode 100644
index 0000000..76972e6
--- /dev/null
+++ b/app/Livewire/Studio/Information/Testimonial.php
@@ -0,0 +1,18 @@
+ 'Testimoni',
+ ]);
+ }
+}
diff --git a/app/Models/Testimonial.php b/app/Models/Testimonial.php
new file mode 100644
index 0000000..026c30c
--- /dev/null
+++ b/app/Models/Testimonial.php
@@ -0,0 +1,32 @@
+ IsShow::class,
+ ];
+ }
+
+ #[Scope]
+ public function show(Builder $query): void
+ {
+ $query->where('is_show', IsShow::SHOW);
+ }
+
+ public function user(): BelongsTo
+ {
+ return $this->belongsTo(User::class);
+ }
+}
diff --git a/app/Providers/ViewServiceProvider.php b/app/Providers/ViewServiceProvider.php
index d5dfe54..817ddd4 100644
--- a/app/Providers/ViewServiceProvider.php
+++ b/app/Providers/ViewServiceProvider.php
@@ -229,6 +229,13 @@ public function boot(): void
'match' => 'studio.information.faq.*',
'can' => 'view faq',
],
+ [
+ 'label' => 'Testimonial',
+ 'icon' => 'chat-bubble-left-ellipsis',
+ 'route' => 'studio.information.testimonial.index',
+ 'match' => 'studio.information.testimonial.*',
+ 'can' => 'view testimonial',
+ ],
],
],
[
diff --git a/database/migrations/2025_12_19_214248_create_testimonials_table.php b/database/migrations/2025_12_19_214248_create_testimonials_table.php
new file mode 100644
index 0000000..e6256f0
--- /dev/null
+++ b/database/migrations/2025_12_19_214248_create_testimonials_table.php
@@ -0,0 +1,32 @@
+id();
+ $table->foreignId('user_id')->constrained()->cascadeOnDelete();
+ $table->text('content');
+ $table->integer('rating');
+ $table->enum('is_show', IsShow::values())->default(IsShow::SHOW)->comment(IsShow::comment());
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('testimonials');
+ }
+};
diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php
index df93d3f..ac69966 100644
--- a/database/seeders/DatabaseSeeder.php
+++ b/database/seeders/DatabaseSeeder.php
@@ -32,6 +32,7 @@ public function run(): void
FaqSeeder::class,
PerfumeFeatureSeeder::class,
ChooseUsSeeder::class,
+ TestimonialSeeder::class,
]);
}
}
diff --git a/database/seeders/RolePermissionSeeder.php b/database/seeders/RolePermissionSeeder.php
index 8f124af..ffc3ebc 100644
--- a/database/seeders/RolePermissionSeeder.php
+++ b/database/seeders/RolePermissionSeeder.php
@@ -137,6 +137,11 @@ public function run(): void
'update faq',
'delete faq',
+ 'view testimonial',
+ 'create testimonial',
+ 'update testimonial',
+ 'delete testimonial',
+
'view broadcast',
'create broadcast',
'delete broadcast',
diff --git a/database/seeders/TestimonialSeeder.php b/database/seeders/TestimonialSeeder.php
new file mode 100644
index 0000000..52841c1
--- /dev/null
+++ b/database/seeders/TestimonialSeeder.php
@@ -0,0 +1,69 @@
+ 'Parfumnya wangi banget, tahan lama seharian! Recommended banget pokoknya.',
+ 'rating' => 5,
+ 'is_show' => IsShow::SHOW,
+ ],
+ [
+ 'content' => 'Pengiriman cepat, packing aman. Wanginya juga sesuai ekspektasi. Terima kasih!',
+ 'rating' => 5,
+ 'is_show' => IsShow::SHOW,
+ ],
+ [
+ 'content' => 'Wanginya enak, tapi sayang kurang tahan lama di luar ruangan yg panas. Tapi worth it lah harga segini.',
+ 'rating' => 4,
+ 'is_show' => IsShow::SHOW,
+ ],
+ [
+ 'content' => 'Suka banget sama varian vanilla-nya. Manis tapi nggak bikin pusing. Bakal repeat order sih ini.',
+ 'rating' => 5,
+ 'is_show' => IsShow::SHOW,
+ ],
+ [
+ 'content' => 'Botolnya pecah dikit pas nyampe, mungkin dari ekspedisinya. Tapi parfumnya masih oke.',
+ 'rating' => 3,
+ 'is_show' => IsShow::HIDDEN,
+ ],
+ [
+ 'content' => 'Pelayanan ramah, admin fast respon. Parfumnya juga original. Top marketop!',
+ 'rating' => 5,
+ 'is_show' => IsShow::SHOW,
+ ],
+ [
+ 'content' => 'Aromanya mewah, cocok buat kondangan. Temen-temen pada nanyain pake parfum apa.',
+ 'rating' => 5,
+ 'is_show' => IsShow::SHOW,
+ ],
+ [
+ 'content' => 'Lumayan lah buat sehari-hari. Gak terlalu menyengat.',
+ 'rating' => 4,
+ 'is_show' => IsShow::SHOW,
+ ],
+ ];
+
+ foreach ($testimonials as $testimonial) {
+ Testimonial::create([
+ 'user_id' => User::whereHas('customer')->inRandomOrder()->first()->id,
+ 'content' => $testimonial['content'],
+ 'rating' => $testimonial['rating'],
+ 'is_show' => $testimonial['is_show'],
+ ]);
+ }
+ }
+}
diff --git a/resources/views/livewire/studio/information/testimonials.blade.php b/resources/views/livewire/studio/information/testimonials.blade.php
new file mode 100644
index 0000000..32f7591
--- /dev/null
+++ b/resources/views/livewire/studio/information/testimonials.blade.php
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
diff --git a/routes/pages/studio.php b/routes/pages/studio.php
index 96c80a3..3d8d503 100644
--- a/routes/pages/studio.php
+++ b/routes/pages/studio.php
@@ -24,6 +24,7 @@
use App\Livewire\Studio\Information\Broadcast as BroadcastComponent;
use App\Livewire\Studio\Information\Faq as FaqComponent;
use App\Livewire\Studio\Information\PriceRequest as PriceRequestComponent;
+use App\Livewire\Studio\Information\Testimonial as TestimonialComponent;
use App\Livewire\Studio\Loyalty\Customer as CustomerComponent;
use App\Livewire\Studio\Loyalty\RedemptionVerification;
use App\Livewire\Studio\Loyalty\Reward as RewardComponent;
@@ -184,6 +185,10 @@
Route::prefix('faqs')->name('faq.')->group(function () {
Route::get('/', FaqComponent::class)->name('index')->middleware('can:view faq');
});
+
+ Route::prefix('testimonials')->name('testimonial.')->group(function () {
+ Route::get('/', TestimonialComponent::class)->name('index')->middleware('can:view testimonial');
+ });
});
Route::prefix('feature')->name('studio.feature.')->group(function () {