validasi kelola tps

This commit is contained in:
rahmagustin 2026-02-17 21:18:50 +07:00
parent 83ffa58000
commit 7100ed2342
12 changed files with 931 additions and 782 deletions

View File

@ -4,20 +4,22 @@
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\LokasiTps;
use App\Models\AduanTps;
use App\Models\Sampah;
class DashboardController extends Controller
{
public function index()
{
$totalTps = \App\Models\LokasiTps::count();
$totalAduan = \App\Models\AduanTps::count();
$sampahTerbaru = \App\Models\Sampah::orderBy('created_at', 'desc')->first();
return view('admin.index', compact(
'totalTps',
'totalAduan',
'sampahTerbaru'
));
}
{
$totalTps = LokasiTps::count();
$totalAduan = AduanTps::count();
$sampahTerbaru = Sampah::orderBy('created_at', 'desc')->first();
return view('admin.index', compact(
'totalTps',
'totalAduan',
'sampahTerbaru'
));
}
}

View File

@ -10,140 +10,241 @@
class TpsController extends Controller
{
public function index()
{
$title = 'Data TPS';
$tps = LokasiTps::with('kategori')
->withCount('aduan')
->get();
return view('admin.tps.index', compact('title', 'tps'));
}
public function index()
{
$title = 'Data TPS';
$tps = LokasiTps::with('kategori')
->withCount('aduan')
->get();
public function create()
{
$title = 'Tambah TPS';
$kategori = KategoriTps::all();
return view('admin.tps.create', compact('title', 'kategori'));
}
private function convertToDecimal($coordinate)
{
if (is_numeric($coordinate)) {
return (float) $coordinate;
}
$coordinate = html_entity_decode($coordinate);
$coordinate = strtoupper(trim($coordinate));
$coordinate = str_replace(
['°', "'", '"'],
[' ', ' ', ' '],
$coordinate
);
preg_match('/([NSEW])/', $coordinate, $dirMatch);
if (!$dirMatch) return null;
$direction = $dirMatch[1];
preg_match_all('/\d+(\.\d+)?/', $coordinate, $numbers);
if (count($numbers[0]) < 3) return null;
[$deg, $min, $sec] = array_map('floatval', $numbers[0]);
$decimal = $deg + ($min / 60) + ($sec / 3600);
if (in_array($direction, ['S', 'W'])) {
$decimal *= -1;
return view('admin.tps.index', compact('title', 'tps'));
}
return $decimal;
}
public function store(Request $request)
{
$request->validate([
'kategori_tps_id' => 'required|exists:kategori_tps,id_kategori_tps',
'nama_tps' => 'required|string|max:255',
'alamat_tps' => 'required|string|max:255',
'status_tps' => 'required',
'tahun_pembuatan' => 'required|numeric',
'kapasitas_tps' => 'required',
'latitude' => 'required',
'longitude' => 'required',
'foto_tps' => 'nullable|image|mimes:jpg,jpeg,png|max:2048',
]);
$latitude = $this->convertToDecimal($request->latitude);
$longitude = $this->convertToDecimal($request->longitude);
if ($latitude === null || $longitude === null) {
return back()->withErrors(['Koordinat tidak valid'])->withInput();
}
$foto = $request->hasFile('foto_tps')
? $request->file('foto_tps')->store('foto-tps', 'public')
: null;
LokasiTps::create([
'kategori_tps_id' => $request->kategori_tps_id,
'nama_tps' => $request->nama_tps,
'alamat_tps' => $request->alamat_tps,
'status_tps' => $request->status_tps,
'tahun_pembuatan' => $request->tahun_pembuatan,
'kapasitas_tps' => $request->kapasitas_tps,
'latitude' => $latitude,
'longitude' => $longitude,
'foto_tps' => $foto,
]);
return redirect()->route('admin.tps.index')
->with('success', 'Data TPS berhasil ditambahkan');
}
public function edit($id)
{
$title = 'Edit TPS';
$tps = LokasiTps::findOrFail($id);
$kategori = KategoriTps::all();
return view('admin.tps.edit', compact('title', 'tps', 'kategori'));
}
public function update(Request $request, $id)
{
$tps = LokasiTps::findOrFail($id);
$request->validate([
'kategori_tps_id' => 'required|exists:kategori_tps,id_kategori_tps',
'nama_tps' => 'required|string|max:255',
'alamat_tps' => 'required|string|max:255',
'status_tps' => 'required',
'tahun_pembuatan' => 'required|numeric',
'kapasitas_tps' => 'required',
'latitude' => 'required',
'longitude' => 'required',
'foto_tps' => 'nullable|image|mimes:jpg,jpeg,png|max:4096',
]);
$latitude = $this->convertToDecimal($request->latitude);
$longitude = $this->convertToDecimal($request->longitude);
if ($latitude === null || $longitude === null) {
return back()
->withErrors(['Koordinat tidak valid. Gunakan format Decimal atau DMS.'])
->withInput();
public function create()
{
$title = 'Tambah TPS';
$kategori = KategoriTps::all();
return view('admin.tps.create', compact('title', 'kategori'));
}
if ($request->hasFile('foto_tps')) {
if ($tps->foto_tps) {
Storage::disk('public')->delete($tps->foto_tps);
}
$foto = $request->file('foto_tps')->store('foto-tps', 'public');
} else {
$foto = $tps->foto_tps;
}
$tps->update([
'kategori_tps_id' => $request->kategori_tps_id,
'nama_tps' => $request->nama_tps,
'alamat_tps' => $request->alamat_tps,
'status_tps' => $request->status_tps,
'tahun_pembuatan' => $request->tahun_pembuatan,
'kapasitas_tps' => $request->kapasitas_tps,
'latitude' => $latitude,
'longitude' => $longitude,
'foto_tps' => $foto,
]);
return redirect()->route('admin.tps.index')
->with('success', 'Data TPS berhasil diperbarui');
}
public function destroy($id)
{
$tps = LokasiTps::findOrFail($id);
if ($tps->foto_tps) {
Storage::disk('public')->delete($tps->foto_tps);
}
$tps->delete();
return redirect()->route('admin.tps.index')
->with('success', 'Data TPS berhasil dihapus');
}
/*
|--------------------------------------------------------------------------
| KONVERSI KOORDINAT (DECIMAL / DMS)
|--------------------------------------------------------------------------
*/
private function convertToDecimal($coordinate)
{
if (is_numeric($coordinate)) {
return (float) $coordinate;
}
$coordinate = html_entity_decode($coordinate);
$coordinate = strtoupper(trim($coordinate));
$coordinate = str_replace(['°', "'", '"'], [' ', ' ', ' '], $coordinate);
preg_match('/([NSEW])/', $coordinate, $dir);
if (!$dir) {
return null;
}
preg_match_all('/\d+(\.\d+)?/', $coordinate, $numbers);
if (count($numbers[0]) < 3) {
return null;
}
[$deg, $min, $sec] = array_map('floatval', $numbers[0]);
$decimal = $deg + ($min / 60) + ($sec / 3600);
if (in_array($dir[1], ['S', 'W'])) {
$decimal *= -1;
}
return $decimal;
}
/*
|--------------------------------------------------------------------------
| STORE (CREATE)
|--------------------------------------------------------------------------
*/
public function store(Request $request)
{
// VALIDASI DASAR + PESAN CUSTOM
$request->validate(
[
'kategori_tps_id' => 'required|exists:kategori_tps,id_kategori_tps',
'nama_tps' => 'required|string|max:255',
'alamat_tps' => 'required|string|max:255',
'status_tps' => 'required|in:Aktif,Tidak Aktif,Pembangunan',
'tahun_pembuatan' => 'required|digits:4',
'kapasitas_tps' => 'required|integer|min:1',
'latitude' => 'required',
'longitude' => 'required',
'foto_tps' => 'nullable|image|mimes:jpg,jpeg,png|max:2048',
],
[
'kategori_tps_id.required' => 'Kategori TPS wajib dipilih.',
'kategori_tps_id.exists' => 'Kategori TPS tidak valid.',
'nama_tps.required' => 'Nama TPS wajib diisi.',
'alamat_tps.required' => 'Alamat TPS wajib diisi.',
'status_tps.required' => 'Status TPS wajib dipilih.',
'status_tps.in' => 'Status TPS tidak valid.',
'tahun_pembuatan.required' => 'Tahun pembuatan wajib diisi.',
'tahun_pembuatan.digits' => 'Tahun pembuatan harus 4 digit (contoh: 2022).',
'kapasitas_tps.required' => 'Kapasitas TPS wajib diisi.',
'kapasitas_tps.integer' => 'Kapasitas TPS harus berupa angka.',
'kapasitas_tps.min' => 'Kapasitas TPS minimal 1.',
'latitude.required' => 'Latitude wajib diisi.',
'longitude.required' => 'Longitude wajib diisi.',
'foto_tps.image' => 'Foto TPS harus berupa gambar.',
'foto_tps.mimes' => 'Format foto TPS harus jpg, jpeg, atau png.',
]
);
// VALIDASI KOORDINAT (TIDAK DOBEL ERROR)
$latitude = $this->convertToDecimal($request->latitude);
$longitude = $this->convertToDecimal($request->longitude);
$errors = [];
if ($latitude === null || $latitude < -90 || $latitude > 90) {
$errors['latitude'] = 'Latitude tidak valid. Contoh: -7.623 atau 7.623';
}
if ($longitude === null || $longitude < -180 || $longitude > 180) {
$errors['longitude'] = 'Longitude tidak valid. Contoh: 111.980 atau -111.980';
}
if (!empty($errors)) {
return back()->withErrors($errors)->withInput();
}
// UPLOAD FOTO
$foto = $request->hasFile('foto_tps')
? $request->file('foto_tps')->store('foto-tps', 'public')
: null;
LokasiTps::create([
'kategori_tps_id' => $request->kategori_tps_id,
'nama_tps' => $request->nama_tps,
'alamat_tps' => $request->alamat_tps,
'status_tps' => $request->status_tps,
'tahun_pembuatan' => $request->tahun_pembuatan,
'kapasitas_tps' => $request->kapasitas_tps,
'latitude' => $latitude,
'longitude' => $longitude,
'foto_tps' => $foto,
]);
return redirect()->route('admin.tps.index')
->with('success', 'Data TPS berhasil ditambahkan.');
}
/*
|--------------------------------------------------------------------------
| EDIT
|--------------------------------------------------------------------------
*/
public function edit($id)
{
$title = 'Edit TPS';
$tps = LokasiTps::findOrFail($id);
$kategori = KategoriTps::all();
return view('admin.tps.edit', compact('title', 'tps', 'kategori'));
}
/*
|--------------------------------------------------------------------------
| UPDATE
|--------------------------------------------------------------------------
*/
public function update(Request $request, $id)
{
$tps = LokasiTps::findOrFail($id);
$request->validate(
[
'kategori_tps_id' => 'required|exists:kategori_tps,id_kategori_tps',
'nama_tps' => 'required|string|max:255',
'alamat_tps' => 'required|string|max:255',
'status_tps' => 'required|in:Aktif,Tidak Aktif,Pembangunan',
'tahun_pembuatan' => 'required|digits:4',
'kapasitas_tps' => 'required|integer|min:1',
'latitude' => 'required',
'longitude' => 'required',
'foto_tps' => 'nullable|image|mimes:jpg,jpeg,png|max:4096',
],
[
'tahun_pembuatan.digits' => 'Tahun pembuatan harus 4 digit.',
]
);
$latitude = $this->convertToDecimal($request->latitude);
$longitude = $this->convertToDecimal($request->longitude);
$errors = [];
if ($latitude === null || $latitude < -90 || $latitude > 90) {
$errors['latitude'] = 'Latitude tidak valid.';
}
if ($longitude === null || $longitude < -180 || $longitude > 180) {
$errors['longitude'] = 'Longitude tidak valid.';
}
if (!empty($errors)) {
return back()->withErrors($errors)->withInput();
}
if ($request->hasFile('foto_tps')) {
if ($tps->foto_tps) {
Storage::disk('public')->delete($tps->foto_tps);
}
$foto = $request->file('foto_tps')->store('foto-tps', 'public');
} else {
$foto = $tps->foto_tps;
}
$tps->update([
'kategori_tps_id' => $request->kategori_tps_id,
'nama_tps' => $request->nama_tps,
'alamat_tps' => $request->alamat_tps,
'status_tps' => $request->status_tps,
'tahun_pembuatan' => $request->tahun_pembuatan,
'kapasitas_tps' => $request->kapasitas_tps,
'latitude' => $latitude,
'longitude' => $longitude,
'foto_tps' => $foto,
]);
return redirect()->route('admin.tps.index')
->with('success', 'Data TPS berhasil diperbarui.');
}
/*
|--------------------------------------------------------------------------
| DELETE
|--------------------------------------------------------------------------
*/
public function destroy($id)
{
$tps = LokasiTps::findOrFail($id);
if ($tps->foto_tps) {
Storage::disk('public')->delete($tps->foto_tps);
}
$tps->delete();
return redirect()->route('admin.tps.index')
->with('success', 'Data TPS berhasil dihapus.');
}
}

View File

@ -33,6 +33,6 @@ public function destroy(Request $request): RedirectResponse
$request->session()->regenerateToken();
return redirect('/index');
return redirect('/');
}
}

