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(
'totalTps',
'totalAduan',
'sampahTerbaru'
));
}
return view('admin.index', compact(
'totalTps',
'totalAduan',
'sampahTerbaru'
));
}
} }

View File

@ -10,140 +10,241 @@
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'));
{
$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 $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) public function create()
{ {
$title = 'Edit TPS'; $title = 'Tambah TPS';
$tps = LokasiTps::findOrFail($id); $kategori = KategoriTps::all();
$kategori = KategoriTps::all();
return view('admin.tps.edit', compact('title', 'tps', 'kategori')); return view('admin.tps.create', compact('title', '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();
} }
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); | KONVERSI KOORDINAT (DECIMAL / DMS)
if ($tps->foto_tps) { |--------------------------------------------------------------------------
Storage::disk('public')->delete($tps->foto_tps); */
} private function convertToDecimal($coordinate)
$tps->delete(); {
return redirect()->route('admin.tps.index') if (is_numeric($coordinate)) {
->with('success', 'Data TPS berhasil dihapus'); 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(); $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,63 +1,106 @@
@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>
@if (session('success')) <h4 class="mb-4 card-title">Profil Admin</h4>
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
<form action="{{ route('admin.profil.update') }}" method="POST"> @if (session('success'))
@csrf <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>
<div class="form-group"> <!-- KANAN : FORM -->
<label>Username</label> <div class="col-md-8">
<input type="text" name="username" class="form-control" value="{{ $admin->username }}"
required> <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>
</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> </div>
</div> </div>
</div>
@endsection @endsection

View File

@ -1,119 +1,141 @@
@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">
<div class="card-body"> <div class="card-body">
<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()) <form action="{{ route('admin.tps.store') }}" method="POST" enctype="multipart/form-data">
<div class="alert alert-danger"> @csrf
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- 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"> <!-- ALAMAT -->
@csrf <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 --> <!-- KATEGORI -->
<div class="form-group"> <div class="form-group">
<label>Nama TPS</label> <label>Kategori TPS</label>
<input type="text" name="nama_tps" class="form-control" placeholder="Nama TPS" required> <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>
<div class="form-group"> @error('foto_tps')
<label>Alamat</label> <small class="text-danger">{{ $message }}</small>
<input type="text" name="alamat_tps" class="form-control" placeholder="Alamat TPS" @enderror
required> </div>
</div>
<div class="form-group"> <button type="submit" class="mr-2 btn btn-primary">Simpan</button>
<label>Kecamatan</label> <a href="{{ route('admin.tps.index') }}" class="btn btn-light">Batal</a>
<input type="text" name="kecamatan" class="form-control" placeholder="Kecamatan TPS" </form>
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 }}">
{{ $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> </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,140 +21,172 @@ 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">
<div class="card-body"> <div class="card-body">
<h4 class="card-title">Edit Data TPS</h4> <h4 class="card-title">Edit Data TPS</h4>
<p class="card-description"> <p class="card-description">
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" @csrf
class="forms-sample"> @method('PUT')
@csrf
@method('PUT')
{{-- 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" <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>
</div> @error('nama_tps')
<small class="text-danger">{{ $message }}</small>
{{-- Alamat --}} @enderror
<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>
</div> </div>
{{-- Foto Lama --}} {{-- Alamat --}}
@if ($tps->foto_tps) <div class="form-group">
<div class="mt-2"> <label>Alamat</label>
<img src="{{ asset('storage/' . $tps->foto_tps) }}" <input type="text" name="alamat_tps" class="form-control"
width="250" value="{{ old('alamat_tps') ?? $tps->alamat_tps }}" required>
class="img-thumbnail"> @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> </div>
@endif
</div>
{{-- Button --}} @error('foto_tps')
<button type="submit" class="mr-2 btn btn-primary"> <small class="text-danger">{{ $message }}</small>
Simpan @enderror
</button>
<a href="{{ route('admin.tps.index') }}" class="btn btn-light">
Batal
</a>
</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> </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>
</div><!-- End Tab 1 Content -->
</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
</h2>
<p class="geo-desc">
Menampilkan jumlah fasilitas persampahan berbasis
Sistem Informasi Geografis secara terintegrasi.
</p>
</div>
.map-wrapper { <!-- KANAN -->
width: 100%; <div class="col-lg-7">
max-width: 1100px; <div class="geo-stats">
border-radius: 12px;
overflow: hidden;
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
position: relative;
}
#mapTPS { <div class="geo-item">
width: 100%; <div class="geo-icon">
height: 450px; <i class="bi bi-trash"></i>
position: relative; </div>
z-index: 1; <h3 class="counter" data-target="{{ $jumlahTps }}">0</h3>
} <span>TPS</span>
</div>
.leaflet-popup-content-wrapper { <div class="geo-line"></div>
border-radius: 14px !important;
}
/* ============================= <div class="geo-item">
FIX LEAFLET VS NAVBAR <div class="geo-icon recycle">
============================= */ <i class="bi bi-recycle"></i>
header, </div>
.navbar, <h3 class="counter" data-target="{{ $jumlahTps3r }}">0</h3>
#header { <span>TPS 3R</span>
position: sticky; </div>
top: 0;
z-index: 1000;
background: #fff;
}
/* paksa semua control leaflet turun dari navbar */ <div class="geo-line"></div>
.leaflet-top {
top: 0px !important;
/* SESUAIKAN TINGGI NAVBAR */
z-index: 400 !important;
}
.leaflet-bottom { <div class="geo-item">
bottom: 0px !important; <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>
/* ============================= </div>
Legend </div>
============================= */
.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>
<!-- MAP -->
<div class="container" data-aos="fade-up">
<div class="map-wrapper">
<div id="mapTPS"></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 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>
</div>
<!-- KANAN: CTA BUTTON --> <div class="faq-container px-xl-5" data-aos="fade-up" data-aos-delay="200">
<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>
{{-- <a href="#map" class="mb-2 btn btn-outline-success w-100"> <!-- FAQ 1 -->
<i class="bi bi-map-fill me-1"></i> Pilih TPS di Peta <div class="faq-item faq-active">
</a> <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> </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';
/* /*