add kategori & ulasan view

This commit is contained in:
Muzakki Parsaoran Siregar 2025-09-01 16:11:43 +07:00
parent c5486575a3
commit 21d61178ac
7 changed files with 600 additions and 114 deletions

View File

@ -9,10 +9,12 @@ use App\Models\Review;
class ReviewController extends Controller class ReviewController extends Controller
{ {
// Ambil semua ulasan // Ambil semua ulasan
public function index() public function index()
{ {
return response()->json(Review::all(), 200); $reviews = Review::all();
} return view('admin.reviews.index', compact('reviews'));
}
// Simpan ulasan baru // Simpan ulasan baru
public function store(Request $request) public function store(Request $request)

View File

@ -7,10 +7,12 @@ use Illuminate\Support\Facades\Storage;
class KategoriController extends Controller class KategoriController extends Controller
{ {
public function index() public function index()
{ {
return response()->json(Kategori::all(), 200); $kategori = Kategori::all();
} return view('admin.kategori.index', compact('kategori'));
}
public function show(Kategori $kategori) public function show(Kategori $kategori)
{ {

View File

@ -1,115 +1,113 @@
<!doctype html> @extends('layouts.app')
<html lang="id">
<head> @section('title', 'Halaman Dasbor')
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Halaman Dasbor</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
<style>
body {
background-color: #f8f9fa;
}
.dashboard-card { @section('content')
border-radius: 12px; <div class="container">
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); <!-- Header -->
padding: 20px; <div class="d-flex justify-content-between align-items-center mb-4">
display: flex; <h3 class="fw-bold">Halaman Dasbor</h3>
justify-content: space-between;
align-items: center;
background: #fff;
}
.dashboard-card h5 { <div class="d-flex align-items-center gap-3">
font-size: 14px; <div class="date-box bg-primary bg-opacity-10 text-primary px-3 py-2 rounded">
color: #6c757d; <i class="bi bi-clock-history"></i>
} {{ \Carbon\Carbon::now()->translatedFormat('l, d F Y') }}
.dashboard-card h3 {
font-weight: bold;
}
.dashboard-icon {
font-size: 28px;
color: #0d6efd;
background: #eef4ff;
padding: 10px;
border-radius: 10px;
}
.date-box {
background: #eef4ff;
color: #0d6efd;
padding: 6px 12px;
border-radius: 10px;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 6px;
}
</style>
</head>
<body class="p-4">
<div class="container">
<!-- Header -->
<div class="d-flex justify-content-between align-items-center mb-4">
<h3 class="fw-bold">Halaman Dasbor</h3>
<div class="d-flex align-items-center gap-3">
<div class="date-box">
<i class="bi bi-clock-history"></i>
{{ \Carbon\Carbon::now()->translatedFormat('l, d F Y') }}
</div>
<!-- Logout -->
<form action="{{ route('admin.logout') }}" method="POST" class="m-0">
@csrf
<button class="btn btn-outline-danger">Logout</button>
</form>
</div> </div>
</div>
<!-- Cards --> <!-- Logout -->
<div class="row g-4">
<div class="col-md-4">
<div class="dashboard-card">
<div>
<h5>Kategori</h5>
<h3>10</h3>
</div>
<i class="bi bi-diagram-3 dashboard-icon"></i>
</div>
</div>
<div class="col-md-4">
<div class="dashboard-card">
<div>
<h5>Templat</h5>
<h3>20</h3>
</div>
<i class="bi bi-card-list dashboard-icon"></i>
</div>
</div>
<div class="col-md-4">
<div class="dashboard-card">
<div>
<h5>Pelanggan</h5>
<h3>24</h3>
</div>
<i class="bi bi-person dashboard-icon"></i>
</div>
</div>
</div>
<!-- Pesan login -->
<div class="alert alert-success mt-4">
Berhasil login sebagai <strong>{{ auth('admin')->user()->name }}</strong>
</div> </div>
</div> </div>
</body> <!-- Cards -->
<div class="row g-4">
<div class="col-md-4">
<div class="dashboard-card">
<div>
<h5>Kategori</h5>
<h3>10</h3>
</div>
<i class="bi bi-diagram-3 dashboard-icon"></i>
</div>
</div>
<div class="col-md-4">
<div class="dashboard-card">
<div>
<h5>Templat</h5>
<h3>20</h3>
</div>
<i class="bi bi-card-list dashboard-icon"></i>
</div>
</div>
<div class="col-md-4">
<div class="dashboard-card">
<div>
<h5>Pelanggan</h5>
<h3>24</h3>
</div>
<i class="bi bi-person dashboard-icon"></i>
</div>
</div>
</div>
</html> <!-- Pesan login -->
<div class="alert alert-success mt-4">
Berhasil login sebagai <strong>{{ auth('admin')->user()->name }}</strong>
</div>
</div>
<style>
/* STYLE DASHBOARD CARD */
.dashboard-card {
border-radius: 12px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
padding: 20px;
display: flex;
justify-content: space-between;
align-items: center;
background: #fff;
transition: all 0.3s ease;
}
.dashboard-card:hover {
transform: translateY(-3px);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
}
.dashboard-card h5 {
font-size: 14px;
color: #6c757d;
}
.dashboard-card h3 {
font-weight: bold;
margin: 0;
}
.dashboard-icon {
width: 50px; /* ukuran kotak tetap */
height: 50px; /* tinggi sama dengan lebar */
display: flex; /* agar icon center */
justify-content: center;
align-items: center;
font-size: 24px; /* ukuran ikon */
color: #0d6efd; /* warna ikon */
background: #eef4ff; /* background biru muda */
border-radius: 12px; /* sudut sedikit rounded */
flex-shrink: 0; /* biar kotak gak mengecil */
}
/* Kotak tanggal di header dashboard */
.date-box {
background: #eef4ff;
color: #0d6efd;
padding: 6px 12px;
border-radius: 10px;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 6px;
}
</style>
@endsection

View File

@ -0,0 +1,135 @@
@extends('layouts.app')
@section('title', 'Manajemen Kategori')
@section('content')
<div class="container">
<!-- Header -->
<div class="d-flex justify-content-between align-items-center mb-4">
<h3 class="fw-bold">Manajemen Kategori</h3>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalTambah">
<i class="bi bi-plus-lg"></i> Tambah Kategori
</button>
</div>
<!-- Tabel Kategori -->
<div class="card shadow-sm border-0">
<div class="card-body">
<table class="table table-hover align-middle">
<thead>
<tr>
<th width="50">No</th>
<th>Foto</th>
<th>Nama</th>
<th>Deskripsi</th>
<th width="180">Aksi</th>
</tr>
</thead>
<tbody>
@forelse ($kategori as $key => $item)
<tr>
<td>{{ $key + 1 }}</td>
<td>
@if($item->foto)
<img src="{{ asset('storage/'.$item->foto) }}" alt="foto" width="50" height="50" style="object-fit:cover; border-radius:6px;">
@else
<img src="{{ asset('default-image.png') }}" alt="default" width="50" height="50" style="object-fit:cover; border-radius:6px;">
@endif
</td>
<td>{{ $item->nama }}</td>
<td>{{ $item->deskripsi ?? '-' }}</td>
<td>
<button class="btn btn-warning btn-sm" data-bs-toggle="modal"
data-bs-target="#modalEdit{{ $item->id }}">
<i class="bi bi-pencil"></i>
</button>
<form action="{{ route('admin.kategori.destroy', $item->id) }}"
method="POST"
class="d-inline"
onsubmit="return confirm('Yakin mau hapus kategori ini?')">
@csrf
@method('DELETE')
<button class="btn btn-danger btn-sm">
<i class="bi bi-trash"></i>
</button>
</form>
</td>
</tr>
<!-- Modal Edit -->
<div class="modal fade" id="modalEdit{{ $item->id }}" tabindex="-1">
<div class="modal-dialog">
<form action="{{ route('admin.kategori.update', $item->id) }}" method="POST" enctype="multipart/form-data" class="modal-content">
@csrf
@method('PUT')
<div class="modal-header">
<h5 class="modal-title">Edit Kategori</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label>Nama</label>
<input type="text" name="nama" value="{{ $item->nama }}" class="form-control" required>
</div>
<div class="mb-3">
<label>Deskripsi</label>
<textarea name="deskripsi" class="form-control" rows="3">{{ $item->deskripsi }}</textarea>
</div>
<div class="mb-3">
<label>Foto</label>
<input type="file" name="foto" class="form-control">
@if($item->foto)
<small class="text-muted">Foto saat ini:</small><br>
<img src="{{ asset('storage/'.$item->foto) }}" alt="foto" width="70" class="mt-1 rounded">
@endif
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
<button class="btn btn-primary">Simpan Perubahan</button>
</div>
</form>
</div>
</div>
@empty
<tr>
<td colspan="5" class="text-center text-muted">Belum ada kategori</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
<!-- Modal Tambah -->
<div class="modal fade" id="modalTambah" tabindex="-1">
<div class="modal-dialog">
<form action="{{ route('admin.kategori.store') }}" method="POST" enctype="multipart/form-data" class="modal-content">
@csrf
<div class="modal-header">
<h5 class="modal-title">Tambah Kategori</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label>Nama</label>
<input type="text" name="nama" class="form-control" required>
</div>
<div class="mb-3">
<label>Deskripsi</label>
<textarea name="deskripsi" class="form-control" rows="3"></textarea>
</div>
<div class="mb-3">
<label>Foto</label>
<input type="file" name="foto" class="form-control">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
<button class="btn btn-primary">Simpan</button>
</div>
</form>
</div>
</div>
@endsection

View File

@ -0,0 +1,109 @@
@extends('layouts.app')
@section('title', 'Manajemen Ulasan')
@section('content')
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-4">
<h3 class="fw-bold">Manajemen Ulasan</h3>
{{-- Info kecil bahwa tambah data via Postman --}}
</div>
{{-- Alert sukses --}}
@if(session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
{{-- Tabel Ulasan --}}
<div class="card shadow-sm border-0">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<th width="60">No</th>
<th>Nama</th>
<th>Kota</th>
<th>Rating</th>
<th>Pesan</th>
<th width="120" class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
@forelse ($reviews as $i => $review)
<tr>
<td>{{ $i + 1 }}</td>
<td>{{ $review->name }}</td>
<td>{{ $review->city }}</td>
<td>
@for($s=1; $s<=5; $s++)
<i class="bi {{ $s <= $review->rating ? 'bi-star-fill text-warning' : 'bi-star text-secondary' }}"></i>
@endfor
</td>
<td>{{ $review->message }}</td>
<td class="text-center">
<button
type="button"
class="btn btn-sm btn-danger btn-delete"
data-action="{{ route('admin.reviews.destroy', $review) }}"
data-name="{{ $review->name }}"
>
<i class="bi bi-trash"></i> Hapus
</button>
</td>
</tr>
@empty
<tr>
<td colspan="6" class="text-center text-muted">Belum ada ulasan</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
</div>
{{-- Modal Konfirmasi Hapus (satu modal untuk semua baris) --}}
<div class="modal fade" id="confirmDeleteModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<form id="deleteForm" method="POST" class="modal-content">
@csrf
@method('DELETE')
<div class="modal-header">
<h5 class="modal-title">Hapus Ulasan</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
Apakah Anda yakin ingin menghapus ulasan dari <strong id="deleteName"></strong>?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
<button type="submit" class="btn btn-danger">Ya, Hapus</button>
</div>
</form>
</div>
</div>
{{-- Script kecil untuk set action form hapus --}}
<script>
document.addEventListener('DOMContentLoaded', () => {
const modalEl = document.getElementById('confirmDeleteModal');
const deleteForm = document.getElementById('deleteForm');
const deleteName = document.getElementById('deleteName');
document.querySelectorAll('.btn-delete').forEach(btn => {
btn.addEventListener('click', () => {
deleteForm.action = btn.dataset.action;
deleteName.textContent = btn.dataset.name || 'pengguna ini';
new bootstrap.Modal(modalEl).show();
});
});
});
</script>
@endsection

View File

@ -0,0 +1,211 @@
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>@yield('title', 'Admin Panel')</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
<style>
body {
background-color: #f8f9fa;
font-family: 'Poppins', sans-serif;
}
/* SIDEBAR */
.sidebar {
width: 250px;
height: 100vh;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
position: fixed;
top: 0;
left: 0;
padding: 20px 0;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.sidebar .logo {
text-align: center;
margin-bottom: 20px;
}
.sidebar .logo img {
width: 120px;
}
.sidebar .menu-title {
font-size: 12px;
font-weight: 600;
padding-left: 20px;
color: #6c757d;
margin-top: 10px;
margin-bottom: 5px;
}
.sidebar ul {
list-style: none;
padding-left: 0;
margin: 0;
}
.sidebar ul li a {
display: flex;
align-items: center;
padding: 10px 20px;
color: #333;
text-decoration: none;
font-weight: 500;
transition: all 0.3s;
cursor: pointer;
}
.sidebar ul li a:hover,
.sidebar ul li a.active {
background-color: #eef4ff;
color: #0d6efd;
}
.sidebar ul li a i {
font-size: 18px;
margin-right: 10px;
}
/* Dropdown submenu */
.submenu {
padding-left: 40px;
display: none;
}
.submenu.show {
display: block;
}
/* BOTTOM PROFILE */
.sidebar-bottom {
padding: 20px;
border-top: 1px solid #eaeaea;
}
.sidebar-bottom .logout {
color: red;
display: flex;
align-items: center;
text-decoration: none;
font-weight: 600;
cursor: pointer;
}
.sidebar-bottom .logout i {
margin-right: 8px;
}
.sidebar-bottom .profile {
margin-top: 15px;
display: flex;
align-items: center;
gap: 10px;
}
.sidebar-bottom .profile img {
width: 35px;
height: 35px;
border-radius: 50%;
object-fit: cover;
}
/* MAIN CONTENT */
.main-content {
margin-left: 250px;
padding: 20px;
}
</style>
</head>
<body>
<!-- SIDEBAR -->
<div class="sidebar">
<div>
<!-- LOGO -->
<div class="logo">
<img src="{{ asset('images/logo.png') }}" alt="Logo">
</div>
<!-- MENU -->
<p class="menu-title">Menu Utama</p>
<ul>
<!-- Dashboard tetap punya route -->
<li>
<a href="{{ route('admin.dashboard') }}"
class="{{ request()->is('admin/dashboard') ? 'active' : '' }}">
<i class="bi bi-house-door"></i> Dasbor
</a>
</li>
<!-- Dummy menu -->
<li>
<a href="{{ route('admin.kategori.index') }}"
class="{{ request()->is('admin/kategori*') ? 'active' : '' }}">
<i class="bi bi-diagram-3"></i> Kategori
</a>
</li>
<li><a href="javascript:void(0)"><i class="bi bi-grid"></i> Fitur</a></li>
<!-- Dropdown dummy -->
<li>
<a href="#templatSubmenu" data-bs-toggle="collapse" aria-expanded="false">
<i class="bi bi-card-list"></i> Templat
<i class="bi bi-chevron-down ms-auto"></i>
</a>
<ul id="templatSubmenu" class="submenu collapse">
<li><a href="javascript:void(0)">Pernikahan</a></li>
<li><a href="javascript:void(0)">Ulang Tahun</a></li>
<li><a href="javascript:void(0)">Khitan</a></li>
</ul>
</li>
<li><a href="javascript:void(0)"><i class="bi bi-people"></i> Pelanggan</a></li>
<li>
<a href="{{ route('admin.reviews.index') }}"
class="{{ request()->is('admin/ulasan') ? 'active' : '' }}">
<i class="bi bi-chat-dots"></i> Ulasan
</a>
</li>
</ul>
</div>
<!-- BOTTOM SIDEBAR -->
<div class="sidebar-bottom">
<a href="{{ route('admin.logout') }}" class="logout"
onclick="event.preventDefault(); document.getElementById('logout-form').submit();">
<i class="bi bi-box-arrow-right"></i> Keluar
</a>
<form id="logout-form" action="{{ route('admin.logout') }}" method="POST" class="d-none">
@csrf
</form>
<div class="profile">
<img src="{{ asset('default-avatar.png') }}" alt="Admin">
<div>
<p class="m-0 fw-bold">{{ auth('admin')->user()->name }}</p>
<small class="text-muted">{{ auth('admin')->user()->email }}</small>
</div>
</div>
</div>
</div>
<!-- MAIN CONTENT -->
<div class="main-content">
@yield('content')
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@ -17,3 +17,32 @@ Route::prefix('admin')->name('admin.')->group(function () {
Route::post('/logout', [AdminAuthController::class, 'logout'])->name('logout'); Route::post('/logout', [AdminAuthController::class, 'logout'])->name('logout');
}); });
}); });
use App\Http\Controllers\KategoriController;
Route::prefix('admin')->name('admin.')->group(function () {
Route::get('/kategori', [KategoriController::class, 'index'])->name('kategori.index');
Route::post('/kategori', [KategoriController::class, 'store'])->name('kategori.store');
Route::put('/kategori/{kategori}', [KategoriController::class, 'update'])->name('kategori.update');
Route::delete('/kategori/{kategori}', [KategoriController::class, 'destroy'])->name('kategori.destroy');
});
use App\Http\Controllers\Api\ReviewController;
use App\Models\Review;
Route::prefix('admin')->name('admin.')->middleware('auth:admin')->group(function () {
// Halaman daftar ulasan
Route::get('/ulasan', function () {
$reviews = \App\Models\Review::latest()->get();
return view('admin.reviews.index', compact('reviews'));
})->name('reviews.index');
// Hapus ulasan
Route::delete('/ulasan/{review}', function (Review $review) {
$review->delete();
return redirect()->route('admin.reviews.index')->with('success', 'Ulasan berhasil dihapus');
})->name('reviews.destroy');
});