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 App\Http\Controllers\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Models\LokasiTps;
use App\Models\AduanTps;
use App\Models\Sampah;
class DashboardController extends Controller class DashboardController extends Controller
{ {
public function index() public function index()
{ {
$totalTps = \App\Models\LokasiTps::count(); $totalTps = LokasiTps::count();
$totalAduan = \App\Models\AduanTps::count(); $totalAduan = AduanTps::count();
$sampahTerbaru = \App\Models\Sampah::orderBy('created_at', 'desc')->first(); $sampahTerbaru = Sampah::orderBy('created_at', 'desc')->first();
return view('admin.index', compact( return view('admin.index', compact(
'totalTps', 'totalTps',
'totalAduan', 'totalAduan',
'sampahTerbaru' 'sampahTerbaru'
)); ));
} }
} }

View File

@ -10,66 +10,127 @@
class TpsController extends Controller class TpsController extends Controller
{ {
public function index() public function index()
{ {
$title = 'Data TPS'; $title = 'Data TPS';
$tps = LokasiTps::with('kategori') $tps = LokasiTps::with('kategori')
->withCount('aduan') ->withCount('aduan')
->get(); ->get();
return view('admin.tps.index', compact('title', 'tps'));
}
public function create() return view('admin.tps.index', compact('title', 'tps'));
{ }
public function create()
{
$title = 'Tambah TPS'; $title = 'Tambah TPS';
$kategori = KategoriTps::all(); $kategori = KategoriTps::all();
return view('admin.tps.create', compact('title', 'kategori')); return view('admin.tps.create', compact('title', 'kategori'));
} }
private function convertToDecimal($coordinate)
{ /*
|--------------------------------------------------------------------------
| KONVERSI KOORDINAT (DECIMAL / DMS)
|--------------------------------------------------------------------------
*/
private function convertToDecimal($coordinate)
{
if (is_numeric($coordinate)) { if (is_numeric($coordinate)) {
return (float) $coordinate; return (float) $coordinate;
} }
$coordinate = html_entity_decode($coordinate); $coordinate = html_entity_decode($coordinate);
$coordinate = strtoupper(trim($coordinate)); $coordinate = strtoupper(trim($coordinate));
$coordinate = str_replace( $coordinate = str_replace(['°', "'", '"'], [' ', ' ', ' '], $coordinate);
['°', "'", '"'],
[' ', ' ', ' '], preg_match('/([NSEW])/', $coordinate, $dir);
$coordinate if (!$dir) {
); return null;
preg_match('/([NSEW])/', $coordinate, $dirMatch); }
if (!$dirMatch) return null;
$direction = $dirMatch[1];
preg_match_all('/\d+(\.\d+)?/', $coordinate, $numbers); preg_match_all('/\d+(\.\d+)?/', $coordinate, $numbers);
if (count($numbers[0]) < 3) return null; if (count($numbers[0]) < 3) {
return null;
}
[$deg, $min, $sec] = array_map('floatval', $numbers[0]); [$deg, $min, $sec] = array_map('floatval', $numbers[0]);
$decimal = $deg + ($min / 60) + ($sec / 3600); $decimal = $deg + ($min / 60) + ($sec / 3600);
if (in_array($direction, ['S', 'W'])) {
if (in_array($dir[1], ['S', 'W'])) {
$decimal *= -1; $decimal *= -1;
} }
return $decimal; return $decimal;
} }
public function store(Request $request)
{ /*
$request->validate([ |--------------------------------------------------------------------------
| STORE (CREATE)
|--------------------------------------------------------------------------
*/
public function store(Request $request)
{
// VALIDASI DASAR + PESAN CUSTOM
$request->validate(
[
'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',
'status_tps' => 'required', 'status_tps' => 'required|in:Aktif,Tidak Aktif,Pembangunan',
'tahun_pembuatan' => 'required|numeric', 'tahun_pembuatan' => 'required|digits:4',
'kapasitas_tps' => 'required', 'kapasitas_tps' => 'required|integer|min:1',
'latitude' => 'required', 'latitude' => 'required',
'longitude' => 'required', 'longitude' => 'required',
'foto_tps' => 'nullable|image|mimes:jpg,jpeg,png|max:2048', '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); $latitude = $this->convertToDecimal($request->latitude);
$longitude = $this->convertToDecimal($request->longitude); $longitude = $this->convertToDecimal($request->longitude);
if ($latitude === null || $longitude === null) {
return back()->withErrors(['Koordinat tidak valid'])->withInput(); $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') $foto = $request->hasFile('foto_tps')
? $request->file('foto_tps')->store('foto-tps', 'public') ? $request->file('foto_tps')->store('foto-tps', 'public')
: null; : null;
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,
@ -81,38 +142,68 @@ public function store(Request $request)
'longitude' => $longitude, 'longitude' => $longitude,
'foto_tps' => $foto, 'foto_tps' => $foto,
]); ]);
return redirect()->route('admin.tps.index')
->with('success', 'Data TPS berhasil ditambahkan');
}
public function edit($id) return redirect()->route('admin.tps.index')
{ ->with('success', 'Data TPS berhasil ditambahkan.');
}
/*
|--------------------------------------------------------------------------
| EDIT
|--------------------------------------------------------------------------
*/
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)
{ /*
|--------------------------------------------------------------------------
| UPDATE
|--------------------------------------------------------------------------
*/
public function update(Request $request, $id)
{
$tps = LokasiTps::findOrFail($id); $tps = LokasiTps::findOrFail($id);
$request->validate([
$request->validate(
[
'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',
'status_tps' => 'required', 'status_tps' => 'required|in:Aktif,Tidak Aktif,Pembangunan',
'tahun_pembuatan' => 'required|numeric', 'tahun_pembuatan' => 'required|digits:4',
'kapasitas_tps' => 'required', 'kapasitas_tps' => 'required|integer|min:1',
'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',
]); ],
[
'tahun_pembuatan.digits' => 'Tahun pembuatan harus 4 digit.',
]
);
$latitude = $this->convertToDecimal($request->latitude); $latitude = $this->convertToDecimal($request->latitude);
$longitude = $this->convertToDecimal($request->longitude); $longitude = $this->convertToDecimal($request->longitude);
if ($latitude === null || $longitude === null) {
return back() $errors = [];
->withErrors(['Koordinat tidak valid. Gunakan format Decimal atau DMS.'])
->withInput(); 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 ($request->hasFile('foto_tps')) {
if ($tps->foto_tps) { if ($tps->foto_tps) {
Storage::disk('public')->delete($tps->foto_tps); Storage::disk('public')->delete($tps->foto_tps);
@ -121,6 +212,7 @@ public function update(Request $request, $id)
} else { } else {
$foto = $tps->foto_tps; $foto = $tps->foto_tps;
} }
$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,
@ -132,18 +224,27 @@ public function update(Request $request, $id)
'longitude' => $longitude, 'longitude' => $longitude,
'foto_tps' => $foto, 'foto_tps' => $foto,
]); ]);
return redirect()->route('admin.tps.index')
->with('success', 'Data TPS berhasil diperbarui');
}
public function destroy($id) return redirect()->route('admin.tps.index')
{ ->with('success', 'Data TPS berhasil diperbarui.');
}
/*
|--------------------------------------------------------------------------
| DELETE
|--------------------------------------------------------------------------
*/
public function destroy($id)
{
$tps = LokasiTps::findOrFail($id); $tps = LokasiTps::findOrFail($id);
if ($tps->foto_tps) { if ($tps->foto_tps) {
Storage::disk('public')->delete($tps->foto_tps); Storage::disk('public')->delete($tps->foto_tps);
} }
$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

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

View File

@ -14,7 +14,10 @@ public function index()
$sampah = Sampah::orderBy('tahun', 'desc')->first(); $sampah = Sampah::orderBy('tahun', 'desc')->first();
$kategoriTps = KategoriTps::orderBy('id_kategori_tps')->get(); $kategoriTps = KategoriTps::orderBy('id_kategori_tps')->get();
$lokasiTps = LokasiTps::all(); $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); color: var(--contrast-color);
background: color-mix(in srgb, var(--accent-color), transparent 15%); 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> <tr>
<th>TPS</th> <th>TPS</th>
<th>Nama Pelapor</th> <th>Nama Pelapor</th>
{{-- <th>Alamat Pelapor</th> --}}
<th>Tanggal Aduan</th> <th>Tanggal Aduan</th>
<th>Status</th> <th>Status</th>
<th class="text-center">Aksi</th> <th class="text-center">Aksi</th>
@ -33,7 +32,6 @@
<tbody> <tbody>
@forelse ($aduan as $item) @forelse ($aduan as $item)
<tr> <tr>
<!-- TPS -->
<td> <td>
<strong> <strong>
{{ $item->lokasiTps->nama_tps ?? '-' }} {{ $item->lokasiTps->nama_tps ?? '-' }}
@ -43,19 +41,10 @@
{{ $item->lokasiTps->alamat_tps ?? '' }} {{ $item->lokasiTps->alamat_tps ?? '' }}
</small> </small>
</td> </td>
<!-- Pelapor -->
<td>{{ $item->nama_pelapor }}</td> <td>{{ $item->nama_pelapor }}</td>
<!-- Alamat -->
{{-- <td>{{ $item->alamat_pelapor }}</td> --}}
<!-- Tanggal -->
<td> <td>
{{ \Carbon\Carbon::parse($item->tanggal_aduan)->format('d M Y') }} {{ \Carbon\Carbon::parse($item->tanggal_aduan)->format('d M Y') }}
</td> </td>
<!-- Status -->
<td> <td>
@if ($item->tanggapan_admin) @if ($item->tanggapan_admin)
<span class="badge badge-success">Ditanggapi</span> <span class="badge badge-success">Ditanggapi</span>
@ -63,8 +52,6 @@
<span class="badge badge-danger">Belum</span> <span class="badge badge-danger">Belum</span>
@endif @endif
</td> </td>
<!-- Aksi -->
<td class="text-center"> <td class="text-center">
<a href="{{ route('admin.aduan.show', $item->id_aduan) }}" <a href="{{ route('admin.aduan.show', $item->id_aduan) }}"
class="btn btn-warning btn-sm" class="btn btn-warning btn-sm"

