search and pagination

This commit is contained in:
rahmagustin 2026-03-11 01:23:18 +07:00
parent 51a3d163cf
commit 4767cae919
17 changed files with 197 additions and 91 deletions

View File

@ -10,13 +10,25 @@
class TpsController extends Controller class TpsController extends Controller
{ {
public function index()
public function index(Request $request)
{ {
$title = 'Data TPS'; $title = 'Data TPS';
$tps = LokasiTps::with('kategori')->withCount('aduan')->get();
return view('admin.tps.index', compact('title', 'tps')); $search = $request->search;
$tps = LokasiTps::with('kategori')
->withCount('aduan')
->when($search, function ($query) use ($search) {
$query->where('nama_tps', 'like', '%' . $search . '%');
})
->orderBy('id_tps', 'desc') // supaya data terbaru muncul di atas
->paginate(10);
return view('admin.tps.index', compact('title', 'tps', 'search'));
} }
public function create() public function create()
{ {
$title = 'Tambah TPS'; $title = 'Tambah TPS';
@ -24,6 +36,7 @@ public function create()
return view('admin.tps.create', compact('title', 'kategori')); return view('admin.tps.create', compact('title', 'kategori'));
} }
private function convertToDecimal($coordinate) private function convertToDecimal($coordinate)
{ {
if (is_numeric($coordinate)) { if (is_numeric($coordinate)) {
@ -49,9 +62,12 @@ private function convertToDecimal($coordinate)
return $decimal; return $decimal;
} }
public function store(Request $request) public function store(Request $request)
{ {
$validator = Validator::make($request->all(), [ $validator = Validator::make($request->all(), [
'kategori_tps_id' => 'required|exists:kategori_tps,id_kategori_tps', 'kategori_tps_id' => 'required|exists:kategori_tps,id_kategori_tps',
'nama_tps' => 'required|string|max:255', 'nama_tps' => 'required|string|max:255',
'alamat_tps' => 'required|string|max:255', 'alamat_tps' => 'required|string|max:255',
@ -61,7 +77,9 @@ public function store(Request $request)
'latitude' => 'required', 'latitude' => 'required',
'longitude' => 'required', 'longitude' => 'required',
'foto_tps' => 'required|image|mimes:jpg,jpeg,png|max:2048', 'foto_tps' => 'required|image|mimes:jpg,jpeg,png|max:2048',
], [ ], [
'kategori_tps_id.required' => 'Kategori TPS wajib dipilih.', 'kategori_tps_id.required' => 'Kategori TPS wajib dipilih.',
'kategori_tps_id.exists' => 'Kategori TPS tidak valid.', 'kategori_tps_id.exists' => 'Kategori TPS tidak valid.',
'nama_tps.required' => 'Nama TPS wajib diisi.', 'nama_tps.required' => 'Nama TPS wajib diisi.',
@ -78,33 +96,48 @@ public function store(Request $request)
'foto_tps.required' => 'Foto TPS wajib diunggah.', 'foto_tps.required' => 'Foto TPS wajib diunggah.',
'foto_tps.image' => 'Foto TPS harus berupa gambar.', 'foto_tps.image' => 'Foto TPS harus berupa gambar.',
'foto_tps.mimes' => 'Format foto harus jpg, jpeg, atau png.', 'foto_tps.mimes' => 'Format foto harus jpg, jpeg, atau png.',
]); ]);
if ($validator->fails()) return back()->withErrors($validator)->withInput(); if ($validator->fails()) {
return back()->withErrors($validator)->withInput();
}
$latitude = $this->convertToDecimal($request->latitude); $latitude = $this->convertToDecimal($request->latitude);
$longitude = $this->convertToDecimal($request->longitude); $longitude = $this->convertToDecimal($request->longitude);
if ($latitude === null || $latitude < -90 || $latitude > 90)
if ($latitude === null || $latitude < -90 || $latitude > 90) {
$validator->errors()->add('latitude', 'Latitude tidak valid.'); $validator->errors()->add('latitude', 'Latitude tidak valid.');
}
if ($longitude === null || $longitude < -180 || $longitude > 180) if ($longitude === null || $longitude < -180 || $longitude > 180) {
$validator->errors()->add('longitude', 'Longitude tidak valid.'); $validator->errors()->add('longitude', 'Longitude tidak valid.');
}
if ($validator->fails()) {
return back()->withErrors($validator)->withInput();
}
if ($validator->fails()) return back()->withErrors($validator)->withInput();
// Upload foto ke public/assets/admin/images/tps
$foto = null; $foto = null;
if ($request->hasFile('foto_tps')) { if ($request->hasFile('foto_tps')) {
$file = $request->file('foto_tps'); $file = $request->file('foto_tps');
$namaTps = strtoupper(preg_replace('/[^A-Za-z0-9]/', '', $request->nama_tps));
$extension = $file->getClientOriginalExtension(); $filename = strtolower(str_replace(' ', '_', $request->nama_tps))
$filename = strtolower(str_replace(' ', '_', $request->nama_tps)) . '_' . time() . '.' . $file->getClientOriginalExtension(); . '_' . time() . '.' . $file->getClientOriginalExtension();
$file->move(public_path('assets/admin/images/tps'), $filename); $file->move(public_path('assets/admin/images/tps'), $filename);
$foto = $filename; $foto = $filename;
} }
LokasiTps::create([ LokasiTps::create([
'kategori_tps_id' => $request->kategori_tps_id, 'kategori_tps_id' => $request->kategori_tps_id,
'nama_tps' => $request->nama_tps, 'nama_tps' => $request->nama_tps,
'alamat_tps' => $request->alamat_tps, 'alamat_tps' => $request->alamat_tps,
@ -114,24 +147,36 @@ public function store(Request $request)
'latitude' => $latitude, 'latitude' => $latitude,
'longitude' => $longitude, 'longitude' => $longitude,
'foto_tps' => $foto, 'foto_tps' => $foto,
]); ]);
return redirect()->route('admin.tps.index')->with('success', 'Data TPS berhasil ditambahkan.');
return redirect()->route('admin.tps.index')
->with('success', 'Data TPS berhasil ditambahkan.');
} }
public function edit($id) public function edit($id)
{ {
$title = 'Edit TPS'; $title = 'Edit TPS';
$tps = LokasiTps::findOrFail($id); $tps = LokasiTps::findOrFail($id);
$kategori = KategoriTps::all(); $kategori = KategoriTps::all();
return view('admin.tps.edit', compact('title', 'tps', 'kategori')); return view('admin.tps.edit', compact('title', 'tps', 'kategori'));
} }
public function update(Request $request, $id) public function update(Request $request, $id)
{ {
$tps = LokasiTps::findOrFail($id); $tps = LokasiTps::findOrFail($id);
$validator = Validator::make($request->all(), [ $validator = Validator::make($request->all(), [
'kategori_tps_id' => 'required|exists:kategori_tps,id_kategori_tps', 'kategori_tps_id' => 'required|exists:kategori_tps,id_kategori_tps',
'nama_tps' => 'required|string|max:255', 'nama_tps' => 'required|string|max:255',
'alamat_tps' => 'required|string|max:255', 'alamat_tps' => 'required|string|max:255',
@ -141,38 +186,53 @@ public function update(Request $request, $id)
'latitude' => 'required', 'latitude' => 'required',
'longitude' => 'required', 'longitude' => 'required',
'foto_tps' => 'nullable|image|mimes:jpg,jpeg,png|max:4096', 'foto_tps' => 'nullable|image|mimes:jpg,jpeg,png|max:4096',
]); ]);
if ($validator->fails()) return back()->withErrors($validator)->withInput();
if ($validator->fails()) {
return back()->withErrors($validator)->withInput();
}
$latitude = $this->convertToDecimal($request->latitude); $latitude = $this->convertToDecimal($request->latitude);
$longitude = $this->convertToDecimal($request->longitude); $longitude = $this->convertToDecimal($request->longitude);
if ($latitude === null || $latitude < -90 || $latitude > 90)
if ($latitude === null || $latitude < -90 || $latitude > 90) {
$validator->errors()->add('latitude', 'Latitude tidak valid.'); $validator->errors()->add('latitude', 'Latitude tidak valid.');
}
if ($longitude === null || $longitude < -180 || $longitude > 180) if ($longitude === null || $longitude < -180 || $longitude > 180) {
$validator->errors()->add('longitude', 'Longitude tidak valid.'); $validator->errors()->add('longitude', 'Longitude tidak valid.');
}
if ($validator->fails()) {
return back()->withErrors($validator)->withInput();
}
if ($validator->fails()) return back()->withErrors($validator)->withInput();
// Upload foto baru jika ada
$foto = $tps->foto_tps; $foto = $tps->foto_tps;
if ($request->hasFile('foto_tps')) { if ($request->hasFile('foto_tps')) {
if ($tps->foto_tps && file_exists(public_path($tps->foto_tps))) {
unlink(public_path($tps->foto_tps)); // hapus foto lama if ($tps->foto_tps && file_exists(public_path('assets/admin/images/tps/' . $tps->foto_tps))) {
unlink(public_path('assets/admin/images/tps/' . $tps->foto_tps));
} }
$file = $request->file('foto_tps'); $file = $request->file('foto_tps');
$namaTps = strtoupper(preg_replace('/[^A-Za-z0-9]/', '', $request->nama_tps));
$extension = $file->getClientOriginalExtension(); $filename = strtolower(str_replace(' ', '_', $request->nama_tps))
$filename = strtolower(str_replace(' ', '_', $request->nama_tps)) . '_' . time() . '.' . $file->getClientOriginalExtension(); . '_' . time() . '.' . $file->getClientOriginalExtension();
$file->move(public_path('assets/admin/images/tps'), $filename); $file->move(public_path('assets/admin/images/tps'), $filename);
$foto = $filename; $foto = $filename;
} }
$tps->update([ $tps->update([
'kategori_tps_id' => $request->kategori_tps_id, 'kategori_tps_id' => $request->kategori_tps_id,
'nama_tps' => $request->nama_tps, 'nama_tps' => $request->nama_tps,
'alamat_tps' => $request->alamat_tps, 'alamat_tps' => $request->alamat_tps,
@ -182,26 +242,33 @@ public function update(Request $request, $id)
'latitude' => $latitude, 'latitude' => $latitude,
'longitude' => $longitude, 'longitude' => $longitude,
'foto_tps' => $foto, 'foto_tps' => $foto,
]); ]);
return redirect()->route('admin.tps.index')->with('success', 'Data TPS berhasil diperbarui.');
return redirect()->route('admin.tps.index')
->with('success', 'Data TPS berhasil diperbarui.');
} }
public function destroy($id) public function destroy($id)
{ {
$tps = LokasiTps::findOrFail($id); $tps = LokasiTps::findOrFail($id);
// Path lengkap foto TPS $fotoPath = $tps->foto_tps
$fotoPath = $tps->foto_tps ? public_path('assets/admin/images/tps/' . $tps->foto_tps) : null; ? public_path('assets/admin/images/tps/' . $tps->foto_tps)
: null;
// Hapus file jika ada
if ($fotoPath && file_exists($fotoPath)) { if ($fotoPath && file_exists($fotoPath)) {
unlink($fotoPath); unlink($fotoPath);
} }
// Hapus data dari database
$tps->delete(); $tps->delete();
return redirect()->route('admin.tps.index') return redirect()->route('admin.tps.index')
->with('success', 'Data TPS berhasil dihapus.'); ->with('success', 'Data TPS berhasil dihapus.');
} }

View File

@ -5,6 +5,7 @@
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View; // wajib use Illuminate\Support\Facades\View; // wajib
use App\Models\KategoriTps; // wajib use App\Models\KategoriTps; // wajib
use Illuminate\Pagination\Paginator;
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
{ {
@ -21,6 +22,7 @@ public function register(): void
*/ */
public function boot(): void public function boot(): void
{ {
Paginator::useBootstrap();
View::composer('user.template', function ($view) { View::composer('user.template', function ($view) {
$view->with('kategoriTps', KategoriTps::all()); $view->with('kategoriTps', KategoriTps::all());
}); });

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 914 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 950 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

View File

@ -10,15 +10,30 @@
<div class="card-body"> <div class="card-body">
<div class="mb-3 d-flex justify-content-between align-items-center"> <div class="mb-3 d-flex justify-content-between align-items-center">
<div> <div>
<h4 class="mb-0 card-title">Data TPS</h4> <h4 class="mb-0 card-title">Data TPS</h4>
<p class="mb-0 card-description"> <p class="mb-0 card-description">
Daftar Tempat Pembuangan Sampah (TPS) Daftar Tempat Pembuangan Sampah (TPS)
</p> </p>
</div> </div>
<div class="mb-3 d-flex align-items-center">
<!-- SEARCH -->
<form action="{{ route('admin.tps.index') }}" method="GET"
style="width:300px; margin-right:20px;">
<input type="text" name="search" value="{{ request('search') }}"
class="form-control" placeholder="Cari nama TPS...">
</form>
<!-- BUTTON TAMBAH -->
<a href="{{ route('admin.tps.create') }}" class="btn btn-primary"> <a href="{{ route('admin.tps.create') }}" class="btn btn-primary">
<i class="bi bi-plus-lg"></i> Tambah <i class="bi bi-plus-lg"></i> Tambah
</a> </a>
</div>
</div> </div>
<div class="table-responsive"> <div class="table-responsive">
@ -29,29 +44,29 @@
<th>Kategori</th> <th>Kategori</th>
<th>Foto</th> <th>Foto</th>
<th>Status</th> <th>Status</th>
<th>Aksi</th> <th class="text-center">Aksi</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@forelse ($tps as $item) @forelse ($tps as $item)
<tr> <tr>
<td>{{ $item->nama_tps }}</td> <td>{{ $item->nama_tps }}</td>
<td> <td>
{{ $item->kategori->nama_kategori ?? '-' }} {{ $item->kategori->nama_kategori ?? '-' }}
</td> </td>
<td> <td>
@if ($item->foto_tps) @if ($item->foto_tps)
<img src="{{ asset('assets/admin/images/tps/' . $item->foto_tps) }}" <img src="{{ asset('assets/admin/images/tps/' . $item->foto_tps) }}"
alt="Foto TPS" alt="Foto TPS" style="width:200px;height:auto;border-radius:4px;">
style="
width:200px;
height:auto;
border-radius:2px;
">
@else @else
<span class="text-muted">-</span> <span class="text-muted">-</span>
@endif @endif
</td> </td>
<td> <td>
@if ($item->status_tps == 'Aktif') @if ($item->status_tps == 'Aktif')
<label class="badge badge-success">Aktif</label> <label class="badge badge-success">Aktif</label>
@ -61,21 +76,30 @@
<label class="badge badge-warning">Pembangunan</label> <label class="badge badge-warning">Pembangunan</label>
@endif @endif
</td> </td>
<td class="text-center"> <td class="text-center">
<!-- EDIT -->
<a href="{{ route('admin.tps.edit', $item->id_tps) }}" <a href="{{ route('admin.tps.edit', $item->id_tps) }}"
class="btn btn-warning btn-sm me-1"> class="btn btn-warning btn-sm me-1">
<i class="bi bi-pencil-square"></i> <i class="bi bi-pencil-square"></i>
</a> </a>
<!-- DELETE -->
<form action="{{ route('admin.tps.destroy', $item->id_tps) }}" <form action="{{ route('admin.tps.destroy', $item->id_tps) }}"
method="POST" class="form-hapus" style="display:inline;"> method="POST" class="form-hapus" style="display:inline;">
@csrf @csrf
@method('DELETE') @method('DELETE')
<button type="submit" class="btn btn-danger btn-sm"> <button type="submit" class="btn btn-danger btn-sm">
<i class="bi bi-trash"></i> <i class="bi bi-trash"></i>
</button> </button>
</form> </form>
</td> </td>
</tr> </tr>
@empty @empty
<tr> <tr>
<td colspan="5" class="text-center"> <td colspan="5" class="text-center">
@ -83,19 +107,27 @@ class="btn btn-warning btn-sm me-1">
</td> </td>
</tr> </tr>
@endforelse @endforelse
</tbody> </tbody>
</table> </table>
</div> </div>
<!-- PAGINATION -->
<div class="mt-3">
{{ $tps->appends(request()->query())->links() }}
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script> <script>
document.querySelectorAll('.form-hapus').forEach(form => { document.querySelectorAll('.form-hapus').forEach(form => {
form.addEventListener('submit', function(e) { form.addEventListener('submit', function(e) {
e.preventDefault(); e.preventDefault();
Swal.fire({ Swal.fire({
@ -111,11 +143,15 @@ class="btn btn-warning btn-sm me-1">
document.querySelector('.swal2-popup').style.fontFamily = document.querySelector('.swal2-popup').style.fontFamily =
'Nunito, sans-serif'; 'Nunito, sans-serif';
} }
}).then((result) => { }).then((result) => {
if (result.isConfirmed) { if (result.isConfirmed) {
form.submit(); form.submit();
} }
}); });
}); });
}); });
</script> </script>
@ -132,4 +168,5 @@ class="btn btn-warning btn-sm me-1">
}); });
</script> </script>
@endif @endif
@endsection @endsection