View File

@ -14,7 +14,10 @@ public function index()
$sampah = Sampah::orderBy('tahun', 'desc')->first();
$kategoriTps = KategoriTps::orderBy('id_kategori_tps')->get();
$lokasiTps = LokasiTps::all();
$jumlahTps = LokasiTps::where('kategori_tps_id', '3')->count();
$jumlahTps3r = LokasiTps::where('kategori_tps_id', '5')->count();
$jumlahTpa = LokasiTps::where('kategori_tps_id', '6')->count();
return view('user.index', compact('sampah', 'kategoriTps', 'lokasiTps'));
return view('user.index', compact('sampah', 'kategoriTps', 'lokasiTps', 'jumlahTps', 'jumlahTps3r', 'jumlahTpa'));
}
}

View File

@ -3068,3 +3068,120 @@ .btn-lokasi:focus:hover {
color: var(--contrast-color);
background: color-mix(in srgb, var(--accent-color), transparent 15%);
}
/* ================================
GEO STAT SECTION FINAL VERSION
================================ */
.geo-stat-section {
position: relative;
padding: 50px 0;
background: #ffffff;
color: #2f2f2f;
overflow: hidden;
}
/* Badge kecil */
.geo-badge {
font-size: 13px;
letter-spacing: 1px;
color: var(--heading-color);
text-transform: uppercase;
}
/* Judul utama */
.geo-title {
font-size: 38px;
font-weight: 700;
line-height: 1.3;
margin: 12px 0;
color: var(--accent-color)
}
/* Deskripsi */
.geo-desc {
font-size: 15px;
color: #6b7280;
max-width: 420px;
line-height: 1.6;
}
/* ================================
STATISTIK AREA
================================ */
.geo-stats {
display: flex;
align-items: center;
justify-content: space-between;
}
.geo-item {
text-align: center;
flex: 1;
}
/* Icon box */
.geo-icon {
width: 64px;
height: 64px;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
margin: 0 auto 14px;
background: rgba(11, 93, 59, 0.08);
color: #0b5d3b;
}
/* Variasi icon */
.geo-icon.recycle {
background: rgba(32, 201, 151, 0.18);
color: #20c997;
}
.geo-icon.location {
background: rgba(255, 193, 7, 0.18);
color: #f59f00;
}
/* Angka statistik */
.geo-item h3 {
font-size: 46px;
font-weight: 800;
color: var(--heading-color);
margin: 0;
}
/* Label bawah angka */
.geo-item span {
font-size: 14px;
letter-spacing: .6px;
color: #6b7280;
}
/* Garis pemisah */
.geo-line {
width: 2px;
height: 110px;
background: rgba(0, 0, 0, 0.15);
}
/* ================================
RESPONSIVE (AMAN MOBILE)
================================ */
@media (max-width: 768px) {
.geo-stats {
flex-direction: column;
gap: 32px;
}
.geo-line {
display: none;
}
.geo-title {
font-size: 30px;
}
}

