Compare commits

2 Commits
Author SHA1 Message Date
Althaf a48d6d75b6 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-06-02 16:34:29 +07:00
Althaf 1d37da0edc update: sanity check 2026-06-02 16:32:20 +07:00
24 changed files with 224 additions and 1620 deletions
@@ -4,13 +4,8 @@ namespace App\Http\Controllers\Web\Dashboard;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Profile;
use App\Models\Wilayah\Provinsi;
use App\Models\wilayah\KabupatenKota;
use App\Models\Wilayah\Kecamatan;
use App\Models\Wilayah\DesaKelurahan;
use App\Models\Pertanian\Lahan;
use Illuminate\Support\Facades\Gate;
class SummaryController extends Controller
{
public function index()
@@ -21,128 +16,4 @@ class SummaryController extends Controller
$title = 'Summary Dashboard';
return view('dashboard.summary', compact('title'));
}
public function produktivitasBackup(Request $request)
{
if (!Gate::allows('super_admin') && !Gate::allows('admin')) {
abort(403);
}
$title = 'Produktivitas Dashboard';
$luasTotal = Lahan::whereNotNull('path')->sum('luas_lahan');
$totalpetani = Profile::where('role', 'petani')->count();
$totallahan = Lahan::whereNotNull('path')->count();
$petaniList = Profile::where('role', 'petani')
->with(['lahan.tanaman.komoditas', 'desaKelurahan'])
->paginate(20);
$allLahan = Lahan::whereNotNull('path')
->with(['profile', 'tanaman.komoditas', 'desaKelurahan.kecamatan.kabupatenKota.provinsi'])
->get()
->map(function($lahan) {
return [
'id' => $lahan->id,
'polygon' => $lahan->path,
'nama_petani' => $lahan->profile->nama ?? 'N/A',
'luas' => $lahan->luas_lahan,
'tanaman' => $lahan->tanaman->map(fn($t) => $t->komoditas->nama ?? null)->filter()->unique()->values()
];
});
return view('dashboard.produktivitas', compact('title', 'petaniList', 'allLahan', 'totalpetani', 'totallahan', 'luasTotal'));
}
public function produktivitas(Request $request)
{
if (!Gate::allows('super_admin') && !Gate::allows('admin')) {
abort(403);
}
$title = 'Produktivitas Dashboard';
$luasTotal = Lahan::whereNotNull('path')->sum('luas_lahan');
$totalpetani = Profile::where('role', 'petani')->count();
$totallahan = Lahan::whereNotNull('path')->count();
$petaniList = Profile::where('role', 'petani')
->with(['lahan.tanaman.komoditas', 'desaKelurahan'])
->paginate(20);
$allLahan = Lahan::whereNotNull('path')
->with(['profile', 'tanaman.komoditas', 'desaKelurahan.kecamatan.kabupatenKota.provinsi'])
->get();
// Penampung data per level (menggunakan ID sebagai key agar unique)
$geoProvinsi = [];
$geoKabupaten = [];
$geoKecamatan = [];
$geoDesa = [];
$geoLahan = [];
foreach ($allLahan as $lahan) {
$desa = $lahan->desaKelurahan;
$kec = $desa ? $desa->kecamatan : null;
$kab = $kec ? $kec->kabupatenKota : null;
$prov = $kab ? $kab->provinsi : null;
// --- Akumulasi Provinsi ---
if ($prov && $prov->path) {
if (!isset($geoProvinsi[$prov->id])) {
$geoProvinsi[$prov->id] = ['id' => $prov->id, 'nama' => $prov->nama, 'polygon' => $prov->path, 'total_lahan' => 0, 'total_luas' => 0];
}
$geoProvinsi[$prov->id]['total_lahan']++;
$geoProvinsi[$prov->id]['total_luas'] += $lahan->luas_lahan;
}
// --- Akumulasi Kabupaten ---
if ($kab && $kab->path) {
if (!isset($geoKabupaten[$kab->id])) {
$geoKabupaten[$kab->id] = ['id' => $kab->id, 'parent_id' => $prov->id ?? null, 'nama' => $kab->nama, 'polygon' => $kab->path, 'total_lahan' => 0, 'total_luas' => 0];
}
$geoKabupaten[$kab->id]['total_lahan']++;
$geoKabupaten[$kab->id]['total_luas'] += $lahan->luas_lahan;
}
// --- Akumulasi Kecamatan ---
if ($kec && $kec->path) {
if (!isset($geoKecamatan[$kec->id])) {
$geoKecamatan[$kec->id] = ['id' => $kec->id, 'parent_id' => $kab->id ?? null, 'nama' => $kec->nama, 'polygon' => $kec->path, 'total_lahan' => 0, 'total_luas' => 0];
}
$geoKecamatan[$kec->id]['total_lahan']++;
$geoKecamatan[$kec->id]['total_luas'] += $lahan->luas_lahan;
}
// --- Akumulasi Desa ---
if ($desa && $desa->path) {
if (!isset($geoDesa[$desa->id])) {
$geoDesa[$desa->id] = ['id' => $desa->id, 'parent_id' => $kec->id ?? null, 'nama' => $desa->nama, 'polygon' => $desa->path, 'total_lahan' => 0, 'total_luas' => 0];
}
$geoDesa[$desa->id]['total_lahan']++;
$geoDesa[$desa->id]['total_luas'] += $lahan->luas_lahan;
}
// Data Lahan Tetap
$geoLahan[] = [
'id' => $lahan->id,
'parent_id' => $desa->id ?? null,
'polygon' => $lahan->path,
'nama_petani' => $lahan->profile->nama ?? 'N/A',
'luas' => $lahan->luas_lahan,
'tanaman' => $lahan->tanaman->map(fn($t) => $t->komoditas->nama ?? null)->filter()->unique()->values()
];
}
return view('dashboard.produktivitas', [
'title' => $title,
'petaniList' => $petaniList,
'totalpetani' => $totalpetani,
'totallahan' => $totallahan,
'luasTotal' => $luasTotal,
// Reset key array agar menjadi format list normal untuk JSON
'geoProvinsi' => array_values($geoProvinsi),
'geoKabupaten' => array_values($geoKabupaten),
'geoKecamatan' => array_values($geoKecamatan),
'geoDesa' => array_values($geoDesa),
'geoLahan' => $geoLahan
]);
}
}
@@ -15,13 +15,13 @@ class AuthController extends Controller
public function login()
{
$title = 'Login';
return view('konfigurasi.auth.login', compact('title'));
return view('auth.login', compact('title'));
}
public function register()
{
$title = 'Register';
return view('konfigurasi.auth.register', compact('title'));
return view('auth.register', compact('title'));
}
public function createAccount(Request $request)
@@ -42,7 +42,7 @@ class AuthController extends Controller
'deleted_by' => null,
]);
return redirect()->route('konfigurasi.auth.login')->with('success', 'Account created successfully. Please login.');
return redirect()->route('auth.login')->with('success', 'Account created successfully. Please login.');
}
public function verify(User $user)
@@ -1,21 +0,0 @@
<?php
namespace App\Http\Controllers\Web\Konfigurasi;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\Profile;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
class ProfileController extends Controller
{
public function index()
{
$userid = auth()->user()->id;
$profile = Profile::where('user_id', $userid)->first();
$title = 'Profile';
return view('konfigurasi.profile.index', compact('title', 'profile'));
}
}
+4 -4
View File
@@ -38,22 +38,22 @@ class Lahan extends Model
'path' => 'array',
];
public function profile()
public function profile(): BelongsTo
{
return $this->belongsTo(Profile::class, 'profile_id');
}
public function desaKelurahan()
public function desaKelurahan(): BelongsTo
{
return $this->belongsTo(DesaKelurahan::class, 'desa_kelurahan_id');
}
public function adat()
public function adat(): BelongsTo
{
return $this->belongsTo(Adat::class, 'adat_pemilik_id');
}
public function tanaman()
public function tanaman(): HasMany
{
return $this->hasMany(Tanaman::class, 'lahan_id');
}
-3
View File
@@ -7,9 +7,6 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use App\Models\Pertanian\Komoditas;
use App\Models\Pertanian\Lahan;
use App\Models\Profile;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Tanaman extends Model
{
+1 -8
View File
@@ -4,11 +4,9 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Models\User;
use App\Models\Pertanian\Lahan;
use App\Models\Wilayah\DesaKelurahan;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Profile extends Model
{
@@ -45,9 +43,4 @@ class Profile extends Model
{
return $this->belongsTo(User::class, 'user_id');
}
public function lahan(): HasMany
{
return $this->hasMany(Lahan::class, 'profile_id');
}
}
+70
View File
@@ -0,0 +1,70 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
use App\Models\Wilayah\Provinsi;
use App\Models\Wilayah\KabupatenKota;
use App\Models\Wilayah\Kecamatan;
use App\Models\Wilayah\DesaKelurahan;
class WilayahDashboard extends Component
{
public function render(): View|Closure|string
{
$kodeJawa = ['31', '32', '33', '34', '35', '36'];
$totalProvinsi = Provinsi::count();
$totalKabKota = KabupatenKota::count();
$totalKecamatan = Kecamatan::count();
$totalDesaKelurahan = DesaKelurahan::count();
$provinsiAktif = Provinsi::has('kabupatenKota')->count();
$provinsiKosong = $totalProvinsi - $provinsiAktif;
$totalKabupaten = KabupatenKota::whereRaw("SUBSTRING(kode, 3, 2) < '70'")->count();
$totalKota = KabupatenKota::whereRaw("SUBSTRING(kode, 3, 2) >= '70'")->count();
if ($totalKabupaten == 0 && $totalKota == 0 && $totalKabKota > 0) {
$totalKabupaten = $totalKabKota;
}
$kecamatanPerdesaan = Kecamatan::whereHas('kabupatenKota', function($query) {
$query->whereRaw("SUBSTRING(kode, 3, 2) < '70'");
})->count();
$kecamatanPerkotaan = max(0, $totalKecamatan - $kecamatanPerdesaan);
$terpetakan = DesaKelurahan::whereNotNull('path')->count();
$belumTerpetakan = max(0, $totalDesaKelurahan - $terpetakan);
$totalDesa = DesaKelurahan::where('nama', 'like', 'DESA%')->count() ?: $totalDesaKelurahan;
$totalKelurahan = DesaKelurahan::where('nama', 'like', 'KEL%')->count();
$data = [
'totalProvinsi' => $totalProvinsi,
'provinsiAktif' => $provinsiAktif,
'provinsiKosong' => $provinsiKosong,
'totalKabKota' => $totalKabKota,
'totalKabupaten' => $totalKabupaten,
'totalKota' => $totalKota,
'totalKecamatan' => $totalKecamatan,
'kecamatanPerdesaan' => $kecamatanPerdesaan,
'kecamatanPerkotaan' => $kecamatanPerkotaan,
'totalDesaKelurahan' => $totalDesaKelurahan,
'totalDesa' => $totalDesa,
'totalKelurahan' => $totalKelurahan,
'terpetakan' => $terpetakan,
'belumTerpetakan' => $belumTerpetakan,
];
return view('components.wilayah-dashboard', $data);
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

+1 -1
View File
@@ -4,7 +4,7 @@
<div class="card-body">
<!-- Logo -->
<div class="app-brand justify-content-center mb-6">
<a href="{{ route('dashboard.produktivitas') }}" class="app-brand-link">
<a href="{{ route('dashboard.summary') }}" class="app-brand-link">
<span class="app-brand-logo demo">
<span class="text-primary">
<svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg">
@@ -0,0 +1,28 @@
@props(['title', 'mainCount', 'icon', 'color' => 'primary', 'subLabel1', 'subCount1', 'subLabel2', 'subCount2'])
<div class="card h-100 shadow-sm border-0">
<div class="card-body p-3">
<div class="d-flex justify-content-between align-items-start mb-3">
<div>
<p class="text-muted fw-medium mb-1 small text-uppercase">{{ $title }}</p>
<h3 class="mb-0 fw-bold text-secondary">{{ number_format($mainCount, 0, ',', '.') }}</h3>
</div>
<div class="badge bg-label-{{ $color }} p-2 rounded">
<i class="ti tabler-{{ $icon }}" style="font-size: 1.5rem;"></i>
</div>
</div>
<div class="bg-lighter rounded p-2 mt-auto">
<div class="row text-center gx-0">
<div class="col-6 border-end">
<span class="text-muted d-block" style="font-size: 0.75rem;">{{ $subLabel1 }}</span>
<span class="fw-semibold text-dark small">{{ number_format($subCount1, 0, ',', '.') }}</span>
</div>
<div class="col-6">
<span class="text-muted d-block" style="font-size: 0.75rem;">{{ $subLabel2 }}</span>
<span class="fw-semibold text-dark small">{{ number_format($subCount2, 0, ',', '.') }}</span>
</div>
</div>
</div>
</div>
</div>
@@ -0,0 +1,50 @@
<div class="row g-3 mb-4">
<div class="col-12 col-sm-6 col-xl-3">
<x-wilayah-card
title="TOTAL PROVINSI"
:mainCount="$totalProvinsi"
icon="map-pin"
color="primary"
subLabel1="Data Aktif"
:subCount1="$provinsiAktif"
subLabel2="Data Kosong"
:subCount2="$provinsiKosong"
/>
</div>
<div class="col-12 col-sm-6 col-xl-3">
<x-wilayah-card
title="Kabupaten & Kota"
mainCount="{{ $totalKabKota }}"
icon="building-skyscraper"
color="info"
subLabel1="Kabupaten"
subCount1="{{ $totalKabupaten }}"
subLabel2="Kota"
subCount2="{{ $totalKota }}"
/>
</div>
<div class="col-12 col-sm-6 col-xl-3">
<x-wilayah-card
title="TOTAL KECAMATAN"
:mainCount="$totalKecamatan"
icon="map-pin"
color="warning"
subLabel1="Zona Perdesaan"
:subCount1="$kecamatanPerdesaan"
subLabel2="Zona Perkotaan"
:subCount2="$kecamatanPerkotaan"
/>
</div>
<div class="col-12 col-sm-6 col-xl-3">
<x-wilayah-card
title="DESA & KELURAHAN"
:mainCount="$totalDesaKelurahan"
icon="home-2"
color="success"
subLabel1="Terpetakan"
:subCount1="$terpetakan"
subLabel2="Blm Pemetaan"
:subCount2="$belumTerpetakan"
/>
</div>
</div>
@@ -1,619 +0,0 @@
@extends('layout.main')
@push('style')
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<style>
body { background-color: #f8faf9; font-family: 'Public Sans', sans-serif; }
.card { border: none; border-radius: 15px; box-shadow: 0 4px 20px rgba(0,0,0,0.05); }
/* Map Container */
#map { height: 600px; width: 100%; border-radius: 15px; }
/* Sidebar Mini Stats */
.stat-card-mini { transition: all 0.3s ease; border-left: 5px solid transparent; }
.stat-card-mini:hover { transform: translateX(5px); border-left-color: var(--agri-green); }
/* Map Switcher Manual */
.map-controls-custom {
position: absolute; top: 20px; right: 20px; z-index: 1000;
background: white; padding: 5px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
/* Table Styling */
.table thead th { background-color: #f8f9fa; text-transform: uppercase; font-size: 11px; letter-spacing: 1px; }
.avatar-label { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; border-radius: 10px; font-weight: bold; }
.leaflet-tooltip.leaflet-modern-tooltip {
background-color: transparent;
border: none;
box-shadow: none;
padding: 0;
color: #333;
font-family: 'Public Sans', sans-serif; /* Pastikan font dashboard Anda */
}
/* Menghilangkan panah kecil di bawah tooltip */
.leaflet-modern-tooltip:before {
border: none !important;
}
/* 2. Gaya untuk Modern Map Card kita */
.modern-map-card {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12);
padding: 16px;
width: 190px; /* Lebar card */
border: 1px solid rgba(0,0,0,0.05);
}
/* Bagian Header */
.card-header-region {
margin-bottom: 8px;
}
.region-label {
font-size: 11px;
text-transform: uppercase;
color: #888;
font-weight: 500;
letter-spacing: 0.5px;
display: block;
margin-bottom: 2px;
}
.region-name {
font-weight: 700;
font-size: 15px;
margin: 0;
color: #1e1e1e;
line-height: 1.2;
}
/* Bagian Stats Row (Flexbox untuk menyusun ikon & teks) */
.d-flex { display: flex; }
.align-items-center { align-items: center; }
.mb-2 { margin-bottom: 8px; }
.me-2 { margin-right: 10px; }
.fw-bold { font-weight: 700; }
.small { font-size: 12px; }
/* Gaya Ikon Baris Statistik */
.stat-icon {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
font-size: 16px;
}
/* Warna Latar Belakang Ringan untuk Ikon (Bootstrap style) */
.bg-success-light { background-color: rgba(40, 167, 69, 0.1); }
.bg-primary-light { background-color: rgba(0, 123, 255, 0.1); }
.text-success { color: #28a745; }
.text-primary { color: #007bff; }
.stat-info {
flex: 1;
}
.stat-value {
font-size: 14px;
color: #222;
line-height: 1;
margin-top: 2px;
}
.text-muted { color: #6c757d; }
/* Bagian Footer Action */
.action-prompt {
font-size: 12px;
}
/* Sedikit animasi pada chevron saat di-hover */
.action-prompt i {
transition: transform 0.2s ease;
}
.leaflet-modern-tooltip:hover .action-prompt i {
transform: translateX(3px);
}
/* Gaya Bootstrap Helper Ringan (untuk jaga-jaga jika dashboard tidak memuatnya) */
.border-top { border-top: 1px solid rgba(0,0,0,0.08) !important; }
.border-bottom { border-bottom: 1px solid rgba(0,0,0,0.08) !important; }
.py-2 { padding-top: 8px !important; padding-bottom: 8px !important; }
.my-2 { margin-top: 8px !important; margin-bottom: 8px !important; }
.leaflet-popup-wrapper.leaflet-modern-popup-wrapper {
box-shadow: none;
}
.leaflet-modern-popup-wrapper .leaflet-popup-content-wrapper {
border-radius: 12px;
padding: 0 !important; /* Hapus padding default Leaflet agar full width */
overflow: hidden;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
border: 1px solid rgba(0,0,0,0.05);
}
.leaflet-modern-popup-wrapper .leaflet-popup-content {
margin: 0 !important;
padding: 0 !important;
}
/* Penyesuaian panah kecil di bawah */
.leaflet-modern-popup-wrapper .leaflet-popup-tip {
background: #f8f9fa; /* Sesuaikan dengan warna body footer popup (bg-light) */
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
/* 2. Gaya untuk Modern Lahan Popup kita */
.modern-lahan-popup {
font-family: 'Public Sans', sans-serif;
min-width: 270px; /* Lebar card */
}
/* Typography Hierarki */
.modern-lahan-popup .h5 { font-size: 16px; margin: 0; }
.modern-lahan-popup .fs-5 { font-size: 1.25rem; }
.modern-lahan-popup small { font-size: 11px; }
/* Header Farmer */
.rounded-top-12 { border-radius: 12px 12px 0 0; }
.header-farmer {
border-bottom: 1px solid rgba(0,0,0,0.06);
}
.label-header {
letter-spacing: 0.5px;
}
.farmer-name {
line-height: 1.2;
}
/* Body Details */
.details-body {
background-color: #f8f9fa;
}
.rounded-bottom-12 { border-radius: 0 0 12px 12px; }
.label-detail {
margin-bottom: 0px;
}
.value-detail {
font-size: 14px;
margin-top: 1px;
line-height: 1.1;
}
.value-commodity {
font-size: 13px;
line-height: 1.2;
}
/* Ikon Container (derived from stats card style) */
.icon-stat-container {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
}
/* Helper Colors (for icons & backgrounds) */
.text-danger-light { color: #dc3545 !important; }
.text-danger { color: #dc3545 !important; }
.text-success { color: #28a745 !important; }
/* Background Ringan (Bootstrap Style) */
.text-success-light { background-color: rgba(40, 167, 69, 0.1) !important; }
.text-danger-light { background-color: rgba(220, 53, 69, 0.1) !important; }
.bg-primary-light { background-color: rgba(0, 123, 255, 0.1) !important; }
/* Bootstrap-like Utilities (untuk berjaga-jaga jika dash belum memuatnya) */
.me-2 { margin-right: 10px !important; }
.mb-3 { margin-bottom: 16px !important; }
.ps-2 { padding-left: 12px !important; }
.col-6 { width: 50%; }
.col-12 { width: 100%; }
.border { border: 1px solid rgba(0,0,0,0.08) !important; }
</style>
@endpush
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
<div class="row">
<div class="col-lg-3">
<div class="card mb-3 stat-card-mini">
<div class="card-body">
<div class="d-flex justify-content-between">
<div class="avatar bg-label-success rounded p-2"><i class="ti tabler-mountain fs-3"></i></div>
<!-- <span class="badge bg-label-success">+2.4%</span> -->
</div>
<div class="mt-3">
<small class="text-muted text-uppercase">Total Land Area</small>
<h4 class="mb-0 fw-bold">{{ number_format($luasTotal, 1) }} <small class="text-muted">ha</small></h4>
</div>
</div>
</div>
<div class="card mb-3 stat-card-mini">
<div class="card-body">
<div class="d-flex justify-content-between">
<div class="avatar bg-label-success rounded p-2"><i class="ti tabler-map fs-3"></i></div>
<!-- <span class="badge bg-label-success"></span> -->
</div>
<div class="mt-3">
<small class="text-muted text-uppercase">Total Lahan</small>
<h4 class="mb-0 fw-bold">{{ $totallahan }}</h4>
</div>
</div>
</div>
<div class="card mb-3 stat-card-mini">
<div class="card-body">
<div class="d-flex justify-content-between">
<div class="avatar bg-label-primary rounded p-2"><i class="ti tabler-users fs-3"></i></div>
<span class="badge bg-success text-white text-center">Active</span>
</div>
<div class="mt-3">
<small class="text-muted text-uppercase">Registered Farmers</small>
<h4 class="mb-0 fw-bold">{{ $totalpetani }}</h4>
</div>
</div>
</div>
<div class="card mb-4">
<div class="card-header"><h6 class="mb-0 fw-bold">Distribusi Komoditas</h6></div>
<div class="card-body">
@foreach(['Vanilla' => 45, 'Candlenut' => 30, 'Cocoa' => 15, 'Coffee' => 10] as $name => $val)
<div class="mb-3">
<div class="d-flex justify-content-between mb-1">
<small class="fw-bold">{{ $name }}</small>
<small class="text-muted">{{ $val }}%</small>
</div>
<div class="progress" style="height: 6px;">
<div class="progress-bar bg-success" style="width: {{ $val }}%"></div>
</div>
</div>
@endforeach
</div>
</div>
</div>
<div class="col-lg-9">
<div class="card mb-4 overflow-hidden position-relative">
<div class="card-header d-flex justify-content-between align-items-center bg-white py-3">
<h6 class="mb-0 fw-bold"><i class="ti tabler-map-2 me-2"></i>Peta Sebaran Lahan</h6>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-secondary active" onclick="setMapLayer('satellite')">Satellite</button>
<button class="btn btn-outline-secondary" onclick="setMapLayer('topo')">Topographic</button>
<button class="btn btn-outline-secondary" onclick="setMapLayer('parcels')">Parcels</button>
</div>
</div>
<div id="map">
<button id="btnBackMap" class="btn btn-sm btn-dark shadow" style="display:none; position:absolute; top:20px; left:50px; z-index:1000;">
<i class="ti tabler-arrow-left me-1"></i> Kembali ke Atas
</button>
</div>
</div>
<div class="card">
<div class="card-header border-bottom d-flex justify-content-between align-items-center">
<h6 class="mb-0 fw-bold">Produktivitas Petani Regional</h6>
<button class="btn btn-sm btn-success"><i class="ti tabler-plus me-1"></i> Bulk Action</button>
</div>
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead>
<tr>
<th>Nama Petani</th>
<th>ID Lahan</th>
<th>Komoditas</th>
<th>Luas (HA)</th>
<th>Status</th>
</tr>
</thead>
<tbody>
@foreach($petaniList as $p)
<tr>
<td>
<div class="d-flex align-items-center">
<div class="avatar-label bg-label-secondary me-2">{{ substr($p->nama, 0, 1) }}</div>
<span class="fw-bold">{{ $p->nama }}</span>
</div>
</td>
<td><span class="text-muted small">TR-{{ $p->id }}</span></td>
<td><span class="badge bg-label-info">Vanilla</span></td>
<td class="fw-bold">{{ number_format($p->lahan->sum('luas_lahan'), 1) }}</td>
<td><span class="badge bg-success">Verified</span></td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
var satellite = L.tileLayer('https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', { maxZoom: 22 });
var topo = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png');
var parcels = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png');
var map = L.map('map', { center: [-0.789, 113.921], zoom: 5, layers: [satellite], zoomControl: false });
L.control.zoom({ position: 'topleft' }).addTo(map);
function setMapLayer(type) {
map.removeLayer(satellite); map.removeLayer(topo); map.removeLayer(parcels);
if(type === 'satellite') satellite.addTo(map);
if(type === 'topo') topo.addTo(map);
if(type === 'parcels') parcels.addTo(map);
event.target.parentElement.querySelectorAll('.btn').forEach(b => b.classList.remove('active'));
event.target.classList.add('active');
}
// 2. Data dari Server
var dataLevels = {
'provinsi': @json($geoProvinsi),
'kabupaten': @json($geoKabupaten),
'kecamatan': @json($geoKecamatan),
'desa': @json($geoDesa),
'lahan': @json($geoLahan)
};
var currentLayerGroup = L.featureGroup().addTo(map);
var mapHistory = [];
var btnBack = document.getElementById('btnBackMap');
function ensureLatLon(coords) {
if (typeof coords[0] === 'number') {
if (Math.abs(coords[0]) > 90) {
return [coords[1], coords[0]];
}
return [coords[0], coords[1]];
}
return coords.map(ensureLatLon);
}
function renderLevel(level, parentId = null, fallbackBounds = null) {
var dataToRender = dataLevels[level];
if (parentId !== null) {
dataToRender = dataToRender.filter(item => item.parent_id == parentId);
}
if (dataToRender.length === 0) {
alert(`Belum ada data pemetaan ${level} yang terdaftar di wilayah ini.`);
if (mapHistory.length > 0) {
mapHistory.pop();
}
return;
}
currentLayerGroup.clearLayers();
if (level === 'lahan' && parentId !== null) {
var parentDesa = dataLevels['desa'].find(d => d.id == parentId);
if (parentDesa && parentDesa.polygon) {
try {
var desaGeojson = typeof parentDesa.polygon === 'string' ? JSON.parse(parentDesa.polygon) : parentDesa.polygon;
var desaLayer;
var desaStyle = {
color: '#dc3545',
weight: 2,
dashArray: '5, 8',
fillColor: 'none',
interactive: false
};
if (desaGeojson !== null && typeof desaGeojson === 'object' && desaGeojson.type) {
desaLayer = L.geoJSON(desaGeojson, {
style: desaStyle,
coordsToLatLng: function (coords) {
var a = coords[0], b = coords[1];
if (Math.abs(a) > 90) return L.latLng(b, a);
if (Math.abs(b) > 90) return L.latLng(a, b);
return L.latLng(b, a);
}
});
} else if (Array.isArray(desaGeojson)) {
var safeCoordsDesa = ensureLatLon(desaGeojson);
desaLayer = L.polygon(safeCoordsDesa, desaStyle);
}
if (desaLayer) {
currentLayerGroup.addLayer(desaLayer);
}
} catch (e) {
console.error("Gagal render batas desa:", e);
}
}
}
dataToRender.forEach(function(item) {
if (!item.polygon) return;
try {
var geojsonData = typeof item.polygon === 'string' ? JSON.parse(item.polygon) : item.polygon;
var layer;
var styleOpts = level === 'lahan'
? { color: '#28a745', weight: 2, fillColor: '#28a745', fillOpacity: 0.6 }
: { color: '#f39c12', weight: 2, fillColor: '#f1c40f', fillOpacity: 0.3 };
if (geojsonData !== null && typeof geojsonData === 'object' && geojsonData.type) {
layer = L.geoJSON(geojsonData, {
style: styleOpts,
coordsToLatLng: function (coords) {
var a = coords[0], b = coords[1];
if (Math.abs(a) > 90) return L.latLng(b, a);
if (Math.abs(b) > 90) return L.latLng(a, b);
return L.latLng(b, a);
}
});
} else if (Array.isArray(geojsonData)) {
var safeCoords = ensureLatLon(geojsonData);
layer = L.polygon(safeCoords, styleOpts);
}
if (layer) {
if (level === 'lahan') {
var listTanaman = item.tanaman && item.tanaman.length > 0 ? item.tanaman.join(', ') : null;
var komoditasText = listTanaman
? listTanaman
: '<span class="text-danger-light fw-medium small">Belum terdaftar</span>';
var cropIcon = listTanaman ? 'ti tabler-plant' : 'ti tabler-leaf-off';
var cropIconColor = listTanaman ? 'text-success' : 'text-danger';
var popupContent = `
<div class="modern-lahan-popup">
<div class="p-3 bg-white rounded-top-12 header-farmer">
<div class="d-flex align-items-center mb-1">
<small class="label-header text-uppercase text-muted fw-semibold">Pemilik Lahan</small>
</div>
<h6 class="mb-0 fw-bold farmer-name h5">${item.nama_petani}</h6>
</div>
<div class="p-3 bg-light rounded-bottom-12 details-body">
<div class="row g-2 mb-3">
<div class="col-12 d-flex align-items-center">
<div class="icon-stat-container rounded-circle bg-white text-muted border me-2">
<i class="ti tabler-hash fs-5"></i>
</div>
<div>
<small class="d-block text-muted text-uppercase fw-medium label-detail">ID Lahan</small>
<span class="fw-bold text-dark value-detail">TR-${item.id}</span>
</div>
</div>
</div>
<div class="row g-1">
<div class="col-6 d-flex align-items-center">
<div class="icon-stat-container rounded ${cropIconColor}-light me-2">
<i class="${cropIcon} fs-5 ${cropIconColor}"></i>
</div>
<div class="flex-grow-1">
<small class="d-block text-muted text-uppercase fw-medium label-detail">Komoditas</small>
<span class="fw-semibold text-dark value-commodity">${komoditasText}</span>
</div>
</div>
<div class="col-6 d-flex align-items-center border-start ps-2">
<div class="icon-stat-container rounded bg-primary-light me-2">
<i class="ti tabler-dimensions fs-5 text-primary"></i>
</div>
<div>
<small class="d-block text-muted text-uppercase fw-medium label-detail">Luas Lahan</small>
<span class="fw-bold text-dark value-detail">${parseFloat(item.luas).toFixed(1)} Ha</span>
</div>
</div>
</div>
</div>
</div>
`;
layer.bindPopup(popupContent, {
maxWidth: 300,
closeButton: true,
offset: [0, 0],
className: 'leaflet-modern-popup-wrapper'
});
} else {
var tooltipContent = `
<div class="modern-map-card">
<div class="card-header-region">
<span class="region-label">Wilayah</span>
<h6 class="region-name">${item.nama}</h6>
</div>
<div class="card-body-stats border-top border-bottom py-2 my-2">
<div class="stat-row d-flex align-items-center mb-2">
<div class="stat-icon bg-success-light text-success me-2 rounded-p-2">
<i class="ti tabler-map"></i>
</div>
<div class="stat-info">
<small class="text-muted text-uppercase fw-medium" style="font-size: 10px;">Jumlah Lahan</small>
<div class="stat-value fw-bold">${parseInt(item.total_lahan)}</div>
</div>
</div>
<div class="stat-row d-flex align-items-center">
<div class="stat-icon bg-primary-light text-primary me-2 rounded-p-2">
<i class="ti tabler-area"></i>
</div>
<div class="stat-info">
<small class="text-muted text-uppercase fw-medium" style="font-size: 10px;">Total Luas</small>
<div class="stat-value fw-bold">${parseFloat(item.total_luas).toFixed(2)} <small class="text-muted">Ha</small></div>
</div>
</div>
</div>
<div class="card-footer-action text-center mt-2">
<span class="action-prompt text-primary fw-medium small">
Klik untuk detail <i class="ti tabler-chevron-right ms-1"></i>
</span>
</div>
</div>
`;
layer.bindTooltip(tooltipContent, {
sticky: true,
direction: 'top',
className: 'leaflet-modern-tooltip',
offset: [0, -10]
});
layer.on('click', function(e) {
L.DomEvent.stopPropagation(e);
var nextLevel = level === 'provinsi' ? 'kabupaten'
: level === 'kabupaten' ? 'kecamatan'
: level === 'kecamatan' ? 'desa' : 'lahan';
mapHistory.push({ level: level, parentId: parentId, bounds: currentLayerGroup.getBounds() });
renderLevel(nextLevel, item.id, e.target.getBounds());
});
}
currentLayerGroup.addLayer(layer);
}
} catch (e) {
console.error("Gagal memproses data level", level, "ID", item.id, e);
}
});
if (btnBack) btnBack.style.display = mapHistory.length > 0 ? 'block' : 'none';
if (currentLayerGroup.getLayers().length > 0) {
var bounds = currentLayerGroup.getBounds();
if (bounds.isValid()) {
map.fitBounds(bounds, { padding: [30, 30], maxZoom: 18 });
}
} else if (fallbackBounds && fallbackBounds.isValid()) {
map.fitBounds(fallbackBounds, { padding: [30, 30], maxZoom: 18 });
}
}
if (btnBack) {
btnBack.addEventListener('click', function() {
var prevState = mapHistory.pop();
if (prevState) {
renderLevel(prevState.level, prevState.parentId);
if (prevState.bounds && prevState.bounds.isValid()) {
map.fitBounds(prevState.bounds, { padding: [30, 30] });
}
}
});
}
setTimeout(() => {
map.invalidateSize();
// Render Awal: Provinsi
renderLevel('provinsi', null);
}, 300);
</script>
@endpush
+8 -8
View File
@@ -33,14 +33,14 @@
<!-- Header Section -->
<div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-4 mb-6">
<div>
<h2 class="text-2xl font-bold teks-header-judul">
Ringkasan M&E (Theory of Change)
</h2>
<p class="text-sm mt-1 teks-header-sub">
Capaian Utama Transformasi Bioekonomi Desa Ngada
</p>
</div>
<h2 class="text-2xl font-bold teks-header-judul">
Ringkasan M&E (Theory of Change)
</h2>
<p class="text-sm mt-1 teks-header-sub">
Capaian Utama Transformasi Bioekonomi Desa Ngada
</p>
</div>
<div class="flex gap-2">
<button class="bg-white border border-gray-200 text-gray-600 px-4 py-2 rounded-lg text-sm font-medium hover:bg-gray-50 flex items-center gap-2">
<i data-lucide="download" class="w-4 h-4"></i> Export PDF
@@ -1,118 +0,0 @@
<!doctype html>
<html
lang="en"
class=" layout-wide customizer-hide"
dir="ltr"
data-skin="default"
data-bs-theme="light"
data-assets-path="../../assets/"
data-template="vertical-menu-template">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
<meta name="robots" content="noindex, nofollow" />
<title>Agomonev | {{ $title ?? 'Auth' }} </title>
<meta name="description" content="" />
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="../../assets/img/favicon/favicon.ico" />
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&ampdisplay=swap"
rel="stylesheet" />
<link rel="stylesheet" href="{{ asset('assets/vendor/fonts/iconify-icons.css') }}" />
<script src="{{ asset('assets/vendor/libs/@algolia/autocomplete-js.js') }}"></script>
<!-- Core CSS -->
<!-- build:css assets/vendor/css/theme.css -->
<link rel="stylesheet" href="{{ asset('assets/vendor/libs/node-waves/node-waves.css') }}" />
<link rel="stylesheet" href="{{ asset('assets/vendor/libs/pickr/pickr-themes.css') }}" />
<link rel="stylesheet" href="{{ asset('assets/vendor/css/core.css') }}" />
<link rel="stylesheet" href="{{ asset('assets/css/demo.css') }}" />
<!-- Vendors CSS -->
<link rel="stylesheet" href="{{ asset('assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css') }}" />
<!-- endbuild -->
<!-- Vendor -->
<link rel="stylesheet" href="{{ asset('assets/vendor/libs/@form-validation/form-validation.css') }}" />
<!-- Page CSS -->
<!-- Page -->
<link rel="stylesheet" href="{{ asset('assets/vendor/css/pages/page-auth.css') }}" />
<!-- Helpers -->
<script src="{{ asset('assets/vendor/js/helpers.js') }}"></script>
<!--! Template customizer & Theme config files MUST be included after core stylesheets and helpers.js in the <head> section -->
<!--? Template customizer: To hide customizer set displayCustomizer value false in config.js. -->
<script src="{{ asset('assets/vendor/js/template-customizer.js') }}"></script>
<!--? Config: Mandatory theme config file contain global vars & default theme options, Set your preferred theme option in this file. -->
<script src="{{ asset('assets/js/config.js') }}"></script>
</head>
<body>
<!-- Content -->
<div class="container-xxl">
<div class="authentication-wrapper authentication-basic container-p-y">
<div class="authentication-inner py-6">
<!-- Register Card -->
@yield('content')
<!-- Register Card -->
</div>
</div>
</div>
<!-- / Content -->
<!-- Core JS -->
<!-- build:js assets/vendor/js/theme.js -->
<script src="{{ asset('assets/vendor/libs/jquery/jquery.js') }}"></script>
<script src="{{ asset('assets/vendor/libs/popper/popper.js') }}"></script>
<script src="{{ asset('assets/vendor/js/bootstrap.js') }}"></script>
<script src="{{ asset('assets/vendor/libs/node-waves/node-waves.js') }}"></script>
<script src="{{ asset('assets/vendor/libs/pickr/pickr.js') }}"></script>
<script src="{{ asset('assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.js') }}"></script>
<script src="{{ asset('assets/vendor/libs/hammer/hammer.js') }}"></script>
<script src="{{ asset('assets/vendor/libs/i18n/i18n.js') }}"></script>
<script src="{{ asset('assets/vendor/js/menu.js') }}"></script>
<!-- endbuild -->
<!-- Vendors JS -->
<script src="{{ asset('assets/vendor/libs/@form-validation/popular.js') }}"></script>
<script src="{{ asset('assets/vendor/libs/@form-validation/bootstrap5.js') }}"></script>
<script src="{{ asset('assets/vendor/libs/@form-validation/auto-focus.js') }}"></script>
<!-- Main JS -->
<script src="{{ asset('assets/js/main.js') }}"></script>
<!-- Page JS -->
<script src="{{ asset('assets/js/pages-auth.js') }}"></script>
</body>
</html>
@@ -1,89 +0,0 @@
@extends('auth.layout')
@section('content')
<div class="card">
<div class="card-body">
<!-- Logo -->
<div class="app-brand justify-content-center mb-6">
<a href="{{ route('dashboard.produktivitas') }}" class="app-brand-link">
<span class="app-brand-logo demo">
<span class="text-primary">
<svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- Daun Bagian Kiri -->
<path opacity="0.3" d="M16 2.5C16 2.5 5 6.5 5 15.5C5 20.5 11 23.5 16 23.5V2.5Z" fill="currentColor" />
<!-- Daun Bagian Kanan -->
<path opacity="0.6" d="M16 2.5C16 2.5 27 6.5 27 15.5C27 20.5 21 23.5 16 23.5V2.5Z" fill="currentColor" />
<!-- Grafik Pertumbuhan (Monev) -->
<path d="M2 19L10 11L15 15L27 4" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" />
<!-- Titik Target/Pencapaian -->
<circle cx="27" cy="4" r="2.5" fill="currentColor" />
</svg>
</span>
</span>
<span class="app-brand-text demo menu-text fw-bold ms-3" style="text-transform: capitalize;">AgroMonev</span>
</a>
</div>
<!-- /Logo -->
<h4 class="mb-1">Selamat datang di AgroMonev!</h4>
<p class="mb-6">Silakan masuk ke akun Anda</p>
@if ($errors->any())
<div class="alert alert-danger">
<ul class="mb-0">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form id="formAuthentication" class="mb-4" action="{{ route('auth.authenticate') }}" method="POST">
@csrf
<div class="mb-6 form-control-validation">
<label for="email" class="form-label">Email atau Username</label>
<input
type="text"
class="form-control"
id="email"
name="email_username"
placeholder="Masukkan email atau username Anda"
autofocus />
</div>
<div class="mb-6 form-password-toggle form-control-validation">
<label class="form-label" for="password">Password</label>
<div class="input-group input-group-merge">
<input
type="password"
id="password"
class="form-control"
name="password"
placeholder="&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;"
aria-describedby="password" />
<span class="input-group-text cursor-pointer"><i class="icon-base ti tabler-eye-off"></i></span>
</div>
</div>
<div class="my-8">
<div class="d-flex justify-content-between">
<div class="form-check mb-0 ms-2">
<input class="form-check-input" type="checkbox" id="remember-me" />
<label class="form-check-label" for="remember-me"> Remember Me </label>
</div>
<a href="auth-forgot-password-basic.html">
<p class="mb-0">Lupa Password?</p>
</a>
</div>
</div>
<div class="mb-6">
<button class="btn btn-primary d-grid w-100" type="submit">Login</button>
</div>
</form>
<p class="text-center">
<span>Anda belum terdaftar?</span>
<a href="{{ route('register') }}">
<span>Buat akun baru</span>
</a>
</p>
</div>
</div>
@endsection
@@ -1,558 +0,0 @@
@extends('layout.main')
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
<!-- Header -->
<div class="row">
<div class="col-12">
<div class="card mb-6">
<!-- <div class="user-profile-header-banner">
<img src="{{ asset('assets/img/pages/profile-banner.png') }}" alt="Banner image" class="rounded-top" />
</div> -->
<div class="user-profile-header d-flex flex-column flex-lg-row text-sm-start text-center mb-5">
<!-- <div class="flex-shrink-0 mt-n2 mx-sm-0 mx-auto">
<img
src="../../assets/img/avatars/1.png"
alt="user image"
class="d-block h-auto ms-0 ms-sm-6 rounded user-profile-img" />
</div> -->
<div class="flex-grow-1 mt-3 mt-lg-5">
<div
class="d-flex align-items-md-end align-items-sm-start align-items-center justify-content-md-between justify-content-start mx-5 flex-md-row flex-column gap-4">
<div class="user-profile-info">
<h4 class="mb-2 mt-lg-6">{{ $profile->nama ?? 'Guest' }}</h4>
<ul
class="list-inline mb-0 d-flex align-items-center flex-wrap justify-content-sm-start justify-content-center gap-4 my-2">
<li class="list-inline-item d-flex gap-2 align-items-center">
<i class="icon-base ti tabler-circles icon-lg"></i
><span class="fw-medium">{{ $profile->role ?? 'N/A' }}</span>
</li>
<li class="list-inline-item d-flex gap-2 align-items-center">
<i class="icon-base ti tabler-map-pin icon-lg"></i
><span class="fw-medium"> {{ $profile->alamat ?? 'N/A' }} </span>
</li>
<li class="list-inline-item d-flex gap-2 align-items-center">
<i class="icon-base ti tabler-calendar icon-lg"></i
><span class="fw-medium"> {{ $profile->created_at->format('F j, Y') ?? 'N/A' }}</span>
</li>
</ul>
</div>
<a href="javascript:void(0)" class="btn btn-primary mb-1">
<i class="icon-base ti tabler-user-check icon-xs me-2"></i>Connected
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!--/ Header -->
<!-- Navbar pills -->
<div class="row">
<div class="col-md-12">
<div class="nav-align-top">
<ul class="nav nav-pills flex-column flex-sm-row mb-6 gap-sm-0 gap-2">
<li class="nav-item">
<a class="nav-link active" href="javascript:void(0);"
><i class="icon-base ti tabler-user-check icon-sm me-1_5"></i> Profile</a
>
</li>
<li class="nav-item">
<a class="nav-link" href="pages-profile-teams.html"
><i class="icon-base ti tabler-lock icon-sm me-1_5"></i> Security</a
>
</li>
<li class="nav-item">
<a class="nav-link" href="pages-profile-projects.html"
><i class="icon-base ti tabler-layout-grid icon-sm me-1_5"></i> Projects</a
>
</li>
<li class="nav-item">
<a class="nav-link" href="pages-profile-connections.html"
><i class="icon-base ti tabler-link icon-sm me-1_5"></i> Connections</a
>
</li>
</ul>
</div>
</div>
</div>
<!--/ Navbar pills -->
<!-- User Profile Content -->
<div class="row">
<div class="col-xl-4 col-lg-5 col-md-5">
<!-- About User -->
<div class="card mb-6">
<div class="card-body">
<p class="card-text text-uppercase text-body-secondary small mb-0">Tentang Pengguna</p>
<ul class="list-unstyled my-3 py-1">
<li class="d-flex align-items-center mb-4">
<i class="icon-base ti tabler-user icon-lg"></i
><span class="fw-medium mx-2">Nama Lengkap:</span> <span>{{ $profile->nama ?? 'N/A' }}</span>
</li>
<li class="d-flex align-items-center mb-4">
<i class="icon-base ti tabler-circles icon-lg"></i><span class="fw-medium mx-2">Role:</span>
<span>{{ $profile->role ?? 'N/A' }}</span>
</li>
<li class="d-flex align-items-center mb-4">
<i class="icon-base ti tabler-layout-collage icon-lg"></i><span class="fw-medium mx-2">Wilayah:</span>
<span>{{ $profile->desa_kelurahan_id ?? 'N/A' }}</span>
</li>
<li class="d-flex align-items-center mb-4">
<i class="icon-base ti tabler-layout-collage icon-lg"></i><span class="fw-medium mx-2">No KTP:</span>
<span>{{ $profile->ktp ?? 'N/A' }}</span>
</li>
<li class="d-flex align-items-center mb-4">
<i class="icon-base ti tabler-layout-collage icon-lg"></i><span class="fw-medium mx-2">No KK:</span>
<span>{{ $profile->kk ?? 'N/A' }}</span>
</li>
</ul>
<p class="card-text text-uppercase text-body-secondary small mb-0">Kontak</p>
<ul class="list-unstyled my-3 py-1">
<li class="d-flex align-items-center mb-4">
<i class="icon-base ti tabler-phone-call icon-lg"></i
><span class="fw-medium mx-2">Telepon:</span>
<span>{{ $profile->telepon ?? 'N/A' }}</span>
</li>
<li class="d-flex align-items-center mb-4">
<i class="icon-base ti tabler-mail icon-lg"></i><span class="fw-medium mx-2">Email:</span>
<span>{{ $profile->email ?? 'N/A' }}</span>
</li>
</ul>
<p class="card-text text-uppercase text-body-secondary small mb-0">Teams</p>
<ul class="list-unstyled mb-0 mt-3 pt-1">
<li class="d-flex flex-wrap mb-4">
<span class="fw-medium me-2">Backend Developer</span><span>(126 Members)</span>
</li>
<li class="d-flex flex-wrap">
<span class="fw-medium me-2">React Developer</span><span>(98 Members)</span>
</li>
</ul>
</div>
</div>
<!--/ About User -->
<!-- Profile Overview -->
<div class="card mb-6">
<div class="card-body">
<p class="card-text text-uppercase text-body-secondary small">Overview</p>
<ul class="list-unstyled mb-0">
<li class="d-flex align-items-center mb-4">
<i class="icon-base ti tabler-plant icon-lg"></i
><span class="fw-medium mx-2">Komoditas:</span> <span>13.5k</span>
</li>
<li class="d-flex align-items-center mb-4">
<i class="icon-base ti tabler-chart-treemap icon-lg"></i
><span class="fw-medium mx-2">Jumlah Lahan:</span> <span>146</span>
</li>
<li class="d-flex align-items-center">
<i class="icon-base ti tabler-map-plus icon-lg"></i
><span class="fw-medium mx-2">Total Luas Lahan:</span> <span>897</span>
</li>
</ul>
</div>
</div>
<!--/ Profile Overview -->
</div>
<div class="col-xl-8 col-lg-7 col-md-7">
<!-- Activity Timeline -->
<div class="card card-action mb-6">
<div class="card-header align-items-center">
<h5 class="card-action-title mb-0">
<i class="icon-base ti tabler-chart-bar-popular icon-lg me-4"></i>Activity Timeline
</h5>
<div class="card-action-element">
<div class="dropdown">
<button
type="button"
class="btn dropdown-toggle hide-arrow p-0 text-body-secondary"
data-bs-toggle="dropdown"
aria-expanded="false"></button>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="javascript:void(0);">Share timeline</a></li>
<li><a class="dropdown-item" href="javascript:void(0);">Suggest edits</a></li>
<li>
<hr class="dropdown-divider" />
</li>
<li><a class="dropdown-item" href="javascript:void(0);">Report bug</a></li>
</ul>
</div>
</div>
</div>
<div class="card-body pt-3">
<ul class="timeline mb-0">
<li class="timeline-item timeline-item-transparent">
<span class="timeline-point timeline-point-primary"></span>
<div class="timeline-event">
<div class="timeline-header mb-3">
<h6 class="mb-0">12 Invoices have been paid</h6>
<small class="text-body-secondary">12 min ago</small>
</div>
<p class="mb-2">Invoices have been paid to the company</p>
<div class="d-flex align-items-center mb-2">
<div class="badge bg-lighter rounded d-flex align-items-center">
<img src="../../assets//img/icons/misc/pdf.png" alt="img" width="15" class="me-2" />
<span class="h6 mb-0 text-body">invoices.pdf</span>
</div>
</div>
</div>
</li>
<li class="timeline-item timeline-item-transparent">
<span class="timeline-point timeline-point-success"></span>
<div class="timeline-event">
<div class="timeline-header mb-3">
<h6 class="mb-0">Client Meeting</h6>
<small class="text-body-secondary">45 min ago</small>
</div>
<p class="mb-2">Project meeting with john @10:15am</p>
<div class="d-flex justify-content-between flex-wrap gap-2 mb-2">
<div class="d-flex flex-wrap align-items-center mb-50">
<div class="avatar avatar-sm me-2">
<img src="../../assets/img/avatars/1.png" alt="Avatar" class="rounded-circle" />
</div>
<div>
<p class="mb-0 small fw-medium">Lester McCarthy (Client)</p>
<small>CEO of Pixinvent</small>
</div>
</div>
</div>
</div>
</li>
<li class="timeline-item timeline-item-transparent">
<span class="timeline-point timeline-point-info"></span>
<div class="timeline-event">
<div class="timeline-header mb-3">
<h6 class="mb-0">Create a new project for client</h6>
<small class="text-body-secondary">2 Day Ago</small>
</div>
<p class="mb-2">6 team members in a project</p>
<ul class="list-group list-group-flush">
<li
class="list-group-item d-flex justify-content-between align-items-center flex-wrap border-top-0 p-0">
<div class="d-flex flex-wrap align-items-center">
<ul class="list-unstyled users-list d-flex align-items-center avatar-group m-0 me-2">
<li
data-bs-toggle="tooltip"
data-popup="tooltip-custom"
data-bs-placement="top"
title="Vinnie Mostowy"
class="avatar pull-up">
<img class="rounded-circle" src="../../assets/img/avatars/1.png" alt="Avatar" />
</li>
<li
data-bs-toggle="tooltip"
data-popup="tooltip-custom"
data-bs-placement="top"
title="Allen Rieske"
class="avatar pull-up">
<img class="rounded-circle" src="../../assets/img/avatars/4.png" alt="Avatar" />
</li>
<li
data-bs-toggle="tooltip"
data-popup="tooltip-custom"
data-bs-placement="top"
title="Julee Rossignol"
class="avatar pull-up">
<img class="rounded-circle" src="../../assets/img/avatars/2.png" alt="Avatar" />
</li>
<li class="avatar">
<span
class="avatar-initial rounded-circle pull-up"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="3 more"
>+3</span
>
</li>
</ul>
</div>
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
<!--/ Activity Timeline -->
<div class="row">
<!-- Connections -->
<div class="col-lg-12 col-xl-6">
<div class="card card-action mb-6">
<div class="card-header align-items-center">
<h5 class="card-action-title mb-0">Connections</h5>
<div class="card-action-element">
<div class="dropdown">
<button
type="button"
class="btn btn-icon btn-text-secondary rounded-pill dropdown-toggle hide-arrow p-0 text-body-secondary"
data-bs-toggle="dropdown"
aria-expanded="false">
<i class="icon-base ti tabler-dots-vertical icon-md text-body-secondary"></i>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="javascript:void(0);">Share connections</a></li>
<li><a class="dropdown-item" href="javascript:void(0);">Suggest edits</a></li>
<li>
<hr class="dropdown-divider" />
</li>
<li><a class="dropdown-item" href="javascript:void(0);">Report bug</a></li>
</ul>
</div>
</div>
</div>
<div class="card-body">
<ul class="list-unstyled mb-0">
<li class="mb-4">
<div class="d-flex align-items-center">
<div class="d-flex align-items-center">
<div class="avatar me-2">
<img src="../../assets/img/avatars/2.png" alt="Avatar" class="rounded-circle" />
</div>
<div class="me-2">
<h6 class="mb-0">Cecilia Payne</h6>
<small>45 Connections</small>
</div>
</div>
<div class="ms-auto">
<button class="btn btn-label-primary btn-icon">
<i class="icon-base ti tabler-user-check icon-22px"></i>
</button>
</div>
</div>
</li>
<li class="mb-4">
<div class="d-flex align-items-center">
<div class="d-flex align-items-center">
<div class="avatar me-2">
<img src="../../assets/img/avatars/3.png" alt="Avatar" class="rounded-circle" />
</div>
<div class="me-2">
<h6 class="mb-0">Curtis Fletcher</h6>
<small>1.32k Connections</small>
</div>
</div>
<div class="ms-auto">
<button class="btn btn-primary btn-icon">
<i class="icon-base ti tabler-user-x icon-22px"></i>
</button>
</div>
</div>
</li>
<li class="mb-4">
<div class="d-flex align-items-center">
<div class="d-flex align-items-center">
<div class="avatar me-2">
<img src="../../assets/img/avatars/10.png" alt="Avatar" class="rounded-circle" />
</div>
<div class="me-2">
<h6 class="mb-0">Alice Stone</h6>
<small>125 Connections</small>
</div>
</div>
<div class="ms-auto">
<button class="btn btn-primary btn-icon">
<i class="icon-base ti tabler-user-x icon-22px"></i>
</button>
</div>
</div>
</li>
<li class="mb-4">
<div class="d-flex align-items-center">
<div class="d-flex align-items-center">
<div class="avatar me-2">
<img src="../../assets/img/avatars/7.png" alt="Avatar" class="rounded-circle" />
</div>
<div class="me-2">
<h6 class="mb-0">Darrell Barnes</h6>
<small>456 Connections</small>
</div>
</div>
<div class="ms-auto">
<button class="btn btn-label-primary btn-icon">
<i class="icon-base ti tabler-user-check icon-22px"></i>
</button>
</div>
</div>
</li>
<li class="mb-6">
<div class="d-flex align-items-center">
<div class="d-flex align-items-center">
<div class="avatar me-2">
<img src="../../assets/img/avatars/12.png" alt="Avatar" class="rounded-circle" />
</div>
<div class="me-2">
<h6 class="mb-0">Eugenia Moore</h6>
<small>1.2k Connections</small>
</div>
</div>
<div class="ms-auto">
<button class="btn btn-label-primary btn-icon">
<i class="icon-base ti tabler-user-check icon-22px"></i>
</button>
</div>
</div>
</li>
<li class="text-center">
<a href="javascript:;">View all connections</a>
</li>
</ul>
</div>
</div>
</div>
<!--/ Connections -->
<!-- Teams -->
<div class="col-lg-12 col-xl-6">
<div class="card card-action mb-6">
<div class="card-header align-items-center">
<h5 class="card-action-title mb-0">Teams</h5>
<div class="card-action-element">
<div class="dropdown">
<button
type="button"
class="btn btn-icon btn-text-secondary dropdown-toggle hide-arrow p-0"
data-bs-toggle="dropdown"
aria-expanded="false">
<i class="icon-base ti tabler-dots-vertical icon-md text-body-secondary"></i>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="javascript:void(0);">Share teams</a></li>
<li><a class="dropdown-item" href="javascript:void(0);">Suggest edits</a></li>
<li>
<hr class="dropdown-divider" />
</li>
<li><a class="dropdown-item" href="javascript:void(0);">Report bug</a></li>
</ul>
</div>
</div>
</div>
<div class="card-body">
<ul class="list-unstyled mb-0">
<li class="mb-4">
<div class="d-flex align-items-center">
<div class="d-flex align-items-center">
<div class="avatar me-2">
<img
src="../../assets/img/icons/brands/react-label.png"
alt="Avatar"
class="rounded-circle" />
</div>
<div class="me-2">
<h6 class="mb-0">React Developers</h6>
<small>72 Members</small>
</div>
</div>
<div class="ms-auto">
<a href="javascript:;"><span class="badge bg-label-danger">Developer</span></a>
</div>
</div>
</li>
<li class="mb-4">
<div class="d-flex align-items-center">
<div class="d-flex align-items-center">
<div class="avatar me-2">
<img
src="../../assets/img/icons/brands/support-label.png"
alt="Avatar"
class="rounded-circle" />
</div>
<div class="me-2">
<h6 class="mb-0">Support Team</h6>
<small>122 Members</small>
</div>
</div>
<div class="ms-auto">
<a href="javascript:;"><span class="badge bg-label-primary">Support</span></a>
</div>
</div>
</li>
<li class="mb-4">
<div class="d-flex align-items-center">
<div class="d-flex align-items-center">
<div class="avatar me-2">
<img
src="../../assets/img/icons/brands/figma-label.png"
alt="Avatar"
class="rounded-circle" />
</div>
<div class="me-2">
<h6 class="mb-0">UI Designers</h6>
<small>7 Members</small>
</div>
</div>
<div class="ms-auto">
<a href="javascript:;"><span class="badge bg-label-info">Designer</span></a>
</div>
</div>
</li>
<li class="mb-4">
<div class="d-flex align-items-center">
<div class="d-flex align-items-center">
<div class="avatar me-2">
<img
src="../../assets/img/icons/brands/vue-label.png"
alt="Avatar"
class="rounded-circle" />
</div>
<div class="me-2">
<h6 class="mb-0">Vue.js Developers</h6>
<small>289 Members</small>
</div>
</div>
<div class="ms-auto">
<a href="javascript:;"><span class="badge bg-label-danger">Developer</span></a>
</div>
</div>
</li>
<li class="mb-6">
<div class="d-flex align-items-center">
<div class="d-flex align-items-center">
<div class="avatar me-2">
<img
src="../../assets/img/icons/brands/twitter-label.png"
alt="Avatar"
class="rounded-circle" />
</div>
<div class="me-w">
<h6 class="mb-0">Digital Marketing</h6>
<small>24 Members</small>
</div>
</div>
<div class="ms-auto">
<a href="javascript:;"><span class="badge bg-label-secondary">Marketing</span></a>
</div>
</div>
</li>
<li class="text-center">
<a href="javascript:;">View all teams</a>
</li>
</ul>
</div>
</div>
</div>
<!--/ Teams -->
</div>
<!-- Projects table -->
<!-- <div class="card mb-6">
<div class="mb-4">
<table class="table datatable-project">
<thead class="border-top">
<tr>
<th></th>
<th></th>
<th>Project</th>
<th>Leader</th>
<th>Team</th>
<th class="w-px-200">Progress</th>
<th>Action</th>
</tr>
</thead>
</table>
</div>
</div> -->
<!--/ Projects table -->
</div>
</div>
<!--/ User Profile Content -->
</div>
@endsection
+1 -1
View File
@@ -361,7 +361,7 @@
<div class="dropdown-divider my-1 mx-n2"></div>
</li>
<li>
<a class="dropdown-item" href="{{ route('userProfile.index') }}">
<a class="dropdown-item" href="pages-profile-user.html">
<i class="icon-base ti tabler-user me-3 icon-md"></i
><span class="align-middle">Profil Saya</span>
</a>
+23 -3
View File
@@ -1,6 +1,6 @@
<aside id="layout-menu" class="layout-menu menu-vertical menu">
<div class="app-brand demo ">
<a href="{{ route('dashboard.produktivitas') }}" class="app-brand-link">
<a href="{{ route('dashboard.summary') }}" class="app-brand-link">
<span class="app-brand-logo demo">
<span>
<svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg">
@@ -58,8 +58,28 @@
</a>
<ul class="menu-sub">
<li class="menu-item">
<a href="{{ route('dashboard.produktivitas') }}" class="menu-link">
<div data-i18n="Produktivitas">Produktivitas</div>
<a href="{{ route('dashboard.summary') }}" class="menu-link">
<div data-i18n="Summary">Summary</div>
</a>
</li>
<li class="menu-item">
<a href="{{ route('dashboard.resiliensi') }}" class="menu-link">
<div data-i18n="Reseliensi">Reseliensi</div>
</a>
</li>
<li class="menu-item">
<a href="{{ route('dashboard.hilirisasi') }}" class="menu-link">
<div data-i18n="Hilirisasi">Hilirisasi</div>
</a>
</li>
<li class="menu-item">
<a href="{{ route('dashboard.konektivitas') }}" class="menu-link">
<div data-i18n="Konektivitas">Konektivitas</div>
</a>
</li>
<li class="menu-item">
<a href="{{ route('dashboard.akselerasi') }}" class="menu-link">
<div data-i18n="Akselerasi">Akselerasi</div>
</a>
</li>
</ul>
@@ -2,6 +2,9 @@
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
<div class="mb-6">
<x-wilayah-dashboard />
</div>
<div class="card">
<div class="card-header border-bottom">
<h5 class="card-title mb-0">Data Desa/Kelurahan</h5>
@@ -2,6 +2,9 @@
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
<div class="mb-6">
<x-wilayah-dashboard />
</div>
<div class="card">
<div class="card-body border-bottom">
<form method="GET" action="{{ route('kabupatenkota.index') }}" class="d-flex justify-content-between align-items-center row gap-3 gap-md-0">
@@ -2,6 +2,9 @@
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
<div class="mb-6">
<x-wilayah-dashboard />
</div>
<div class="card">
<div class="card-header border-bottom">
<h5 class="card-title mb-0">Data Kecamatan</h5>
@@ -140,11 +140,12 @@
</div>
</div>
</div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
@endsection
@push('scripts')
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
@@ -159,7 +160,7 @@
let regionBoundaryLayer = L.featureGroup().addTo(map);
function focusToRegionBoundary(selectElement) {
regionBoundaryLayer.clearLayers();
regionBoundaryLayer.clearLayers(); // Bersihkan garis wilayah sebelumnya
let selectedOption = selectElement.options[selectElement.selectedIndex];
if (!selectedOption || !selectedOption.hasAttribute('data-path')) return;
@@ -174,7 +175,7 @@
function formatCoordinates(coords) {
if (coords.length === 2 && typeof coords[0] === 'number') {
return [coords[0], coords[1]]; // JANGAN DIBALIK (Leaflet Draw butuh format asli)
return [coords[0], coords[1]]; // JANGAN DIBALIK
}
return coords.map(formatCoordinates);
}
@@ -182,11 +183,11 @@
let latLngs = formatCoordinates(rawData);
let polygon = L.polygon(latLngs, {
color: '#ffc107',
fillColor: '#ffc107',
fillOpacity: 0.15,
weight: 3,
dashArray: '8, 6',
color: '#3b5998',
fillColor: '#3b5998',
fillOpacity: 0.1,
weight: 2,
dashArray: '5, 5',
interactive: false
});
@@ -228,8 +229,10 @@
map.on(L.Draw.Event.CREATED, function (e) {
let layer = e.layer;
drawnItems.clearLayers();
drawnItems.addLayer(layer);
updatePathTextarea(layer);
});
@@ -241,32 +244,14 @@
map.on(L.Draw.Event.DELETED, function () {
document.getElementById('path').value = '';
let luasInput = document.querySelector('input[name="luas_lahan"]');
if (luasInput) luasInput.value = '';
});
function updatePathTextarea(layer) {
let latlngs = layer.getLatLngs()[0];
let pathData = latlngs.map(function(latlng) {
return [latlng.lng, latlng.lat];
});
document.getElementById('path').value = JSON.stringify(pathData);
let areaSquareMeters = L.GeometryUtil.geodesicArea(latlngs);
let areaHectares = areaSquareMeters / 10000;
let luasInput = document.querySelector('input[name="luas_lahan"]');
if (luasInput) {
luasInput.value = areaHectares.toFixed(2);
luasInput.style.transition = "background-color 0.5s ease";
luasInput.style.backgroundColor = "#e8fdf0";
setTimeout(() => {
luasInput.style.backgroundColor = "";
}, 1500);
}
}
let statusSelect = document.getElementById('status_kepemilikan');
@@ -162,11 +162,12 @@
</div>
</div>
</div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
@endsection
@push('scripts')
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
@@ -203,11 +204,11 @@
let latLngs = formatCoordinates(rawData);
let polygon = L.polygon(latLngs, {
color: '#ffc107',
fillColor: '#ffc107',
fillOpacity: 0.15,
weight: 3,
dashArray: '8, 6',
color: '#3b5998',
fillColor: '#3b5998',
fillOpacity: 0.1,
weight: 2,
dashArray: '5, 5',
interactive: false
});
@@ -275,32 +276,14 @@
map.on(L.Draw.Event.DELETED, function () {
document.getElementById('path').value = '';
let luasInput = document.querySelector('input[name="luas_lahan"]');
if (luasInput) luasInput.value = '';
});
function updatePathTextarea(layer) {
let latlngs = layer.getLatLngs()[0];
let pathData = latlngs.map(function(latlng) {
return [latlng.lng, latlng.lat];
});
document.getElementById('path').value = JSON.stringify(pathData);
let areaSquareMeters = L.GeometryUtil.geodesicArea(latlngs);
let areaHectares = areaSquareMeters / 10000;
let luasInput = document.querySelector('input[name="luas_lahan"]');
if (luasInput) {
luasInput.value = areaHectares.toFixed(2);
luasInput.style.transition = "background-color 0.5s ease";
luasInput.style.backgroundColor = "#e8fdf0";
setTimeout(() => {
luasInput.style.backgroundColor = "";
}, 1500);
}
}
let statusSelect = document.getElementById('status_kepemilikan');
+5 -2
View File
@@ -15,9 +15,12 @@ Route::middleware('auth')
->group(function () {
// Home
Route::get('/', [App\Http\Controllers\Web\Dashboard\SummaryController::class, 'produktivitas'])->name('dashboard.produktivitas');
Route::get('/', [App\Http\Controllers\Web\Dashboard\SummaryController::class, 'index'])->name('dashboard.summary');
Route::get('/resiliensi', [App\Http\Controllers\Web\Dashboard\ResiliensiController::class, 'index'])->name('dashboard.resiliensi');
Route::get('/hilirisasi', [App\Http\Controllers\Web\Dashboard\HilirisasiController::class, 'index'])->name('dashboard.hilirisasi');
Route::get('/konektivitas', [App\Http\Controllers\Web\Dashboard\KonektivitasController::class, 'index'])->name('dashboard.konektivitas');
Route::get('/akselerasi', [App\Http\Controllers\Web\Dashboard\AkselerasiController::class, 'index'])->name('dashboard.akselerasi');
Route::get('/UserProfile', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'index'])->name('userProfile.index');
// User
Route::resource('users', App\Http\Controllers\Web\Konfigurasi\UserController::class);
Route::patch('/users/{user}/verify', [App\Http\Controllers\Web\Konfigurasi\UserController::class, 'verify'])->name('users.verify');