View File

@ -1,12 +1,13 @@
@extends('admin.template') @extends('admin.template')
@section('content') @section('content')
<div class="content-wrapper"> <div class="content-wrapper">
<div class="row"> <div class="row justify-content-center">
<div class="col-md-12 grid-margin stretch-card"> <div class="col-md-12 grid-margin stretch-card">
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<h4 class="card-title">Profil Admin</h4>
<h4 class="mb-4 card-title">Profil Admin</h4>
@if (session('success')) @if (session('success'))
<div class="alert alert-success"> <div class="alert alert-success">
@ -14,50 +15,92 @@
</div> </div>
@endif @endif
<form action="{{ route('admin.profil.update') }}" method="POST"> <form action="{{ route('admin.profil.update') }}" method="POST" enctype="multipart/form-data">
@csrf @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>
<!-- KANAN : FORM -->
<div class="col-md-8">
<div class="form-group"> <div class="form-group">
<label>Nama</label> <label>Nama</label>
<input type="text" name="name" class="form-control" value="{{ $admin->name }}" <input type="text" name="name"
required> class="form-control"
value="{{ $admin->name }}" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Username</label> <label>Username</label>
<input type="text" name="username" class="form-control" value="{{ $admin->username }}" <input type="text" name="username"
required> class="form-control"
value="{{ $admin->username }}" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Role</label> <label>Role</label>
<input type="text" class="form-control" value="{{ $admin->role }}" disabled> <input type="text"
class="form-control"
value="{{ $admin->role }}" disabled>
</div> </div>
<hr> <hr>
<div class="form-group"> <div class="form-group">
<label>Password Baru (opsional)</label> <label>Password Baru (opsional)</label>
<input type="password" name="password" class="form-control" <input type="password"
name="password"
class="form-control"
placeholder="Kosongkan jika tidak diganti"> placeholder="Kosongkan jika tidak diganti">
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Konfirmasi Password</label> <label>Konfirmasi Password</label>
<input type="password" name="password_confirmation" class="form-control"> <input type="password"
name="password_confirmation"
class="form-control">
</div> </div>
<div class="mt-4">
<button type="submit" class="btn btn-primary"> <button type="submit" class="btn btn-primary">
Simpan Simpan
</button> </button>
<a href="{{ url()->previous() }}" class="btn btn-light ml-2">
<a href="{{ url()->previous() }}"
class="ml-2 btn btn-light">
Batal Batal
</a> </a>
</div>
</div>
</div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@endsection @endsection