View File

@ -24,7 +24,6 @@
<tr>
<th>TPS</th>
<th>Nama Pelapor</th>
{{-- <th>Alamat Pelapor</th> --}}
<th>Tanggal Aduan</th>
<th>Status</th>
<th class="text-center">Aksi</th>
@ -33,7 +32,6 @@
<tbody>
@forelse ($aduan as $item)
<tr>
<!-- TPS -->
<td>
<strong>
{{ $item->lokasiTps->nama_tps ?? '-' }}
@ -43,19 +41,10 @@
{{ $item->lokasiTps->alamat_tps ?? '' }}
</small>
</td>
<!-- Pelapor -->
<td>{{ $item->nama_pelapor }}</td>
<!-- Alamat -->
{{-- <td>{{ $item->alamat_pelapor }}</td> --}}
<!-- Tanggal -->
<td>
{{ \Carbon\Carbon::parse($item->tanggal_aduan)->format('d M Y') }}
</td>
<!-- Status -->
<td>
@if ($item->tanggapan_admin)
<span class="badge badge-success">Ditanggapi</span>
@ -63,8 +52,6 @@
<span class="badge badge-danger">Belum</span>
@endif
</td>
<!-- Aksi -->
<td class="text-center">
<a href="{{ route('admin.aduan.show', $item->id_aduan) }}"
class="btn btn-warning btn-sm"

View File