View File

@ -1,7 +1,7 @@
@extends('admin.template') @extends('admin.template')
@section('content') @section('content')
<div class="content-wrapper"> <div class="content-wrapper">
<div class="row"> <div class="row">
<div class="col-12 grid-margin stretch-card"> <div class="col-12 grid-margin stretch-card">
<div class="card"> <div class="card">
@ -9,85 +9,103 @@
<h4 class="card-title">Tambah Data TPS</h4> <h4 class="card-title">Tambah Data TPS</h4>
<p class="card-description">Form tambah data TPS</p> <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"> <form action="{{ route('admin.tps.store') }}" method="POST" enctype="multipart/form-data">
@csrf @csrf
<!-- NAMA TPS --> <!-- NAMA TPS -->
<div class="form-group"> <div class="form-group">
<label>Nama TPS</label> <label>Nama TPS</label>
<input type="text" name="nama_tps" class="form-control" placeholder="Nama TPS" required> <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> </div>
<!-- ALAMAT -->
<div class="form-group"> <div class="form-group">
<label>Alamat</label> <label>Alamat</label>
<input type="text" name="alamat_tps" class="form-control" placeholder="Alamat TPS" <input type="text" name="alamat_tps" class="form-control"
required> value="{{ old('alamat_tps') }}"
placeholder="Alamat TPS">
@error('alamat_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
<div class="form-group"> <!-- KATEGORI -->
<label>Kecamatan</label>
<input type="text" name="kecamatan" class="form-control" placeholder="Kecamatan TPS"
required>
</div>
<!-- KATEGORI TPS -->
<div class="form-group"> <div class="form-group">
<label>Kategori TPS</label> <label>Kategori TPS</label>
<select name="kategori_tps_id" class="form-control" required> <select name="kategori_tps_id" class="form-control">
<option value="">Pilih Kategori</option> <option value="">Pilih Kategori</option>
@foreach ($kategori as $item) @foreach ($kategori as $item)
<option value="{{ $item->id_kategori_tps }}"> <option value="{{ $item->id_kategori_tps }}"
{{ old('kategori_tps_id') == $item->id_kategori_tps ? 'selected' : '' }}>
{{ $item->nama_kategori }} {{ $item->nama_kategori }}
</option> </option>
@endforeach @endforeach
</select> </select>
@error('kategori_tps_id')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
<!-- TAHUN --> <!-- TAHUN -->
<div class="form-group"> <div class="form-group">
<label>Tahun Pembuatan</label> <label>Tahun Pembuatan</label>
<input type="number" name="tahun_pembuatan" class="form-control" <input type="number" name="tahun_pembuatan" class="form-control"
placeholder="Tahun Pembuatan" required> value="{{ old('tahun_pembuatan') }}"
placeholder="Contoh: 2022">
@error('tahun_pembuatan')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
<!-- KAPASITAS --> <!-- KAPASITAS -->
<div class="form-group"> <div class="form-group">
<label>Kapasitas</label> <label>Kapasitas</label>
<input type="text" name="kapasitas_tps" class="form-control" placeholder="Kapasitas TPS" <input type="text" name="kapasitas_tps" class="form-control"
required> value="{{ old('kapasitas_tps') }}"
placeholder="Kapasitas TPS">
@error('kapasitas_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
<!-- STATUS --> <!-- STATUS -->
<div class="form-group"> <div class="form-group">
<label>Status</label> <label>Status</label>
<select name="status_tps" class="form-control" required> <select name="status_tps" class="form-control">
<option value="Aktif">Aktif</option> <option value="Aktif" {{ old('status_tps') == 'Aktif' ? 'selected' : '' }}>Aktif</option>
<option value="Non-Aktif">Tidak Aktif</option> <option value="Tidak Aktif" {{ old('status_tps') == 'Tidak Aktif' ? 'selected' : '' }}>Tidak Aktif</option>
<option value="Pembangunan">Pembangunan</option> <option value="Pembangunan" {{ old('status_tps') == 'Pembangunan' ? 'selected' : '' }}>Pembangunan</option>
</select> </select>
@error('status_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
<!-- LATITUDE -->
<div class="form-group"> <div class="form-group">
<label>Latitude</label> <label>Latitude</label>
<input type="text" name="latitude" class="form-control" <input type="text" name="latitude" class="form-control"
placeholder="Contoh: 7°35'17.25&quot;S" required> value="{{ old('latitude') }}"
placeholder="Contoh: -7.623 atau 7°35'17.25&quot;S">
@error('latitude')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
<!-- LONGITUDE -->
<div class="form-group"> <div class="form-group">
<label>Longitude</label> <label>Longitude</label>
<input type="text" name="longitude" class="form-control" <input type="text" name="longitude" class="form-control"
placeholder="Contoh: 111°55'0.97&quot;E" required> value="{{ old('longitude') }}"
placeholder="Contoh: 111.980 atau 111°55'0.97&quot;E">
@error('longitude')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
<!-- FOTO --> <!-- FOTO -->
@ -105,6 +123,10 @@
</button> </button>
</span> </span>
</div> </div>
@error('foto_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
<button type="submit" class="mr-2 btn btn-primary">Simpan</button> <button type="submit" class="mr-2 btn btn-primary">Simpan</button>
@ -115,5 +137,5 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@endsection @endsection

View File

@ -1,11 +1,11 @@
@php @php
function decimalToDms($decimal, $type = 'lat') function decimalToDms($decimal, $type = 'lat')
{ {
if ($decimal === null || $decimal === '') return ''; if ($decimal === null || $decimal === '') {
return '';
}
$direction = $decimal >= 0 $direction = $decimal >= 0 ? ($type === 'lat' ? 'N' : 'E') : ($type === 'lat' ? 'S' : 'W');
? ($type === 'lat' ? 'N' : 'E')
: ($type === 'lat' ? 'S' : 'W');
$decimal = abs($decimal); $decimal = abs($decimal);
@ -21,7 +21,7 @@ function decimalToDms($decimal, $type = 'lat')
@extends('admin.template') @extends('admin.template')
@section('content') @section('content')
<div class="content-wrapper"> <div class="content-wrapper">
<div class="row"> <div class="row">
<div class="col-12 grid-margin stretch-card"> <div class="col-12 grid-margin stretch-card">
<div class="card"> <div class="card">
@ -31,10 +31,8 @@ function decimalToDms($decimal, $type = 'lat')
Form edit data Tempat Pembuangan Sampah Form edit data Tempat Pembuangan Sampah
</p> </p>
<form action="{{ route('admin.tps.update', $tps->id_tps) }}" <form action="{{ route('admin.tps.update', $tps->id_tps) }}" method="POST"
method="POST" enctype="multipart/form-data" class="forms-sample">
enctype="multipart/form-data"
class="forms-sample">
@csrf @csrf
@method('PUT') @method('PUT')
@ -42,20 +40,20 @@ class="forms-sample">
<div class="form-group"> <div class="form-group">
<label>Nama TPS</label> <label>Nama TPS</label>
<input type="text" name="nama_tps" class="form-control" <input type="text" name="nama_tps" class="form-control"
value="{{ old('nama_tps', $tps->nama_tps) }}" required> value="{{ old('nama_tps') ?? $tps->nama_tps }}" required>
@error('nama_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
{{-- Alamat --}} {{-- Alamat --}}
<div class="form-group"> <div class="form-group">
<label>Alamat</label> <label>Alamat</label>
<input type="text" name="alamat_tps" class="form-control" <input type="text" name="alamat_tps" class="form-control"
value="{{ old('alamat_tps', $tps->alamat_tps) }}" required> value="{{ old('alamat_tps') ?? $tps->alamat_tps }}" required>
</div> @error('alamat_tps')
<small class="text-danger">{{ $message }}</small>
<div class="form-group"> @enderror
<label>Kecamatan</label>
<input type="text" name="kecamatan" class="form-control"
value="{{ old('kecamatan', $tps->kecamatan) }}" required>
</div> </div>
{{-- Kategori TPS --}} {{-- Kategori TPS --}}
@ -65,63 +63,81 @@ class="forms-sample">
<option value="">-- Pilih Kategori --</option> <option value="">-- Pilih Kategori --</option>
@foreach ($kategori as $item) @foreach ($kategori as $item)
<option value="{{ $item->id_kategori_tps }}" <option value="{{ $item->id_kategori_tps }}"
{{ old('kategori_tps_id', $tps->kategori_tps_id) == $item->id_kategori_tps ? 'selected' : '' }}> {{ (old('kategori_tps_id') ?? $tps->kategori_tps_id) == $item->id_kategori_tps ? 'selected' : '' }}>
{{ $item->nama_kategori }} {{ $item->nama_kategori }}
</option> </option>
@endforeach @endforeach
</select> </select>
@error('kategori_tps_id')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
{{-- Tahun Pembuatan --}} {{-- Tahun Pembuatan --}}
<div class="form-group"> <div class="form-group">
<label>Tahun Pembuatan</label> <label>Tahun Pembuatan</label>
<input type="number" name="tahun_pembuatan" class="form-control" <input type="number" name="tahun_pembuatan" class="form-control"
value="{{ old('tahun_pembuatan', $tps->tahun_pembuatan) }}" required> value="{{ old('tahun_pembuatan') ?? $tps->tahun_pembuatan }}" required>
@error('tahun_pembuatan')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
{{-- Kapasitas TPS --}} {{-- Kapasitas TPS --}}
<div class="form-group"> <div class="form-group">
<label>Kapasitas TPS</label> <label>Kapasitas TPS</label>
<input type="text" name="kapasitas_tps" class="form-control" <input type="number" name="kapasitas_tps" class="form-control"
value="{{ old('kapasitas_tps', $tps->kapasitas_tps) }}" required> value="{{ old('kapasitas_tps') ?? $tps->kapasitas_tps }}" required>
@error('kapasitas_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
{{-- Status TPS --}} {{-- Status TPS --}}
<div class="form-group"> <div class="form-group">
<label>Status TPS</label> <label>Status TPS</label>
<select name="status_tps" class="form-control" required> <select name="status_tps" class="form-control" required>
<option value="Aktif" {{ old('status_tps', $tps->status_tps) == 'Aktif' ? 'selected' : '' }}> <option value="Aktif"
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> </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> </select>
@error('status_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
{{-- Latitude (DMS) --}} {{-- Latitude --}}
<div class="form-group"> <div class="form-group">
<label>Latitude</label> <label>Latitude</label>
<input type="text" name="latitude" class="form-control" <input type="text" name="latitude" class="form-control" placeholder="Contoh: 7°35'17.25S"
placeholder="Contoh: 7°35'17.25&quot;S" value="{{ old('latitude') ?? decimalToDms($tps->latitude, 'lat') }}" required>
value="{{ old('latitude', decimalToDms($tps->latitude, 'lat')) }}" required> @error('latitude')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
{{-- Longitude (DMS) --}} {{-- Longitude --}}
<div class="form-group"> <div class="form-group">
<label>Longitude</label> <label>Longitude</label>
<input type="text" name="longitude" class="form-control" <input type="text" name="longitude" class="form-control"
placeholder="Contoh: 111°55'0.97&quot;E" placeholder="Contoh: 111°55'0.97E"
value="{{ old('longitude', decimalToDms($tps->longitude, 'lng')) }}" required> value="{{ old('longitude') ?? decimalToDms($tps->longitude, 'lng') }}" required>
@error('longitude')
<small class="text-danger">{{ $message }}</small>
@enderror
</div> </div>
{{-- Foto TPS --}} {{-- Foto TPS --}}
<div class="form-group"> <div class="form-group">
<label>Foto TPS</label> <label>Foto TPS</label>
<input type="file" name="foto_tps" class="file-upload-default">
<input type="file" name="foto_tps" id="foto_tps" class="file-upload-default">
<div class="input-group col-xs-12"> <div class="input-group col-xs-12">
<input type="text" class="form-control file-upload-info" disabled <input type="text" class="form-control file-upload-info" disabled
@ -133,28 +149,44 @@ class="forms-sample">
</span> </span>
</div> </div>
{{-- Foto Lama --}} @error('foto_tps')
<small class="text-danger">{{ $message }}</small>
@enderror
@if ($tps->foto_tps) @if ($tps->foto_tps)
<div class="mt-2"> <div class="mt-2">
<img src="{{ asset('storage/' . $tps->foto_tps) }}" <img src="{{ asset('storage/' . $tps->foto_tps) }}" width="250"
width="250"
class="img-thumbnail"> class="img-thumbnail">
</div> </div>
@endif @endif
</div> </div>
{{-- Button --}} {{-- Button --}}
<button type="submit" class="mr-2 btn btn-primary"> <button type="submit" class="mr-2 btn btn-primary">Simpan</button>
Simpan <a href="{{ route('admin.tps.index') }}" class="btn btn-light">Batal</a>
</button>
<a href="{{ route('admin.tps.index') }}" class="btn btn-light">
Batal
</a>
</form> </form>
</div> </div>
</div> </div>
</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 @endsection

View File

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

View File

@ -8,8 +8,7 @@
<h1>Selamat Datang di <span>SIG TPS</span></h1> <h1>Selamat Datang di <span>SIG TPS</span></h1>
<p>Sistem Informasi Geografis Pemetaan Tempat Pembuangan Sampah di Kabupaten Nganjuk</p> <p>Sistem Informasi Geografis Pemetaan Tempat Pembuangan Sampah di Kabupaten Nganjuk</p>
<div class="d-flex"> <div class="d-flex">
<a href="#about" class="btn-get-started scrollto">Lihat Peta</a> <a href="{{ route('user.sig-tps') }}" 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> -->
</div> </div>
</div> </div>
@ -19,12 +18,11 @@
<section id="featured-services" class="featured-services section"> <section id="featured-services" class="featured-services section">
<div class="container"> <div class="container">
<!-- Section Title --> <div class="container section-title" data-aos="fade-up">
<div class="text-center section-title" data-aos="fade-up"> <h2>Sampah</h2>
<h2>Timbulan Sampah</h2> <p>Total sampah yang terkumpul di seluruh wilayah Kabupaten Nganjuk pada tahun
<p>Data berikut menunjukkan total timbulan, pengelolaan, daur ulang, dan sisa sampah dalam <strong>ton per {{ $sampah->tahun ?? 'Tahun Tidak Tersedia' }}</p>
hari</strong>.</p> </div><!-- End Section Title -->
</div>
<div class="row gy-4"> <div class="row gy-4">
@ -34,10 +32,10 @@
<div class="icon"> <div class="icon">
<i class="bi bi-trash2 icon"></i> <i class="bi bi-trash2 icon"></i>
</div> </div>
<h1> <h2>
{{ number_format($sampah->total_sampah ?? 0, 2, ',', '.') }} {{ number_format($sampah->total_sampah ?? 0, 2, ',', '.') }}
</h1> </h2>
<p><strong>Total Timbulan Sampah</strong></p> <p>Total Timbulan Sampah (ton)</p>
</div> </div>
</div> </div>
@ -47,10 +45,10 @@
<div class="icon"> <div class="icon">
<i class="bi bi-gear icon"></i> <i class="bi bi-gear icon"></i>
</div> </div>
<h1> <h2>
{{ number_format($sampah->total_kelola ?? 0, 2, ',', '.') }} {{ number_format($sampah->total_kelola ?? 0, 2, ',', '.') }}
</h1> </h2>
<p><strong>Total Sampah Dikelola</strong></p> <p>Total Sampah Dikelola (ton)</p>
</div> </div>
</div> </div>
@ -60,10 +58,10 @@
<div class="icon"> <div class="icon">
<i class="bi bi-recycle icon"></i> <i class="bi bi-recycle icon"></i>
</div> </div>
<h1> <h2>
{{ number_format($sampah->total_daur_ulang ?? 0, 2, ',', '.') }} {{ number_format($sampah->total_daur_ulang ?? 0, 2, ',', '.') }}
</h1> </h2>
<p><strong>Total Sampah Didaur Ulang</strong></p> <p>Total Sampah Didaur Ulang (ton)</p>
</div> </div>
</div> </div>
@ -73,10 +71,10 @@
<div class="icon"> <div class="icon">
<i class="bi bi-exclamation-triangle icon"></i> <i class="bi bi-exclamation-triangle icon"></i>
</div> </div>
<h1> <h2>
{{ number_format($sampah->sisa_sampah ?? 0, 2, ',', '.') }} {{ number_format($sampah->sisa_sampah ?? 0, 2, ',', '.') }}
</h1> </h2>
<p><strong>Total Sisa Sampah</strong></p> <p>Total Sisa Sampah (ton)</p>
</div> </div>
</div> </div>
@ -98,54 +96,40 @@
</div><!-- End Section Title --> </div><!-- End Section Title -->
<div class="container" data-aos="fade-up"> <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="row g-4 g-lg-5" data-aos="fade-up" data-aos-delay="200">
<div class="col-lg-5"> <div class="col-lg-5">
<div class="about-img"> <div class="about-img">
<img src="{{ asset('assets/user/img/tentang-lg.png') }}" class="img-fluid" alt=""> <img src="{{ asset('assets/user/img/tentang-lg.png') }}" class="img-fluid" alt="">
</div> </div>
</div> </div>
<div class="col-lg-7"> <div class="col-lg-7">
<h3 class="pt-0 pt-lg-5">Sistem Informasi Geografis Tempat Pembuangan Sampah di Kabupaten Nganjuk</h3> <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-content">
<div class="tab-pane fade show active" id="about-tab1"> <div class="tab-pane fade show active" id="about-tab1">
<p class="fst-italic">Sistem Informasi Geografis yang menampilkan visualisasi lokasi Tempat <p class="fst-italic">Sistem Informasi Geografis yang menampilkan visualisasi lokasi Tempat
Pembuangan Sampah di Kabupaten Nganjuk secara mudah, cepat, dan interaktif.</p> Pembuangan Sampah di Kabupaten Nganjuk secara mudah, cepat, dan interaktif.</p>
<div class="mt-4 d-flex align-items-center"> <div class="mt-4 d-flex align-items-center">
<i class="bi bi-check2"></i> <i class="bi bi-check2"></i>
<h4>Peta Interaktif Lokasi TPS</h4> <h4>Peta Interaktif Lokasi TPS</h4>
</div> </div>
<p>Peta digital yang memudahkan pengguna menemukan lokasi TPS terdekat, lengkap dengan tampilan <p>Peta digital yang memudahkan pengguna menemukan lokasi TPS terdekat, lengkap dengan tampilan
yang intuitif sehingga informasi dapat diakses dengan cepat dan jelas.</p> yang intuitif sehingga informasi dapat diakses dengan cepat dan jelas.</p>
<div class="mt-4 d-flex align-items-center"> <div class="mt-4 d-flex align-items-center">
<i class="bi bi-check2"></i> <i class="bi bi-check2"></i>
<h4>Informasi TPS Lengkap</h4> <h4>Informasi TPS Lengkap</h4>
</div> </div>
<p>Menyajikan berbagai informasi penting seperti kapasitas, kondisi, status, hingga jenis <p>Menyajikan berbagai informasi penting seperti kapasitas, kondisi, status, hingga jenis
pengelolaan TPS, sehingga pengguna dapat memahami keadaan TPS secara menyeluruh.</p> pengelolaan TPS, sehingga pengguna dapat memahami keadaan TPS secara menyeluruh.</p>
<div class="mt-4 d-flex align-items-center"> <div class="mt-4 d-flex align-items-center">
<i class="bi bi-check2"></i> <i class="bi bi-check2"></i>
<h4>Layanan Aduan TPS</h4> <h4>Layanan Aduan TPS</h4>
</div> </div>
<p>Fitur yang memungkinkan masyarakat menyampaikan keluhan atau laporan terkait TPS dengan <p>Fitur yang memungkinkan masyarakat menyampaikan keluhan atau laporan terkait TPS dengan
mudah, membantu pemerintah dalam memperbaiki serta meningkatkan pengelolaan sampah.</p> mudah, membantu pemerintah dalam memperbaiki serta meningkatkan pengelolaan sampah.</p>
</div><!-- End Tab 1 Content -->
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
</section><!-- /About Section --> </section><!-- /About Section -->
@ -191,7 +175,6 @@
<p> <p>
{{ explode('.', $item->deskripsi)[0] }}. {{ explode('.', $item->deskripsi)[0] }}.
</p> </p>
</div> </div>
</div> </div>
@ -201,266 +184,172 @@
</div> </div>
</div> </div>
</section> </section>
<!-- /Services Section -->
{{-- Leaflet CSS & JS --}} <section class="geo-stat-section">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" /> <div class="geo-bg"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<style> <div class="container position-relative" data-aos="fade-up" data-aos-delay="100">
/* ============================= <div class="row align-items-center">
MAP SECTION
============================= */
#call-to-action.call-to-action {
padding: 0 !important;
margin: 0 !important;
}
#call-to-action .container { <!-- KIRI -->
display: flex; <div class="mb-4 col-lg-5 mb-lg-0">
justify-content: center; <span class="geo-badge">Statistik SIG TPS</span>
padding: 20px 0; <h2 class="geo-title">
} Pemetaan & Pengelolaan<br>
Sampah Kabupaten Nganjuk
.map-wrapper { </h2>
width: 100%; <p class="geo-desc">
max-width: 1100px; Menampilkan jumlah fasilitas persampahan berbasis
border-radius: 12px; Sistem Informasi Geografis secara terintegrasi.
overflow: hidden; </p>
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12); </div>
position: relative;
} <!-- KANAN -->
<div class="col-lg-7">
#mapTPS { <div class="geo-stats">
width: 100%;
height: 450px; <div class="geo-item">
position: relative; <div class="geo-icon">
z-index: 1; <i class="bi bi-trash"></i>
} </div>
<h3 class="counter" data-target="{{ $jumlahTps }}">0</h3>
.leaflet-popup-content-wrapper { <span>TPS</span>
border-radius: 14px !important; </div>
}
<div class="geo-line"></div>
/* =============================
FIX LEAFLET VS NAVBAR <div class="geo-item">
============================= */ <div class="geo-icon recycle">
header, <i class="bi bi-recycle"></i>
.navbar, </div>
#header { <h3 class="counter" data-target="{{ $jumlahTps3r }}">0</h3>
position: sticky; <span>TPS 3R</span>
top: 0; </div>
z-index: 1000;
background: #fff; <div class="geo-line"></div>
}
<div class="geo-item">
/* paksa semua control leaflet turun dari navbar */ <div class="geo-icon location">
.leaflet-top { <i class="bi bi-geo-alt"></i>
top: 0px !important; </div>
/* SESUAIKAN TINGGI NAVBAR */ <h3 class="counter" data-target="{{ $jumlahTpa }}">0</h3>
z-index: 400 !important; <span>TPA</span>
}
.leaflet-bottom {
bottom: 0px !important;
}
/* =============================
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;
}
.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> </div>
<!-- MAP -->
<div class="container" data-aos="fade-up">
<div class="map-wrapper">
<div id="mapTPS"></div>
</div> </div>
</div> </div>
</div>
</div>
</section> </section>
<script> <section id="faq" class="faq section">
// =============================
// INIT MAP
// =============================
var map = L.map('mapTPS', {
zoomControl: true
}).setView([-7.6078, 111.903], 12);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { <div class="container-fluid">
attribution: "© OpenStreetMap contributors",
maxZoom: 19
}).addTo(map);
// ============================= <div class="row gy-4 justify-content-center">
// 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]
});
}
var iconTPS = markerIcon('green'); // TPS <div class="order-2 col-lg-7 d-flex flex-column justify-content-center order-lg-1">
var iconTPS3R = markerIcon('blue'); // TPS 3R
var iconTPA = markerIcon('red'); // TPA
var iconDefault = markerIcon('black');
// ============================= <div class="text-center content px-xl-6" data-aos="fade-up" data-aos-delay="100">
// DATA TPS DARI DATABASE <h3><span>Pertanyaan yang Sering </span><strong>Diajukan</strong></h3>
// =============================
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>
<p> <p>
Jika Anda menemukan TPS yang penuh, kotor, atau bermasalah, Berikut adalah beberapa pertanyaan yang sering diajukan oleh pengguna terkait
silakan laporkan agar dapat segera ditindaklanjuti oleh petugas. informasi, fitur, dan layanan pada website.
</p> </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>
<div class="info-item d-flex"> <div class="faq-container px-xl-5" data-aos="fade-up" data-aos-delay="200">
<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"> <!-- FAQ 1 -->
<i class="flex-shrink-0 bi bi-chat-dots-fill"></i> <div class="faq-item faq-active">
<div> <i class="faq-icon bi bi-question-circle"></i>
<h4>Ditanggapi Admin</h4> <h3>Apa tujuan utama website ini?</h3>
<p>Aduan akan diproses oleh admin terkait.</p> <div class="faq-content">
</div> <p>
</div> Website ini bertujuan untuk menyediakan informasi yang akurat dan mudah diakses
</div> oleh masyarakat mengenai lokasi dan data Tempat Pembuangan Sampah (TPS). Dengan adanya
</div> website ini, diharapkan masyarakat dapat lebih memahami kondisi
TPS serta mendukung pengelolaan lingkungan yang lebih baik.
<!-- 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> </p>
{{-- <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>
<p class="my-2 small text-muted">atau</p> --}}
<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>
<i class="faq-toggle bi bi-chevron-right"></i>
</div><!-- End Faq item-->
<!-- 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-->
</div> </div>
</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> </section>
@endsection @endsection

View File

@ -22,10 +22,10 @@
*/ */
Route::get('/', function () { 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', [AboutController::class, 'index'])->name('user.about');
Route::get('/about/{id}', [AboutController::class, 'show'])->name('user.about.kategori'); 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::get('/kontak', [KontakController::class, 'index'])->name('user.kontak');
/*
|--------------------------------------------------------------------------
| ROUTE AUTH (LARAVEL BREEZE)
|--------------------------------------------------------------------------
|
| Login : /login
| Logout : /logout
|
*/
require __DIR__.'/auth.php'; require __DIR__.'/auth.php';
/* /*