@ -1,63 +1,106 @@
@extends('admin.template')
@section('content')
<div class="content-wrapper">
<div class="row">
<div class="col-md-12 grid-margin stretch-card">
<div class="card">
<div class="card-body">
<h4 class="card-title">Profil Admin</h4>
<div class="content-wrapper">
<div class="row justify-content-center">
<div class="col-md-12 grid-margin stretch-card">
<div class="card">
<div class="card-body">
@if (session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
<h4 class="mb-4 card-title">Profil Admin</h4>
<form action="{{ route('admin.profil.update') }}" method="POST">
@csrf
@if (session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
<form action="{{ route('admin.profil.update') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="row">
<!-- KIRI : FOTO -->
<div class="text-center col-md-4 border-right">
<img
src="{{ $admin->foto
? asset('storage/foto-admin/' . $admin->foto)
: asset('assets/admin/images/user.jpg') }}"
class="mb-3 rounded-circle"
width="160"
height="160"
style="object-fit: cover;"
>
<div class="form-group">
<input type="file" name="foto" class="form-control-file">
<small class="mt-2 text-muted d-block">
JPG / PNG, maksimal 2MB
</small>
</div>
<div class="form-group">
<label>Nama</label>
<input type="text" name="name" class="form-control" value="{{ $admin->name }}"
required>
</div>
<div class="form-group">
<label>Username</label>
<input type="text" name="username" class="form-control" value="{{ $admin->username }}"
required>
<!-- KANAN : FORM -->
<div class="col-md-8">
<div class="form-group">
<label>Nama</label>
<input type="text" name="name"
class="form-control"
value="{{ $admin->name }}" required>
</div>
<div class="form-group">
<label>Username</label>
<input type="text" name="username"
class="form-control"
value="{{ $admin->username }}" required>
</div>
<div class="form-group">
<label>Role</label>
<input type="text"
class="form-control"
value="{{ $admin->role }}" disabled>
</div>
<hr>
<div class="form-group">
<label>Password Baru (opsional)</label>
<input type="password"
name="password"
class="form-control"
placeholder="Kosongkan jika tidak diganti">
</div>
<div class="form-group">
<label>Konfirmasi Password</label>
<input type="password"
name="password_confirmation"
class="form-control">
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary">
Simpan
</button>
<a href="{{ url()->previous() }}"
class="ml-2 btn btn-light">
Batal
</a>
</div>
</div>
</div>
</form>
<div class="form-group">
<label>Role</label>
<input type="text" class="form-control" value="{{ $admin->role }}" disabled>
</div>
<hr>
<div class="form-group">
<label>Password Baru (opsional)</label>
<input type="password" name="password" class="form-control"
placeholder="Kosongkan jika tidak diganti">
</div>
<div class="form-group">
<label>Konfirmasi Password</label>
<input type="password" name="password_confirmation" class="form-control">
</div>
<button type="submit" class="btn btn-primary">
Simpan
</button>
<a href="{{ url()->previous() }}" class="btn btn-light ml-2">
Batal
</a>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@ -1,119 +1,141 @@
@extends('admin.template')
@section('content')
<div class="content-wrapper">
<div class="row">
<div class="col-12 grid-margin stretch-card">
<div class="card">
<div class="card-body">
<h4 class="card-title">Tambah Data TPS</h4>
<p class="card-description">Form tambah data TPS</p>
<div class="content-wrapper">
<div class="row">
<div class="col-12 grid-margin stretch-card">
<div class="card">
<div class="card-body">
<h4 class="card-title">Tambah Data TPS</h4>
<p class="card-description">Form tambah data TPS</p>
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('admin.tps.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<!-- NAMA TPS -->
<div class="form-group">
<label>Nama TPS</label>
<input type="text" name="nama_tps" class="form-control"
value="{{ old('nama_tps') }}"
placeholder="Nama TPS">
@error('nama_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
<form action="{{ route('admin.tps.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<!-- ALAMAT -->
<div class="form-group">
<label>Alamat</label>
<input type="text" name="alamat_tps" class="form-control"
value="{{ old('alamat_tps') }}"
placeholder="Alamat TPS">
@error('alamat_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
<!-- NAMA TPS -->
<div class="form-group">
<label>Nama TPS</label>
<input type="text" name="nama_tps" class="form-control" placeholder="Nama TPS" required>
<!-- KATEGORI -->
<div class="form-group">
<label>Kategori TPS</label>
<select name="kategori_tps_id" class="form-control">
<option value="">Pilih Kategori</option>
@foreach ($kategori as $item)
<option value="{{ $item->id_kategori_tps }}"
{{ old('kategori_tps_id') == $item->id_kategori_tps ? 'selected' : '' }}>
{{ $item->nama_kategori }}
</option>
@endforeach
</select>
@error('kategori_tps_id')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
<!-- TAHUN -->
<div class="form-group">
<label>Tahun Pembuatan</label>
<input type="number" name="tahun_pembuatan" class="form-control"
value="{{ old('tahun_pembuatan') }}"
placeholder="Contoh: 2022">
@error('tahun_pembuatan')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
<!-- KAPASITAS -->
<div class="form-group">
<label>Kapasitas</label>
<input type="text" name="kapasitas_tps" class="form-control"
value="{{ old('kapasitas_tps') }}"
placeholder="Kapasitas TPS">
@error('kapasitas_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
<!-- STATUS -->
<div class="form-group">
<label>Status</label>
<select name="status_tps" class="form-control">
<option value="Aktif" {{ old('status_tps') == 'Aktif' ? 'selected' : '' }}>Aktif</option>
<option value="Tidak Aktif" {{ old('status_tps') == 'Tidak Aktif' ? 'selected' : '' }}>Tidak Aktif</option>
<option value="Pembangunan" {{ old('status_tps') == 'Pembangunan' ? 'selected' : '' }}>Pembangunan</option>
</select>
@error('status_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
<!-- LATITUDE -->
<div class="form-group">
<label>Latitude</label>
<input type="text" name="latitude" class="form-control"
value="{{ old('latitude') }}"
placeholder="Contoh: -7.623 atau 7°35'17.25&quot;S">
@error('latitude')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
<!-- LONGITUDE -->
<div class="form-group">
<label>Longitude</label>
<input type="text" name="longitude" class="form-control"
value="{{ old('longitude') }}"
placeholder="Contoh: 111.980 atau 111°55'0.97&quot;E">
@error('longitude')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
<!-- FOTO -->
<div class="form-group">
<label>Foto TPS</label>
<input type="file" name="foto_tps" id="foto_tps" class="file-upload-default">
<div class="input-group col-xs-12">
<input type="text" class="form-control file-upload-info" disabled
placeholder="Upload Foto">
<span class="input-group-append">
<button class="file-upload-browse btn btn-primary" type="button">
Upload
</button>
</span>
</div>
<div class="form-group">
<label>Alamat</label>
<input type="text" name="alamat_tps" class="form-control" placeholder="Alamat TPS"
required>
</div>
@error('foto_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
<div class="form-group">
<label>Kecamatan</label>
<input type="text" name="kecamatan" class="form-control" placeholder="Kecamatan TPS"
required>
</div>
<button type="submit" class="mr-2 btn btn-primary">Simpan</button>
<a href="{{ route('admin.tps.index') }}" class="btn btn-light">Batal</a>
</form>
<!-- KATEGORI TPS -->
<div class="form-group">
<label>Kategori TPS</label>
<select name="kategori_tps_id" class="form-control" required>
<option value="">Pilih Kategori</option>
@foreach ($kategori as $item)
<option value="{{ $item->id_kategori_tps }}">
{{ $item->nama_kategori }}
</option>
@endforeach
</select>
</div>
<!-- TAHUN -->
<div class="form-group">
<label>Tahun Pembuatan</label>
<input type="number" name="tahun_pembuatan" class="form-control"
placeholder="Tahun Pembuatan" required>
</div>
<!-- KAPASITAS -->
<div class="form-group">
<label>Kapasitas</label>
<input type="text" name="kapasitas_tps" class="form-control" placeholder="Kapasitas TPS"
required>
</div>
<!-- STATUS -->
<div class="form-group">
<label>Status</label>
<select name="status_tps" class="form-control" required>
<option value="Aktif">Aktif</option>
<option value="Non-Aktif">Tidak Aktif</option>
<option value="Pembangunan">Pembangunan</option>
</select>
</div>
<div class="form-group">
<label>Latitude</label>
<input type="text" name="latitude" class="form-control"
placeholder="Contoh: 7°35'17.25&quot;S" required>
</div>
<div class="form-group">
<label>Longitude</label>
<input type="text" name="longitude" class="form-control"
placeholder="Contoh: 111°55'0.97&quot;E" required>
</div>
<!-- FOTO -->
<div class="form-group">
<label>Foto TPS</label>
<input type="file" name="foto_tps" id="foto_tps" class="file-upload-default">
<div class="input-group col-xs-12">
<input type="text" class="form-control file-upload-info" disabled
placeholder="Upload Foto">
<span class="input-group-append">
<button class="file-upload-browse btn btn-primary" type="button">
Upload
</button>
</span>
</div>
</div>
<button type="submit" class="mr-2 btn btn-primary">Simpan</button>
<a href="{{ route('admin.tps.index') }}" class="btn btn-light">Batal</a>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@ -1,11 +1,11 @@
@php
function decimalToDms($decimal, $type = 'lat')
{
if ($decimal === null || $decimal === '') return '';
if ($decimal === null || $decimal === '') {
return '';
}
$direction = $decimal >= 0
? ($type === 'lat' ? 'N' : 'E')
: ($type === 'lat' ? 'S' : 'W');
$direction = $decimal >= 0 ? ($type === 'lat' ? 'N' : 'E') : ($type === 'lat' ? 'S' : 'W');
$decimal = abs($decimal);
@ -21,140 +21,172 @@ function decimalToDms($decimal, $type = 'lat')
@extends('admin.template')
@section('content')
<div class="content-wrapper">
<div class="row">
<div class="col-12 grid-margin stretch-card">
<div class="card">
<div class="card-body">
<h4 class="card-title">Edit Data TPS</h4>
<p class="card-description">
Form edit data Tempat Pembuangan Sampah
</p>
<div class="content-wrapper">
<div class="row">
<div class="col-12 grid-margin stretch-card">
<div class="card">
<div class="card-body">
<h4 class="card-title">Edit Data TPS</h4>
<p class="card-description">
Form edit data Tempat Pembuangan Sampah
</p>
<form action="{{ route('admin.tps.update', $tps->id_tps) }}"
method="POST"
enctype="multipart/form-data"
class="forms-sample">
@csrf
@method('PUT')
<form action="{{ route('admin.tps.update', $tps->id_tps) }}" method="POST"
enctype="multipart/form-data" class="forms-sample">
@csrf
@method('PUT')
{{-- Nama TPS --}}
<div class="form-group">
<label>Nama TPS</label>
<input type="text" name="nama_tps" class="form-control"
value="{{ old('nama_tps', $tps->nama_tps) }}" required>
</div>
{{-- Alamat --}}
<div class="form-group">
<label>Alamat</label>
<input type="text" name="alamat_tps" class="form-control"
value="{{ old('alamat_tps', $tps->alamat_tps) }}" required>
</div>
<div class="form-group">
<label>Kecamatan</label>
<input type="text" name="kecamatan" class="form-control"
value="{{ old('kecamatan', $tps->kecamatan) }}" required>
</div>
{{-- Kategori TPS --}}
<div class="form-group">
<label>Kategori TPS</label>
<select name="kategori_tps_id" class="form-control" required>
<option value="">-- Pilih Kategori --</option>
@foreach ($kategori as $item)
<option value="{{ $item->id_kategori_tps }}"
{{ old('kategori_tps_id', $tps->kategori_tps_id) == $item->id_kategori_tps ? 'selected' : '' }}>
{{ $item->nama_kategori }}
</option>
@endforeach
</select>
</div>
{{-- Tahun Pembuatan --}}
<div class="form-group">
<label>Tahun Pembuatan</label>
<input type="number" name="tahun_pembuatan" class="form-control"
value="{{ old('tahun_pembuatan', $tps->tahun_pembuatan) }}" required>
</div>
{{-- Kapasitas TPS --}}
<div class="form-group">
<label>Kapasitas TPS</label>
<input type="text" name="kapasitas_tps" class="form-control"
value="{{ old('kapasitas_tps', $tps->kapasitas_tps) }}" required>
</div>
{{-- Status TPS --}}
<div class="form-group">
<label>Status TPS</label>
<select name="status_tps" class="form-control" required>
<option value="Aktif" {{ old('status_tps', $tps->status_tps) == 'Aktif' ? 'selected' : '' }}>
Aktif
</option>
<option value="Tidak Aktif" {{ old('status_tps', $tps->status_tps) == 'Tidak Aktif' ? 'selected' : '' }}>
Tidak Aktif
</option>
<option value="Pembangunan" {{ old('status_tps', $tps->status_tps) == 'Pembangunan' ? 'selected' : '' }}>
Pembangunan
</option>
</select>
</div>
{{-- Latitude (DMS) --}}
<div class="form-group">
<label>Latitude</label>
<input type="text" name="latitude" class="form-control"
placeholder="Contoh: 7°35'17.25&quot;S"
value="{{ old('latitude', decimalToDms($tps->latitude, 'lat')) }}" required>
</div>
{{-- Longitude (DMS) --}}
<div class="form-group">
<label>Longitude</label>
<input type="text" name="longitude" class="form-control"
placeholder="Contoh: 111°55'0.97&quot;E"
value="{{ old('longitude', decimalToDms($tps->longitude, 'lng')) }}" required>
</div>
{{-- Foto TPS --}}
<div class="form-group">
<label>Foto TPS</label>
<input type="file" name="foto_tps" class="file-upload-default">
<div class="input-group col-xs-12">
<input type="text" class="form-control file-upload-info" disabled
placeholder="Upload Foto TPS">
<span class="input-group-append">
<button class="file-upload-browse btn btn-primary" type="button">
Upload
</button>
</span>
{{-- Nama TPS --}}
<div class="form-group">
<label>Nama TPS</label>
<input type="text" name="nama_tps" class="form-control"
value="{{ old('nama_tps') ?? $tps->nama_tps }}" required>
@error('nama_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
{{-- Foto Lama --}}
@if ($tps->foto_tps)
<div class="mt-2">
<img src="{{ asset('storage/' . $tps->foto_tps) }}"
width="250"
class="img-thumbnail">
{{-- Alamat --}}
<div class="form-group">
<label>Alamat</label>
<input type="text" name="alamat_tps" class="form-control"
value="{{ old('alamat_tps') ?? $tps->alamat_tps }}" required>
@error('alamat_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
{{-- Kategori TPS --}}
<div class="form-group">
<label>Kategori TPS</label>
<select name="kategori_tps_id" class="form-control" required>
<option value="">-- Pilih Kategori --</option>
@foreach ($kategori as $item)
<option value="{{ $item->id_kategori_tps }}"
{{ (old('kategori_tps_id') ?? $tps->kategori_tps_id) == $item->id_kategori_tps ? 'selected' : '' }}>
{{ $item->nama_kategori }}
</option>
@endforeach
</select>
@error('kategori_tps_id')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
{{-- Tahun Pembuatan --}}
<div class="form-group">
<label>Tahun Pembuatan</label>
<input type="number" name="tahun_pembuatan" class="form-control"
value="{{ old('tahun_pembuatan') ?? $tps->tahun_pembuatan }}" required>
@error('tahun_pembuatan')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
{{-- Kapasitas TPS --}}
<div class="form-group">
<label>Kapasitas TPS</label>
<input type="number" name="kapasitas_tps" class="form-control"
value="{{ old('kapasitas_tps') ?? $tps->kapasitas_tps }}" required>
@error('kapasitas_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
{{-- Status TPS --}}
<div class="form-group">
<label>Status TPS</label>
<select name="status_tps" class="form-control" required>
<option value="Aktif"
{{ (old('status_tps') ?? $tps->status_tps) == 'Aktif' ? 'selected' : '' }}>Aktif
</option>
<option value="Tidak Aktif"
{{ (old('status_tps') ?? $tps->status_tps) == 'Tidak Aktif' ? 'selected' : '' }}>
Tidak Aktif</option>
<option value="Pembangunan"
{{ (old('status_tps') ?? $tps->status_tps) == 'Pembangunan' ? 'selected' : '' }}>
Pembangunan</option>
</select>
@error('status_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
{{-- Latitude --}}
<div class="form-group">
<label>Latitude</label>
<input type="text" name="latitude" class="form-control" placeholder="Contoh: 7°35'17.25S"
value="{{ old('latitude') ?? decimalToDms($tps->latitude, 'lat') }}" required>
@error('latitude')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
{{-- Longitude --}}
<div class="form-group">
<label>Longitude</label>
<input type="text" name="longitude" class="form-control"
placeholder="Contoh: 111°55'0.97E"
value="{{ old('longitude') ?? decimalToDms($tps->longitude, 'lng') }}" required>
@error('longitude')
<small class="text-danger">{{ $message }}</small>
@enderror
</div>
{{-- Foto TPS --}}
<div class="form-group">
<label>Foto TPS</label>
<input type="file" name="foto_tps" id="foto_tps" class="file-upload-default">
<div class="input-group col-xs-12">
<input type="text" class="form-control file-upload-info" disabled
placeholder="Upload Foto TPS">
<span class="input-group-append">
<button class="file-upload-browse btn btn-primary" type="button">
Upload
</button>
</span>
</div>
@endif
</div>
{{-- Button --}}
<button type="submit" class="mr-2 btn btn-primary">
Simpan
</button>
<a href="{{ route('admin.tps.index') }}" class="btn btn-light">
Batal
</a>
@error('foto_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</form>
@if ($tps->foto_tps)
<div class="mt-2">
<img src="{{ asset('storage/' . $tps->foto_tps) }}" width="250"
class="img-thumbnail">
</div>
@endif
</div>
{{-- Button --}}
<button type="submit" class="mr-2 btn btn-primary">Simpan</button>
<a href="{{ route('admin.tps.index') }}" class="btn btn-light">Batal</a>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
document.querySelectorAll('.file-upload-browse').forEach(function(button) {
button.addEventListener('click', function() {
this.closest('.form-group')
.querySelector('.file-upload-default')
.click();
});
});
document.querySelectorAll('.file-upload-default').forEach(function(input) {
input.addEventListener('change', function() {
const fileName = this.files[0]?.name || '';
this.closest('.form-group')
.querySelector('.file-upload-info')
.value = fileName;
});
});
</script>
@endsection

View File

@ -1,67 +1,30 @@
<?php
public function create()
{
$title = 'Tambah Data Sampah';
$users = User::all();
return view('admin.sampah.create', compact('title', 'users'));
}
public function store(Request $request)
{
$request->validate([
'tahun' => 'required|numeric',
'total_sampah' => 'required|numeric',
'total_kelola' => 'required|numeric',
'total_daur_ulang' => 'required|numeric',
]);
$sisa_sampah = $request->total_sampah
- ($request->total_kelola + $request->total_daur_ulang);
Sampah::create([
'user_id' => Auth::id(),
'tahun' => $request->tahun,
'total_sampah' => $request->total_sampah,
'total_kelola' => $request->total_kelola,
'total_daur_ulang' => $request->total_daur_ulang,
'sisa_sampah' => $sisa_sampah,
]);
return redirect()->route('admin.sampah.index')
->with('success', 'Data sampah berhasil ditambahkan');
}
public function edit($id)
{
$title = 'Edit Data Sampah';
$sampah = Sampah::findOrFail($id);
$users = User::all();
return view('admin.sampah.edit', compact('title', 'sampah', 'users'));
}
public function update(Request $request, $id)
{
$sampah = Sampah::findOrFail($id);
$request->validate([
'user_id' => 'required|exists:users,id',
'tahun' => 'required|numeric',
'total_sampah' => 'required|numeric',
'total_kelola' => 'required|numeric',
'total_daur_ulang' => 'required|numeric',
]);
$sisa_sampah = $request->total_sampah
- ($request->total_kelola + $request->total_daur_ulang);
$sampah->update([
'user_id' => $request->user_id,
'tahun' => $request->tahun,
'total_sampah' => $request->total_sampah,
'total_kelola' => $request->total_kelola,
'total_daur_ulang' => $request->total_daur_ulang,
'sisa_sampah' => $sisa_sampah,
]);
return redirect()->route('admin.sampah.index')
->with('success', 'Data sampah berhasil diperbarui');
}
public function destroy($id)
{
$sampah = Sampah::findOrFail($id);
$sampah->delete();
return redirect()->route('admin.sampah.index')
->with('success', 'Data sampah berhasil dihapus');
}
<tbody>
@foreach ($kategori as $item)
<tr>
<td>{{ $item->nama_kategori }}</td>
<td>
@if ($item->foto_kategori)
<img src="{{ asset('storage/' . $item->foto_kategori) }}" class="img-thumbnail" width="100">
@else
<span class="text-muted">-</span>
@endif
</td>
<td>
<div class="deskripsi-truncate-div">
{{ $item->deskripsi ?? '-' }}
</div>
</td>
<td class="text-center">
<a href="{{ route('admin.kategori.edit', $item->id_kategori_tps) }}">
<i class="bi bi-pencil-square"></i>
</a>
<form action="{{ route('admin.tps.destroy', $item->id_kategori_tps) }}" method="POST" class="form-hapus">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger btn-sm">
<i class="bi bi-trash"></i>
</button>
</form>
</td>
</tr>
</tbody>

View File

@ -8,8 +8,7 @@
<h1>Selamat Datang di <span>SIG TPS</span></h1>
<p>Sistem Informasi Geografis Pemetaan Tempat Pembuangan Sampah di Kabupaten Nganjuk</p>
<div class="d-flex">
<a href="#about" class="btn-get-started scrollto">Lihat Peta</a>
<!-- <a href="https://www.youtube.com/watch?v=Y7f98aduVJ8" class="glightbox btn-watch-video d-flex align-items-center"><i class="bi bi-play-circle"></i><span>Watch Video</span></a> -->
<a href="{{ route('user.sig-tps') }}" class="btn-get-started scrollto">Lihat Peta</a>
</div>
</div>
@ -19,12 +18,11 @@
<section id="featured-services" class="featured-services section">
<div class="container">
<!-- Section Title -->
<div class="text-center section-title" data-aos="fade-up">
<h2>Timbulan Sampah</h2>
<p>Data berikut menunjukkan total timbulan, pengelolaan, daur ulang, dan sisa sampah dalam <strong>ton per
hari</strong>.</p>
</div>
<div class="container section-title" data-aos="fade-up">
<h2>Sampah</h2>
<p>Total sampah yang terkumpul di seluruh wilayah Kabupaten Nganjuk pada tahun
{{ $sampah->tahun ?? 'Tahun Tidak Tersedia' }}</p>
</div><!-- End Section Title -->
<div class="row gy-4">
@ -34,10 +32,10 @@
<div class="icon">
<i class="bi bi-trash2 icon"></i>
</div>
<h1>
<h2>
{{ number_format($sampah->total_sampah ?? 0, 2, ',', '.') }}
</h1>
<p><strong>Total Timbulan Sampah</strong></p>
</h2>
<p>Total Timbulan Sampah (ton)</p>
</div>
</div>
@ -47,10 +45,10 @@
<div class="icon">
<i class="bi bi-gear icon"></i>
</div>
<h1>
<h2>
{{ number_format($sampah->total_kelola ?? 0, 2, ',', '.') }}
</h1>
<p><strong>Total Sampah Dikelola</strong></p>
</h2>
<p>Total Sampah Dikelola (ton)</p>
</div>
</div>
@ -60,10 +58,10 @@
<div class="icon">
<i class="bi bi-recycle icon"></i>
</div>
<h1>
<h2>
{{ number_format($sampah->total_daur_ulang ?? 0, 2, ',', '.') }}
</h1>
<p><strong>Total Sampah Didaur Ulang</strong></p>
</h2>
<p>Total Sampah Didaur Ulang (ton)</p>
</div>
</div>
@ -73,10 +71,10 @@
<div class="icon">
<i class="bi bi-exclamation-triangle icon"></i>
</div>
<h1>
<h2>
{{ number_format($sampah->sisa_sampah ?? 0, 2, ',', '.') }}
</h1>
<p><strong>Total Sisa Sampah</strong></p>
</h2>
<p>Total Sisa Sampah (ton)</p>
</div>
</div>
@ -98,54 +96,40 @@
</div><!-- End Section Title -->
<div class="container" data-aos="fade-up">
<div class="row g-4 g-lg-5" data-aos="fade-up" data-aos-delay="200">
<div class="col-lg-5">
<div class="about-img">
<img src="{{ asset('assets/user/img/tentang-lg.png') }}" class="img-fluid" alt="">
</div>
</div>
<div class="col-lg-7">
<h3 class="pt-0 pt-lg-5">Sistem Informasi Geografis Tempat Pembuangan Sampah di Kabupaten Nganjuk</h3>
<!-- Tab Content -->
<div class="tab-content">
<div class="tab-pane fade show active" id="about-tab1">
<p class="fst-italic">Sistem Informasi Geografis yang menampilkan visualisasi lokasi Tempat
Pembuangan Sampah di Kabupaten Nganjuk secara mudah, cepat, dan interaktif.</p>
<div class="mt-4 d-flex align-items-center">
<i class="bi bi-check2"></i>
<h4>Peta Interaktif Lokasi TPS</h4>
</div>
<p>Peta digital yang memudahkan pengguna menemukan lokasi TPS terdekat, lengkap dengan tampilan
yang intuitif sehingga informasi dapat diakses dengan cepat dan jelas.</p>
<div class="mt-4 d-flex align-items-center">
<i class="bi bi-check2"></i>
<h4>Informasi TPS Lengkap</h4>
</div>
<p>Menyajikan berbagai informasi penting seperti kapasitas, kondisi, status, hingga jenis
pengelolaan TPS, sehingga pengguna dapat memahami keadaan TPS secara menyeluruh.</p>
<div class="mt-4 d-flex align-items-center">
<i class="bi bi-check2"></i>
<h4>Layanan Aduan TPS</h4>
</div>
<p>Fitur yang memungkinkan masyarakat menyampaikan keluhan atau laporan terkait TPS dengan
mudah, membantu pemerintah dalam memperbaiki serta meningkatkan pengelolaan sampah.</p>
</div><!-- End Tab 1 Content -->
</div>
</div>
</div>
</div>
</div>
</section><!-- /About Section -->
@ -191,7 +175,6 @@
<p>
{{ explode('.', $item->deskripsi)[0] }}.
</p>
</div>
</div>
@ -201,266 +184,172 @@
</div>
</div>
</section>
<!-- /Services Section -->
{{-- Leaflet CSS & JS --}}
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<section class="geo-stat-section">
<div class="geo-bg"></div>
<style>
/* =============================
MAP SECTION
============================= */
#call-to-action.call-to-action {
padding: 0 !important;
margin: 0 !important;
}
<div class="container position-relative" data-aos="fade-up" data-aos-delay="100">
<div class="row align-items-center">
#call-to-action .container {
display: flex;
justify-content: center;
padding: 20px 0;
}
<!-- KIRI -->
<div class="mb-4 col-lg-5 mb-lg-0">
<span class="geo-badge">Statistik SIG TPS</span>
<h2 class="geo-title">
Pemetaan & Pengelolaan<br>
Sampah Kabupaten Nganjuk
</h2>
<p class="geo-desc">
Menampilkan jumlah fasilitas persampahan berbasis
Sistem Informasi Geografis secara terintegrasi.
</p>
</div>
.map-wrapper {
width: 100%;
max-width: 1100px;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
position: relative;
}
<!-- KANAN -->
<div class="col-lg-7">
<div class="geo-stats">
#mapTPS {
width: 100%;
height: 450px;
position: relative;
z-index: 1;
}
<div class="geo-item">
<div class="geo-icon">
<i class="bi bi-trash"></i>
</div>
<h3 class="counter" data-target="{{ $jumlahTps }}">0</h3>
<span>TPS</span>
</div>
.leaflet-popup-content-wrapper {
border-radius: 14px !important;
}
<div class="geo-line"></div>
/* =============================
FIX LEAFLET VS NAVBAR
============================= */
header,
.navbar,
#header {
position: sticky;
top: 0;
z-index: 1000;
background: #fff;
}
<div class="geo-item">
<div class="geo-icon recycle">
<i class="bi bi-recycle"></i>
</div>
<h3 class="counter" data-target="{{ $jumlahTps3r }}">0</h3>
<span>TPS 3R</span>
</div>
/* paksa semua control leaflet turun dari navbar */
.leaflet-top {
top: 0px !important;
/* SESUAIKAN TINGGI NAVBAR */
z-index: 400 !important;
}
<div class="geo-line"></div>
.leaflet-bottom {
bottom: 0px !important;
}
<div class="geo-item">
<div class="geo-icon location">
<i class="bi bi-geo-alt"></i>
</div>
<h3 class="counter" data-target="{{ $jumlahTpa }}">0</h3>
<span>TPA</span>
</div>
/* =============================
Legend
============================= */
.legend {
background: white;
padding: 10px 12px;
border-radius: 10px;
line-height: 18px;
color: #333;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
font-size: 14px;
}
</div>
</div>
.legend i {
width: 16px;
height: 16px;
float: left;
margin-right: 8px;
opacity: 1;
}
</style>
<section id="call-to-action" class="call-to-action section">
<!-- SECTION TITLE -->
<div class="section-title" data-aos="fade-up">
<h2>Peta Sebaran TPS</h2>
<p>Sistem Informasi Geografis Tempat Pembuangan Sampah di Kabupaten Nganjuk</p>
</div>
<!-- MAP -->
<div class="container" data-aos="fade-up">
<div class="map-wrapper">
<div id="mapTPS"></div>
</div>
</div>
</section>
<script>
// =============================
// INIT MAP
// =============================
var map = L.map('mapTPS', {
zoomControl: true
}).setView([-7.6078, 111.903], 12);
<section id="faq" class="faq section">
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: "© OpenStreetMap contributors",
maxZoom: 19
}).addTo(map);
<div class="container-fluid">
// =============================
// ICON MARKER PER KATEGORI
// =============================
function markerIcon(color) {
return new L.Icon({
iconUrl: `https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-${color}.png`,
shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
}
<div class="row gy-4 justify-content-center">
var iconTPS = markerIcon('green'); // TPS
var iconTPS3R = markerIcon('blue'); // TPS 3R
var iconTPA = markerIcon('red'); // TPA
var iconDefault = markerIcon('black');
<div class="order-2 col-lg-7 d-flex flex-column justify-content-center order-lg-1">
// =============================
// DATA TPS DARI DATABASE
// =============================
var tpsData = @json($lokasiTps);
tpsData.forEach(function(tps) {
if (tps.latitude && tps.longitude) {
let iconKategori = iconDefault;
// SESUAIKAN ID KATEGORI
if (tps.kategori_tps_id == 3) {
iconKategori = iconTPS;
} else if (tps.kategori_tps_id == 5) {
iconKategori = iconTPS3R;
} else if (tps.kategori_tps_id == 6) {
iconKategori = iconTPA;
}
L.marker([tps.latitude, tps.longitude], {
icon: iconKategori
})
.addTo(map)
.bindPopup(`
<div style="min-width:200px">
<strong>${tps.nama_tps}</strong><br>
${tps.alamat_tps ?? '-'}<br>
<small>Status: ${tps.status_tps ?? '-'}</small>
</div>
`);
}
});
// =============================
// LEGEND
// =============================
var legend = L.control({
position: "bottomleft"
});
legend.onAdd = function() {
var div = L.DomUtil.create("div", "legend");
div.innerHTML = `
<strong>Kategori TPS</strong><br>
<i style="background:#198754"></i> TPS<br>
<i style="background:#0d6efd"></i> TPS 3R<br>
<i style="background:#dc3545"></i> TPA
`;
return div;
};
legend.addTo(map);
</script>
<!-- Aduan Section -->
<section id="aduan" class="contact section">
<!-- Section Title -->
<div class="container section-title" data-aos="fade-up">
<h2>Aduan TPS</h2>
<p>Laporkan permasalahan Tempat Pembuangan Sampah (TPS) di sekitar Anda</p>
</div>
<!-- End Section Title -->
<div class="container" data-aos="fade">
<div class="row gy-4 gx-lg-5 align-items-center">
<!-- KIRI: INFO ADUAN -->
<div class="col-lg-6">
<div class="info">
<h3>Temukan Masalah di TPS?</h3>
<div class="text-center content px-xl-6" data-aos="fade-up" data-aos-delay="100">
<h3><span>Pertanyaan yang Sering </span><strong>Diajukan</strong></h3>
<p>
Jika Anda menemukan TPS yang penuh, kotor, atau bermasalah,
silakan laporkan agar dapat segera ditindaklanjuti oleh petugas.
Berikut adalah beberapa pertanyaan yang sering diajukan oleh pengguna terkait
informasi, fitur, dan layanan pada website.
</p>
<div class="info-item d-flex">
<i class="flex-shrink-0 bi bi-exclamation-triangle-fill"></i>
<div>
<h4>Cepat & Mudah</h4>
<p>Aduan dapat dikirim hanya dalam beberapa langkah.</p>
</div>
</div>
<div class="info-item d-flex">
<i class="flex-shrink-0 bi bi-geo-alt-fill"></i>
<div>
<h4>Berbasis Lokasi TPS</h4>
<p>Pilih TPS langsung dari peta.</p>
</div>
</div>
<div class="info-item d-flex">
<i class="flex-shrink-0 bi bi-chat-dots-fill"></i>
<div>
<h4>Ditanggapi Admin</h4>
<p>Aduan akan diproses oleh admin terkait.</p>
</div>
</div>
</div>
</div>
<!-- KANAN: CTA BUTTON -->
<div class="text-center col-lg-6">
<div class="p-4 shadow-sm card">
<h4 class="mb-3">Ingin Mengajukan Aduan?</h4>
<p class="mb-4">
Klik tombol di bawah ini untuk memilih TPS dan mengisi form aduan.
</p>
<div class="faq-container px-xl-5" data-aos="fade-up" data-aos-delay="200">
{{-- <a href="#map" class="mb-2 btn btn-outline-success w-100">
<i class="bi bi-map-fill me-1"></i> Pilih TPS di Peta
</a>
<!-- FAQ 1 -->
<div class="faq-item faq-active">
<i class="faq-icon bi bi-question-circle"></i>
<h3>Apa tujuan utama website ini?</h3>
<div class="faq-content">
<p>
Website ini bertujuan untuk menyediakan informasi yang akurat dan mudah diakses
oleh masyarakat mengenai lokasi dan data Tempat Pembuangan Sampah (TPS). Dengan adanya
website ini, diharapkan masyarakat dapat lebih memahami kondisi
TPS serta mendukung pengelolaan lingkungan yang lebih baik.
</p>
</div>
<i class="faq-toggle bi bi-chevron-right"></i>
</div><!-- End Faq item-->
<p class="my-2 small text-muted">atau</p> --}}
<!-- FAQ 2 -->
<div class="faq-item">
<i class="faq-icon bi bi-question-circle"></i>
<h3>Bagaimana cara melihat peta sebaran TPS?</h3>
<div class="faq-content">
<p>
Peta sebaran TPS dapat dilihat melalui menu Sebaran TPS yang tersedia pada halaman utama
website. Peta tersebut bersifat interaktif dan menampilkan lokasi TPS berdasarkan
wilayah. Pengguna dapat mengklik setiap penanda lokasi untuk melihat detail informasi
seperti alamat TPS dan keterangan tambahan lainnya.
</p>
{{-- <p>
</p> --}}
</div>
<i class="faq-toggle bi bi-chevron-right"></i>
</div><!-- End Faq item-->
<!-- FAQ 3 -->
<div class="faq-item">
<i class="faq-icon bi bi-question-circle"></i>
<h3>Bagaimana cara mengadukan permasalahan TPS?</h3>
<div class="faq-content">
<p>
Pengaduan permasalahan TPS dapat dilakukan melalui menu Aduan TPS yang tersedia
pada website dengan mengisi formulir yang telah disediakan. Laporan yang masuk akan
diteruskan kepada pihak terkait untuk ditindaklanjuti
guna meningkatkan kualitas pengelolaan TPS.
</p>
</div>
<i class="faq-toggle bi bi-chevron-right"></i>
</div><!-- End Faq item-->
<!-- FAQ 4 -->
<div class="faq-item">
<i class="faq-icon bi bi-question-circle"></i>
<h3>Apakah website ini dapat diakses melalui perangkat mobile?</h3>
<div class="faq-content">
<p>
Ya, website ini dirancang secara responsif sehingga dapat diakses melalui
berbagai perangkat, termasuk smartphone dan tablet. Tampilan website akan menyesuaikan
ukuran layar perangkat pengguna tanpa
mengurangi fungsi dan informasi yang tersedia.
</p>
</div>
<i class="faq-toggle bi bi-chevron-right"></i>
</div><!-- End Faq item-->
<a href="{{ route('user.aduan', $tpsPertama->id ?? 1) }}" class="btn btn-danger w-100">
<i class="bi bi-megaphone-fill me-1"></i> Laporkan Aduan
</a>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll(".counter").forEach(el => {
const target = +el.dataset.target;
let val = 0;
const step = () => {
val += Math.ceil(target / 90);
if (val < target) {
el.textContent = val;
requestAnimationFrame(step);
} else {
el.textContent = target;
}
};
step();
});
});
</script>
</section>
@endsection

View File

@ -22,10 +22,10 @@
*/
Route::get('/', function () {
return view('welcome');
return view('user.index');
});
Route::get('/index', [IndexController::class, 'index'])->name('user.index');
Route::get('/', [IndexController::class, 'index'])->name('user.index');
Route::get('/about', [AboutController::class, 'index'])->name('user.about');
Route::get('/about/{id}', [AboutController::class, 'show'])->name('user.about.kategori');
@ -37,16 +37,6 @@
Route::get('/kontak', [KontakController::class, 'index'])->name('user.kontak');
/*
|--------------------------------------------------------------------------
| ROUTE AUTH (LARAVEL BREEZE)
|--------------------------------------------------------------------------
|
| Login : /login
| Logout : /logout
|
*/
require __DIR__.'/auth.php';
/*