85 Commits
Author SHA1 Message Date
irwan.l.cahyono 909f03cb9a update project 2026-08-19 00:00:14 +07:00
afriadirahman 4475cd0098 Update Logo Sidebar 2026-07-28 16:18:41 +07:00
afriadirahman 67c111a2b3 Update Logo Agromonev & Agropro 2026-07-28 16:10:47 +07:00
Syaharani 3bcaa3ea50 solve survey produktivitas 2026-07-27 10:14:36 +07:00
Syaharani bed9a6f620 solve 2026-07-23 18:26:24 +07:00
Althaf 712b10e405 Merge branches 'main' and 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-22 17:06:45 +07:00
Althaf 6cfcf46ba6 use assets avatars 2026-07-22 17:06:31 +07:00
Syaharani b1b9828514 update jumlah tanaman 2026-07-22 16:54:57 +07:00
Syaharani 7af7e1bdaf update jumlah lahan 2026-07-22 16:40:24 +07:00
Syaharani bd05fc7f0f update hama dan penyakit 2026-07-22 16:23:32 +07:00
Syaharani 17b5687db8 update user profile 2026-07-22 15:55:07 +07:00
Syaharani e7f48b6500 solve lahan & tanaman 2026-07-22 15:49:25 +07:00
Syaharani a5884d0f8c solve akses pasar 2026-07-22 15:22:56 +07:00
Syaharani 9576c6295e solve sosial ekonomi 2026-07-22 14:41:05 +07:00
irwan.l.cahyono 079e300d5d Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-22 14:39:10 +07:00
irwan.l.cahyono 2c94316439 petani lahan hapus 2026-07-22 14:38:10 +07:00
Syaharani 690b53e5a2 Merge origin/main 2026-07-22 14:08:34 +07:00
irwan.l.cahyono 50c9adfdc7 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-22 13:56:56 +07:00
irwan.l.cahyono 696c7dede8 hama dan penyakit lahan 2026-07-22 13:56:55 +07:00
Syaharani 5967e7d6f3 solve pendidikan & pelatihan 2026-07-22 13:28:58 +07:00
Syaharani 4c66d72dc5 solve praktik budidaya 2026-07-22 13:27:35 +07:00
Althaf c43483a9f8 default profile-iconize & fixed overlapping tab 2026-07-22 13:24:39 +07:00
Syaharani e02a34a527 solve lahan & tanaman 2026-07-22 11:58:51 +07:00
Althaf 713355ce0a add text-heading to adjust icon color theme 2026-07-22 10:35:36 +07:00
Althaf 12f8d0bbda integrate image cropper for avatar upload/delete option/retouch 2026-07-22 10:10:06 +07:00
Althaf 8afe7f9b38 solve view-controller dropzone 2026-07-21 11:49:32 +07:00
Althaf fbf84eb4cb enhance UX alerts 2026-07-20 16:45:00 +07:00
Althaf e04093ad3f Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-20 16:36:29 +07:00
Althaf 3e1d3a33ee fix: resolve existing photos preview in Dropzone Lahan&Tanaman 2026-07-20 16:36:12 +07:00
irwan.l.cahyono e316d064ef auth dan user profile 2026-07-17 11:19:09 +07:00
irwan.l.cahyono 0c289ec244 dashboard indeks 2026-07-17 01:19:12 +07:00
irwan.l.cahyono 089f1b515d tanaman penaung di lahan 2026-07-16 15:22:42 +07:00
irwan.l.cahyono 4c647ea8ce Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-16 13:46:45 +07:00
irwan.l.cahyono 419404e273 null jumlah tanaman 2026-07-16 13:46:43 +07:00
Althaf 837e542851 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-16 11:42:40 +07:00
Althaf 9378d15d71 edit foto tambah lahan 2026-07-16 11:41:35 +07:00
irwan.l.cahyono 0381e9bf0e Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-15 15:00:14 +07:00
irwan.l.cahyono 3a70445e9a petani lahan required not 2026-07-15 15:00:13 +07:00
afriadirahman d2ed2c58fd Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-15 14:37:48 +07:00
afriadirahman 9b201efa06 update Praktik budidaya migration 2026-07-15 14:37:39 +07:00
irwan.l.cahyono 2b3a0b7c58 tanggal jqueryvalidation 2026-07-15 14:05:25 +07:00
irwan.l.cahyono a187fb1095 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-15 11:44:39 +07:00
irwan.l.cahyono 6b44c11181 header dan index 2026-07-15 11:44:38 +07:00
afriadirahman 090153e53a Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-15 11:30:37 +07:00
afriadirahman a79a93d291 Update komoditas Utama 2026-07-15 11:30:10 +07:00
irwan.l.cahyono 62f0f1bdbc tgl lahir edit 2026-07-15 10:55:11 +07:00
irwan.l.cahyono f0acd8c7ed dashboard komoditas 2026-07-15 10:41:27 +07:00
irwan.l.cahyono 3908b0be71 komoditas utama 2026-07-15 10:37:38 +07:00
irwan.l.cahyono 05cc3be9d3 enum pendidikan 2026-07-15 01:34:47 +07:00
irwan.l.cahyono f4c83d348a filter fasil 2026-07-15 01:19:12 +07:00
irwan.l.cahyono 61bd8dc388 redirect web 2026-07-15 01:11:19 +07:00
irwan.l.cahyono 002d6044b4 profil petani dashboard 2026-07-15 01:06:10 +07:00
irwan.l.cahyono 30196278d7 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-15 00:18:55 +07:00
irwan.l.cahyono 08c19c0714 skor petani 2026-07-15 00:18:00 +07:00
afriadirahman d6c036e19a Update Header Survey Petani 2026-07-14 23:35:15 +07:00
afriadirahman 981bc0d494 Update Master Komoditas 2026-07-14 23:05:16 +07:00
afriadirahman 857da1e900 Update Master Komoditas & Varietas 2026-07-14 22:34:38 +07:00
irwan.l.cahyono 66fc7227e6 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-14 17:13:55 +07:00
irwan.l.cahyono 3edfc57ba7 skor petani praktik budidaya 2026-07-14 17:13:52 +07:00
Althaf 4a560ebc4e Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-14 15:41:40 +07:00
Althaf d4eb27e583 foto tambah lahan 2026-07-14 15:41:16 +07:00
irwan.l.cahyono d1c0f90afd sidebar 2026-07-14 15:39:22 +07:00
irwan.l.cahyono a1dadd1b1b petani lahan tanaman edit 2026-07-14 14:50:33 +07:00
irwan.l.cahyono 2c28bb06db asset avatar 2026-07-14 11:15:23 +07:00
irwan.l.cahyono 96a53c8754 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-14 10:49:08 +07:00
irwan.l.cahyono fcc5d7dcc5 header skor 2026-07-14 10:44:35 +07:00
afriadirahman e383aacbeb Update Dashboard Survey Petani 2026-07-14 10:34:46 +07:00
irwan.l.cahyono 5b776b2ae8 header 2026-07-14 09:20:46 +07:00
irwan.l.cahyono c4e3e460b1 hidden show 2026-07-13 16:45:23 +07:00
irwan.l.cahyono a7dc1dc58b dashboard survey 2026-07-13 16:43:27 +07:00
irwan.l.cahyono d01c737364 web fasil 2026-07-13 16:39:46 +07:00
irwan.l.cahyono 8d50757b51 foto petani 2026-07-13 16:29:00 +07:00
irwan.l.cahyono f146cb2608 sideba petani profil 2026-07-13 16:22:00 +07:00
irwan.l.cahyono 095d84ec7f sidebar env 2026-07-13 16:13:54 +07:00
irwan.l.cahyono f259c6728a register 2026-07-13 15:53:50 +07:00
irwan.l.cahyono a241a62136 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-13 14:03:24 +07:00
irwan.l.cahyono 4755c8a482 dashboard profil petani 2026-07-13 14:03:19 +07:00
afriadirahman 7672877299 update Model Petani 2026-07-13 10:19:04 +07:00
irwan.l.cahyono 92e8efb247 skor petani 2026-07-13 10:18:32 +07:00
irwan.l.cahyono 599269410b foto lahan 2026-07-13 01:04:55 +07:00
irwan.l.cahyono c5b5721b31 Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web 2026-07-12 23:37:37 +07:00
irwan.l.cahyono 2bf2a68a3a perbaikan petani dan lahan 2026-07-12 23:37:36 +07:00
afriadirahman b445392e9f Update Pendidikan & Pelatihan 2026-07-12 23:00:58 +07:00
afriadirahman bcc15d5240 Update Create User Register 2026-07-12 22:51:23 +07:00
afriadirahman d33bc8a42b Update Pendidikan Pelatihan 2026-07-11 15:19:44 +07:00
81 changed files with 7298 additions and 572 deletions
+3 -3
View File
@@ -11,9 +11,9 @@ enum KeparahanSerangan: string
public function label(): string
{
return match($this) {
self::RINGAN => 'Ringan',
self::SEDANG => 'Sedang',
self::BERAT => 'Berat',
self::RINGAN => 'Ringan, hanya beberapa tanaman',
self::SEDANG => 'Sedang, sebagian tanaman terdampak',
self::BERAT => 'Parah, sebagian besar tanaman terdampak',
};
}
+4 -4
View File
@@ -13,10 +13,10 @@ enum KondisiTanaman: string
public function label(): string
{
return match($this) {
self::BAIK => 'Baik',
self::SEDANG => 'Sedang',
self::BURUK => 'Buruk',
self::MATI => 'Mati',
self::BAIK => 'Baik, tumbuh lebat, banyak buah',
self::SEDANG => 'Sedang, cukup tumbuh, ada masalah',
self::BURUK => 'Buruk, banyak tanaman tua dan lemah/tidak berbuah',
self::MATI => 'Mati, tanaman telah mati, tidak dapat tumbuh maupun berbuah',
};
}
+6 -6
View File
@@ -19,13 +19,13 @@ enum Pendidikan: string
{
return match($this) {
self::TIDAK_SEKOLAH => 'Tidak Sekolah',
self::SD => 'SD atau Sederajat',
self::SMP => 'SMP atau Sederajat',
self::SMA => 'SMA atau Sederajat',
self::SD => 'SD',
self::SMP => 'SMP',
self::SMA => 'SMA/SMK',
self::DIPLOMA => 'Diploma 1-3 (D1-D3)',
self::SARJANA => 'Sarjana (S1) atau sederajat',
self::MAGISTER => 'Magister (S2) atau sederajat',
self::DOKTOR => 'Doktor (S3) atau sederajat',
self::SARJANA => 'Sarjana (S1)',
self::MAGISTER => 'Magister (S2)',
self::DOKTOR => 'Doktor (S3)',
self::PESANTREN => 'Pesantren, Semiari, Wihara, atau Pendidikan Keagamaan Formal',
self::LAINNYA => 'Lainnya',
};
@@ -0,0 +1,26 @@
<?php
namespace App\Enums\PendidikanPelatihan;
enum PelatihanGAP: string
{
case PEMANGKASAN = 'Pemangkasan atau perawatan tanaman';
case PEMUPUKAN = 'Pemupukan atau nutrisi tanah';
case PENGENDALIAN = 'Pengendalian hama dan penyakit';
case PRAKTIK = 'Praktik Berkebun yang Baik (GAP)';
case PENGOLAHAN = 'Pengolahan/pascapanen';
case PENYERBUKAN = 'Penyerbukan manual (Vanili)';
public function label(): string
{
return $this->value;
}
public static function options(): array
{
return collect(self::cases())->map(fn ($case) => [
'value' => $case->value,
'label' => $case->label(),
])->toArray();
}
}
+18
View File
@@ -8,4 +8,22 @@ enum PenyakitTanaman: string
case DAUN_MENGUNING = 'daun_menguning';
case DAUN_BERCAK = 'daun_bercak';
case TANAMAN_LAYU = 'tanaman_layu';
public function label(): string
{
return match ($this) {
self::BUSUK_BUAH => 'Busuk Buah',
self::DAUN_MENGUNING => 'Daun Menguning',
self::DAUN_BERCAK => 'Daun Bercak',
self::TANAMAN_LAYU => 'Tanaman Layu',
};
}
public static function options(): array
{
return collect(self::cases())->map(fn ($case) => [
'value' => $case->value,
'label' => $case->label(),
])->toArray();
}
}
+17
View File
@@ -7,4 +7,21 @@ enum SeranganHama: string
case ULAT = 'ulat';
case BELALANG = 'belalang';
case KUTU = 'kutu';
public function label(): string
{
return match ($this) {
self::ULAT => 'Ulat',
self::BELALANG => 'Belalang',
self::KUTU => 'Kutu',
};
}
public static function options(): array
{
return collect(self::cases())->map(fn ($case) => [
'value' => $case->value,
'label' => $case->label(),
])->toArray();
}
}
@@ -16,7 +16,7 @@ use App\Enums\StatusLahan;
class LahanController extends Controller
{
/**
/**
* Display a listing of the resource.
*/
public function index(Request $request): AnonymousResourceCollection
@@ -97,11 +97,12 @@ class LahanController extends Controller
'nama' => ['required', 'string', 'max:255'],
'status_kepemilikan' => ['required', new Enum(StatusLahan::class)],
'desa_kelurahan_id' => ['nullable', 'numeric', 'exists:master_desa_kelurahan,id'],
'path' => ['nullable', 'array'],
'path.*' => ['array'],
'path' => ['nullable', 'string'],
'luas_lahan' => ['nullable', 'numeric'],
'uid' => ['required', 'string'],
'profile_id' => $profileRule,
'foto' => ['nullable', 'array'],
'foto.*' => ['image', 'mimes:jpeg,png,jpg', 'max:5120'], // Max 5MB
]);
$targetProfileId = $user->role === 'fasilitator'
@@ -120,10 +121,22 @@ class LahanController extends Controller
? $profile->desa_kelurahan_id
: ($validated['desa_kelurahan_id'] ?? $profile->desa_kelurahan_id);
$fotoPaths = [];
if ($request->hasFile('foto')) {
foreach ($request->file('foto') as $file) {
$fotoPaths[] = $file->store('foto_lahan', 'public');
}
}
$lahan = Lahan::create([
...$validated,
'profile_id' => $profile->id,
'nama' => $validated['nama'],
'status_kepemilikan' => $validated['status_kepemilikan'],
'desa_kelurahan_id' => $desaKelurahanId,
'path' => $validated['path'] ?? null,
'luas_lahan' => $validated['luas_lahan'] ?? null,
'uid' => $validated['uid'],
'profile_id' => $profile->id,
'foto' => $fotoPaths,
]);
return (new LahanResource($lahan))
@@ -153,7 +166,7 @@ class LahanController extends Controller
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id): JsonResponse
public function update(Request $request, string $id): JsonResponse
{
if (!Gate::any(['petani', 'fasilitator','super_admin'])) {
abort(403);
@@ -173,9 +186,26 @@ class LahanController extends Controller
'path' => ['nullable', 'array'],
'path.*' => ['array'],
'luas_lahan' => ['nullable', 'numeric'],
'foto' => ['nullable', 'array'],
'foto.*' => ['image', 'mimes:jpeg,png,jpg', 'max:5120'],
]);
$lahan->update($validated);
$fotoPaths = $lahan->foto ?? [];
if ($request->hasFile('foto')) {
foreach ($request->file('foto') as $file) {
$fotoPaths[] = $file->store('foto_lahan', 'public');
}
}
$lahan->update([
'nama' => $validated['nama'],
'status_kepemilikan' => $validated['status_kepemilikan'],
'desa_kelurahan_id' => $validated['desa_kelurahan_id'] ?? $lahan->desa_kelurahan_id,
'path' => $validated['path'] ?? null,
'luas_lahan' => $validated['luas_lahan'] ?? null,
'foto' => $fotoPaths,
]);
return (new LahanResource($lahan))->response();
}
@@ -0,0 +1,150 @@
<?php
namespace App\Http\Controllers\Web\Dashboard;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\DB;
use App\Models\Pertanian\Petani;
use App\Models\Pertanian\Komoditas;
use App\Models\Pertanian\Lahan;
use App\Models\Pertanian\Tanaman;
use App\Models\Pertanian\SkorPetani;
class ProfilPetaniController extends Controller
{
public function index()
{
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
abort(403);
}
$title = 'Dashboard Profil Petani';
$komoditas = Komoditas::where('is_utama', true)->get();
$petani = Petani::pluck('id');
$lahan = Lahan::whereIn('petani_id', $petani)->get();
$petaniSummary = Petani::select(
'komoditas_id',
DB::raw('COUNT(*) as total')
)
->groupBy('komoditas_id')
->get();
$lahanSummary = Lahan::select(
'komoditas_id',
DB::raw('COUNT(*) as total'),
DB::raw('SUM(luas_lahan) as luas_lahan')
)
->whereIn('petani_id', $petani)
->groupBy('komoditas_id')
->get();
$tanamanSummary = Tanaman::select(
'komoditas_id',
DB::raw('COUNT(*) as total')
)
->whereIn('lahan_id', $lahan->pluck('id'))
->groupBy('komoditas_id')
->get();
$case = "
CASE
WHEN skor_kesiapan_adopsi >= 4.0 THEN 'Penggerak'
WHEN skor_kesiapan_adopsi >= 3.0 THEN 'Perintis'
WHEN skor_kesiapan_adopsi >= 2.0 THEN 'Pemerhati'
WHEN skor_kesiapan_adopsi >= 1.0 THEN 'Pemula'
ELSE 'Belum Lengkap'
END
";
$skorSummary = SkorPetani::selectRaw("$case AS segmen, COUNT(*) AS total")
->whereIn('petani_id', $petani)
->groupByRaw($case)
->get();
$skorKomoditasSummary = SkorPetani::query()
->join('petani', 'petani_skor.petani_id', '=', 'petani.id')
->selectRaw("
petani.komoditas_id,
$case AS segmen,
COUNT(petani.id) AS total
")
->whereIn('petani_skor.petani_id', $petani)
->groupBy('petani.komoditas_id')
->groupByRaw($case)
->get();
$skorAverage = SkorPetani::query()
->join('petani', 'petani_skor.petani_id', '=', 'petani.id')
->whereIn('petani_id', $petani)
->whereIn('petani.komoditas_id', $komoditas->pluck('id'))
->avg('skor_kesiapan_adopsi');
if ($skorAverage >= 4.0) {
$segmenAverage = 'Penggerak';
} elseif ($skorAverage >= 3.0) {
$segmenAverage = 'Perintis';
} elseif ($skorAverage >= 2.0) {
$segmenAverage = 'Pemerhati';
} elseif ($skorAverage >= 1.0) {
$segmenAverage = 'Pemula';
} else {
$segmenAverage = 'Belum Lengkap';
}
$skorDimensi = SkorPetani::query()
->join('petani', 'petani_skor.petani_id', '=', 'petani.id')
->whereIn('petani_id', $petani)
->whereIn('petani.komoditas_id', $komoditas->pluck('id'))
->selectRaw("
avg(skor_d2_sistem_praktik_budidaya) as skor_d2_sistem_praktik_budidaya,
avg(skor_d4_sosial_ekonomi) as skor_d4_sosial_ekonomi,
avg(skor_d6_rantai_nilai_akses_pasar) as skor_d6_rantai_nilai_akses_pasar")
->first();
$skorKomponen = SkorPetani::query()
->join('petani', 'petani_skor.petani_id', '=', 'petani.id')
->whereIn('petani_id', $petani)
->whereIn('petani.komoditas_id', $komoditas->pluck('id'))
->selectRaw("avg(skor_komp_1_d4_k3_motivasi_kapasitas_adopsi) as skor_komp_1_d4_k3_motivasi_kapasitas_adopsi,
avg(skor_komp_2_d4_k2_ekonomi_rumah_tangga) as skor_komp_2_d4_k2_ekonomi_rumah_tangga,
avg(skor_komp_3_d2_praktik_budidaya_gap) as skor_komp_3_d2_praktik_budidaya_gap,
avg(skor_komp_4_d4_k4_keterlibatan_kelembagaan) as skor_komp_4_d4_k4_keterlibatan_kelembagaan,
avg(skor_komp_5_d4_k5_k6_akses_kebebasan_keuangan) as skor_komp_5_d4_k5_k6_akses_kebebasan_keuanga,
avg(skor_komp_6_d6_k1_k4_k5_rantai_nilai_akses_pasar) as skor_komp_6_d6_k1_k4_k5_rantai_nilai_akses_pasar")
->first();
$skorMultiDimensi = SkorPetani::query()
->join('petani', 'petani_skor.petani_id', '=', 'petani.id')
->whereIn('petani_id', $petani)
->whereIn('petani.komoditas_id', $komoditas->pluck('id'))
->selectRaw("$case AS segmen,
avg(skor_kesiapan_adopsi) as skor_kesiapan_adopsi,
avg(skor_d2_sistem_praktik_budidaya) as skor_d2_sistem_praktik_budidaya,
avg(skor_d4_sosial_ekonomi) as skor_d4_sosial_ekonomi,
avg(skor_d6_rantai_nilai_akses_pasar) as skor_d6_rantai_nilai_akses_pasar")
->groupByRaw($case)
->get();
$petani = Petani::with(['skor'])
->whereIn('id', $petani)
->whereIn('komoditas_id', $komoditas->pluck('id'))
->get();
return view('dashboard.petani', compact('title',
'komoditas',
'petaniSummary',
'lahanSummary',
'tanamanSummary',
'skorSummary',
'skorKomoditasSummary',
'segmenAverage',
'skorAverage',
'skorDimensi',
'skorKomponen',
'skorMultiDimensi',
'petani',
));
}
}
@@ -34,12 +34,42 @@ class SummaryController extends Controller
$totalpetani = Profile::where('role', 'petani')->count();
$totallahan = Lahan::whereNotNull('path')->count();
$petaniList = Profile::where('role', 'petani')
->with(['lahan.tanaman.komoditas', 'desaKelurahan'])
$petaniList = Profile::select('id', 'nama', 'role', 'desa_kelurahan_id')
->where('role', 'petani')
->with([
'lahan:id,profile_id,luas_lahan',
'desaKelurahan:id,nama,kecamatan_id',
])
->paginate(20);
$allLahan = Lahan::whereNotNull('path')
->with(['profile', 'tanaman.komoditas', 'desaKelurahan.kecamatan.kabupatenKota.provinsi'])
$lahanSummaryByDesa = Lahan::whereNotNull('path')
->whereNotNull('desa_kelurahan_id')
->select('desa_kelurahan_id')
->selectRaw('COUNT(*) as total_lahan')
->selectRaw('COALESCE(SUM(luas_lahan), 0) as total_luas')
->groupBy('desa_kelurahan_id')
->get();
$desaList = DesaKelurahan::select('id', 'nama', 'path', 'kecamatan_id')
->whereIn('id', $lahanSummaryByDesa->pluck('desa_kelurahan_id')->filter()->unique()->values())
->with([
'kecamatan:id,nama,path,kabupaten_kota_id',
'kecamatan.kabupatenKota:id,nama,path,provinsi_id',
'kecamatan.kabupatenKota.provinsi:id,nama,path',
])
->get()
->keyBy('id');
$mapLahanLimit = min(max((int) $request->integer('map_lahan_limit', 500), 0), 2000);
$mapLahan = Lahan::whereNotNull('path')
->select('id', 'profile_id', 'desa_kelurahan_id', 'path', 'luas_lahan')
->with([
'profile:id,nama',
'tanaman:id,lahan_id,komoditas_id',
'tanaman.komoditas:id,nama',
])
->orderByDesc('updated_at')
->limit($mapLahanLimit)
->get();
$geoProvinsi = [];
@@ -48,47 +78,51 @@ class SummaryController extends Controller
$geoDesa = [];
$geoLahan = [];
foreach ($allLahan as $lahan) {
$desa = $lahan->desaKelurahan;
foreach ($lahanSummaryByDesa as $summary) {
$desa = $desaList->get($summary->desa_kelurahan_id);
$kec = $desa ? $desa->kecamatan : null;
$kab = $kec ? $kec->kabupatenKota : null;
$prov = $kab ? $kab->provinsi : null;
$totalLahan = (int) $summary->total_lahan;
$totalLuas = (float) $summary->total_luas;
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;
$geoProvinsi[$prov->id]['total_lahan'] += $totalLahan;
$geoProvinsi[$prov->id]['total_luas'] += $totalLuas;
}
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;
$geoKabupaten[$kab->id]['total_lahan'] += $totalLahan;
$geoKabupaten[$kab->id]['total_luas'] += $totalLuas;
}
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;
$geoKecamatan[$kec->id]['total_lahan'] += $totalLahan;
$geoKecamatan[$kec->id]['total_luas'] += $totalLuas;
}
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;
$geoDesa[$desa->id]['total_lahan'] += $totalLahan;
$geoDesa[$desa->id]['total_luas'] += $totalLuas;
}
}
foreach ($mapLahan as $lahan) {
$geoLahan[] = [
'id' => $lahan->id,
'parent_id' => $desa->id ?? null,
'parent_id' => $lahan->desa_kelurahan_id,
'polygon' => $lahan->path,
'nama_petani' => $lahan->profile->nama ?? 'N/A',
'luas' => $lahan->luas_lahan,
@@ -0,0 +1,377 @@
<?php
namespace App\Http\Controllers\Web\Dashboard;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use App\Models\User;
use App\Models\Pertanian\Petani;
use App\Models\Pertanian\Komoditas;
use App\Models\Pertanian\Lahan;
use App\Models\Pertanian\Tanaman;
use App\Models\Pertanian\SurveyPelatihan;
use App\Models\Pertanian\SurveySertifikasi;
use BackedEnum;
class SurveyPetaniController extends Controller
{
private const GAP_ENUM_CLASS = 'App\\Enums\\PendidikanPelatihan\\PelatihanGap';
public function index()
{
$colors = $this->colors();
// Progres per enumerator
$enumerators = User::query()
->where('role', 'fasilitator')
->withCount([
'petaniDibuat as done',
])
->orderByDesc('done')
->get()
->map(function ($enumerator) use ($colors) {
$color = $colors[array_rand($colors)];
return [
'name' => $enumerator->name,
'done' => (int) $enumerator->done,
'color' => $color['color'],
'bg' => $color['bg'],
'tx' => $color['tx'],
];
})
->values();
// Tabel dan nama model
$petaniTable = (new Petani())->getTable();
$komoditasTable = (new Komoditas())->getTable();
$lahanTable = (new Lahan())->getTable();
// Distribusi petani berdasarkan komoditas
$komoditasCollection = DB::table("{$petaniTable} as p")
->leftJoin("{$komoditasTable} as k", 'k.id', '=', 'p.komoditas_id')
->selectRaw("COALESCE(k.nama, 'Belum ditentukan') as nama")
->selectRaw('COUNT(p.id) as petani_count')
->where('k.is_utama', true)
->groupBy('k.id', 'k.nama')
->orderByDesc('petani_count')
->get();
$totalPetani = (int) $komoditasCollection->sum('petani_count');
$circumference = 2 * pi() * 46;
$komoditas = $komoditasCollection
->map(function ($item, $index) use (
$colors,
$totalPetani,
$circumference
) {
$color = $colors[$index % count($colors)];
$ratio = $totalPetani > 0
? (int) $item->petani_count / $totalPetani
: 0;
return [
'label' => $item->nama,
'total' => (int) $item->petani_count,
'pct' => round($ratio * 100, 1),
'arc' => $ratio * $circumference,
'color' => $color['color'],
];
})
->values();
// Progres pengisian data per petani
$progressPetani = Petani::query()
->select([
'id',
'nama',
])
->withExists([
'lahans as has_lahan',
'praktikBudidaya as has_praktik_budidaya',
'sosialEkonomi as has_sosial_ekonomi',
'aksesPasar as has_akses_pasar',
])
->orderBy('nama')
->get()
->map(function ($petani) {
$status = [
'lahan' => [
'label' => 'Lahan',
'done' => (bool) $petani->has_lahan,
],
'praktik_budidaya' => [
'label' => 'Praktik Budidaya',
'done' => (bool) $petani->has_praktik_budidaya,
],
'sosial_ekonomi' => [
'label' => 'Sosial Ekonomi',
'done' => (bool) $petani->has_sosial_ekonomi,
],
'akses_pasar' => [
'label' => 'Akses Pasar',
'done' => (bool) $petani->has_akses_pasar,
],
];
$totalModul = count($status);
$modulSelesai = collect($status)
->where('done', true)
->count();
return [
'id' => $petani->id,
'name' => $petani->nama,
'status' => $status,
'done' => $modulSelesai,
'total' => $totalModul,
'percent' => $totalModul > 0
? (int) round(($modulSelesai / $totalModul) * 100)
: 0,
];
})
->values();
// Ringkasan lahan
$totalLuasLahan = ((float) Lahan::query()
->sum('luas_lahan')) / 10000;
// Jumlah tanaman berdasarkan komoditas petani
$tanamanTable = (new Tanaman())->getTable();
$tanamanPerKomoditasCollection = DB::table("{$tanamanTable} as t")
->join("{$lahanTable} as l", 'l.id', '=', 't.lahan_id')
->join("{$petaniTable} as p", 'p.id', '=', 'l.petani_id')
->leftJoin("{$komoditasTable} as k", 'k.id', '=', 't.komoditas_id')
->selectRaw("COALESCE(k.nama, 'Belum ditentukan') as label")
->selectRaw('COUNT(t.id) as total')
->where('k.is_utama', true)
->whereNull('t.deleted_at')
->whereNull('l.deleted_at')
->whereNull('p.deleted_at')
->groupBy('k.id', 'k.nama')
->orderByDesc('total')
->get();
$totalJumlahTanaman = (int) $tanamanPerKomoditasCollection->sum('total');
$tanamanPerKomoditas = $tanamanPerKomoditasCollection
->map(function ($item, $index) use ($colors, $totalJumlahTanaman) {
$color = $colors[$index % count($colors)];
$total = (int) $item->total;
return [
'label' => $item->label,
'total' => $total,
'pct' => $totalJumlahTanaman > 0
? round(($total / $totalJumlahTanaman) * 100, 1)
: 0,
'color' => $color['color'],
'bg' => $color['bg'],
'tx' => $color['tx'],
];
})
->values();
// Distribusi peserta pelatihan GAP
$gapOptions = collect($this->pelatihanGapOptions());
$knownGapOptions = $gapOptions->reject(function ($label, $value) {
return $this->normalizeText((string) $value) === 'lainnya'
|| $this->normalizeText((string) $label) === 'lainnya';
});
$gapLookup = [];
foreach ($knownGapOptions as $value => $label) {
$gapLookup[$this->normalizeText((string) $value)] = (string) $label;
$gapLookup[$this->normalizeText((string) $label)] = (string) $label;
}
$pelatihanPairs = SurveyPelatihan::query()
->whereNotNull('petani_id')
->whereNotNull('jenis_pelatihan')
->where('jenis_pelatihan', '!=', '')
->get([
'petani_id',
'jenis_pelatihan',
])
->map(function ($row) use ($gapLookup) {
$normalized = $this->normalizeText((string) $row->jenis_pelatihan);
return [
'petani_id' => $row->petani_id,
'label' => $gapLookup[$normalized] ?? 'Lainnya',
];
})
->unique(fn ($item) => $item['petani_id'] . '|' . $item['label'])
->values();
$pelatihanCounts = $pelatihanPairs->countBy('label');
$pelatihanLabels = $knownGapOptions
->values()
->unique()
->push('Lainnya')
->values();
$pelatihanGap = $pelatihanLabels
->map(function ($label, $index) use ($pelatihanCounts, $colors) {
$color = $colors[$index % count($colors)];
return [
'label' => $label,
'total' => (int) $pelatihanCounts->get($label, 0),
'color' => $color['color'],
'bg' => $color['bg'],
'tx' => $color['tx'],
];
})
->values();
$totalPetaniPelatihan = $pelatihanPairs
->pluck('petani_id')
->unique()
->count();
// Sertifikasi
$totalPetaniBersertifikat = SurveySertifikasi::query()
->whereNotNull('petani_id')
->distinct()
->count('petani_id');
$totalPetaniSertifikatAktif = SurveySertifikasi::query()
->whereNotNull('petani_id')
->where('is_aktif', true)
->distinct()
->count('petani_id');
return view('dashboard.survey-petani', [
'enumerators' => $enumerators,
'komoditas' => $komoditas,
'totalPetani' => $totalPetani,
'circumference' => $circumference,
'progressPetani' => $progressPetani,
'totalLuasLahan' => $totalLuasLahan,
'totalJumlahTanaman' => $totalJumlahTanaman,
'tanamanPerKomoditas' => $tanamanPerKomoditas,
'pelatihanGap' => $pelatihanGap,
'totalPetaniPelatihan' => $totalPetaniPelatihan,
'totalPetaniBersertifikat' => $totalPetaniBersertifikat,
'totalPetaniSertifikatAktif' => $totalPetaniSertifikatAktif,
]);
}
private function pelatihanGapOptions(): array
{
$enumClass = self::GAP_ENUM_CLASS;
if (enum_exists($enumClass)) {
if (method_exists($enumClass, 'options')) {
return collect($enumClass::options())
->mapWithKeys(function ($option, $key) {
if (is_array($option)) {
$value = (string) ($option['value'] ?? $key);
$label = (string) (
$option['label']
?? $option['name']
?? $option['value']
?? $key
);
return [$value => $label];
}
return [(string) $key => (string) $option];
})
->all();
}
return collect($enumClass::cases())
->mapWithKeys(function ($case) {
$value = $case instanceof BackedEnum
? (string) $case->value
: (string) $case->name;
$label = method_exists($case, 'label')
? (string) $case->label()
: Str::headline($case->name);
return [$value => $label];
})
->all();
}
return [
'pemangkasan_perawatan_tanaman'
=> 'Pemangkasan/perawatan tanaman',
'pemupukan_nutrisi_tanah'
=> 'Pemupukan/nutrisi tanah',
'pengendalian_hama_penyakit'
=> 'Pengendalian hama & penyakit',
'praktik_berkebun_baik_gap'
=> 'Praktik Berkebun yang Baik (GAP)',
'pengolahan_pascapanen'
=> 'Pengolahan/pascapanen',
'penyerbukan_manual_vanili'
=> 'Penyerbukan manual (vanili)',
'lainnya'
=> 'Lainnya',
];
}
private function normalizeText(string $value): string
{
return Str::lower(Str::squish($value));
}
private function colors(): array
{
return [
[
'color' => '#28a745',
'bg' => 'rgba(40,167,69,.15)',
'tx' => '#28a745',
],
[
'color' => '#007bff',
'bg' => 'rgba(0,123,255,.15)',
'tx' => '#007bff',
],
[
'color' => '#fd7e14',
'bg' => 'rgba(253,126,20,.15)',
'tx' => '#fd7e14',
],
[
'color' => '#dc3545',
'bg' => 'rgba(220,53,69,.15)',
'tx' => '#dc3545',
],
[
'color' => '#6f42c1',
'bg' => 'rgba(111,66,193,.15)',
'tx' => '#6f42c1',
],
[
'color' => '#20c997',
'bg' => 'rgba(32,201,151,.15)',
'tx' => '#20c997',
],
];
}
}
@@ -9,6 +9,7 @@ use Illuminate\Support\Str;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
use App\Models\Profile;
class AuthController extends Controller
{
@@ -27,21 +28,46 @@ class AuthController extends Controller
public function createAccount(Request $request)
{
$credentials = $request->validate([
'username' => 'required|string|max:255|unique:users,username',
'username' => 'required|string|min:6|max:255|unique:users,username',
'email' => 'required|string|email|max:255|unique:users,email',
'password' => 'required|string|min:8|confirmed',
], [
'username.unique' => 'Nama pengguna sudah digunakan.',
'username.min' => 'Nama pengguna minimal 6 karakter.',
'email.unique' => 'Email sudah digunakan.',
'password.confirmed' => 'Konfirmasi password tidak cocok.',
'password.min' => 'Password minimal 8 karakter.',
]);
User::create([
'uid' => (string) Str::uuid(),
'name' => $request->name,
'username' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
'status' => 'pending',
'role' => null,
'email_verified_at' => null,
]);
$user = User::create([
'uid' => (string) Str::uuid(),
'name' => $request->username,
'username' => $request->username,
'email' => $request->email,
'password' => Hash::make($request->password),
'status' => 'pending',
'role' => null,
'email_verified_at' => null,
]);
$user->update([
'created_by' => $user->id,
'updated_by' => $user->id,
]);
Profile::create([
'user_id' => $user->id,
'user_uid' => $user->uid,
'role' => $request->role,
'nama' => $request->username,
'email' => $request->email,
'telepon' => $request->telepon,
'alamat' => $request->alamat,
'kk' => $request->kk,
'ktp' => $request->ktp,
'desa_kelurahan_id' => $request->desa_kelurahan_id,
'created_by' => $user->id,
'updated_by' => $user->id,
]);
return redirect()->route('login')->with('success', 'Account created successfully. Please login.');
}
@@ -69,6 +95,9 @@ class AuthController extends Controller
$request->validate([
'email_username' => 'required|string',
'password' => 'required|string',
], [
'email_username.required' => 'Email atau username harus diisi.',
'password.required' => 'Password harus diisi.',
]);
$login = $request->input('email_username');
@@ -99,18 +99,20 @@ class UserController extends Controller
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'username' => ['required', 'string', 'max:255', 'unique:users,username'],
'username' => ['required', 'string', 'max:255', 'min:6', 'unique:users,username'],
'nama' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
'role' => ['required', 'string'],
'telepon' => ['required', 'max:13'],
'desa_kelurahan_id' => ['required'],
'desa_kelurahan_id' => ['nullable', 'exists:desa_kelurahan,id'],
'ktp' => ['nullable', 'min:16', 'max:16'],
'kk' => ['nullable', 'min:16', 'max:16'],
'file_ktp' => ['nullable', 'file', 'mimes:jpeg,jpg,png,pdf', 'max:2048'],
'file_kk' => ['nullable', 'file', 'mimes:jpeg,jpg,pdf,png', 'max:2048'],
], [
'username.unique' => 'Nama pengguna sudah digunakan.',
'username.min' => 'Nama pengguna minimal 6 karakter.',
'password.confirmed' => 'Konfirmasi password tidak cocok!',
'password.min' => 'Password minimal 8 karakter!',
'email.unique' => 'Email sudah terdaftar.',
@@ -28,9 +28,13 @@ class KomoditasController extends Controller
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'nama' => ['required', 'string', 'max:255', 'unique:master_komoditas,nama'], // Tambah unique biar nggak ada data kembar
'nama' => ['required', 'string', 'max:255', 'unique:master_komoditas,nama'],
'kode' => ['required', 'string', 'max:2', 'unique:master_komoditas,kode'],
'is_utama' => ['nullable', 'boolean'],
], [
'nama.unique' => 'Nama komoditas ini sudah ada di database.'
'nama.unique' => 'Nama komoditas ini sudah ada di database.',
'kode.unique' => 'Kode komoditas ini sudah ada di database.',
'kode.max' => 'Kode komoditas maksimal 2 Digit.'
]);
if ($validator->fails()) {
@@ -39,6 +43,8 @@ class KomoditasController extends Controller
Komoditas::create([
'nama' => $request->nama,
'kode' => $request->kode,
'is_utama' => $request->is_utama,
'created_by' => auth()->id(),
'updated_by' => auth()->id(),
]);
@@ -55,9 +61,13 @@ class KomoditasController extends Controller
public function update(Request $request, $id)
{
$validator = Validator::make($request->all(), [
'nama' => ['required', 'string', 'max:255', 'unique:master_komoditas,nama,' . $id],
'nama' => ['required', 'string', 'max:255', 'unique:master_komoditas,nama,' . $id],
'kode' => ['required', 'string', 'max:2', 'unique:master_komoditas,kode,' . $id],
'is_utama' => ['nullable', 'boolean'],
], [
'nama.unique' => 'Nama komoditas ini sudah digunakan.'
'nama.unique' => 'Nama komoditas ini sudah ada di database.',
'kode.unique' => 'Kode komoditas ini sudah ada di database.',
'kode.max' => 'Kode komoditas maksimal 2 Digit.'
]);
if ($validator->fails()) {
@@ -66,8 +76,10 @@ class KomoditasController extends Controller
$komoditas = Komoditas::findOrFail($id);
$komoditas->update([
'nama' => $request->nama,
'updated_by' => auth()->id(),
'nama' => $request->nama,
'kode' => $request->kode,
'is_utama' => $request->is_utama,
'updated_by' => auth()->id(),
]);
return response()->json(['status' => 'success', 'message' => 'Komoditas berhasil diupdate.']);
@@ -25,9 +25,25 @@ class AksesPasarController extends Controller
$aksesPasar = AksesPasar::where('petani_id', $petaniId)->first();
$hargaJualPanen = HargaJualPanen::where('petani_id', $petaniId)->get();
$hargaJualRows = collect([
'Buah segar hasil petik',
'Biji basah',
'Biji kering/Biji Kupas',
'Terfermentasi (Rp/kg)',
])->map(function (string $bentuk, int $index) use ($hargaJualPanen) {
$existingData = $hargaJualPanen->firstWhere('bentuk_produk', $bentuk);
return [
'index' => $index,
'bentuk' => $bentuk,
'harga_panen_terakhir' => $this->currencyForDisplay($existingData?->harga_panen_terakhir),
'harga_tahun_lalu' => $this->currencyForDisplay($existingData?->harga_tahun_lalu),
'harga_dua_tahun_lalu' => $this->currencyForDisplay($existingData?->harga_dua_tahun_lalu),
];
});
return view('produktivitas.petani.akses-pasar.index', array_merge(
compact('petani', 'aksesPasar', 'hargaJualPanen'),
compact('petani', 'aksesPasar', 'hargaJualPanen', 'hargaJualRows'),
$this->aksesPasarOptions()
));
}
@@ -42,6 +58,7 @@ class AksesPasarController extends Controller
$aksesPasarData = $this->aksesPasarPayload($validated);
$aksesPasarData['uid'] = 'AKP-' . Str::uuid();
$aksesPasarData['created_by'] = Auth::id();
$aksesPasarData['updated_by'] = Auth::id();
$aksesPasar = AksesPasar::create($aksesPasarData);
@@ -59,7 +76,7 @@ class AksesPasarController extends Controller
}
}
public function update(Request $request, $id)
public function update(Request $request, $petaniId, $id)
{
$validated = $this->validateData($request);
@@ -143,6 +160,38 @@ class AksesPasarController extends Controller
'harga_jual.*.harga_panen_terakhir' => ['nullable', 'numeric', 'min:0'],
'harga_jual.*.harga_tahun_lalu' => ['nullable', 'numeric', 'min:0'],
'harga_jual.*.harga_dua_tahun_lalu' => ['nullable', 'numeric', 'min:0'],
], [
'petani_id.required' => 'Petani harus dipilih.',
'petani_id.exists' => 'Petani tidak ditemukan.',
'skor_pengalaman.integer' => 'Skor pengalaman harus berupa angka.',
'skor_pengalaman.in' => 'Skor pengalaman tidak valid.',
'alasan_berhenti.required' => 'Alasan berhenti harus diisi.',
'alasan_berhenti.string' => 'Alasan berhenti harus berupa string.',
'alasan_berhenti.max' => 'Alasan berhenti tidak boleh lebih dari 255 karakter.',
'saluran_terdahulu.array' => 'Saluran terdahulu harus berupa array.',
'saluran_terdahulu.*.string' => 'Saluran terdahulu harus berupa string.',
'saluran_terdahulu.*.in' => 'Saluran terdahulu tidak valid.',
'saluran_terdahulu_lainnya.required' => 'Saluran terdahulu lainnya harus diisi.',
'saluran_terdahulu_lainnya.string' => 'Saluran terdahulu lainnya harus berupa string.',
'saluran_terdahulu_lainnya.max' => 'Saluran terdahulu lainnya tidak boleh lebih dari 255 karakter.',
'praktik_fermentasi.string' => 'Praktik fermentasi harus berupa string.',
'praktik_fermentasi.in' => 'Praktik fermentasi tidak valid.',
'proses_fermentasi.required' => 'Proses fermentasi harus diisi.',
'proses_fermentasi.string' => 'Proses fermentasi harus berupa string.',
'model_fermentasi_memungkinkan.required' => 'Model fermentasi memungkinkan harus diisi.',
'model_fermentasi_memungkinkan.string' => 'Model fermentasi memungkinkan harus berupa string.',
'skor_kesadaran_premium.integer' => 'Skor kesadaran premium harus berupa angka.',
'skor_kesadaran_premium.in' => 'Skor kesadaran premium tidak valid.',
'sumber_info_premium.string' => 'Sumber info premium harus berupa string.',
'sumber_info_premium.max' => 'Sumber info premium tidak boleh lebih dari 255 karakter.',
'harga_jual.array' => 'Harga jual harus berupa array.',
'harga_jual.*.bentuk_produk.string' => 'Bentuk produk harus berupa string.',
'harga_jual.*.harga_panen_terakhir.numeric' => 'Harga panen terakhir harus berupa angka.',
'harga_jual.*.harga_tahun_lalu.numeric' => 'Harga tahun lalu harus berupa angka.',
'harga_jual.*.harga_dua_tahun_lalu.numeric' => 'Harga dua tahun lalu harus berupa angka.',
'harga_jual.*.harga_panen_terakhir.min' => 'Harga panen terakhir minimal 0.',
'harga_jual.*.harga_tahun_lalu.min' => 'Harga tahun lalu minimal 0.',
'harga_jual.*.harga_dua_tahun_lalu.min' => 'Harga dua tahun lalu minimal 0.',
]);
}
@@ -218,4 +267,11 @@ class AksesPasarController extends Controller
$digits = preg_replace('/\D/', '', (string) $value);
return $digits === '' ? null : $digits;
}
}
private function currencyForDisplay(mixed $value): string
{
$digits = $this->currencyDigits($value);
return is_null($digits) ? '' : number_format((int) $digits, 0, ',', '.');
}
}
@@ -5,20 +5,186 @@ namespace App\Http\Controllers\Web\Produktivitas;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Str;
use App\Models\Pertanian\Petani;
use App\Models\Pertanian\SurveyPelatihan;
use App\Models\Pertanian\SurveySertifikasi;
class PendidikanPelatihanController extends Controller
{
public function index($petaniId, Request $request)
private function authorizeAccess(): void
{
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
abort(403);
}
}
public function index(Petani $petani)
{
$this->authorizeAccess();
$title = 'Petani - Pendidikan dan Pelatihan';
$petani = Petani::findOrFail($petaniId);
return view('produktivitas.petani.pendidikan-pelatihan.add', compact('title', 'petani'));
$petani->load([
'surveyPelatihan',
'surveySertifikasi',
]);
return view('produktivitas.petani.pendidikan-pelatihan.index', compact(
'title',
'petani'
));
}
public function storePelatihan(Request $request, Petani $petani)
{
$this->authorizeAccess();
$validatedData = $request->validate([
'riwayat_pelatihan' => ['nullable', 'array'],
'riwayat_pelatihan.*.jenis_pelatihan' => ['nullable', 'string', 'max:255'],
'riwayat_pelatihan.*.penyelenggara' => ['nullable', 'string', 'max:255'],
'riwayat_pelatihan.*.tahun' => ['nullable', 'integer', 'min:1900', 'max:' . date('Y')],
], [
'riwayat_pelatihan.*.tahun.integer' => 'Tahun pelatihan harus berupa angka.',
'riwayat_pelatihan.*.tahun.min' => 'Tahun pelatihan tidak valid.',
'riwayat_pelatihan.*.tahun.max' => 'Tahun pelatihan tidak boleh melebihi tahun saat ini.',
], [
'riwayat_pelatihan.*.jenis_pelatihan' => 'jenis pelatihan',
'riwayat_pelatihan.*.penyelenggara' => 'penyelenggara',
'riwayat_pelatihan.*.tahun' => 'tahun pelatihan',
]);
foreach ($validatedData['riwayat_pelatihan'] ?? [] as $item) {
if (
empty($item['jenis_pelatihan']) &&
empty($item['penyelenggara']) &&
empty($item['tahun'])
) {
continue;
}
$petani->surveyPelatihan()->create([
'uid' => 'SPL-' . strtoupper(Str::random(10)),
'petani_id' => $petani->id,
'jenis_pelatihan' => $item['jenis_pelatihan'] ?? null,
'penyelenggara' => $item['penyelenggara'] ?? null,
'tahun_pelaksanaan' => $item['tahun'] ?? null,
'created_by' => auth()->id(),
'updated_by' => auth()->id(),
]);
}
return $this->redirectBackToFragment($request, 'section-sertifikasi')
->with('success', 'Riwayat pelatihan berhasil disimpan.');
}
public function destroyPelatihan(Request $request, Petani $petani, SurveyPelatihan $surveyPelatihan)
{
$this->authorizeAccess();
abort_unless($surveyPelatihan->petani_id === $petani->id, 404);
$surveyPelatihan->update([
'deleted_by' => auth()->id(),
]);
$surveyPelatihan->delete();
return $this->redirectBackToFragment($request, 'section-pelatihan')
->with('success', 'Riwayat pelatihan berhasil dihapus.');
}
public function storeSertifikasi(Request $request, Petani $petani)
{
$this->authorizeAccess();
$sertifikasi = $request->input('sertifikasi', []);
foreach ($sertifikasi as $index => $item) {
$status = $item['status_berlaku_sertifikat'] ?? 0;
if (is_array($status)) {
$status = in_array('1', $status, true) ? 1 : 0;
} else {
$status = $status == 1 ? 1 : 0;
}
$sertifikasi[$index]['status_berlaku_sertifikat'] = $status;
}
$request->merge([
'sertifikasi' => $sertifikasi,
]);
$validatedData = $request->validate([
'sertifikasi' => ['nullable', 'array'],
'sertifikasi.*.jenis_sertifikasi' => ['nullable', 'string', 'max:255'],
'sertifikasi.*.lembaga_penerbit' => ['nullable', 'string', 'max:255'],
'sertifikasi.*.tahun' => ['nullable', 'integer', 'min:1900', 'max:' . date('Y')],
'sertifikasi.*.status_berlaku_sertifikat' => ['nullable', 'boolean'],
], [
'sertifikasi.*.tahun.integer' => 'Tahun sertifikasi harus berupa angka.',
'sertifikasi.*.tahun.min' => 'Tahun sertifikasi tidak valid.',
'sertifikasi.*.tahun.max' => 'Tahun sertifikasi tidak boleh melebihi tahun saat ini.',
], [
'sertifikasi.*.jenis_sertifikasi' => 'jenis sertifikasi',
'sertifikasi.*.lembaga_penerbit' => 'lembaga penerbit',
'sertifikasi.*.tahun' => 'tahun sertifikasi',
'sertifikasi.*.status_berlaku_sertifikat' => 'status sertifikat',
]);
foreach ($validatedData['sertifikasi'] ?? [] as $item) {
if (
empty($item['jenis_sertifikasi']) &&
empty($item['lembaga_penerbit']) &&
empty($item['tahun'])
) {
continue;
}
$petani->surveySertifikasi()->create([
'uid' => 'SPS-' . strtoupper(Str::random(10)),
'petani_id' => $petani->id,
'jenis_sertifikasi' => $item['jenis_sertifikasi'] ?? null,
'lembaga_penerbit' => $item['lembaga_penerbit'] ?? null,
'tahun_pelaksanaan' => $item['tahun'] ?? null,
'is_aktif' => $item['status_berlaku_sertifikat'] ?? 0,
'created_by' => auth()->id(),
'updated_by' => auth()->id(),
]);
}
return $this->redirectBackToFragment($request, 'section-sertifikasi')
->with('success', 'Sertifikasi berhasil disimpan.');
}
public function destroySertifikasi(Request $request, Petani $petani, SurveySertifikasi $surveySertifikasi)
{
$this->authorizeAccess();
abort_unless($surveySertifikasi->petani_id === $petani->id, 404);
$surveySertifikasi->update([
'deleted_by' => auth()->id(),
]);
$surveySertifikasi->delete();
return $this->redirectBackToFragment($request, 'section-sertifikasi')
->with('success', 'Sertifikasi berhasil dihapus.');
}
private function redirectBackToFragment(Request $request, string $defaultFragment)
{
$fragment = $request->input('redirect_fragment', $defaultFragment);
if (!is_string($fragment) || !preg_match('/^[A-Za-z0-9_-]+$/', $fragment)) {
$fragment = $defaultFragment;
}
return redirect()->to(Str::before(url()->previous(), '#') . '#' . $fragment);
}
}
@@ -14,6 +14,10 @@ use Illuminate\Support\Facades\Storage;
use App\Models\Wilayah\Provinsi;
use App\Models\Pertanian\Petani;
use App\Models\Wilayah\DesaKelurahan;
use App\Models\Pertanian\Komoditas;
use App\Models\Pertanian\Tanaman;
use App\Models\Pertanian\Lahan;
use App\Models\Pertanian\SkorPetani;
use App\Enums\Pendidikan;
use App\Enums\Pekerjaan;
@@ -26,9 +30,20 @@ class PetaniController extends Controller
*/
public function index(Request $request)
{
$provinsi = Provinsi::orderBy('kode', 'asc')->get();
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
abort(403);
}
$query = Petani::with('desakelurahan')
$provinsi = Provinsi::select('id', 'kode', 'nama')->orderBy('kode', 'asc')->get();
$query = Petani::with([
'desaKelurahan:id,nama,kecamatan_id',
'desaKelurahan.kecamatan:id,nama,kabupaten_kota_id',
'desaKelurahan.kecamatan.kabupatenKota:id,nama,provinsi_id',
'desaKelurahan.kecamatan.kabupatenKota.provinsi:id,nama',
'komoditas:id,nama',
'skor:id,petani_id,skor_kesiapan_adopsi',
])
->orderBy('created_at', 'desc');
if ($request->search) {
@@ -38,9 +53,35 @@ class PetaniController extends Controller
});
}
if (auth()->user()->role->value === 'fasilitator') {
$query->where('created_by', auth()->user()->id);
}
$summaryPetaniIds = (clone $query)->pluck('id');
$petani = $query->paginate($request->per_page ?? 10);
return view('produktivitas.petani.index', compact('petani', 'provinsi'));
$komoditas = Komoditas::select('id', 'nama')->where('is_utama', true)->get();
$lahanQuery = Lahan::whereIn('petani_id', $summaryPetaniIds)
->whereIn('komoditas_id', $komoditas->pluck('id'));
$lahanIds = (clone $lahanQuery)->pluck('id');
$totalLuasLahan = (clone $lahanQuery)->sum('luas_lahan');
$totalTanaman = Tanaman::whereIn('lahan_id', $lahanIds)->count();
$case = "
CASE
WHEN skor_kesiapan_adopsi >= 4.0 THEN 'Penggerak'
WHEN skor_kesiapan_adopsi >= 3.0 THEN 'Perintis'
WHEN skor_kesiapan_adopsi >= 2.0 THEN 'Pemerhati'
WHEN skor_kesiapan_adopsi >= 1.0 THEN 'Pemula'
ELSE 'Belum Lengkap'
END
";
$skor = SkorPetani::selectRaw("$case AS segmen, COUNT(*) AS total")
->whereIn('petani_id', $summaryPetaniIds)
->groupByRaw($case)
->get();
return view('produktivitas.petani.index', compact('petani', 'provinsi', 'komoditas', 'skor', 'totalLuasLahan', 'totalTanaman'));
}
public function create()
@@ -53,19 +94,17 @@ class PetaniController extends Controller
$pekerjaan = Pekerjaan::options();
$pernikahan = Pernikahan::options();
$komoditas = Komoditas::where('is_utama', true)->get();
$provinsi = Provinsi::orderBy('kode', 'asc')->get();
return view('produktivitas.petani.add', compact('pendidikan', 'pekerjaan',
'pernikahan', 'provinsi'));
'pernikahan', 'provinsi', 'komoditas'));
}
public function store(Request $request)
private function validatePetani(Request $request)
{
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
abort(403);
}
$validatedData = $request->validate([
return $request->validate([
'nama' => ['required','string','max:255'],
'jenis_kelamin' => ['required','boolean'],
'tempat_lahir' => ['required','string','max:255'],
@@ -73,7 +112,7 @@ class PetaniController extends Controller
'pendidikan_terakhir' => ['required', Rule::enum(Pendidikan::class)],
'alamat' => ['required','string','max:500'],
'desa_kelurahan_id' => ['required','exists:master_desa_kelurahan,id'],
//'komoditas_id' => ['required','exists:master_komoditas,id'],
'komoditas_id' => ['required','exists:master_komoditas,id'],
'status_perkawinan' => ['required', Rule::enum(Pernikahan::class)],
'ktp' => ['nullable', 'min:16', 'max:16'],
'file_ktp' => ['nullable', 'image', 'mimes:jpeg,jpg,png', 'max:2048'],
@@ -82,8 +121,48 @@ class PetaniController extends Controller
'foto' => ['nullable', 'image', 'mimes:jpeg,jpg,png', 'max:2048'],
'nomor_telepon' => ['nullable', 'digits_between:11,13'],
], [
'nama.required' => 'Nama harus diisi.',
'nama.string' => 'Nama harus berupa string.',
'nama.max' => 'Nama tidak boleh lebih dari 255 karakter.',
'jenis_kelamin.required' => 'Jenis kelamin harus dipilih.',
'tempat_lahir.required' => 'Tempat lahir harus diisi.',
'tempat_lahir.string' => 'Tempat lahir harus berupa string.',
'tempat_lahir.max' => 'Tempat lahir tidak boleh lebih dari 255 karakter.',
'tanggal_lahir.required' => 'Tanggal lahir harus diisi.',
'tanggal_lahir.date' => 'Tanggal lahir harus berupa tanggal.',
'pendidikan_terakhir.required' => 'Pendidikan terakhir harus dipilih.',
'alamat.required' => 'Alamat harus diisi.',
'alamat.string' => 'Alamat harus berupa string.',
'alamat.max' => 'Alamat tidak boleh lebih dari 500 karakter.',
'desa_kelurahan_id.required' => 'Desa kelurahan harus dipilih.',
'desa_kelurahan_id.exists' => 'Desa kelurahan tidak ditemukan.',
'komoditas_id.required' => 'Komoditas harus dipilih.',
'komoditas_id.exists' => 'Komoditas tidak ditemukan.',
'status_perkawinan.required' => 'Status perkawinan harus dipilih.',
'ktp.min' => 'KTP harus berupa 16 digit.',
'ktp.max' => 'KTP harus berupa 16 digit.',
'kk.min' => 'KK harus berupa 16 digit.',
'kk.max' => 'KK harus berupa 16 digit.',
'file_ktp.image' => 'File KTP harus berupa gambar.',
'file_ktp.mimes' => 'File KTP harus berupa jpeg, jpg, atau png.',
'file_ktp.max' => 'File KTP tidak boleh lebih dari 2MB.',
'file_kk.image' => 'File KK harus berupa gambar.',
'file_kk.mimes' => 'File KK harus berupa jpeg, jpg, atau png.',
'file_kk.max' => 'File KK tidak boleh lebih dari 2MB.',
'foto.image' => 'Foto harus berupa gambar.',
'foto.mimes' => 'Foto harus berupa jpeg, jpg, atau png.',
'foto.max' => 'Foto tidak boleh lebih dari 2MB.',
'nomor_telepon.digits_between' => 'Nomor telepon harus berupa angka 11 sampai 13 digit.',
]);
}
public function store(Request $request)
{
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
abort(403);
}
$validatedData = $this->validatePetani($request);
if ($request->hasFile('file_ktp')) {
$file_ktp = $request->file('file_ktp');
@@ -106,7 +185,7 @@ class PetaniController extends Controller
'created_by' => auth()->id(),
'updated_by' => auth()->id()]);
return redirect()->route('petani.index')->with('success', 'Data petani berhasil ditambahkan.');
return redirect()->route('petani.edit', $petani->id)->with('success', 'Data petani berhasil ditambahkan.');
}
public function show(string $id)
@@ -135,10 +214,10 @@ class PetaniController extends Controller
$provinsi = Provinsi::all();
$section = $request->section ?? 'budidaya';
$komoditas = Komoditas::where('is_utama', true)->get();
return view('produktivitas.petani.edit', compact('petani', 'pendidikan', 'pekerjaan',
'pernikahan', 'provinsi', 'section'));
'pernikahan', 'provinsi', 'komoditas'));
}
@@ -150,25 +229,14 @@ class PetaniController extends Controller
$petani = Petani::findOrFail($id);
$validatedData = $request->validate([
'nama' => ['required','string','max:255'],
'jenis_kelamin' => ['required','boolean'],
'tempat_lahir' => ['required','string','max:255'],
'tanggal_lahir' => ['required','date'],
'pendidikan_terakhir' => ['required', Rule::enum(Pendidikan::class)],
'alamat' => ['required','string','max:500'],
'desa_kelurahan_id' => ['required','exists:master_desa_kelurahan,id'],
//'komoditas_id' => ['required','exists:master_komoditas,id'],
'status_perkawinan' => ['required', Rule::enum(Pernikahan::class)],
'ktp' => ['nullable', 'min:16', 'max:16'],
'file_ktp' => ['nullable', 'file', 'mimes:jpeg,jpg,png,pdf', 'max:2048'],
'kk' => ['nullable', 'min:16', 'max:16'],
'file_kk' => ['nullable', 'file', 'mimes:jpeg,jpg,png,pdf', 'max:2048'],
'foto' => ['nullable', 'file', 'mimes:jpeg,jpg,png', 'max:2048'],
'nomor_telepon' => ['nullable', 'digits_between:11,13'],
], [
'nomor_telepon.digits_between' => 'Nomor telepon harus berupa angka 11 sampai 13 digit.',
]);
$validatedData = $this->validatePetani($request);
if ($request->input('hapus_foto') == '1') {
if ($petani->foto && Storage::exists($petani->foto)) {
Storage::delete($petani->foto);
}
$validatedData['foto'] = null;
}
if ($request->hasFile('file_ktp')) {
$file_ktp = $request->file('file_ktp');
@@ -181,6 +249,10 @@ class PetaniController extends Controller
$validatedData['file_kk'] = $file_kk->getClientOriginalName();
}
if ($request->hasFile('foto')) {
if ($petani->foto && Storage::exists($petani->foto)) {
Storage::delete($petani->foto);
}
$file_foto = $request->file('foto');
$validatedData['foto'] = $file_foto->store('petani/foto');
}
@@ -188,7 +260,7 @@ class PetaniController extends Controller
$petani->update([...$validatedData,
'updated_by' => auth()->id()]);
return redirect()->route('petani.index')->with('success', 'Data petani berhasil diupdate.');
return redirect()->route('petani.edit', $petani->id)->with('success', 'Data petani berhasil diupdate.');
}
/**
@@ -7,6 +7,7 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Validation\Rules\Enum;
@@ -17,7 +18,9 @@ use App\Models\Pertanian\Lahan;
use App\Models\Wilayah\DesaKelurahan;
use App\Models\Wilayah\Provinsi;
use App\Models\Pertanian\Komoditas;
use App\Models\Pertanian\PraktikBudidaya;
use App\Models\Pertanian\Tanaman;
use App\Models\Master\JenisTanaman;
use App\Enums\StatusLahan;
use App\Enums\KondisiTanaman;
@@ -62,8 +65,131 @@ class PetaniLahanController extends Controller
$provinsi = Provinsi::orderBy('kode', 'asc')->get();
$komoditas = Komoditas::all();
$tanamanPenaung = JenisTanaman::all();
$autoPestDiseaseData = $this->autoPestDiseaseData($petaniId);
$jenisHamaOtomatis = $autoPestDiseaseData['jenis_hama'];
$jenisPenyakitOtomatis = $autoPestDiseaseData['jenis_penyakit'];
return view('produktivitas.petani.lahan.add', compact('petani', 'lahan', 'provinsi', 'komoditas'));
return view('produktivitas.petani.lahan.add', compact('petani', 'lahan', 'provinsi', 'komoditas', 'tanamanPenaung', 'jenisHamaOtomatis', 'jenisPenyakitOtomatis'));
}
private function autoPestDiseaseData(string|int $petaniId): array
{
$praktikBudidaya = PraktikBudidaya::where('petani_id', $petaniId)->latest()->first();
return [
'jenis_hama' => $this->normalizeArrayValue($praktikBudidaya?->jenis_hama),
'jenis_penyakit' => $this->normalizeArrayValue($praktikBudidaya?->jenis_penyakit),
];
}
private function normalizeArrayValue(mixed $value): array
{
if (is_array($value)) {
return array_values(array_filter($value, fn ($item) => filled($item)));
}
if (is_string($value) && $value !== '') {
$decoded = json_decode($value, true);
if (is_array($decoded)) {
return array_values(array_filter($decoded, fn ($item) => filled($item)));
}
return [$value];
}
return [];
}
private function hasPestDiseaseColumns(string $table): bool
{
return Schema::hasColumn($table, 'jenis_hama')
&& Schema::hasColumn($table, 'jenis_penyakit');
}
private function validateLahan(Request $request)
{
return $request->validate([
'nama' => ['nullable', 'string', 'max:255'],
'status_kepemilikan' => ['nullable', 'string', 'max:255'],
'profile_id' => ['nullable'],
'petani_id' => ['nullable'],
'keluarga_pengelola_id' => ['nullable'],
'adat_pemilik_id' => ['nullable'],
'desa_kelurahan_id' => ['nullable'],
'luas_lahan' => ['required', 'numeric', 'min:0.01'],
'path' => ['nullable', 'string'],
'komoditas_id' => ['required', 'exists:master_komoditas,id'],
'jenis_komoditas_id' => ['required', 'exists:jenis_komoditas,id'],
'varietas_id' => ['nullable', 'exists:master_varietas,id'],
'jumlah_tanaman' => ['nullable', 'numeric', 'min:0'],
'umur_lahan' => ['nullable', 'numeric', 'min:1'],
'umur_tanaman' => ['required', 'numeric', 'min:1'],
'kondisi_tanaman' => ['required', 'string', new Enum(KondisiTanaman::class)],
'serangan_hama' => ['nullable', 'string', new Enum(SeranganHama::class)],
'penyakit_tanaman' => ['nullable', 'string', new Enum(PenyakitTanaman::class)],
'keparahan_serangan' => ['nullable', 'string', new Enum(KeparahanSerangan::class)],
'komoditas_lain' => ['nullable', 'array'],
'komoditas_lain.*' => ['integer', 'exists:master_komoditas,id'],
'tanaman_penaung' => ['nullable', 'array'],
'tanaman_penaung.*' => ['string'],
'foto' => ['nullable', 'array'],
'foto.*' => ['image', 'mimes:jpeg,jpg,png', 'max:2048'],
], [
'nama.string' => 'Nama lahan diisi dengan huruf.',
'nama.max' => 'Nama lahan maksimal 255 karakter.',
'status_kepemilikan.string' => 'Status kepemilikan diisi dengan huruf.',
'status_kepemilikan.max' => 'Status kepemilikan maksimal 255 karakter.',
'luas_lahan.required' => 'Luas lahan wajib diisi.',
'luas_lahan.numeric' => 'Luas lahan diisi dengan angka.',
'luas_lahan.min' => 'Luas lahan minimal 0.01.',
//'jumlah_tanaman.required' => 'Jumlah tanaman wajib diisi.',
'jumlah_tanaman.numeric' => 'Jumlah tanaman diisi dengan angka.',
'jumlah_tanaman.min' => 'Jumlah tanaman minimal 0.',
//'umur_lahan.required' => 'Umur lahan wajib diisi.',
'umur_lahan.numeric' => 'Umur lahan diisi dengan angka.',
'umur_lahan.min' => 'Umur lahan minimal 1.',
'umur_tanaman.required' => 'Umur tanaman wajib diisi.',
'umur_tanaman.numeric' => 'Umur tanaman diisi dengan angka.',
'umur_tanaman.min' => 'Umur tanaman minimal 1.',
'kondisi_tanaman.required' => 'Kondisi tanaman wajib dipilih.',
'kondisi_tanaman.string' => 'Kondisi tanaman diisi dengan huruf.',
'serangan_hama.string' => 'Serangan hama diisi dengan huruf.',
'penyakit_tanaman.string' => 'Penyakit tanaman diisi dengan huruf.',
'keparahan_serangan.string' => 'Keparahan serangan diisi dengan huruf.',
'komoditas_lain.array' => 'Komoditas lain diisi dengan array.',
'komoditas_lain.*.exists' => 'Komoditas lain yang dipilih tidak valid.',
'tanaman_penaung.array' => 'Tanaman penaung diisi dengan array.',
//'tanaman_penaung.*.exists' => 'Tanaman penaung yang dipilih tidak valid.',
'foto.array' => 'Foto diisi dengan array.',
'foto.*.image' => 'Foto harus berupa gambar.',
'foto.*.mimes' => 'Foto harus berupa gambar dengan ekstensi jpeg, jpg, atau png.',
'foto.*.max' => 'Foto maksimal 2MB.',
]);
}
private function syncTanamanPenaung(Request $request)
{
$existing = JenisTanaman::pluck('nama')->toArray();
$tanamanPenaung = collect($request->tanaman_penaung)
->unique()
->reject(fn ($nama) => in_array($nama, $existing))
->map(fn ($nama) => [
'nama' => Str::title($nama),
'created_by' => auth()->id(),
'updated_by' => auth()->id(),
'created_at' => now(),
'updated_at' => now(),
])
->values()
->toArray();
if (!empty($tanamanPenaung)) {
JenisTanaman::insert($tanamanPenaung);
}
}
public function store($petaniId, Request $request)
@@ -74,38 +200,42 @@ class PetaniLahanController extends Controller
$petani = Petani::findOrFail($petaniId);
$validated = $request->validate([
'nama' => ['nullable', 'string', 'max:255'],
'status_kepemilikan' => ['nullable', 'string', 'max:255'],
'profile_id' => ['nullable'],
'petani_id' => ['nullable'],
'keluarga_pengelola_id' => ['nullable'],
'adat_pemilik_id' => ['nullable'],
'desa_kelurahan_id' => ['nullable'],
'luas_lahan' => ['required', 'numeric'],
'path' => ['nullable', 'string'],
'komoditas_id' => ['required', 'exists:master_komoditas,id'],
'jenis_komoditas_id' => ['required', 'exists:jenis_komoditas,id'],
'varietas_id' => ['nullable', 'exists:master_varietas,id'],
'jumlah_tanaman' => ['required', 'numeric'],
'umur_lahan' => ['required', 'numeric'],
'umur_tanaman' => ['required', 'numeric'],
'kondisi_tanaman' => ['required', 'string', new Enum(KondisiTanaman::class)],
'serangan_hama' => ['nullable', 'string', new Enum(SeranganHama::class)],
'penyakit_tanaman' => ['nullable', 'string', new Enum(PenyakitTanaman::class)],
'keparahan_serangan' => ['nullable', 'string', new Enum(KeparahanSerangan::class)],
'komoditas_lain' => ['nullable', 'array'],
'komoditas_lain.*' => ['integer', 'exists:master_komoditas,id'],
'tanaman_penaung' => ['nullable', 'array'],
'tanaman_penaung.*' => ['integer', 'exists:master_komoditas,id'],
]);
$request->merge([
'tanaman_penaung' => collect($request->tanaman_penaung)
->map(fn ($nama) => Str::title($nama))
->toArray()
]);
$validated = $this->validateLahan($request);
$autoPestDiseaseData = $this->autoPestDiseaseData($petaniId);
$lahanHasPestDiseaseColumns = $this->hasPestDiseaseColumns((new Lahan)->getTable());
$tanamanHasPestDiseaseColumns = $this->hasPestDiseaseColumns((new Tanaman)->getTable());
if ($lahanHasPestDiseaseColumns) {
$validated = array_merge($validated, $autoPestDiseaseData);
}
$komoditas = Komoditas::where('id', $request->komoditas_id)->first();
$lahanCount = Lahan::where('petani_id', $petaniId)
->count();
$lahanUid = strtoupper(Str::random(10));
$foto = null;
if ($request->hasFile('foto')) {
$foto = [];
foreach ($request->file('foto') as $file) {
$path = $file->store('lahan', 'public');
$foto[] = [
'path' => $path,
'file' => $file->getClientOriginalName(),
];
}
}
$this->syncTanamanPenaung($request);
$lahan = Lahan::create([...$validated,
'foto' => $foto && count($foto) > 0 ? json_encode($foto) : null,
'nama' => 'Lahan ' . $komoditas->nama . ' #' . ($lahanCount + 1),
'uid' => 'LHN-' . $petani->uid . '-' . $lahanUid,
'petani_id' => $petaniId,
@@ -113,9 +243,9 @@ class PetaniLahanController extends Controller
'updated_by' => auth()->id()]
);
if ($lahan) {
$data = collect(range(1, $lahan->jumlah_tanaman))->map(function ($i) use ($lahan, $komoditas, $lahanUid) {
return [
if ($lahan && $lahan->jumlah_tanaman > 0) {
$data = collect(range(1, $lahan->jumlah_tanaman))->map(function ($i) use ($lahan, $komoditas, $lahanUid, $autoPestDiseaseData, $tanamanHasPestDiseaseColumns) {
$row = [
'lahan_id' => $lahan->id,
'uid' => 'TNM-' . $lahanUid . '-' . strtoupper(Str::random(10)),
'komoditas_id' => $lahan->komoditas_id,
@@ -133,14 +263,31 @@ class PetaniLahanController extends Controller
'created_at' => now(),
'updated_at' => now(),
];
if ($tanamanHasPestDiseaseColumns) {
$row['jenis_hama'] = json_encode($autoPestDiseaseData['jenis_hama'] ?? []);
$row['jenis_penyakit'] = json_encode($autoPestDiseaseData['jenis_penyakit'] ?? []);
}
return $row;
});
$data->chunk(500)->each(function ($chunk) {
Tanaman::insert($chunk->toArray());
});
return redirect()->route('petani.lahan-tanaman.index', $petaniId)->with('success', 'Lahan berhasil ditambahkan.');
if ($request->ajax()) {
return response()->json([
'success' => true,
'redirect' => route('petani.lahan-tanaman.edit', [$petaniId, $lahan->id]),
'message' => 'Lahan berhasil ditambahkan.'
]);
}
return redirect()->route('petani.lahan-tanaman.edit', [$petaniId, $lahan->id])->with('success', 'Lahan berhasil ditambahkan.');
}
return redirect()->route('petani.lahan-tanaman.edit', [$petaniId, $lahan->id])->with('success', 'Lahan berhasil ditambahkan.');
}
public function show(string $petaniId, string $id)
@@ -176,10 +323,14 @@ class PetaniLahanController extends Controller
$lahanSelected = Lahan::where('petani_id', $petaniId)->findOrFail($id);
$komoditas = Komoditas::all();
$tanamanPenaung = JenisTanaman::all();
$autoPestDiseaseData = $this->autoPestDiseaseData($petaniId);
$jenisHamaOtomatis = $autoPestDiseaseData['jenis_hama'];
$jenisPenyakitOtomatis = $autoPestDiseaseData['jenis_penyakit'];
$provinsi = Provinsi::orderBy('kode', 'asc')->get();
return view('produktivitas.petani.lahan.edit', compact('lahan', 'lahanSelected', 'petani', 'komoditas', 'provinsi'));
return view('produktivitas.petani.lahan.edit', compact('lahan', 'lahanSelected', 'petani', 'komoditas', 'provinsi', 'tanamanPenaung', 'jenisHamaOtomatis', 'jenisPenyakitOtomatis'));
}
public function update(Request $request, string $petaniId, string $id)
@@ -191,40 +342,62 @@ class PetaniLahanController extends Controller
$petani = Petani::findOrFail($petaniId);
$lahan = Lahan::where('petani_id', $petaniId)->findOrFail($id);
$validated = $request->validate([
'nama' => ['nullable', 'string', 'max:255'],
'status_kepemilikan' => ['nullable', 'string', 'max:255'],
'profile_id' => ['nullable'],
'petani_id' => ['nullable'],
'keluarga_pengelola_id' => ['nullable'],
'adat_pemilik_id' => ['nullable'],
'desa_kelurahan_id' => ['nullable'],
'luas_lahan' => ['required', 'numeric'],
'path' => ['nullable', 'string'],
'komoditas_id' => ['required', 'exists:master_komoditas,id'],
'jenis_komoditas_id' => ['required', 'exists:jenis_komoditas,id'],
'varietas_id' => ['nullable', 'exists:master_varietas,id'],
'jumlah_tanaman' => ['required', 'numeric'],
'umur_lahan' => ['required', 'numeric'],
'umur_tanaman' => ['required', 'numeric'],
'kondisi_tanaman' => ['required', 'string', new Enum(KondisiTanaman::class)],
'serangan_hama' => ['nullable', 'string', new Enum(SeranganHama::class)],
'penyakit_tanaman' => ['nullable', 'string', new Enum(PenyakitTanaman::class)],
'keparahan_serangan' => ['nullable', 'string', new Enum(KeparahanSerangan::class)],
'komoditas_lain' => ['nullable', 'array'],
'komoditas_lain.*' => ['integer', 'exists:master_komoditas,id'],
'tanaman_penaung' => ['nullable', 'array'],
'tanaman_penaung.*' => ['integer', 'exists:master_komoditas,id'],
]);
$request->merge([
'tanaman_penaung' => collect($request->tanaman_penaung)
->map(fn ($nama) => Str::title($nama))
->toArray()
]);
$validated = $this->validateLahan($request);
$autoPestDiseaseData = $this->autoPestDiseaseData($petaniId);
$lahanHasPestDiseaseColumns = $this->hasPestDiseaseColumns((new Lahan)->getTable());
$tanamanHasPestDiseaseColumns = $this->hasPestDiseaseColumns((new Tanaman)->getTable());
if ($lahanHasPestDiseaseColumns) {
$validated = array_merge($validated, $autoPestDiseaseData);
}
$komoditas = Komoditas::where('id', $request->komoditas_id)->first();
$tanamanCount = Tanaman::where('lahan_id', $lahan->id)->count();
$lahanCount = Lahan::where('petani_id', $petaniId)->count();
$lahanCount = Lahan::where('petani_id', $petaniId)
->count();
$fotoLama = $lahan->foto ?? [];
if (is_string($fotoLama)) {
$fotoLama = json_decode($fotoLama, true);
}
if (!is_array($fotoLama)) {
$fotoLama = [];
}
if ($request->has('deleted_photos') && is_array($request->deleted_photos)) {
foreach ($request->deleted_photos as $deletedPath) {
if (Storage::disk('public')->exists($deletedPath)) {
Storage::disk('public')->delete($deletedPath);
}
$fotoLama = array_filter($fotoLama, function($item) use ($deletedPath) {
$currentPath = is_array($item) ? ($item['path'] ?? '') : $item;
return $currentPath !== $deletedPath;
});
}
}
$fotoLama = array_values($fotoLama);
if ($request->hasFile('foto')) {
foreach ($request->file('foto') as $file) {
$path = $file->store('lahan', 'public');
$fotoLama[] = [
'path' => $path,
'file' => $file->getClientOriginalName(),
];
}
}
unset($validated['foto']);
$lahan->update([...$validated,
'nama' => 'Lahan ' . $komoditas->nama . ' #' . ($lahanCount + 1),
'petani_id' => $petaniId,
'foto' => count($fotoLama) > 0 ? json_encode($fotoLama) : null,
'updated_by' => auth()->id()]
);
@@ -232,9 +405,11 @@ class PetaniLahanController extends Controller
$lahanUidParts = explode('LHN-', $lahanUid);
$lahanUid = end($lahanUidParts);
if ($lahan) {
$data = collect(range($lahanCount, $lahan->jumlah_tanaman))->map(function ($i) use ($lahan, $komoditas, $lahanUid) {
return [
$this->syncTanamanPenaung($request);
if ($lahan && $lahan->jumlah_tanaman > $tanamanCount) {
$data = collect(range($tanamanCount + 1, $lahan->jumlah_tanaman))->map(function ($i) use ($lahan, $komoditas, $lahanUid, $autoPestDiseaseData, $tanamanHasPestDiseaseColumns) {
$row = [
'lahan_id' => $lahan->id,
'komoditas_id' => $lahan->komoditas_id,
'jenis_komoditas_id' => $lahan->jenis_komoditas_id,
@@ -252,19 +427,56 @@ class PetaniLahanController extends Controller
'created_at' => now(),
'updated_at' => now(),
];
if ($tanamanHasPestDiseaseColumns) {
$row['jenis_hama'] = json_encode($autoPestDiseaseData['jenis_hama'] ?? []);
$row['jenis_penyakit'] = json_encode($autoPestDiseaseData['jenis_penyakit'] ?? []);
}
return $row;
});
$data->chunk(500)->each(function ($chunk) {
Tanaman::insert($chunk->toArray());
});
return redirect()->route('petani.lahan-tanaman.index', $petaniId)->with('success', 'Lahan berhasil ditambahkan.');
}
if ($tanamanHasPestDiseaseColumns) {
$lahan->tanaman()->update([
'jenis_hama' => json_encode($autoPestDiseaseData['jenis_hama'] ?? []),
'jenis_penyakit' => json_encode($autoPestDiseaseData['jenis_penyakit'] ?? []),
'updated_by' => auth()->id(),
]);
}
if ($request->ajax()) {
return response()->json([
'success' => true,
'redirect' => route('petani.lahan-tanaman.edit', [$petaniId, $lahan->id]),
'message' => 'Lahan berhasil diupdate.'
]);
}
return redirect()->route('petani.lahan-tanaman.edit', [$petaniId, $lahan->id])->with('success', 'Lahan berhasil diperbarui.');
}
public function destroy(string $id)
public function destroy(string $petaniId, string $id)
{
//
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
abort(403);
}
$lahan = Lahan::findOrFail($id);
$lahan->tanaman()->update([
'deleted_by' => auth()->id()
]);
$lahan->tanaman()->delete();
$lahan->update([
'deleted_by' => auth()->id()
]);
$lahan->delete();
return redirect()->route('petani.lahan-tanaman.index', $petaniId)->with('success', 'Lahan berhasil dihapus.');
}
public function summary(string $petaniId)
@@ -178,8 +178,14 @@ class PraktikBudidayaController extends Controller
$teknik_pemangkasan = array_values($teknik_pemangkasan);
if ((int) ($validatedData['frekuensi_pemangkasan_komoditas_utama'] ?? 0) === FrekuensiPemangkasanUtama::TIDAK_PERNAH->value) {
$teknik_pemangkasan = [];
}
$petani = Petani::findOrFail($petaniId);
$pemupukanTidakPernah = (int) ($validatedData['pemberian_pupuk'] ?? 0) === PemberianPupuk::TIDAK_PERNAH->value;
$praktikBudidaya = $petani->praktikBudidaya()->create([
'petani_id' => $petani->id,
'uid' => 'PB-' . strtoupper(Str::random(10)),
@@ -193,12 +199,12 @@ class PraktikBudidayaController extends Controller
'deskripsi_penyerbukan_manual' => $validatedData['alasan_tidak_penyerbukan'] ?? null,
'tingkat_keberhasilan_penyerbukan' => $validatedData['tingkat_keberhasilan_penyerbukan'] ?? null,
'pemberian_pupuk' => $validatedData['pemberian_pupuk'] ?? null,
'jenis_pupuk' => $validatedData['jenis_pupuk'] ?? null,
'frekuensi_pemberian_pupuk' => ($validatedData['frekuensi_pemupukan'] ?? null) === 'Lainnya' ? ($validatedData['frekuensi_pemupukan_lainnya'] ?? null) : ($validatedData['frekuensi_pemupukan'] ?? null),
'estimasi_dosis_pupuk_organik' => $validatedData['estimasi_dosis_pupuk_organik'] ?? null,
'estimasi_dosis_pupuk_anorganik' => $validatedData['estimasi_dosis_pupuk_anorganik'] ?? null,
'waktu_pemberian_pupuk' => ($validatedData['waktu_pemberian_pupuk'] ?? null) === 'Lainnya' ? ($validatedData['waktu_pemberian_pupuk_lainnya'] ?? null) : ($validatedData['waktu_pemberian_pupuk'] ?? null),
'cara_pemberian_pupuk' => ($validatedData['cara_pemberian_pupuk'] ?? null) === 'Lainnya' ? ($validatedData['cara_pemberian_pupuk_lainnya'] ?? null) : ($validatedData['cara_pemberian_pupuk'] ?? null),
'jenis_pupuk' => $pemupukanTidakPernah ? null : ($validatedData['jenis_pupuk'] ?? null),
'frekuensi_pemberian_pupuk' => $pemupukanTidakPernah ? null : (($validatedData['frekuensi_pemupukan'] ?? null) === 'Lainnya' ? ($validatedData['frekuensi_pemupukan_lainnya'] ?? null) : ($validatedData['frekuensi_pemupukan'] ?? null)),
'estimasi_dosis_pupuk_organik' => $pemupukanTidakPernah ? null : ($validatedData['estimasi_dosis_pupuk_organik'] ?? null),
'estimasi_dosis_pupuk_anorganik' => $pemupukanTidakPernah ? null : ($validatedData['estimasi_dosis_pupuk_anorganik'] ?? null),
'waktu_pemberian_pupuk' => $pemupukanTidakPernah ? null : (($validatedData['waktu_pemberian_pupuk'] ?? null) === 'Lainnya' ? ($validatedData['waktu_pemberian_pupuk_lainnya'] ?? null) : ($validatedData['waktu_pemberian_pupuk'] ?? null)),
'cara_pemberian_pupuk' => $pemupukanTidakPernah ? null : (($validatedData['cara_pemberian_pupuk'] ?? null) === 'Lainnya' ? ($validatedData['cara_pemberian_pupuk_lainnya'] ?? null) : ($validatedData['cara_pemberian_pupuk'] ?? null)),
'created_by' => auth()->id(),
'updated_by' => auth()->id(),
], [
@@ -554,6 +560,12 @@ class PraktikBudidayaController extends Controller
}
}
$teknikPemangkasan = array_values($teknik_pemangkasan);
if ((int) ($validatedData['frekuensi_pemangkasan_komoditas_utama'] ?? 0) === FrekuensiPemangkasanUtama::TIDAK_PERNAH->value) {
$teknikPemangkasan = [];
}
$pemupukanTidakPernah = (int) ($validatedData['pemberian_pupuk'] ?? 0) === PemberianPupuk::TIDAK_PERNAH->value;
$dataPraktikBudidaya = [
'tenaga_kerja' => $validatedData['tenaga_kerja'],
@@ -566,12 +578,12 @@ class PraktikBudidayaController extends Controller
'deskripsi_penyerbukan_manual' => $validatedData['alasan_tidak_penyerbukan'] ?? null,
'tingkat_keberhasilan_penyerbukan' => $validatedData['tingkat_keberhasilan_penyerbukan'] ?? null,
'pemberian_pupuk' => $validatedData['pemberian_pupuk'] ?? null,
'jenis_pupuk' => $validatedData['jenis_pupuk'] ?? null,
'frekuensi_pemberian_pupuk' => ($validatedData['frekuensi_pemupukan'] ?? null) === 'Lainnya' ? ($validatedData['frekuensi_pemupukan_lainnya'] ?? null) : ($validatedData['frekuensi_pemupukan'] ?? null),
'estimasi_dosis_pupuk_organik' => $validatedData['estimasi_dosis_pupuk_organik'] ?? null,
'estimasi_dosis_pupuk_anorganik' => $validatedData['estimasi_dosis_pupuk_anorganik'] ?? null,
'waktu_pemberian_pupuk' => ($validatedData['waktu_pemberian_pupuk'] ?? null) === 'Lainnya' ? ($validatedData['waktu_pemberian_pupuk_lainnya'] ?? null) : ($validatedData['waktu_pemberian_pupuk'] ?? null),
'cara_pemberian_pupuk' => ($validatedData['cara_pemberian_pupuk'] ?? null) === 'Lainnya' ? ($validatedData['cara_pemberian_pupuk_lainnya'] ?? null) : ($validatedData['cara_pemberian_pupuk'] ?? null),
'jenis_pupuk' => $pemupukanTidakPernah ? null : ($validatedData['jenis_pupuk'] ?? null),
'frekuensi_pemberian_pupuk' => $pemupukanTidakPernah ? null : (($validatedData['frekuensi_pemupukan'] ?? null) === 'Lainnya' ? ($validatedData['frekuensi_pemupukan_lainnya'] ?? null) : ($validatedData['frekuensi_pemupukan'] ?? null)),
'estimasi_dosis_pupuk_organik' => $pemupukanTidakPernah ? null : ($validatedData['estimasi_dosis_pupuk_organik'] ?? null),
'estimasi_dosis_pupuk_anorganik' => $pemupukanTidakPernah ? null : ($validatedData['estimasi_dosis_pupuk_anorganik'] ?? null),
'waktu_pemberian_pupuk' => $pemupukanTidakPernah ? null : (($validatedData['waktu_pemberian_pupuk'] ?? null) === 'Lainnya' ? ($validatedData['waktu_pemberian_pupuk_lainnya'] ?? null) : ($validatedData['waktu_pemberian_pupuk'] ?? null)),
'cara_pemberian_pupuk' => $pemupukanTidakPernah ? null : (($validatedData['cara_pemberian_pupuk'] ?? null) === 'Lainnya' ? ($validatedData['cara_pemberian_pupuk_lainnya'] ?? null) : ($validatedData['cara_pemberian_pupuk'] ?? null)),
];
}
@@ -675,6 +687,17 @@ class PraktikBudidayaController extends Controller
}
}
return back()->with('success', 'Data berhasil diperbarui.');
return $this->redirectBackToFragment($request)->with('success', 'Data berhasil diperbarui.');
}
private function redirectBackToFragment(Request $request)
{
$fragment = $request->input('redirect_fragment');
if (!is_string($fragment) || !preg_match('/^[A-Za-z0-9_-]+$/', $fragment)) {
return back();
}
return redirect()->to(Str::before(url()->previous(), '#') . '#' . $fragment);
}
}
@@ -64,12 +64,26 @@ class ProfileController extends Controller
$validator = Validator::make($request->all(), [
'nama' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'max:255'],
'telepon' => ['required', 'max:13'],
'desa_kelurahan_id' => ['required'],
'telepon' => ['nullable', 'max:13'],
'desa_kelurahan_id' => ['nullable', 'exists:master_desa_kelurahan,id'],
'ktp' => ['nullable', 'min:16', 'max:16'],
'file_ktp' => ['nullable', 'file', 'mimes:jpeg,jpg,png,pdf', 'max:2048'],
'kk' => ['nullable', 'min:16', 'max:16'],
'file_kk' => ['nullable', 'file', 'mimes:jpeg,jpg,png,pdf', 'max:2048'],
], [
'nama.required' => 'Nama wajib diisi.',
'email.required' => 'Email wajib diisi.',
'email.email' => 'Format email tidak sesuai.',
'telepon.max' => 'Nomor telepon tidak sesuai.',
'desa_kelurahan_id.exists' => 'Desa kelurahan tidak ditemukan.',
'ktp.min' => 'KTP harus terdiri dari 16 digit.',
'ktp.max' => 'KTP harus terdiri dari 16 digit.',
'kk.min' => 'KK harus terdiri dari 16 digit.',
'kk.max' => 'KK harus terdiri dari 16 digit.',
'file_ktp.mimes' => 'Format file harus dalam bentuk JPEG, JPG, PNG, atau PDF.',
'file_kk.mimes' => 'Format file harus dalam bentuk JPEG, JPG, PNG, atau PDF.',
'file_ktp.max' => 'Ukuran file maksimal 2MB.',
'file_kk.max' => 'Ukuran file maksimal 2MB.',
]);
if ($validator->fails()) {
@@ -143,12 +157,31 @@ class ProfileController extends Controller
$validator = Validator::make($request->all(), [
'nama' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'max:255'],
'telepon' => ['required', 'max:13'],
'desa_kelurahan_id' => ['required'],
'telepon' => ['nullable', 'max:13'],
'desa_kelurahan_id' => ['nullable', 'exists:master_desa_kelurahan,id'],
'ktp' => ['nullable', 'min:16', 'max:16'],
'file_ktp' => ['nullable', 'file', 'mimes:jpeg,jpg,png,pdf', 'max:2048'],
'kk' => ['nullable', 'min:16', 'max:16'],
'file_kk' => ['nullable', 'file', 'mimes:jpeg,jpg,png,pdf', 'max:2048'],
], [
'nama.required' => 'Nama harus diisi.',
'nama.string' => 'Nama harus berupa string.',
'nama.max' => 'Nama tidak boleh lebih dari 255 karakter.',
'email.required' => 'Email harus diisi.',
'email.email' => 'Email harus berupa alamat email yang valid.',
'email.max' => 'Email tidak boleh lebih dari 255 karakter.',
'telepon.max' => 'Nomor telepon tidak boleh lebih dari 13 karakter.',
'desa_kelurahan_id.exists' => 'Desa kelurahan tidak ditemukan.',
'ktp.min' => 'Nomor KTP harus terdiri dari 16 karakter.',
'ktp.max' => 'Nomor KTP harus terdiri dari 16 karakter.',
'kk.min' => 'Nomor KK harus terdiri dari 16 karakter.',
'kk.max' => 'Nomor KK harus terdiri dari 16 karakter.',
'file_ktp.file' => 'File harus berupa file.',
'file_ktp.mimes' => 'File harus berupa file dengan ekstensi jpeg, jpg, png, atau pdf.',
'file_ktp.max' => 'Ukuran file tidak boleh lebih dari 2MB.',
'file_kk.file' => 'File harus berupa file.',
'file_kk.mimes' => 'File harus berupa file dengan ekstensi jpeg, jpg, png, atau pdf.',
'file_kk.max' => 'Ukuran file tidak boleh lebih dari 2MB.',
]);
if ($validator->fails()) {
@@ -0,0 +1,76 @@
<?php
namespace App\Http\Controllers\Web\Produktivitas;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use App\Models\Pertanian\SkorPetani;
use App\Models\Pertanian\Petani;
class SkorPetaniController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(string $petaniId)
{
if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
abort(403);
}
$petani = Petani::findOrFail($petaniId);
$skor = $petani->skor;
return view('produktivitas.petani.skor.index', compact('petani', 'skor'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $petaniId, string $id)
{
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}
@@ -154,8 +154,7 @@ class SosialEkonomiController extends Controller
});
if (!$request->expectsJson()) {
return redirect()
->route('petani.sosial-ekonomi.edit', [$sosialEkonomi->petani_id, $sosialEkonomi->id])
return $this->redirectToEditSection($sosialEkonomi, $request)
->with('success', 'Data sosial ekonomi berhasil disimpan.');
}
@@ -206,8 +205,7 @@ class SosialEkonomiController extends Controller
});
if (!$request->expectsJson()) {
return redirect()
->route('petani.sosial-ekonomi.edit', [$sosialEkonomi->petani_id, $sosialEkonomi->id])
return $this->redirectToEditSection($sosialEkonomi, $request)
->with('success', 'Data sosial ekonomi berhasil diperbarui.');
}
@@ -218,6 +216,18 @@ class SosialEkonomiController extends Controller
]);
}
private function redirectToEditSection(SosialEkonomi $sosialEkonomi, Request $request): RedirectResponse
{
$url = route('petani.sosial-ekonomi.edit', [$sosialEkonomi->petani_id, $sosialEkonomi->id]);
$fragment = $request->input('redirect_fragment');
if (is_string($fragment) && preg_match('/^[A-Za-z0-9_-]+$/', $fragment)) {
$url .= '#' . $fragment;
}
return redirect()->to($url);
}
public function destroy(string $id): JsonResponse
{
$sosialEkonomi = SosialEkonomi::findOrFail($id);
@@ -589,6 +599,14 @@ class SosialEkonomiController extends Controller
$payload = $this->normalizeSkorPayload($payload);
if (array_key_exists('ada_sengketa', $payload) && !filter_var($payload['ada_sengketa'], FILTER_VALIDATE_BOOLEAN)) {
$payload['keterangan_sengketa'] = null;
$payload['pihak_membantu_konflik'] = null;
$payload['pihak_membantu_konflik_nama'] = null;
$payload['tahun_bantuan_konflik'] = null;
$payload['status_konflik'] = null;
}
if (($payload['pihak_membantu_konflik'] ?? null) === PihakMembantuKonflik::TIDAK_ADA_SELESAIKAN_SENDIRI->value) {
$payload['pihak_membantu_konflik_nama'] = null;
$payload['tahun_bantuan_konflik'] = null;
@@ -3,26 +3,43 @@
namespace App\Http\Controllers\Web\Produktivitas;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Models\Pertanian\Petani;
use App\Models\Pertanian\SurveyProduktivitas;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
class SurveyProduktivitasController extends Controller
{
public function store($petaniId, Request $request)
{
$petani = Petani::findOrFail($petaniId);
$validated = $request->validate([
'produktivitas_komoditas' => ['required', 'array'],
'produktivitas_komoditas.*.komoditas_id' => ['nullable', 'exists:master_komoditas,id'],
'produktivitas_komoditas.*.hasil_panen_3_musim' => ['nullable', 'numeric'],
'produktivitas_komoditas.*.satuan' => ['nullable', 'string'],
$validator = Validator::make($request->all(), [
'produktivitas_komoditas' => ['required', 'array', 'min:1'],
'produktivitas_komoditas.*.komoditas_id' => ['required', 'exists:master_komoditas,id'],
'produktivitas_komoditas.*.hasil_panen_3_musim' => ['required', 'numeric', 'min:0'],
'produktivitas_komoditas.*.satuan' => ['required', 'in:ha_tahun,pohon_tahun'],
], [
'produktivitas_komoditas.required' => 'Minimal satu data produktivitas harus diisi.',
'produktivitas_komoditas.*.komoditas_id.required' => 'Komoditas wajib dipilih.',
'produktivitas_komoditas.*.komoditas_id.exists' => 'Komoditas yang dipilih tidak valid.',
'produktivitas_komoditas.*.hasil_panen_3_musim.required' => 'Hasil panen wajib diisi.',
'produktivitas_komoditas.*.hasil_panen_3_musim.numeric' => 'Hasil panen harus berupa angka.',
'produktivitas_komoditas.*.hasil_panen_3_musim.min' => 'Hasil panen tidak boleh kurang dari 0.',
'produktivitas_komoditas.*.satuan.required' => 'Satuan wajib dipilih.',
'produktivitas_komoditas.*.satuan.in' => 'Satuan yang dipilih tidak valid.',
]);
if ($validator->fails()) {
return $this->redirectBackToFragment($request)->withErrors($validator)->withInput();
}
$validated = $validator->validated();
foreach ($validated['produktivitas_komoditas'] as $row) {
SurveyProduktivitas::create([
'uid' => 'SPV-' . strtoupper(Str::random(10)),
'uid' => 'SPV-'.strtoupper(Str::random(10)),
'petani_id' => $petani->id,
'komoditas_id' => $row['komoditas_id'],
'kuantitas' => $row['hasil_panen_3_musim'],
@@ -32,10 +49,10 @@ class SurveyProduktivitasController extends Controller
]);
}
return back()->with('success', 'Data produktivitas berhasil disimpan.');
return $this->redirectBackToFragment($request)->with('success', 'Data produktivitas berhasil disimpan.');
}
public function destroy($petaniId, $surveyProduktivitasId)
public function destroy($petaniId, $surveyProduktivitasId, Request $request)
{
$surveyProduktivitas = SurveyProduktivitas::where('petani_id', $petaniId)
->where('id', $surveyProduktivitasId)
@@ -44,6 +61,17 @@ class SurveyProduktivitasController extends Controller
$surveyProduktivitas->save();
$surveyProduktivitas->delete();
return back()->with('success', 'Data produktivitas berhasil dihapus.');
return $this->redirectBackToFragment($request)->with('success', 'Data produktivitas berhasil dihapus.');
}
private function redirectBackToFragment(Request $request)
{
$fragment = $request->input('redirect_fragment');
if (! is_string($fragment) || ! preg_match('/^[A-Za-z0-9_-]+$/', $fragment)) {
return back();
}
return redirect()->to(Str::before(url()->previous(), '#').'#'.$fragment);
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Models\Master;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class JenisTanaman extends Model
{
use HasFactory, SoftDeletes;
protected $table = 'master_jenis_tanaman';
protected $fillable = [
'nama',
'created_by',
'updated_by',
'deleted_by',
];
}
+6 -1
View File
@@ -8,6 +8,10 @@ use Illuminate\Support\Str;
use App\Models\User;
use App\Models\Pertanian\Petani;
use App\Models\Pertanian\SkorPetani;
use App\Enums\AksesPasar\PraktikFermentasi;
use App\Enums\AksesPasar\SaluranTerdahulu;
use App\Enums\AksesPasar\SkorPengalaman;
use App\Enums\AksesPasar\SkorKesadaranPremium;
class AksesPasar extends Model
{
@@ -46,7 +50,7 @@ class AksesPasar extends Model
static::saved(function (AksesPasar $aksesPasar) {
$petani = Petani::find($aksesPasar->petani_id);
$skor = SkorPetani::where('petani_id')->orderBy('id')->first();
$skor = SkorPetani::where('petani_id', $petani->id)->orderBy('id')->first();
if (!$skor) {
$petaniUid = $petani->uid;
$part = explode('-', $petaniUid);
@@ -57,6 +61,7 @@ class AksesPasar extends Model
'updated_by' => $petani->updated_by
]);
}
$skor->update([
'skor_d6_k1_6_pengalaman_menjual_ke_saluran_berbeda' => $aksesPasar->skor_pengalaman,
'skor_d6_k4_1_kesadaran_akses_pasar_premium' => $aksesPasar->skor_kesadaran_premium,
+13
View File
@@ -5,8 +5,10 @@ namespace App\Models\Pertanian;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\HasMany;
use App\Models\Master\JenisKomoditas;
use App\Models\Master\Varietas;
use App\Models\Pertanian\Petani;
class Komoditas extends Model
{
@@ -14,11 +16,17 @@ class Komoditas extends Model
protected $table = 'master_komoditas';
protected $casts = [
'is_utama' => 'boolean',
];
protected $fillable = [
'nama',
'kode',
'created_by',
'updated_by',
'deleted_by',
'is_utama',
];
protected static function booted()
@@ -42,4 +50,9 @@ class Komoditas extends Model
{
return $this->hasMany(Varietas::class, 'komoditas_id');
}
public function petani(): HasMany
{
return $this->hasMany(Petani::class, 'komoditas_id');
}
}
+14
View File
@@ -15,6 +15,9 @@ use App\Models\Pertanian\Komoditas;
use App\Models\Master\JenisKomoditas;
use App\Models\Master\Varietas;
use App\Enums\KondisiTanaman;
use App\Enums\SeranganHama;
use App\Enums\PenyakitTanaman;
use App\Enums\KeparahanSerangan;
class Lahan extends Model
{
@@ -52,6 +55,11 @@ class Lahan extends Model
'komoditas_lain',
'tanaman_penaung',
'foto',
'jenis_hama',
'jenis_penyakit',
];
protected $casts = [
@@ -60,6 +68,12 @@ class Lahan extends Model
'komoditas_lain' => 'array',
'tanaman_penaung' => 'array',
'kondisi_tanaman' => KondisiTanaman::class,
'serangan_hama' => SeranganHama::class,
'penyakit_tanaman' => PenyakitTanaman::class,
'keparahan_serangan' => KeparahanSerangan::class,
'foto' => 'array',
'jenis_hama' => 'array',
'jenis_penyakit' => 'array'
];
public function profile(): BelongsTo
+89 -3
View File
@@ -4,7 +4,19 @@ namespace App\Models\Pertanian;
use App\Enums\Pendidikan;
use App\Enums\Pernikahan;
use App\Models\User;
use App\Models\Wilayah\DesaKelurahan;
use App\Models\Pertanian\Lahan;
use App\Models\Pertanian\Komoditas;
use App\Models\Pertanian\PraktikBudidaya;
use App\Models\Pertanian\SurveyPanen;
use App\Models\Pertanian\SurveyPelatihan;
use App\Models\Pertanian\SurveyProduktivitas;
use App\Models\Pertanian\SurveySertifikasi;
use App\Models\Pertanian\SkorPetani;
use App\Models\Pertanian\AksesPasar;
use App\Models\Pertanian\HargaJualPanen;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -12,6 +24,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
class Petani extends Model
{
@@ -44,6 +57,8 @@ class Petani extends Model
'pendidikan_terakhir',
'status_perkawinan',
'komoditas_id',
'created_by',
'updated_by',
'deleted_by',
@@ -93,6 +108,11 @@ class Petani extends Model
});
}
public function komoditas(): BelongsTo
{
return $this->belongsTo(Komoditas::class, 'komoditas_id');
}
public function skor(): HasOne
{
return $this->hasOne(SkorPetani::class, 'petani_id');
@@ -105,12 +125,22 @@ class Petani extends Model
public function surveyPanen(): HasOne
{
return $this->hasOne(surveyPanen::class, 'petani_id')->latestOfMany();
return $this->hasOne(SurveyPanen::class, 'petani_id')->latestOfMany();
}
public function surveyProduktivitas(): HasOne
public function surveyPelatihan(): HasMany
{
return $this->hasOne(surveyProduktivitas::class, 'petani_id')->latestOfMany();
return $this->hasMany(SurveyPelatihan::class, 'petani_id');
}
public function surveySertifikasi(): HasMany
{
return $this->hasMany(SurveySertifikasi::class, 'petani_id');
}
public function surveyProduktivitas(): HasMany
{
return $this->hasMany(SurveyProduktivitas::class, 'petani_id');
}
public function lahans(): HasMany
@@ -128,6 +158,11 @@ class Petani extends Model
return $this->hasOne(AksesPasar::class, 'petani_id');
}
public function hargaJualPanen(): HasMany
{
return $this->hasMany(HargaJualPanen::class, 'petani_id');
}
public function skorLahanTanaman(): ?float
{
if (! Schema::hasTable('map_lahan')) {
@@ -312,4 +347,55 @@ class Petani extends Model
{
return $value instanceof \BackedEnum ? $value->value : $value;
}
public function segmen(): ?string
{
$skor = $this->skor;
if (!$skor) {
return null;
}
if ($skor->skor_kesiapan_adopsi >= 4.0) {
return 'Penggerak';
} elseif ($skor->skor_kesiapan_adopsi >= 3.0) {
return 'Perintis';
} elseif ($skor->skor_kesiapan_adopsi >= 2.0) {
return 'Pemerhati';
} elseif ($skor->skor_kesiapan_adopsi >= 1.0) {
return 'Pemula';
} else {
return 'Belum tersegmentasi';
}
return 'Belum tersegmentasi';
}
public function keteranganSegmen(): ?string
{
$skor = $this->skor;
if (!$skor) {
return null;
}
if ($skor->skor_kesiapan_adopsi >= 4.0) {
return 'Siap menjadi peserta agrolab utama dan panutan bagi petani lain';
} elseif ($skor->skor_kesiapan_adopsi >= 3.0) {
return 'Berpotensi berkembang menjadi Penggerak dengan dukungan yang tepat';
} elseif ($skor->skor_kesiapan_adopsi >= 2.0) {
return 'Perlu melihat bukti hasil nyata dari Penggerak sebelum mau bergerak';
} elseif ($skor->skor_kesiapan_adopsi >= 1.0) {
return 'Butuh penanganan hambatan dasar terlebih dahulu sebelum intervensi teknis';
} else {
return 'Belum tersegmentasi, data belum lengkap';
}
return 'Belum tersegmentasi, data belum lengkap';
}
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
}
+48 -7
View File
@@ -8,10 +8,13 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
use App\Models\Pertanian\Petani;
use App\Models\Pertanian\SkorPetani;
use App\Models\Pertanian\Tanaman;
use App\Models\Pertanian\Lahan;
class PraktikBudidaya extends Model
{
@@ -91,16 +94,54 @@ class PraktikBudidaya extends Model
'updated_by' => $petani->updated_by
]);
}
$kebiasaan = $praktikBudidaya->kebiasaan_konservasi_tanah ? count($praktikBudidaya->kebiasaan_konservasi_tanah) : 0;
$pemahaman = $praktikBudidaya->pemahaman_manfaat_konservasi_tanah == 'Ya, tahu manfaatnya' ? 1 : 0;
$skor_konservasi_tanah = 0;
$jenisHama = $praktikBudidaya->jenis_hama ?? [];
$jenisPenyakit = $praktikBudidaya->jenis_penyakit ?? [];
if (Schema::hasColumn((new Lahan)->getTable(), 'jenis_hama')
&& Schema::hasColumn((new Lahan)->getTable(), 'jenis_penyakit')) {
Lahan::where('petani_id', $praktikBudidaya->petani_id)->get()->each(function (Lahan $lahan) use ($jenisHama, $jenisPenyakit, $praktikBudidaya) {
$lahan->update([
'jenis_hama' => $jenisHama,
'jenis_penyakit' => $jenisPenyakit,
'updated_by' => $praktikBudidaya->updated_by,
]);
});
}
if (Schema::hasColumn((new Tanaman)->getTable(), 'jenis_hama')
&& Schema::hasColumn((new Tanaman)->getTable(), 'jenis_penyakit')) {
Tanaman::where('petani_id', $praktikBudidaya->petani_id)->get()->each(function (Tanaman $tanaman) use ($jenisHama, $jenisPenyakit, $praktikBudidaya) {
$tanaman->update([
'jenis_hama' => $jenisHama,
'jenis_penyakit' => $jenisPenyakit,
'updated_by' => $praktikBudidaya->updated_by,
]);
});
}
if ($kebiasaan == 0) {
$skor_konservasi_tanah = 1;
} elseif ($kebiasaan == 1 && $pemahaman == 0) {
$skor_konservasi_tanah = 2;
} elseif ($kebiasaan == 1 && $pemahaman == 1) {
$skor_konservasi_tanah = 3;
} elseif ($kebiasaan > 1 && $pemahaman == 0) {
$skor_konservasi_tanah = 4;
} elseif ($kebiasaan > 1 && $pemahaman == 1) {
$skor_konservasi_tanah = 5;
}
$skor->update([
'skor_d2_k2_3_praktik_pemangkasan' => $praktikBudidaya->frekuensi_pemangkasan_komoditas_utama,
'skor_d2_k2_3_praktik_pemangkasan' => $praktikBudidaya->frekuensi_pemangkasan_utama,
'skor_d2_k2_4_praktik_pemupukan' => $praktikBudidaya->pemberian_pupuk,
'skor_d2_k2_5_pengendalian_opt' => $praktikBudidaya->metode_penanganan_hama_penyakit,
'skor_d2_k2_5_pengendalian_opt' => $praktikBudidaya->metode_penanganan_opt,
'skor_d2_k2_6_sanitasi_kebun' => $praktikBudidaya->frekuensi_sanitasi_lahan,
'skor_d2_k2_6b_pengelolaan_gulma' => $praktikBudidaya->penanganan_gulma,
'skor_d2_k2_7_penglolaan_air_irigasi' => $praktikBudidaya->kondisi_pengelolaan_air_irigasi,
//'skor_d2_k2_8_praktik_konservasi_tanah' => $praktikBudidaya->kebiasaan_konservasi_tanah,
//'skor_d2_k3_1_penentuan_pematangan' => $praktikBudidaya->
'skor_d2_k2_7_penglolaan_air_irigasi' => $praktikBudidaya->kondisi_pengelolaan_air,
'skor_d2_k2_8_praktik_konservasi_tanah' => $skor_konservasi_tanah,
]);
});
}
@@ -109,4 +150,4 @@ class PraktikBudidaya extends Model
{
return $this->belongsTo(Petani::class, 'petani_id');
}
}
}
+1 -1
View File
@@ -50,7 +50,7 @@ class SkorPetani extends Model
'skor_d4_k5_2_pengalaman_kredit_formal',
'skor_d4_k5_3_kepemilikan_aset_produktif',
'skor_d4_k5_4_kepemilikan_aset_tidak_produktif',
'skor_d4_k5_4_5_akses_program_bantuan',
'skor_d4_k5_4_akses_program_bantuan',
'skor_d4_k6_3_keberadaan_hutang_terkait_panen',
'skor_d4_k6_5a_praktik_ijon',
'skor_d4_k6_5b_kebebasan_memilih_pembeli',
+44 -8
View File
@@ -41,6 +41,7 @@ use App\Enums\SosialEkonomi\UsahaMutuTambahanHarga;
use App\Models\Pertanian\Petani;
use App\Models\Pertanian\SkorPetani;
use App\Models\Pertanian\PraktikBudidaya;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -204,15 +205,50 @@ class SosialEkonomi extends Model
'updated_by' => $petani->updated_by
]);
}
$skor->update([
'skor_d4_k5_1_kepemilikan_rekening' => $sosialEkonomi->status_rekening_tabungan,
'skor_d4_k5_2_pengalaman_kredit_formal' => $sosialEkonomi->pengalaman_kredit_kebun,
'skor_d4_k5_3_kepemilikan_aset_produktif' => $sosialEkonomi->kondisi_aset_produktif,
'skor_d4_k5_4_akses_program_bantuan' => $sosialEkonomi->keterlibatan_program_keuangan_formal,
$praktik = PraktikBudidaya::where('petani_id', $petani->id)->orderBy('id')->first();
$pendapatan = PendapatanKomoditas::where('sosial_ekonomi_id', $sosialEkonomi->id)->get();
'skor_d4_k6_3_keberadaan_hutang_terkait_panen' => $sosialEkonomi->keterikatan_hutang_panen,
'skor_d4_k6_5a_praktik_ijon' => $sosialEkonomi->praktik_ijon,
'skor_d4_k6_5b_kebebasan_memilih_pembeli' => $sosialEkonomi->kebebasan_memilih_pembeli,
$rasio = 0;
if ($praktik && ($pendapatan && $pendapatan->count() > 0 && $pendapatan->sum('pendapatan') > 0)) {
$rasio = $praktik->total_estimasi_biaya_produksi / $pendapatan->sum('pendapatan');
}
if ($rasio >= 0.8) {
$skorRasio = 1;
} else if ($rasio >= 0.6) {
$skorRasio = 2;
} else if ($rasio >= 0.45) {
$skorRasio = 3;
} else if ($rasio >= 0.3) {
$skorRasio = 4;
} else {
$skorRasio = 5;
}
$skor->update([
'skor_d4_k3_1_praktik_baru' => $sosialEkonomi->kemauan_mencoba_praktik_baru?->value,
'skor_d4_k3_4_pemahaman_mutu_harga' => $sosialEkonomi->pemahaman_mutu_harga?->value,
'skor_d4_k3_5_role_model' => $sosialEkonomi->panutan_petani_sukses?->value,
'skor_d4_k3_6_kemampuan_keterlibatan_program' => $sosialEkonomi->kemauan_ikut_program?->value,
'skor_d4_k3_7_orientasi_jangka_panjang' => $sosialEkonomi->orientasi_rencana_jangka_panjang?->value,
'skor_d4_k2_5_stabilitas_penghasilan' => $sosialEkonomi->skor_periode_paceklik?->value,
'skor_d4_k2_8_kemampuan_menabung' => $sosialEkonomi->skor_kemampuan_menabung?->value,
'skor_d4_k2_9_kecukupan_penghasilan' => $sosialEkonomi->skor_kecukupan_penghasilan?->value,
'skor_d4_k2_3_k2_7_rasio_biaya_produksi_pendapatan' => $skorRasio,
'skor_d4_k2_11_hak_kelola_lahan' => $sosialEkonomi->skor_kejelasan_status_lahan?->value,
'skor_d4_k4_2_keaktifan_pertemuan' => $sosialEkonomi->keaktifan_pertemuan_kelompok?->value,
'skor_d4_k4_3_peran_dalam_kelompok' => $sosialEkonomi->peran_dalam_kelompok?->value,
'skor_d4_k4_4_manfaat_dirasakan' => $sosialEkonomi->manfaat_kelompok_tani?->value,
'skor_d4_k5_1_kepemilikan_rekening' => $sosialEkonomi->status_rekening_tabungan?->value,
'skor_d4_k5_2_pengalaman_kredit_formal' => $sosialEkonomi->pengalaman_kredit_kebun?->value,
'skor_d4_k5_3_kepemilikan_aset_produktif' => $sosialEkonomi->kondisi_aset_produktif?->value,
'skor_d4_k5_4_akses_program_bantuan' => $sosialEkonomi->keterlibatan_program_keuangan_formal?->value,
'skor_d4_k6_3_keberadaan_hutang_terkait_panen' => $sosialEkonomi->keterikatan_hutang_panen?->value,
'skor_d4_k6_5a_praktik_ijon' => $sosialEkonomi->praktik_ijon?->value,
'skor_d4_k6_5b_kebebasan_memilih_pembeli' => $sosialEkonomi->kebebasan_memilih_pembeli?->value,
]);
});
}
+24
View File
@@ -44,6 +44,30 @@ class SurveyPanen extends Model
'deleted_by',
];
protected static function booted(): void
{
static::saved(function (SurveyPanen $survey) {
$petani = Petani::find($survey->petani_id);
$skor = SkorPetani::where('petani_id', $petani->id)->orderBy('id')->first();
if (!$skor) {
$petaniUid = $petani->uid;
$part = explode('-', $petaniUid);
$skor = SkorPetani::create([
'petani_id' => $petani->id,
'uid' => 'SKR-' . $part[1] . '-' . strtoupper(Str::random(10)),
'created_by' => $petani->created_by,
'updated_by' => $petani->updated_by
]);
}
$skor->update([
'skor_d2_k3_1_penentuan_pematangan' => $survey->dasar_penentuan_panen,
'skor_d2_k3_5_sortasi_awal_pemisahan_kualitas' => $survey->praktik_sortasi,
]);
});
}
public function petani(): BelongsTo
{
return $this->belongsTo(Petani::class, 'petani_id');
+33
View File
@@ -0,0 +1,33 @@
<?php
namespace App\Models\Pertanian;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Models\Pertanian\Petani;
class SurveyPelatihan extends Model
{
use HasFactory, SoftDeletes;
protected $table = 'survey_pelatihan';
protected $fillable = [
'uid',
'petani_id',
'jenis_pelatihan',
'penyelenggara',
'tahun_pelaksanaan',
'created_by',
'updated_by',
'deleted_by',
];
public function petani(): BelongsTo
{
return $this->belongsTo(Petani::class, 'petani_id');
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Models\Pertanian;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class SurveySertifikasi extends Model
{
use HasFactory, SoftDeletes;
protected $table = 'survey_sertifikasi';
protected $fillable = [
'uid',
'petani_id',
'jenis_sertifikasi',
'lembaga_penerbit',
'tahun_pelaksanaan',
'is_aktif',
'created_by',
'updated_by',
'deleted_by',
];
public function petani()
{
return $this->belongsTo(Petani::class, 'petani_id');
}
}
+5
View File
@@ -42,6 +42,9 @@ class Tanaman extends Model
'serangan_hama',
'penyakit_tanaman',
'keparahan_serangan',
'jenis_hama',
'jenis_penyakit',
];
protected $casts = [
@@ -49,6 +52,8 @@ class Tanaman extends Model
'serangan_hama' => SeranganHama::class,
'penyakit_tanaman' => PenyakitTanaman::class,
'keparahan_serangan' => KeparahanSerangan::class,
'jenis_hama' => 'array',
'jenis_penyakit' => 'array'
];
public function komoditas()
+8
View File
@@ -9,8 +9,11 @@ use App\Enums\Role;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Laravel\Sanctum\HasApiTokens;
use App\Models\Pertanian\Petani;
class User extends Authenticatable
{
use HasFactory, Notifiable, HasApiTokens, SoftDeletes;
@@ -44,4 +47,9 @@ class User extends Authenticatable
{
return $this->hasOne(\App\Models\Profile::class);
}
public function petaniDibuat(): HasMany
{
return $this->hasMany(Petani::class, 'created_by');
}
}
+2
View File
@@ -124,4 +124,6 @@ return [
],
'force_https' => env('FORCE_HTTPS', false),
'desc' => env('APP_DESC', 'Laravel'),
];
@@ -35,24 +35,25 @@ return new class extends Migration
$table->string('cara_pemberian_pupuk')->nullable();
// 2.5 Pengendalian Organisme Pengganggu Tumbuhan (OPT)
$table->integer('metode_penanganan_opt')->nullable();
$table->string('jenis_hama')->nullable();
$table->string('jenis_penyakit')->nullable();
$table->jsonb('jenis_hama')->nullable();
$table->jsonb('jenis_penyakit')->nullable();
$table->string('intensitas_serangan')->nullable();
$table->string('waktu_kemunculan_terparah')->nullable();
$table->string('metode_paling_sering_dilakukan')->nullable();
$table->integer('volume_obat_obatan_permusim')->nullable();
$table->decimal('volume_obat_obatan_padat_permusim', 10, 2)->nullable();
$table->decimal('volume_obat_obatan_cair_permusim', 10, 2)->nullable();
// 2.6 Sanitasi Kebun
$table->integer('frekuensi_sanitasi_lahan')->nullable();
$table->string('penanganan_sisa_buah_ranting')->nullable();
$table->integer('penanganan_gulma')->nullable();
// 2.7 Pengelolaan Air & irigasi
$table->integer('kondisi_pengelolaan_air')->nullable();
$table->string('sumber_air')->nullable();
$table->jsonb('sumber_air')->nullable();
$table->string('sistem_irigasi')->nullable();
$table->string('kebutuhan_air_permusim')->nullable();
// 2.8 Praktik konservasi tanah
$table->string('kebiasaan_konservasi_tanah')->nullable();
$table->jsonb('kebiasaan_konservasi_tanah')->nullable();
$table->string('pemahaman_manfaat_konservasi_tanah')->nullable();
$table->integer('nilai_konservasi_tanah')->nullable();
@@ -99,7 +100,7 @@ return new class extends Migration
$table->string('tindakan_panen_reject')->nullable();
$table->decimal('upah_tenaga_panen', 13, 2)->nullable();
$table->decimal('biaya_pengangkutan_panen', 13, 2)->nullable();
$table->decimal('biaya_wadah-Panen', 13, 2)->nullable();
$table->decimal('biaya_wadah_Panen', 13, 2)->nullable();
$table->decimal('biaya_sewa_alat_panen', 13, 2)->nullable();
$table->decimal('biaya_panen_lainnya', 13, 2)->nullable();
$table->decimal('total_estimasi_biaya_panen', 13, 2)->nullable();
@@ -11,9 +11,16 @@ return new class extends Migration
*/
public function up(): void
{
Schema::table('petani', function (Blueprint $table) {
$table->foreignId('komoditas_id')->nullable()->constrained('master_komoditas')->onDelete('set null');
});
Schema::table('map_lahan', function (Blueprint $table) {
$table->json('komoditas_lain')->nullable();
$table->json('tanaman_penaung')->nullable();
$table->json('foto')->nullable();
});
}
@@ -0,0 +1,52 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('survey_pelatihan', function (Blueprint $table) {
$table->id();
$table->string('uid')->unique();
$table->foreignId('petani_id')->nullable()->constrained('petani')->onDelete('set null');
$table->string('jenis_pelatihan');
$table->string('penyelenggara');
$table->integer('tahun_pelaksanaan');
$table->foreignId('created_by')->nullable()->constrained('users')->onDelete('set null');
$table->foreignId('updated_by')->nullable()->constrained('users')->onDelete('set null');
$table->foreignId('deleted_by')->nullable()->constrained('users')->onDelete('set null');
$table->timestamps();
$table->softDeletes();
});
Schema::create('survey_sertifikasi', function (Blueprint $table) {
$table->id();
$table->string('uid')->unique();
$table->foreignId('petani_id')->nullable()->constrained('petani')->onDelete('set null');
$table->string('jenis_sertifikasi');
$table->string('lembaga_penerbit');
$table->integer('tahun_pelaksanaan');
$table->boolean('is_aktif')->default(false);
$table->foreignId('created_by')->nullable()->constrained('users')->onDelete('set null');
$table->foreignId('updated_by')->nullable()->constrained('users')->onDelete('set null');
$table->foreignId('deleted_by')->nullable()->constrained('users')->onDelete('set null');
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('pelatihan');
Schema::dropIfExists('sertifikasi');
}
};
@@ -0,0 +1,25 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('master_komoditas', function (Blueprint $table) {
$table->boolean('is_utama')->default(false);
});
}
public function down(): void
{
Schema::table('master_komoditas', function (Blueprint $table) {
$table->dropColumn('is_utama');
});
}
};
@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('master_jenis_tanaman', function (Blueprint $table) {
$table->id();
$table->string('nama');
$table->foreignId('created_by')->nullable()->constrained('users')->onDelete('set null');
$table->foreignId('updated_by')->nullable()->constrained('users')->onDelete('set null');
$table->foreignId('deleted_by')->nullable()->constrained('users')->onDelete('set null');
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('jenis_tanamen');
}
};
@@ -0,0 +1,57 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('map_lahan', function (Blueprint $table) {
if (! Schema::hasColumn('map_lahan', 'jenis_hama')) {
$table->jsonb('jenis_hama')->nullable();
}
if (! Schema::hasColumn('map_lahan', 'jenis_penyakit')) {
$table->jsonb('jenis_penyakit')->nullable();
}
});
Schema::table('map_tanaman', function (Blueprint $table) {
if (! Schema::hasColumn('map_tanaman', 'jenis_hama')) {
$table->jsonb('jenis_hama')->nullable();
}
if (! Schema::hasColumn('map_tanaman', 'jenis_penyakit')) {
$table->jsonb('jenis_penyakit')->nullable();
}
});
}
public function down(): void
{
Schema::table('map_lahan', function (Blueprint $table) {
if (Schema::hasColumn('map_lahan', 'jenis_hama')) {
$table->dropColumn('jenis_hama');
}
if (Schema::hasColumn('map_lahan', 'jenis_penyakit')) {
$table->dropColumn('jenis_penyakit');
}
});
Schema::table('map_tanaman', function (Blueprint $table) {
if (Schema::hasColumn('map_tanaman', 'jenis_hama')) {
$table->dropColumn('jenis_hama');
}
if (Schema::hasColumn('map_tanaman', 'jenis_penyakit')) {
$table->dropColumn('jenis_penyakit');
}
});
}
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

+8 -8
View File
@@ -14,21 +14,21 @@ document.addEventListener('DOMContentLoaded', function () {
username: {
validators: {
notEmpty: {
message: 'Please enter username'
message: 'Silakan masukkan username'
},
stringLength: {
min: 6,
message: 'Username must be more than 6 characters'
message: 'Username harus terdiri dari minimal 6 karakter'
}
}
},
email: {
validators: {
notEmpty: {
message: 'Please enter your email'
message: 'Silakan masukkan email Anda'
},
emailAddress: {
message: 'Please enter a valid email address'
message: 'Silakan masukkan email yang valid'
}
}
},
@@ -57,22 +57,22 @@ document.addEventListener('DOMContentLoaded', function () {
'confirm-password': {
validators: {
notEmpty: {
message: 'Please confirm password'
message: 'Silakan konfirmasi password Anda'
},
identical: {
compare: () => formAuthentication.querySelector('[name="password"]').value,
message: 'The password and its confirmation do not match'
message: 'Password tidak cocok dengan konfirmasi password'
},
stringLength: {
min: 6,
message: 'Password must be more than 6 characters'
message: 'Password harus terdiri dari minimal 6 karakter'
}
}
},
terms: {
validators: {
notEmpty: {
message: 'Please agree to terms & conditions'
message: 'Silakan terima syarat dan ketentuan kami'
}
}
}
+8 -3
View File
@@ -111,15 +111,20 @@
<!-- endbuild -->
<!-- Vendors JS -->
<script src="{{ asset('assets/vendor/libs/@form-validation/popular.js') }}"></script>
<!-- <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>
<script src="{{ asset('assets/vendor/libs/@form-validation/auto-focus.js') }}"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.5/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.5/additional-methods.min.js"></script>
<!-- Main JS -->
<script src="{{ asset('assets/js/main.js') }}"></script>
<!-- Page JS -->
<script src="{{ asset('assets/js/pages-auth.js') }}"></script>
<!-- <script src="{{ asset('assets/js/pages-auth.js') }}"></script> -->
@stack('scripts')
</body>
</html>
+67 -1
View File
@@ -5,6 +5,7 @@
<!-- Logo -->
<div class="app-brand justify-content-center mb-6">
<a href="{{ route('home') }}" class="app-brand-link">
@if(config('app.name') == 'AgroMonev')
<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">
@@ -20,10 +21,34 @@
</span>
</span>
<span class="app-brand-text demo menu-text fw-bold ms-3" style="text-transform: capitalize;">AgroMonev</span>
@elseif(config('app.name') == 'AgroPro')
<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">
<path opacity="0.25" d="M16 2.5C16 2.5 5 6.5 5 15.5C5 20.5 11 23.5 16 23.5V2.5Z" fill="#28A745"/>
<path opacity="0.5" d="M16 2.5C16 2.5 27 6.5 27 15.5C27 20.5 21 23.5 16 23.5V2.5Z" fill="#28A745"/>
<rect x="5.5" y="5.5" width="21" height="15" rx="2.5" fill="white" stroke="#0054A6" stroke-width="1.5"/>
<rect x="11" y="3.5" width="10" height="4" rx="2" fill="#0054A6"/>
<circle cx="9.5" cy="10" r="1.7" fill="#28A745"/>
<path d="M8.7 10L9.3 10.6L10.4 9.3" stroke="white" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13 10H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 10H22" stroke="#0054A6" stroke-width="2" stroke-linecap="round"/>
<circle cx="9.5" cy="14" r="1.7" fill="#28A745"/>
<path d="M8.7 14L9.3 14.6L10.4 13.3" stroke="white" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13 14H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 14H19.5" stroke="#F4B400" stroke-width="2" stroke-linecap="round"/>
<circle cx="9.5" cy="18" r="1.7" fill="white" stroke="#ED1C24" stroke-width="1.3"/>
<path d="M13 18H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 18H17" stroke="#ED1C24" stroke-width="2" stroke-linecap="round"/>
</svg>
</span>
</span>
<span class="app-brand-text demo menu-text fw-bold ms-3" style="text-transform: capitalize;">AgroPro</span>
@endif
</a>
</div>
<!-- /Logo -->
<h4 class="mb-1">Selamat datang di AgroMonev!</h4>
<h4 class="mb-1">Selamat datang di {{ config('app.name') }}!</h4>
<p class="mb-6">Silakan masuk ke akun Anda</p>
@if ($errors->any())
<div class="alert alert-danger">
@@ -87,3 +112,44 @@
</div>
</div>
@endsection
@push('scripts')
<script>
$(document).ready(function () {
$('#formAuthentication').validate({
rules: {
email_username: {
required: true,
minlength: 6,
},
password: {
required: true,
},
},
messages: {
email_username: {
required: 'Email atau Nama Pengguna wajib diisi',
minlength: 'Email atau Nama Pengguna minimal 6 karakter',
},
password: {
required: 'Password wajib diisi',
},
},
errorElement: 'div',
errorPlacement: function (error, element) {
error.addClass('invalid-feedback');
element.closest('.mb-6, .form-control-validation').append(error);
},
highlight: function (element) {
$(element).addClass('is-invalid');
},
unhighlight: function (element) {
$(element).removeClass('is-invalid');
},
submitHandler: function (form) {
form.submit();
}
})
})
</script>
@endpush
+67 -2
View File
@@ -113,7 +113,7 @@
</a>
</p>
<div class="divider my-6">
<!-- <div class="divider my-6">
<div class="divider-text">atau</div>
</div>
@@ -133,7 +133,72 @@
<a href="javascript:;" class="btn btn-icon rounded-circle btn-text-google-plus">
<i class="icon-base ti tabler-brand-google-filled icon-20px"></i>
</a>
</div>
</div> -->
</div>
</div>
@endsection
@push('scripts')
<script>
$(document).ready(function () {
$('#formAuthentication').validate({
rules: {
username: {
required: true,
minlength: 6,
},
email: {
required: true,
email: true,
},
password: {
required: true,
minlength: 8,
},
password_confirmation: {
required: true,
equalTo: '#password',
},
terms: {
required: true,
},
},
messages: {
username: {
required: 'Username wajib diisi',
minlength: 'Username minimal 6 karakter',
},
email: {
required: 'Email wajib diisi',
email: 'Format email tidak sesuai',
},
password: {
required: 'Kata Sandi wajib diisi',
},
password_confirmation: {
required: 'Konfirmasi Kata Sandi wajib diisi',
equalTo: 'Konfirmasi Kata Sandi tidak sesuai',
minlength: 'Password minimal 8 karakter',
},
terms: {
required: 'Anda harus menyetujui ketentuan layanan',
},
},
errorElement: 'div',
errorPlacement: function (error, element) {
error.addClass('invalid-feedback');
element.closest('.mb-6, .form-control-validation').append(error);
},
highlight: function (element) {
$(element).addClass('is-invalid');
},
unhighlight: function (element) {
$(element).removeClass('is-invalid');
},
submitHandler: function (form) {
form.submit();
}
})
})
</script>
@endpush
@@ -4,7 +4,7 @@
<div class="card-body d-flex justify-content-between align-items-center">
<div>
<p class="text-muted fw-medium mb-1">{{ $title }}</p>
<h3 class="text-dark fw-bold mb-1">{{ $count }}</h3>
<h3 class="text-dark fw-bold mb-1">{!! $count !!}</h3>
<small class="text-muted">{{ $subtitle }}</small>
</div>
<div class="badge bg-label-{{ $color }} p-2 rounded">
+704
View File
@@ -0,0 +1,704 @@
@extends('layout.main')
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
<div class="row g-6">
<div class="col-lg-3 col-sm-6">
<div class="card card-border-shadow-primary h-100">
<div class="card-body">
<div class="d-flex align-items-center mb-2">
<div class="avatar me-4">
<span class="avatar-initial rounded bg-label-primary">
<i class="icon-base ti tabler-user-check icon-28px"></i>
</span>
</div>
<h4 class="mb-0">{{ $petaniSummary->sum('total') }}</h4>
</div>
<p class="mb-1">Petani</p>
<p class="mb-0">
<span class="text-heading fw-medium me-2">{{ $petaniSummary->count('total') }}</span>
<small class="text-body-secondary">komoditas utama</small>
</p>
</div>
</div>
</div>
<div class="col-lg-3 col-sm-6">
<div class="card card-border-shadow-warning h-100">
<div class="card-body">
<div class="d-flex align-items-center mb-2">
<div class="avatar me-4">
<span class="avatar-initial rounded bg-label-warning">
<i class="icon-base ti tabler-trees icon-28px"></i>
</span>
</div>
<h4 class="mb-0">{{ number_format($lahanSummary->sum('luas_lahan') / 10000, 2, ',', '.') }} ha</h4>
</div>
<p class="mb-1">Lahan</p>
<p class="mb-0">
<span class="text-heading fw-medium me-2">{{ $lahanSummary->count('total') }}</span>
<small class="text-body-warning">komoditas utama</small>
</p>
</div>
</div>
</div>
<!-- <div class="col-lg-6 col-sm-12">
<div class="card card-border-shadow-danger h-100">
<div class="card-body">
<div class="d-flex align-items-center mb-2">
<div class="avatar me-4">
<span class="avatar-initial rounded bg-label-danger">
<i class="icon-base ti tabler-seedling icon-28px"></i>
</span>
</div>
<h4 class="mb-0">{{ $tanamanSummary->sum('total') }}</h4>
</div>
<p class="mb-1">Tanaman Komoditas Utama</p>
<div class="d-flex justify-content-between mb-2">
@foreach($komoditas as $k)
<p class="mb-0">
<span class="text-heading fw-medium me-2">{{ $tanamanSummary->where('komoditas_id', $k->id)->sum('total') }}</span>
<small class="text-body-danger">tanaman {{ $k->nama }}</small>
</p>
@endforeach
</div>
</div>
</div>
</div> -->
<div class="col-lg-3 col-sm-6">
<div class="card card-border-shadow-info h-100">
<div class="card-body">
<div class="d-flex align-items-center mb-2">
<div class="avatar me-4">
<span class="avatar-initial rounded bg-label-warning">
<i class="icon-base ti tabler-star icon-28px"></i>
</span>
</div>
<h4 class="mb-0">{{ number_format($skorAverage, 2, ',', '.') }}</h4>
</div>
<p class="mb-1">Rata-rata Indeks Kesiapan Adopsi</p>
<p class="mb-0">
<span class="text-heading fw-medium me-2">{{ $segmenAverage }}</span>
<small class="text-body-info">komoditas utama</small>
</p>
</div>
</div>
</div>
</div>
<div class="row g-6 py-4">
<div class="col-lg-6 col-sm-12">
<div class="card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Segmentasi Petani</h5>
<p class="card-subtitle">untuk semua komoditas</p>
</div>
</div>
<div class="card-body">
<table class="table card-table table-border-top-0 table-border-bottom-0">
<tbody>
<tr>
<td class="w-60 ps-0"></td>
<td class="text-end pe-0">Petani</td>
<td class="text-end pe-0">%</td>
</tr>
<tr>
<td class="w-60 ps-0">
<div class="d-flex justify-content-start align-items-center">
<div class="me-2">
<i class="icon-base ti tabler-crown icon-lg text-heading"></i>
</div>
<div>
<h6 class="mb-0 fw-normal text-success">Penggerak (4.0 - 5.0)</h6>
<!-- <small class="text-body-secondary text-wrap">Siap menjadi peserta agrolab utama dan panutan bagi petani lain</small> -->
</div>
</div>
</td>
<td class="text-end pe-0">
<span>{{ $skorSummary->where('segmen', 'Penggerak')->sum('total') }} petani</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format(($skorSummary->where('segmen', 'Penggerak')->sum('total') / $petaniSummary->sum('total')) * 100, 2) }}%</span>
</td>
</tr>
<tr>
<td class="w-60 ps-0">
<div class="d-flex justify-content-start align-items-center">
<div class="me-2">
<i class="icon-base ti tabler-flag icon-lg text-heading"></i>
</div>
<div>
<h6 class="mb-0 fw-normal text-info">Perintis (3.0 - 3.9)</h6>
<!-- <small class="text-body-secondary text-wrap">Berpotensi berkembang menjadi Penggerak dengan dukungan yang tepat</small> -->
</div>
</div>
</td>
<td class="text-end pe-0">
<span>{{ $skorSummary->where('segmen', 'Perintis')->sum('total') }} petani</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format(($skorSummary->where('segmen', 'Perintis')->sum('total') / $petaniSummary->sum('total')) * 100, 2) }}%</span>
</td>
</tr>
<tr>
<td class="w-60 ps-0">
<div class="d-flex justify-content-start align-items-center">
<div class="me-2">
<i class="icon-base ti tabler-eye icon-lg text-heading text-success"></i>
</div>
<div>
<h6 class="mb-0 fw-normal text-warning">Pemerhati (2.0 - 2.9)</h6>
<!-- <small class="text-body-secondary text-wrap">Perlu melihat bukti hasil nyata dari Penggerak sebelum mau bergerak</small> -->
</div>
</div>
</td>
<td class="text-end pe-0">
<span>{{ $skorSummary->where('segmen', 'Pemerhati')->sum('total') }} petani</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format(($skorSummary->where('segmen', 'Pemerhati')->sum('total') / $petaniSummary->sum('total')) * 100, 2) }}%</span>
</td>
</tr>
<tr>
<td class="w-60 ps-0">
<div class="d-flex justify-content-start align-items-center">
<div class="me-2">
<i class="icon-base ti tabler-seedling icon-lg text-heading"></i>
</div>
<div>
<h6 class="mb-0 fw-normal text-danger">Pemula (1.0 - 1.9)</h6>
<!-- <small class="text-body-secondary text-wrap">Butuh penanganan hambatan dasar terlebih dahulu sebelum intervensi langsung</small> -->
</div>
</div>
</td>
<td class="text-end pe-0">
<span>{{ $skorSummary->where('segmen', 'Pemula')->sum('total') }} petani</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format(($skorSummary->where('segmen', 'Pemula')->sum('total') / $petaniSummary->sum('total')) * 100, 2) }}%</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- <div class="col-lg-6 col-sm-12">
<div class="card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Segmentasi Petani Komoditas</h5>
<p class="card-subtitle">berdasarkan mayoritas segmentasi</p>
</div>
</div>
<div class="card-body">
<table class="table card-table table-border-top-0 table-border-bottom-0">
<tbody>
@foreach ($komoditas as $k)
<?php
$max = $skorKomoditasSummary->where('komoditas_id', $k->id)
->whereIn('segmen', ['Penggerak', 'Perintis', 'Pemerhati', 'Pemula'])
->sortByDesc('total')
->first();
?>
<tr>
<td class="w-40 ps-0">
<h6 class="mb-0 fw-normal text-heading">{{ $k->nama }}</h6>
</td>
<td class="pe-0">
@if(isset($max))
@if($max->segmen == 'Penggerak')
<span class="text-success">Petani Penggerak</span>
@elseif($max->segmen == 'Perintis')
<span class="text-info">Petani Perintis</span>
@elseif($max->segmen == 'Pemerhati')
<span class="text-warning">Petani Pemerhati</span>
@elseif($max->segmen == 'Pemula')
<span class="text-danger">Petani Pemula</span>
@else
<span>Belum Lengkap</span>
@endif
@else
<span>Belum Tersegmentasi</span>
@endif
</td>
<td class="text-end pe-0">
<span>{{ isset($max) ? $max->total : 0 }} Petani</span>
</td>
<td class="text-end pe-0">
<span>{{ isset($max) ? number_format(($max->total / $petaniSummary->sum('total')) * 100, 2) : 0 }}%</span>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div> -->
<div class="col-lg-6 col-sm-12">
<div class="card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Segmentasi Multi Dimensi Petani</h5>
<p class="card-subtitle">untuk semua komoditas</p>
</div>
</div>
<div class="card-body">
<table class="table card-table table-border-top-0 table-border-bottom-0">
<tbody>
<tr>
<td class="w-60 ps-0"></td>
<td class="text-end pe-0">Indeks</td>
<td class="text-end pe-0">D1</td>
<td class="text-end pe-0">D2</td>
<td class="text-end pe-0">D3</td>
</tr>
<tr>
<td class="w-60 ps-0">
<div class="d-flex justify-content-start align-items-center">
<div class="me-2">
<i class="icon-base ti tabler-crown icon-lg text-heading"></i>
</div>
<div>
<h6 class="mb-0 fw-normal text-success">Penggerak (4.0 - 5.0)</h6>
<!-- <small class="text-body-secondary text-wrap">Siap menjadi peserta agrolab utama dan panutan bagi petani lain</small> -->
</div>
</div>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Penggerak')->value('skor_kesiapan_adopsi'), 2, '.', ',') }}</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Penggerak')->value('skor_d2_sistem_praktik_budidaya'), 2, '.', ',') }}</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Penggerak')->value('skor_d4_sosial_ekonomi'), 2, '.', ',') }}</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Penggerak')->value('skor_d6_rantai_nilai_akses_pasar'), 2, '.', ',') }}</span>
</td>
</tr>
<tr>
<td class="w-60 ps-0">
<div class="d-flex justify-content-start align-items-center">
<div class="me-2">
<i class="icon-base ti tabler-flag icon-lg text-heading"></i>
</div>
<div>
<h6 class="mb-0 fw-normal text-info">Perintis (3.0 - 3.9)</h6>
<!-- <small class="text-body-secondary text-wrap">Berpotensi berkembang menjadi Penggerak dengan dukungan yang tepat</small> -->
</div>
</div>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Perintis')->value('skor_kesiapan_adopsi'), 2, '.', ',') }}</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Perintis')->value('skor_d2_sistem_praktik_budidaya'), 2, '.', ',') }}</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Perintis')->value('skor_d4_sosial_ekonomi'), 2, '.', ',') }}</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Perintis')->value('skor_d6_rantai_nilai_akses_pasar'), 2, '.', ',') }}</span>
</td>
</tr>
<tr>
<td class="w-60 ps-0">
<div class="d-flex justify-content-start align-items-center">
<div class="me-2">
<i class="icon-base ti tabler-eye icon-lg text-heading text-success"></i>
</div>
<div>
<h6 class="mb-0 fw-normal text-warning">Pemerhati (2.0 - 2.9)</h6>
<!-- <small class="text-body-secondary text-wrap">Perlu melihat bukti hasil nyata dari Penggerak sebelum mau bergerak</small> -->
</div>
</div>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Pemerhati')->value('skor_kesiapan_adopsi'), 2, '.', ',') }}</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Pemerhati')->value('skor_d2_sistem_praktik_budidaya'), 2, '.', ',') }}</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Pemerhati')->value('skor_d4_sosial_ekonomi'), 2, '.', ',') }}</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Pemerhati')->value('skor_d6_rantai_nilai_akses_pasar'), 2, '.', ',') }}</span>
</td>
</tr>
<tr>
<td class="w-60 ps-0">
<div class="d-flex justify-content-start align-items-center">
<div class="me-2">
<i class="icon-base ti tabler-seedling icon-lg text-heading"></i>
</div>
<div>
<h6 class="mb-0 fw-normal text-danger">Pemula (1.0 - 1.9)</h6>
<!-- <small class="text-body-secondary text-wrap">Butuh penanganan hambatan dasar terlebih dahulu sebelum intervensi langsung</small> -->
</div>
</div>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Pemula')->value('skor_kesiapan_adopsi'), 2, '.', ',') }}</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Pemula')->value('skor_d2_sistem_praktik_budidaya'), 2, '.', ',') }}</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Pemula')->value('skor_d4_sosial_ekonomi'), 2, '.', ',') }}</span>
</td>
<td class="text-end pe-0">
<span>{{ number_format($skorMultiDimensi->where('segmen', 'Pemula')->value('skor_d6_rantai_nilai_akses_pasar'), 2, '.', ',') }}</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="row g-6 py-4">
<div class="col-lg-6 col-sm-12">
<div class="card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Rata-rata Dimensi Kesiapan Adopsi</h5>
<p class="card-subtitle">untuk semua komoditas</p>
</div>
</div>
<div class="card-body">
<div id="chart-dimensi"></div>
<div class="d-flex flex-wrap gap-3 mt-3 small justify-content-center">
<div>
<span class="badge bg-label-primary">D1</span> Sistem &amp; Praktik Budidaya
</div>
<div>
<span class="badge bg-label-primary">D2</span> Sosial Ekonomi Rumah Tangga
</div>
<div>
<span class="badge bg-label-primary">D3</span> Rantai Nilai &amp; Akses Pasar
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-6 col-sm-12">
<div class="card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Rata-rata Komponen Kesiapan Adopsi</h5>
<p class="card-subtitle">untuk semua komoditas</p>
</div>
</div>
<div class="card-body">
<div id="chart-komponen"></div>
<div class="d-flex flex-wrap gap-3 mt-3 small justify-content-center">
<div>
<span class="badge bg-label-primary">K1</span> Motivasi &amp; Kapasitas Adopsi
</div>
<div>
<span class="badge bg-label-primary">K2</span> Kondisi Ekonomi Rumah Tangga
</div>
<div>
<span class="badge bg-label-primary">K3</span> Praktik Budidaya &amp; GAP
</div>
<div>
<span class="badge bg-label-primary">K4</span> Keterlibatan Kelembagaan
</div>
<div>
<span class="badge bg-label-primary">K5</span> Akses &amp; Kebebasan Keuangan
</div>
<div>
<span class="badge bg-label-primary">K6</span> Rantai Nilai &amp; Akses Pasar
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row g-6 py-4">
<div class="col-lg-12 col-sm-12">
<div class="card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Segmentasi Petani</h5>
<p class="card-subtitle">untuk semua komoditas</p>
</div>
</div>
<div class="card-body">
<div class="table-responsive text-nowrap">
<table class="table card-table table-border-top-0 table-border-bottom-0" id="tabel-petani">
<thead>
<tr>
<th>Petani</th>
<th>Jenis Kelamin</th>
<th>Usia</th>
<th>Komoditas Utama</th>
<th>Segmentasi</th>
<th>Indeks</th>
<th>D2</th>
<th>D4</th>
<th>D6</th>
</thead>
<tbody>
@foreach ($petani as $item)
<tr>
<td><span class="text-heading">{{ $item->nama }}</span></td>
<td>{{ $item->jenis_kelamin ? 'Laki-laki' : 'Perempuan' }}</td>
<td>{{ $item->umur }} tahun</td>
<td>{{ $item->komoditas?->nama }}</td>
<td>
@if($item->segmen() == 'Penggerak')
<span class="badge bg-label-success">Penggerak</span>
@elseif($item->segmen() == 'Perintis')
<span class="badge bg-label-info">Perintis</span>
@elseif($item->segmen() == 'Pemerhati')
<span class="badge bg-label-warning">Pemerhati</span>
@elseif($item->segmen() == 'Pemula')
<span class="badge bg-label-danger">Pemula</span>
@endif
</td>
<td>{{ number_format($item->skor?->skor_kesiapan_adopsi, 2, '.', ',') }}</td>
<td>{{ number_format($item->skor?->skor_d2_sistem_praktik_budidaya, 2, '.', ',') }}</td>
<td>{{ number_format($item->skor?->skor_d4_sosial_ekonomi, 2, '.', ',') }}</td>
<td>{{ number_format($item->skor?->skor_d6_rantai_nilai_akses_pasar, 2, '.', ',') }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script>
$(document).ready(function() {
$("#tabel-petani").DataTable({
"paging": true,
"lengthChange": true,
"searching": true,
"ordering": false,
"info": true,
"autoWidth": false,
"responsive": true,
})
let cardColor, labelColor, fontFamily, headingColor, shadeColor, legendColor, borderColor, barBgColor;
if (isDarkStyle) {
barBgColor = '#3d4157';
shadeColor = 'dark';
} else {
barBgColor = '#efeef0';
shadeColor = '';
}
cardColor = config.colors.cardColor;
labelColor = config.colors.textMuted;
legendColor = config.colors.bodyColor;
borderColor = config.colors.borderColor;
headingColor = config.colors.headingColor;
var radarDimensi = new ApexCharts($("#chart-dimensi")[0],
options = {
chart: {
height: 340,
type: 'radar',
toolbar: {
show: false
}
},
series: [
{
name: "Rata-rata Dimensi Kesiapan Adopsi",
data: [{{ round($skorDimensi->skor_d2_sistem_praktik_budidaya, 2) }},
{{ round($skorDimensi->skor_d4_sosial_ekonomi, 2) }},
{{ round($skorDimensi->skor_d6_rantai_nilai_akses_pasar, 2) }}]
}
],
labels: ['Sistem & Praktik Budidaya', 'Sosial Ekonomi Rumah Tangga', 'Rantai Nilai & Akses Pasar'],
plotOptions: {
radar: {
polygons: {
strokeColors: borderColor,
connectorColors: borderColor
}
}
},
stroke: {
width: 2
},
legend: {
show: true,
fontSize: '13px',
position: 'bottom',
labels: {
colors: legendColor,
useSeriesColors: false
},
markers: {
height: 12,
width: 12
},
itemMargin: {
horizontal: 10
},
onItemHover: {
highlightDataSeries: false
}
},
colors: [config.colors.primary, config.colors.info],
fill: {
opacity: 0.85
},
markers: {
show: true,
width: 1,
},
grid: {
show: false,
padding: {
top: -25,
bottom: -5
}
},
xaxis: {
categories: ['D1', 'D2', 'D3'],
labels: {
show: true,
style: {
colors: [labelColor, labelColor, labelColor, labelColor, labelColor, labelColor],
fontSize: '13px',
fontFamily: fontFamily
}
}
},
yaxis: {
show: true,
min: 0,
max: 5,
tickAmount: 5
},
responsive: [
{
breakpoint: 769,
options: {
chart: {
height: 400
}
}
}
]
});
radarDimensi.render();
var radarKomponen = new ApexCharts($("#chart-komponen")[0],
options = {
chart: {
height: 340,
type: 'radar',
toolbar: {
show: false
}
},
series: [
{
name: "Rata-rata Komponen Kesiapan Adopsi",
data: [
{{ round($skorKomponen->skor_komp_1_d4_k3_motivasi_kapasitas_adopsi, 2) }},
{{ round($skorKomponen->skor_komp_2_d4_k2_ekonomi_rumah_tangga, 2) }},
{{ round($skorKomponen->skor_komp_3_d2_praktik_budidaya_gap, 2) }},
{{ round($skorKomponen->skor_komp_4_d4_k4_keterlibatan_kelembagaan, 2) }},
{{ round($skorKomponen->skor_komp_5_d4_k5_k6_akses_kebebasan_keuangan, 2) }},
{{ round($skorKomponen->skor_komp_6_d6_k1_k4_k5_rantai_nilai_akses_pasar, 2) }}
]
}
],
lotOptions: {
radar: {
polygons: {
strokeColors: borderColor,
connectorColors: borderColor
}
}
},
stroke: {
width: 2
},
legend: {
show: true,
fontSize: '13px',
position: 'bottom',
labels: {
colors: legendColor,
useSeriesColors: false
},
markers: {
height: 12,
width: 12
},
itemMargin: {
horizontal: 10
},
onItemHover: {
highlightDataSeries: false
}
},
colors: [config.colors.primary, config.colors.info],
fill: {
opacity: 0.85
},
markers: {
show: true,
width: 1,
},
grid: {
show: false,
padding: {
top: -25,
bottom: -5
}
},
xaxis: {
categories: ['K1', 'K2', 'K3', 'K4', 'K5', 'K6'],
labels: {
show: true,
style: {
colors: [labelColor, labelColor, labelColor, labelColor, labelColor, labelColor],
fontSize: '13px',
fontFamily: fontFamily
}
}
},
yaxis: {
show: true,
min: 0,
max: 5,
tickAmount: 5
},
responsive: [
{
breakpoint: 769,
options: {
chart: {
height: 400
}
}
}
]
});
radarKomponen.render();
});
</script>
@endpush
@@ -0,0 +1,821 @@
@extends('layout.main')
@push('style')
<style>
.tk-stat {
border-left: 4px solid transparent;
transition: transform .2s ease, box-shadow .2s ease;
}
.tk-stat:hover {
transform: translateY(-2px);
box-shadow: 0 .25rem 1rem rgba(34, 48, 62, .08);
}
.tk-stat.green { border-left-color: #28a745; }
.tk-stat.blue { border-left-color: #007bff; }
.tk-stat.amber { border-left-color: #fd7e14; }
.tk-stat-lbl {
font-size: 10px;
text-transform: uppercase;
letter-spacing: .7px;
font-weight: 600;
}
.tk-stat-val {
font-size: 20px;
font-weight: 800;
line-height: 1;
}
.tk-stat-top {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 10px;
}
.tk-pb {
display: flex;
align-items: center;
gap: 6px;
}
.tk-pbt {
flex: 1;
height: 6px;
background: rgba(128, 128, 128, .15);
border-radius: 3px;
overflow: hidden;
}
.tk-pbf {
height: 100%;
border-radius: 3px;
}
.tk-bar {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
}
.tk-bar:last-child {
margin-bottom: 0;
}
.tk-bar-lbl {
width: 105px;
font-size: 11px;
flex-shrink: 0;
}
.tk-bar-trk {
flex: 1;
height: 7px;
background: rgba(128, 128, 128, .15);
border-radius: 4px;
overflow: hidden;
}
.tk-bar-fil {
height: 100%;
border-radius: 4px;
}
.tk-bar-val {
font-size: 11px;
min-width: 58px;
}
.tk-erow {
display: flex;
align-items: center;
gap: 10px;
padding: 9px 0;
border-bottom: 1px solid rgba(128, 128, 128, .1);
}
.tk-erow:last-child {
border-bottom: none;
}
.tk-av {
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: 700;
flex-shrink: 0;
}
.tk-leg {
display: flex;
align-items: center;
gap: 7px;
margin-bottom: 7px;
font-size: 12px;
}
.tk-leg:last-child {
margin-bottom: 0;
}
.tk-leg-dot {
width: 9px;
height: 9px;
border-radius: 50%;
flex-shrink: 0;
}
.tk-leg-val {
margin-left: auto;
font-weight: 700;
font-size: 12px;
}
.tk-divider {
height: 1px;
background: rgba(128, 128, 128, .1);
margin: 12px 0;
}
.tk-donut-num {
fill: var(--bs-body-color);
font-size: 15px;
font-weight: 800;
}
.tk-donut-sub {
fill: var(--bs-secondary-color, #6c757d);
font-size: 9px;
}
.enumerator-scroll {
max-height: 244px;
overflow-y: auto;
overflow-x: hidden;
padding-right: 5px;
}
.progress-petani-scroll {
max-height: 575px;
overflow-y: auto;
overflow-x: auto;
}
.progress-petani-scroll thead th {
position: sticky;
top: 0;
z-index: 3;
background: var(--bs-table-bg, #f8f9fa);
white-space: nowrap;
}
.tk-training-scroll {
max-height: 330px;
overflow-y: auto;
overflow-x: hidden;
padding-right: 5px;
}
.enumerator-scroll::-webkit-scrollbar,
.progress-petani-scroll::-webkit-scrollbar,
.tk-training-scroll::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.enumerator-scroll::-webkit-scrollbar-thumb,
.progress-petani-scroll::-webkit-scrollbar-thumb,
.tk-training-scroll::-webkit-scrollbar-thumb {
background: rgba(128, 128, 128, .28);
border-radius: 10px;
}
.enumerator-scroll::-webkit-scrollbar-track,
.progress-petani-scroll::-webkit-scrollbar-track,
.tk-training-scroll::-webkit-scrollbar-track {
background: transparent;
}
</style>
@endpush
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
{{-- Ringkasan utama --}}
<div class="row g-3 mb-3">
<div class="col-md-4">
<div class="card tk-stat green h-100">
<div class="card-body">
<div class="tk-stat-top">
<div>
<div class="tk-stat-lbl text-muted mb-2">
Total Petani
</div>
<div class="tk-stat-val">
{{ number_format($totalPetani, 0, ',', '.') }}
<span class="text-muted fw-normal" style="font-size: 12px">
petani
</span>
</div>
</div>
<div class="avatar">
<span class="avatar-initial rounded bg-label-success">
<i class="ti tabler-users"></i>
</span>
</div>
</div>
<small class="text-muted">
Seluruh petani yang sudah masuk ke sistem
</small>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card tk-stat blue h-100">
<div class="card-body">
<div class="tk-stat-top">
<div>
<div class="tk-stat-lbl text-muted mb-2">
Total Luas Lahan
</div>
<div class="tk-stat-val">
{{ number_format($totalLuasLahan, 2, ',', '.') }}
<span class="text-muted fw-normal" style="font-size: 12px">
ha
</span>
</div>
</div>
<div class="avatar">
<span class="avatar-initial rounded bg-label-primary">
<i class="ti tabler-map-2"></i>
</span>
</div>
</div>
<small class="text-muted">
Akumulasi luas seluruh lahan petani
</small>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card tk-stat amber h-100">
<div class="card-body">
<div class="tk-stat-top">
<div>
<div class="tk-stat-lbl text-muted mb-2">
Total Tanaman
</div>
<div class="tk-stat-val">
{{ number_format($totalJumlahTanaman, 0, ',', '.') }}
<span class="text-muted fw-normal" style="font-size: 12px">
tanaman
</span>
</div>
</div>
<div class="avatar">
<span class="avatar-initial rounded bg-label-warning">
<i class="ti tabler-trees"></i>
</span>
</div>
</div>
<small class="text-muted">
Akumulasi jumlah tanaman seluruh lahan
</small>
</div>
</div>
</div>
</div>
<div class="row g-3">
{{-- Kolom utama --}}
<div class="col-xl-8">
{{-- Progres enumerator --}}
<div class="card mb-3">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="mb-0 fw-bold">
<i class="ti tabler-chart-bar me-2 text-success"></i>
Progres per Enumerator
</h6>
<span class="badge bg-label-secondary text-secondary">
{{ now()->format('M Y') }}
</span>
</div>
<div class="card-body">
@php
$maxDone = $enumerators->max('done') ?: 1;
@endphp
@if ($enumerators->isNotEmpty())
<div class="enumerator-scroll">
@foreach ($enumerators as $e)
@php
$pct = round(($e['done'] / $maxDone) * 100);
@endphp
<div class="tk-erow">
<div
class="tk-av rounded"
style="
width: 36px;
height: 36px;
background: {{ $e['bg'] }};
color: {{ $e['tx'] }};
"
>
{{ strtoupper(substr($e['name'], 0, 2)) }}
</div>
<div class="flex-grow-1">
<div class="d-flex justify-content-between mb-1">
<span class="fw-semibold" style="font-size: 13px">
{{ $e['name'] }}
</span>
<small class="text-muted">
{{ number_format($e['done'], 0, ',', '.') }} survei
</small>
</div>
<div class="tk-pb">
<div class="tk-pbt">
<div
class="tk-pbf"
style="
width: {{ $pct }}%;
background: {{ $e['color'] }};
"
></div>
</div>
</div>
</div>
</div>
@endforeach
</div>
@else
<div class="text-center text-muted py-3">
Belum ada data enumerator.
</div>
@endif
</div>
</div>
{{-- Progres data petani --}}
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="mb-0 fw-bold">
<i class="ti tabler-list-check me-2 text-success"></i>
Progres Data Petani
</h6>
<span class="badge bg-label-secondary text-secondary">
{{ $progressPetani->count() }} petani
</span>
</div>
<div class="table-responsive progress-petani-scroll">
<table class="table table-hover mb-0" style="font-size: 12.5px">
<thead class="table-light">
<tr>
<th style="font-size:10px;letter-spacing:.7px;text-transform:uppercase">
Petani
</th>
<th class="text-center"
style="font-size:10px;letter-spacing:.7px;text-transform:uppercase">
Lahan
</th>
<th class="text-center"
style="font-size:10px;letter-spacing:.7px;text-transform:uppercase">
Praktik Budidaya
</th>
<th class="text-center"
style="font-size:10px;letter-spacing:.7px;text-transform:uppercase">
Sosial Ekonomi
</th>
<th class="text-center"
style="font-size:10px;letter-spacing:.7px;text-transform:uppercase">
Akses Pasar
</th>
<th style="
min-width: 140px;
font-size: 10px;
letter-spacing: .7px;
text-transform: uppercase;
">
Progres
</th>
<th style="font-size:10px;letter-spacing:.7px;text-transform:uppercase">
Status
</th>
</tr>
</thead>
<tbody>
@forelse ($progressPetani as $petani)
@php
$barColor = match (true) {
$petani['percent'] === 100 => '#28a745',
$petani['percent'] >= 50 => '#007bff',
$petani['percent'] >= 20 => '#fd7e14',
default => '#dc3545',
};
$initial = collect(explode(' ', trim($petani['name'])))
->filter()
->take(2)
->map(fn ($word) => strtoupper(substr($word, 0, 1)))
->implode('');
@endphp
<tr>
<td>
<div class="d-flex align-items-center gap-2">
<div
class="tk-av rounded"
style="
width: 28px;
height: 28px;
background: rgba(40,167,69,.15);
color: #28a745;
"
>
{{ $initial ?: 'PT' }}
</div>
<span class="fw-semibold">
{{ $petani['name'] }}
</span>
</div>
</td>
@foreach ($petani['status'] as $status)
<td class="text-center">
@if ($status['done'])
<span
class="badge rounded-pill bg-label-success text-success"
title="{{ $status['label'] }} sudah diisi"
>
<i class="ti tabler-check"></i>
</span>
@else
<span
class="badge rounded-pill bg-label-secondary text-secondary"
title="{{ $status['label'] }} belum diisi"
>
<i class="ti tabler-minus"></i>
</span>
@endif
</td>
@endforeach
<td style="min-width: 140px">
<div class="tk-pb">
<div class="tk-pbt">
<div
class="tk-pbf"
style="
width: {{ $petani['percent'] }}%;
background: {{ $barColor }};
"
></div>
</div>
<small
class="text-muted"
style="min-width: 30px; text-align: right"
>
{{ $petani['percent'] }}%
</small>
</div>
</td>
<td>
@if ($petani['percent'] === 100)
<span class="badge bg-label-success text-success">
Selesai
</span>
@elseif ($petani['percent'] > 0)
<span class="badge bg-label-primary text-primary">
Sedang diisi
</span>
@else
<span class="badge bg-label-warning text-warning">
Draft
</span>
@endif
</td>
</tr>
@empty
<tr>
<td colspan="7" class="text-center text-muted py-4">
Belum ada data petani.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
{{-- Kolom samping --}}
<div class="col-xl-4">
{{-- Distribusi komoditas petani --}}
<div class="card mb-3">
<div class="card-header">
<h6 class="mb-0 fw-bold">
<i class="ti tabler-plant me-2 text-success"></i>
Distribusi Komoditas
</h6>
</div>
<div class="card-body">
@if ($komoditas->isNotEmpty())
@php
$donutOff = 0;
@endphp
<div class="d-flex justify-content-center py-2">
<svg
width="120"
height="120"
viewBox="0 0 120 120"
role="img"
aria-label="Distribusi komoditas petani"
>
<circle
cx="60"
cy="60"
r="46"
fill="none"
stroke="rgba(128,128,128,.15)"
stroke-width="16"
/>
@foreach ($komoditas as $k)
<circle
cx="60"
cy="60"
r="46"
fill="none"
stroke="{{ $k['color'] }}"
stroke-width="16"
stroke-dasharray="
{{ $k['arc'] }}
{{ $circumference - $k['arc'] }}
"
stroke-dashoffset="{{ -$donutOff }}"
transform="rotate(-90 60 60)"
/>
@php
$donutOff += $k['arc'];
@endphp
@endforeach
<text
x="60"
y="56"
text-anchor="middle"
class="tk-donut-num"
>
{{ $totalPetani }}
</text>
<text
x="60"
y="70"
text-anchor="middle"
class="tk-donut-sub"
>
petani
</text>
</svg>
</div>
@foreach ($komoditas as $k)
<div class="tk-leg">
<div
class="tk-leg-dot"
style="background: {{ $k['color'] }}"
></div>
<span class="text-muted">
{{ $k['label'] }}
</span>
<span class="tk-leg-val">
{{ number_format($k['total'], 0, ',', '.') }}
<span
class="text-muted fw-normal"
style="font-size: 10px"
>
{{ $k['pct'] }}%
</span>
</span>
</div>
@endforeach
@else
<div class="text-center text-muted py-4">
Belum ada data distribusi komoditas.
</div>
@endif
</div>
</div>
{{-- Jumlah tanaman per komoditas --}}
<div class="card mb-3">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="mb-0 fw-bold">
<i class="ti tabler-trees me-2 text-primary"></i>
Tanaman per Komoditas
</h6>
<span class="badge bg-label-primary text-primary">
{{ number_format($totalJumlahTanaman, 0, ',', '.') }}
</span>
</div>
<div class="card-body">
@if ($tanamanPerKomoditas->isNotEmpty())
@foreach ($tanamanPerKomoditas as $tanaman)
<div class="tk-bar">
<span
class="tk-bar-lbl text-muted text-truncate"
title="{{ $tanaman['label'] }}"
>
{{ $tanaman['label'] }}
</span>
<div class="tk-bar-trk">
<div
class="tk-bar-fil"
style="
width: {{ $tanaman['pct'] }}%;
background: {{ $tanaman['color'] }};
"
></div>
</div>
<span class="tk-bar-val fw-semibold text-end">
{{ number_format($tanaman['total'], 0, ',', '.') }}
</span>
</div>
@endforeach
@else
<div class="text-center text-muted py-4">
Belum ada data jumlah tanaman.
</div>
@endif
</div>
</div>
{{-- Pelatihan GAP --}}
<div class="card mb-3">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="mb-0 fw-bold">
<i class="ti tabler-school me-2 text-warning"></i>
Pelatihan GAP
</h6>
<span class="badge bg-label-warning text-warning">
{{ number_format($totalPetaniPelatihan, 0, ',', '.') }} petani
</span>
</div>
<div class="card-body">
@if ($pelatihanGap->isNotEmpty())
<div class="tk-training-scroll">
@foreach ($pelatihanGap as $pelatihan)
<div class="tk-erow">
<div
class="tk-av rounded"
style="
width: 34px;
height: 34px;
background: {{ $pelatihan['bg'] }};
color: {{ $pelatihan['tx'] }};
"
>
<i class="ti tabler-certificate"></i>
</div>
<div class="flex-grow-1">
<div class="d-flex justify-content-between align-items-center gap-2">
<span
class="fw-semibold"
style="font-size: 12px"
>
{{ $pelatihan['label'] }}
</span>
<span
class="badge flex-shrink-0"
style="
background: {{ $pelatihan['bg'] }};
color: {{ $pelatihan['tx'] }};
"
>
{{ $pelatihan['total'] }}
</span>
</div>
</div>
</div>
@endforeach
</div>
<div class="tk-divider"></div>
<small class="text-muted">
Satu petani dapat tercatat pada lebih dari satu jenis pelatihan.
</small>
@else
<div class="text-center text-muted py-4">
Belum ada data pelatihan.
</div>
@endif
</div>
</div>
{{-- Sertifikasi --}}
<div class="card">
<div class="card-body">
<div class="d-flex align-items-center justify-content-between gap-3">
<div class="d-flex align-items-center gap-3">
<div class="avatar">
<span class="avatar-initial rounded bg-label-success">
<i class="ti tabler-rosette-discount-check"></i>
</span>
</div>
<div>
<div class="tk-stat-lbl text-muted mb-1">
Petani Bersertifikasi
</div>
<div class="d-flex align-items-baseline gap-1">
<span class="tk-stat-val">
{{ number_format(
$totalPetaniBersertifikat,
0,
',',
'.'
) }}
</span>
<span class="text-muted" style="font-size: 12px">
petani
</span>
</div>
</div>
</div>
<span class="badge bg-label-success text-success">
{{ number_format(
$totalPetaniSertifikatAktif,
0,
',',
'.'
) }}
aktif
</span>
</div>
<div class="tk-divider"></div>
<small class="text-muted">
Petani unik yang memiliki minimal satu riwayat sertifikasi.
</small>
</div>
</div>
</div>
</div>
</div>
@endsection
@@ -88,12 +88,13 @@
@if($profile)
<button
type="button"
class="btn btn-sm btn-icon btn-text-secondary rounded-pill"
class="btn btn-sm btn-outline-primary d-inline-flex align-items-center gap-1 px-3"
data-bs-toggle="offcanvas"
data-bs-target="#editProfileOffcanvas"
aria-controls="editProfileOffcanvas"
title="Edit profil">
<i class="icon-base ti tabler-edit icon-lg"></i>
<i class="icon-base ti tabler-edit icon-sm"></i>
<span>Edit</span>
</button>
@endif
</div>
@@ -106,6 +107,7 @@
<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>
@if(auth()->user()->role === \App\Enums\Role::PETANI)
<li class="d-flex align-items-start mb-4">
<i class="icon-base ti tabler-id icon-lg"></i><span class="fw-medium mx-2">No KTP:</span>
<span>{{ $profile->ktp ?? 'N/A' }}</span>
@@ -114,6 +116,7 @@
<i class="icon-base ti tabler-users icon-lg"></i><span class="fw-medium mx-2">No KK:</span>
<span>{{ $profile->kk ?? 'N/A' }}</span>
</li>
@endif
<li class="d-flex align-items-start mb-0">
<i class="icon-base ti tabler-map-pin icon-lg flex-shrink-0"></i><span class="fw-medium mx-2">Alamat:</span>
<span>{{ $alamatLengkap ?? 'N/A' }}</span>
@@ -268,16 +271,18 @@
</div>
<div class="mb-4">
<label class="form-label" for="quick-profile-telepon">Telepon</label>
<input type="text" class="form-control" id="quick-profile-telepon" name="telepon" value="{{ $profile->telepon }}" maxlength="13" required>
<input type="text" class="form-control" id="quick-profile-telepon" name="telepon" value="{{ $profile->telepon }}" maxlength="13">
</div>
@if($profile->role === \App\Enums\Role::PETANI->value)
<div class="mb-4">
<label class="form-label" for="quick-profile-ktp">No KTP</label>
<input type="text" class="form-control" id="quick-profile-ktp" name="ktp" value="{{ $profile->ktp }}" maxlength="16">
</div>
</div>
<div class="mb-4">
<label class="form-label" for="quick-profile-kk">No KK</label>
<input type="text" class="form-control" id="quick-profile-kk" name="kk" value="{{ $profile->kk }}" maxlength="16">
</div>
@endif
<div class="mb-4">
<label class="form-label" for="quick-profile-alamat">Alamat</label>
<textarea class="form-control" id="quick-profile-alamat" name="alamat" rows="4">{{ $profile->alamat }}</textarea>
+1 -1
View File
@@ -15,7 +15,7 @@
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>AgroMonev | {{ $title ?? 'Database Petani' }}</title>
<title>{{ config('app.name') }} | {{ $title ?? config('app.desc') }}</title>
<meta name="description" content="" />
+7
View File
@@ -4,7 +4,13 @@
<div class="layout-wrapper layout-content-navbar ">
<div class="layout-container">
<!-- Menu -->
@if(config('app.name') == 'AgroMonev')
@include('layout.sidebar_monev')
@elseif(config('app.name') == 'AgroPro')
@include('layout.sidebar_pro')
@else
@include('layout.sidebar')
@endif
<!-- / Menu -->
<!-- Layout container -->
@@ -80,6 +86,7 @@
<script src="{{ asset('assets/js/dashboards-analytics.js') }}"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.5/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.5/additional-methods.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
+2 -2
View File
@@ -338,7 +338,7 @@
href="javascript:void(0);"
data-bs-toggle="dropdown">
<div class="avatar avatar-online">
<img src="../../assets/img/avatars/1.png" alt class="rounded-circle" />
<img src="{{ asset('assets/img/avatars/3.jpg') }}" alt="Avatar" class="rounded-circle" />
</div>
</a>
<ul class="dropdown-menu dropdown-menu-end">
@@ -347,7 +347,7 @@
<div class="d-flex align-items-center">
<div class="flex-shrink-0 me-2">
<div class="avatar avatar-online">
<img src="../../assets/img/avatars/1.png" alt class="rounded-circle" />
<img src="{{ asset('assets/img/avatars/3.jpg') }}" alt="Avatar" class="rounded-circle" />
</div>
</div>
<div class="flex-grow-1">
+42 -11
View File
@@ -3,6 +3,7 @@
<a href="{{ route('home') }}" class="app-brand-link">
<span class="app-brand-logo demo">
<span>
<!-- AgroMonev -->
<svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<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="#28a745" />
<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="#28a745" />
@@ -10,6 +11,24 @@
<path d="M15 15L27 4" stroke="#ED1C24" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" />
<circle cx="27" cy="4" r="2.5" fill="#ED1C24" />
</svg>
<!-- AgroPro -->
<!-- <svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.25" d="M16 2.5C16 2.5 5 6.5 5 15.5C5 20.5 11 23.5 16 23.5V2.5Z" fill="#28A745"/>
<path opacity="0.5" d="M16 2.5C16 2.5 27 6.5 27 15.5C27 20.5 21 23.5 16 23.5V2.5Z" fill="#28A745"/>
<rect x="5.5" y="5.5" width="21" height="15" rx="2.5" fill="white" stroke="#0054A6" stroke-width="1.5"/>
<rect x="11" y="3.5" width="10" height="4" rx="2" fill="#0054A6"/>
<circle cx="9.5" cy="10" r="1.7" fill="#28A745"/>
<path d="M8.7 10L9.3 10.6L10.4 9.3" stroke="white" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13 10H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 10H22" stroke="#0054A6" stroke-width="2" stroke-linecap="round"/>
<circle cx="9.5" cy="14" r="1.7" fill="#28A745"/>
<path d="M8.7 14L9.3 14.6L10.4 13.3" stroke="white" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13 14H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 14H19.5" stroke="#F4B400" stroke-width="2" stroke-linecap="round"/>
<circle cx="9.5" cy="18" r="1.7" fill="white" stroke="#ED1C24" stroke-width="1.3"/>
<path d="M13 18H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 18H17" stroke="#ED1C24" stroke-width="2" stroke-linecap="round"/>
</svg> -->
</span>
</span>
@@ -32,14 +51,14 @@
$userRole = auth()->check() ? (auth()->user()->role instanceof \App\Enums\Role ? auth()->user()->role->value : auth()->user()->role) : null;
@endphp
@if(in_array($userRole, ['super_admin', 'admin', 'fasilitator']))
@if(in_array($userRole, ['super_admin', 'admin', 'fasilitator']) )
<li class="menu-item active open">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-smart-home"></i>
<div data-i18n="Dashboards">Dashboards</div>
</a>
@if(in_array($userRole, ['super_admin', 'admin']))
@if(in_array($userRole, ['super_admin', 'admin']) && env('APP_NAME') == 'AgroMonev')
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('dashboard.produktivitas') ? 'active' : '' }}">
<a href="{{ route('dashboard.produktivitas') }}" class="menu-link">
@@ -49,17 +68,26 @@
</ul>
@endif
@if(in_array($userRole, ['super_admin', 'admin', 'fasilitator']) && env('APP_NAME') == 'AgroMonev')
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('dashboard.survey') ? 'active' : '' }}">
<a href="{{ route('dashboard.survey') }}" class="menu-link">
<div data-i18n="Survey">Survey</div>
<li class="menu-item {{ request()->routeIs('dashboard.survey-petani') ? 'active' : '' }}">
<a href="{{ route('dashboard.survey-petani') }}" class="menu-link">
<div data-i18n="Survey Petani">Survey Petani</div>
</a>
</li>
</ul>
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('dashboard.petani') ? 'active' : '' }}">
<a href="{{ route('dashboard.petani') }}" class="menu-link">
<div data-i18n="Profil Petani">Profil Petani</div>
</a>
</li>
</ul>
@endif
</li>
@endif
@if(in_array($userRole, ['fasilitator']))
@if(in_array($userRole, ['fasilitator', 'super_admin', 'admin']) && env('APP_NAME') == 'AgroMonev')
<li class="menu-header small">
<span class="menu-header-text" data-i18n="Data Pertanian">Data Pertanian</span>
</li>
@@ -71,7 +99,7 @@
</li>
@endif
@if(in_array($userRole, ['super_admin', 'admin']))
@if(in_array($userRole, ['super_admin', 'admin']) && env('APP_NAME') == 'AgroPro')
<!-- Ekosistem -->
<li class="menu-header small">
<span class="menu-header-text" data-i18n="Ekosistem">Ekosistem</span>
@@ -203,6 +231,9 @@
<i class="menu-icon icon-base ti tabler-users"></i><div data-i18n="Daftar Pengguna">Daftar Pengguna</div>
</a>
</li>
@endif
@if(in_array($userRole, ['super_admin', 'admin']) && env('APP_NAME') == 'AgroPro')
<li class="menu-item {{ request()->routeIs(['program.*', 'framework.*']) ? 'active open' : '' }}">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-transform"></i><div data-i18n="Program Transformasi">Program Transformasi</div>
@@ -229,18 +260,18 @@
</li>
</ul>
</li>
@endif
<!-- Misc -->
<li class="menu-header small">
<!-- <li class="menu-header small">
<span class="menu-header-text" data-i18n="Misc">Misc</span>
</li>
<li class="menu-item">
<a href="https://docs.google.com/spreadsheets/d/1nbh4xW-K_GwRW34-cD81p9B-LnLvkvro/edit?usp=sharing&ouid=103442063105125817060&rtpof=true&sd=true" target="_blank" class="menu-link">
<i class="menu-icon icon-base ti tabler-file-description"></i><div data-i18n="Documentation">Documentation</div>
</a>
</li>
@endif
</li> -->
</ul>
</aside>
@@ -0,0 +1,283 @@
<aside id="layout-menu" class="layout-menu menu-vertical menu">
<div class="app-brand demo ">
<a href="{{ route('home') }}" class="app-brand-link">
<span class="app-brand-logo demo">
<span>
<!-- AgroMonev -->
<svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<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="#28a745" />
<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="#28a745" />
<path d="M2 19L10 11L15 15" stroke="#0054A6" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" />
<path d="M15 15L27 4" stroke="#ED1C24" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" />
<circle cx="27" cy="4" r="2.5" fill="#ED1C24" />
</svg>
<!-- AgroPro -->
<!-- <svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.25" d="M16 2.5C16 2.5 5 6.5 5 15.5C5 20.5 11 23.5 16 23.5V2.5Z" fill="#28A745"/>
<path opacity="0.5" d="M16 2.5C16 2.5 27 6.5 27 15.5C27 20.5 21 23.5 16 23.5V2.5Z" fill="#28A745"/>
<rect x="5.5" y="5.5" width="21" height="15" rx="2.5" fill="white" stroke="#0054A6" stroke-width="1.5"/>
<rect x="11" y="3.5" width="10" height="4" rx="2" fill="#0054A6"/>
<circle cx="9.5" cy="10" r="1.7" fill="#28A745"/>
<path d="M8.7 10L9.3 10.6L10.4 9.3" stroke="white" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13 10H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 10H22" stroke="#0054A6" stroke-width="2" stroke-linecap="round"/>
<circle cx="9.5" cy="14" r="1.7" fill="#28A745"/>
<path d="M8.7 14L9.3 14.6L10.4 13.3" stroke="white" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13 14H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 14H19.5" stroke="#F4B400" stroke-width="2" stroke-linecap="round"/>
<circle cx="9.5" cy="18" r="1.7" fill="white" stroke="#ED1C24" stroke-width="1.3"/>
<path d="M13 18H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 18H17" stroke="#ED1C24" stroke-width="2" stroke-linecap="round"/>
</svg> -->
</span>
</span>
<span class="app-brand-text demo menu-text fw-bold ms-3" style="text-transform: capitalize;">
AgroMonev
</span>
</a>
<a href="javascript:void(0);" class="layout-menu-toggle menu-link text-large ms-auto">
<i class="icon-base ti menu-toggle-icon d-none d-xl-block"></i>
<i class="icon-base ti tabler-x d-block d-xl-none"></i>
</a>
</div>
<div class="menu-inner-shadow"></div>
<ul class="menu-inner py-1">
<!-- Dashboards -->
@php
$userRole = auth()->check() ? (auth()->user()->role instanceof \App\Enums\Role ? auth()->user()->role->value : auth()->user()->role) : null;
@endphp
@if(in_array($userRole, ['super_admin', 'admin', 'fasilitator']) )
<li class="menu-item active open">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-smart-home"></i>
<div data-i18n="Dashboards">Dashboards</div>
</a>
@if(in_array($userRole, ['super_admin', 'admin']) && env('APP_NAME') == 'AgroMonev')
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('dashboard.produktivitas') ? 'active' : '' }}">
<a href="{{ route('dashboard.produktivitas') }}" class="menu-link">
<div data-i18n="Produktivitas">Produktivitas</div>
</a>
</li>
</ul>
@endif
@if(in_array($userRole, ['super_admin', 'admin', 'fasilitator']) && env('APP_NAME') == 'AgroMonev')
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('dashboard.survey-petani') ? 'active' : '' }}">
<a href="{{ route('dashboard.survey-petani') }}" class="menu-link">
<div data-i18n="Survey Petani">Survey Petani</div>
</a>
</li>
</ul>
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('dashboard.petani') ? 'active' : '' }}">
<a href="{{ route('dashboard.petani') }}" class="menu-link">
<div data-i18n="Profil Petani">Profil Petani</div>
</a>
</li>
</ul>
@endif
</li>
@endif
@if(in_array($userRole, ['fasilitator', 'super_admin', 'admin']) && env('APP_NAME') == 'AgroMonev')
<li class="menu-header small">
<span class="menu-header-text" data-i18n="Data Pertanian">Data Pertanian</span>
</li>
<li class="menu-item {{ request()->routeIs('petani.*') ? 'active' : '' }}">
<a href="{{ route('petani.index') }}" class="menu-link">
<i class="menu-icon icon-base ti tabler-file-description"></i>
<div data-i18n="Profil Petani">Profil Petani</div>
</a>
</li>
@endif
@if(in_array($userRole, ['super_admin', 'admin']) && env('APP_NAME') == 'AgroPro')
<!-- Ekosistem -->
<li class="menu-header small">
<span class="menu-header-text" data-i18n="Ekosistem">Ekosistem</span>
</li>
<li class="menu-item {{ request()->routeIs(['profile.*', 'produksi.*', 'lahan.*', 'tanaman.*']) ? 'active open' : '' }}">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-file-description"></i>
<div data-i18n="Data Pertanian">Data Pertanian</div>
</a>
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('petani.*') ? 'active' : '' }}">
<a href="{{ route('petani.index') }}" class="menu-link"><div data-i18n="Profil Petani">Profil Petani</div></a>
</li>
<li class="menu-item {{ request()->routeIs('produksi.*') ? 'active' : '' }}">
<a href="{{ route('produksi.index') }}" class="menu-link"><div data-i18n="Hasil Panen">Hasil Panen</div></a>
</li>
<li class="menu-item {{ request()->routeIs('lahan.*') ? 'active' : '' }}">
<a href="{{ route('lahan.index') }}" class="menu-link"><div data-i18n="Pemantauan Lahan">Pemantauan Lahan</div></a>
</li>
<li class="menu-item {{ request()->routeIs('tanaman.*') ? 'active' : '' }}">
<a href="{{ route('tanaman.index') }}" class="menu-link"><div data-i18n="Pemantauan Tanaman">Pemantauan Tanaman</div></a>
</li>
</ul>
</li>
<li class="menu-item {{ request()->routeIs(['petani-cpm.*', 'lahan-cpcl.*', 'tabel.data.*']) ? 'active open' : '' }}">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-folder-root"></i>
<div data-i18n="Basis Data Ekosistem">Basis Data Ekosistem</div>
</a>
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('petani-cpm.*') ? 'active' : '' }}">
<a href="{{ route('petani-cpm.index') }}" class="menu-link"><div data-i18n="Petani CPM">Petani CPM</div></a>
</li>
<li class="menu-item {{ request()->routeIs('lahan-cpcl.*') ? 'active' : '' }}">
<a href="{{ route('lahan-cpcl.index') }}" class="menu-link"><div data-i18n="Lahan CPCL">Lahan CPCL</div></a>
</li>
</ul>
@foreach ($tabel_menu ?? [] as $tbl)
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('tabel.data.*') && request()->route('tabel') == $tbl->id ? 'active' : '' }}">
<a href="{{ route('tabel.data.index', $tbl->id) }}" class="menu-link">
<div data-i18n="{{ $tbl->menu }}">{{ $tbl->menu }}</div>
</a>
</li>
</ul>
@endforeach
</li>
<!-- <li class="menu-item">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-line-scan"></i>
<div data-i18n="Tracebility">Tracebility</div>
</a>
<ul class="menu-sub">
<li class="menu-item">
<a href="#" class="menu-link">
<div data-i18n="Manajemen Batch & Kode">Manajemen Batch & Kode</div>
</a>
</li>
</ul>
<ul class="menu-sub">
<li class="menu-item">
<a href="#" class="menu-link">
<div data-i18n="Penelusuran Product">Penelusuran Product</div>
</a>
</li>
</ul>
</li> -->
<li class="menu-item {{ request()->routeIs(['realisasi.*', 'kelompok-belajar-tani.*', 'workshop.*']) ? 'active open' : '' }}">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-webhook"></i>
<div data-i18n="Program & Komunitas">Program & Komunitas</div>
</a>
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('realisasi.*') ? 'active' : '' }}">
<a href="{{ route('realisasi.index') }}" class="menu-link"><div data-i18n="Capaian Program">Capaian Program</div></a>
</li>
<li class="menu-item {{ request()->routeIs('kelompok-belajar-tani.*') ? 'active' : '' }}">
<a href="{{ route('kelompok-belajar-tani.index') }}" class="menu-link"><div data-i18n="Kelompok Belajar Petani">Kelompok Belajar Petani</div></a>
</li>
<li class="menu-item {{ request()->routeIs('workshop.*') ? 'active' : '' }}">
<a href="{{ route('workshop.index') }}" class="menu-link"><div data-i18n="Workshop & Lokakarya">Workshop & Lokakarya</div></a>
</li>
</ul>
</li>
@endif
@if(in_array($userRole, ['super_admin']))
<!-- Master Data -->
<li class="menu-header small">
<span class="menu-header-text" data-i18n="Master Data">Master Data</span>
</li>
<li class="menu-item">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-world"></i>
<div data-i18n="Wilayah">Wilayah</div>
</a>
<ul class="menu-sub">
<li class="menu-item"><a href="{{ route('provinsi.index') }}" class="menu-link"><div data-i18n="Provinsi">Provinsi</div></a></li>
<li class="menu-item"><a href="{{ route('kabupatenkota.index') }}" class="menu-link"><div data-i18n="Kabupaten Kota">Kabupaten Kota</div></a></li>
<li class="menu-item"><a href="{{ route('kecamatan.index') }}" class="menu-link"><div data-i18n="Kecamatan">Kecamatan</div></a></li>
<li class="menu-item"><a href="{{ route('desakelurahan.index') }}" class="menu-link"><div data-i18n="Desa Kelurahan">Desa Kelurahan</div></a></li>
</ul>
</li>
<li class="menu-item">
<a href="{{ route('adat.index') }}" class="menu-link"><i class="menu-icon icon-base ti tabler-matrix"></i><div data-i18n="Adat">Adat</div></a>
</li>
<li class="menu-item">
<a href="{{ route('keluarga.index') }}" class="menu-link"><i class="menu-icon icon-base ti tabler-sitemap"></i><div data-i18n="Keluarga">Keluarga</div></a>
</li>
<li class="menu-item">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-plant"></i><div data-i18n="Tanaman">Tanaman</div>
</a>
<ul class="menu-sub">
<li class="menu-item"><a href="{{ route('komoditas.index') }}" class="menu-link"><div data-i18n="Komoditas">Komoditas</div></a></li>
<li class="menu-item"><a href="{{ route('jenis-komoditas.index') }}" class="menu-link"><div data-i18n="Jenis Komoditas">Jenis Komoditas</div></a></li>
<li class="menu-item"><a href="{{ route('varietas.index') }}" class="menu-link"><div data-i18n="Varietas">Varietas</div></a></li>
</ul>
</li>
@endif
@if(in_array($userRole, ['super_admin', 'admin']))
<li class="menu-header small">
<span class="menu-header-text" data-i18n="Konfigurasi">Konfigurasi</span>
</li>
<li class="menu-item {{ request()->routeIs('users.*') ? 'active' : '' }}">
<a href="{{ route('users.index') }}" class="menu-link">
<i class="menu-icon icon-base ti tabler-users"></i><div data-i18n="Daftar Pengguna">Daftar Pengguna</div>
</a>
</li>
@endif
@if(in_array($userRole, ['super_admin', 'admin']) && env('APP_NAME') == 'AgroPro')
<li class="menu-item {{ request()->routeIs(['program.*', 'framework.*']) ? 'active open' : '' }}">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-transform"></i><div data-i18n="Program Transformasi">Program Transformasi</div>
</a>
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('program.*') ? 'active' : '' }}">
<a href="{{ route('program.index') }}" class="menu-link"><div data-i18n="Program Transformasi">Program Transformasi</div></a>
</li>
<li class="menu-item {{ request()->routeIs('framework.*') ? 'active' : '' }}">
<a href="{{ route('framework.index') }}" class="menu-link"><div data-i18n="Framework">Framework</div></a>
</li>
</ul>
</li>
<li class="menu-item {{ request()->routeIs(['group.*', 'tabel.*']) && !request()->routeIs('tabel.data.*') ? 'active open' : '' }}">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-database"></i><div data-i18n="Basis Data Ekosistem">Basis Data Ekosistem</div>
</a>
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('group.*') ? 'active' : '' }}">
<a href="{{ route('group.index') }}" class="menu-link"><div data-i18n="Kelompok">Kelompok</div></a>
</li>
<li class="menu-item {{ request()->routeIs('tabel.*') && !request()->routeIs('tabel.data.*') ? 'active' : '' }}">
<a href="{{ route('tabel.index') }}" class="menu-link"><div data-i18n="Tabel">Tabel</div></a>
</li>
</ul>
</li>
@endif
<!-- Misc -->
<!-- <li class="menu-header small">
<span class="menu-header-text" data-i18n="Misc">Misc</span>
</li>
<li class="menu-item">
<a href="https://docs.google.com/spreadsheets/d/1nbh4xW-K_GwRW34-cD81p9B-LnLvkvro/edit?usp=sharing&ouid=103442063105125817060&rtpof=true&sd=true" target="_blank" class="menu-link">
<i class="menu-icon icon-base ti tabler-file-description"></i><div data-i18n="Documentation">Documentation</div>
</a>
</li> -->
</ul>
</aside>
<div class="menu-mobile-toggler d-xl-none rounded-1">
<a href="javascript:void(0);" class="layout-menu-toggle menu-link text-large text-bg-secondary p-2 rounded-1">
<i class="ti tabler-menu icon-base"></i>
<i class="ti tabler-chevron-right icon-base"></i>
</a>
</div>
@@ -0,0 +1,159 @@
<aside id="layout-menu" class="layout-menu menu-vertical menu">
<div class="app-brand demo ">
<a href="{{ route('home') }}" class="app-brand-link">
<span class="app-brand-logo demo">
<span>
<!-- AgroPro -->
<svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.25" d="M16 2.5C16 2.5 5 6.5 5 15.5C5 20.5 11 23.5 16 23.5V2.5Z" fill="#28A745"/>
<path opacity="0.5" d="M16 2.5C16 2.5 27 6.5 27 15.5C27 20.5 21 23.5 16 23.5V2.5Z" fill="#28A745"/>
<rect x="5.5" y="5.5" width="21" height="15" rx="2.5" fill="white" stroke="#0054A6" stroke-width="1.5"/>
<rect x="11" y="3.5" width="10" height="4" rx="2" fill="#0054A6"/>
<circle cx="9.5" cy="10" r="1.7" fill="#28A745"/>
<path d="M8.7 10L9.3 10.6L10.4 9.3" stroke="white" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13 10H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 10H22" stroke="#0054A6" stroke-width="2" stroke-linecap="round"/>
<circle cx="9.5" cy="14" r="1.7" fill="#28A745"/>
<path d="M8.7 14L9.3 14.6L10.4 13.3" stroke="white" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13 14H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 14H19.5" stroke="#F4B400" stroke-width="2" stroke-linecap="round"/>
<circle cx="9.5" cy="18" r="1.7" fill="white" stroke="#ED1C24" stroke-width="1.3"/>
<path d="M13 18H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 18H17" stroke="#ED1C24" stroke-width="2" stroke-linecap="round"/>
</svg>
</span>
</span>
<span class="app-brand-text demo menu-text fw-bold ms-3" style="text-transform: capitalize;">
{{ env('APP_NAME') }}
</span>
</a>
<a href="javascript:void(0);" class="layout-menu-toggle menu-link text-large ms-auto">
<i class="icon-base ti menu-toggle-icon d-none d-xl-block"></i>
<i class="icon-base ti tabler-x d-block d-xl-none"></i>
</a>
</div>
<div class="menu-inner-shadow"></div>
<ul class="menu-inner py-1">
<!-- Dashboards -->
@canany(['fasilitator', 'super_admin', 'admin'])
<li class="menu-item active open">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-smart-home"></i>
<div data-i18n="Dashboards">Dashboards</div>
</a>
</li>
@endcanany
@canany(['super_admin', 'admin'])
<!-- Ekosistem -->
<li class="menu-header small">
<span class="menu-header-text" data-i18n="Ekosistem">Ekosistem</span>
</li>
<li class="menu-item {{ request()->routeIs(['realisasi.*', 'kelompok-belajar-tani.*', 'workshop.*']) ? 'active open' : '' }}">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-webhook"></i>
<div data-i18n="Program & Komunitas">Program & Komunitas</div>
</a>
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('realisasi.*') ? 'active' : '' }}">
<a href="{{ route('realisasi.index') }}" class="menu-link"><div data-i18n="Capaian Program">Capaian Program</div></a>
</li>
<li class="menu-item {{ request()->routeIs('kelompok-belajar-tani.*') ? 'active' : '' }}">
<a href="{{ route('kelompok-belajar-tani.index') }}" class="menu-link"><div data-i18n="Kelompok Belajar Petani">Kelompok Belajar Petani</div></a>
</li>
<li class="menu-item {{ request()->routeIs('workshop.*') ? 'active' : '' }}">
<a href="{{ route('workshop.index') }}" class="menu-link"><div data-i18n="Workshop & Lokakarya">Workshop & Lokakarya</div></a>
</li>
</ul>
</li>
@endcanany
@canany(['super_admin'])
<!-- Master Data -->
<li class="menu-header small">
<span class="menu-header-text" data-i18n="Master Data">Master Data</span>
</li>
<li class="menu-item">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-world"></i>
<div data-i18n="Wilayah">Wilayah</div>
</a>
<ul class="menu-sub">
<li class="menu-item"><a href="{{ route('provinsi.index') }}" class="menu-link"><div data-i18n="Provinsi">Provinsi</div></a></li>
<li class="menu-item"><a href="{{ route('kabupatenkota.index') }}" class="menu-link"><div data-i18n="Kabupaten Kota">Kabupaten Kota</div></a></li>
<li class="menu-item"><a href="{{ route('kecamatan.index') }}" class="menu-link"><div data-i18n="Kecamatan">Kecamatan</div></a></li>
<li class="menu-item"><a href="{{ route('desakelurahan.index') }}" class="menu-link"><div data-i18n="Desa Kelurahan">Desa Kelurahan</div></a></li>
</ul>
</li>
<li class="menu-item">
<a href="{{ route('adat.index') }}" class="menu-link"><i class="menu-icon icon-base ti tabler-matrix"></i><div data-i18n="Adat">Adat</div></a>
</li>
<li class="menu-item">
<a href="{{ route('keluarga.index') }}" class="menu-link"><i class="menu-icon icon-base ti tabler-sitemap"></i><div data-i18n="Keluarga">Keluarga</div></a>
</li>
<li class="menu-item">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-plant"></i><div data-i18n="Tanaman">Tanaman</div>
</a>
<ul class="menu-sub">
<li class="menu-item"><a href="{{ route('komoditas.index') }}" class="menu-link"><div data-i18n="Komoditas">Komoditas</div></a></li>
<li class="menu-item"><a href="{{ route('jenis-komoditas.index') }}" class="menu-link"><div data-i18n="Jenis Komoditas">Jenis Komoditas</div></a></li>
<li class="menu-item"><a href="{{ route('varietas.index') }}" class="menu-link"><div data-i18n="Varietas">Varietas</div></a></li>
</ul>
</li>
@endcanany
@canany(['super_admin', 'admin'])
<li class="menu-header small">
<span class="menu-header-text" data-i18n="Konfigurasi">Konfigurasi</span>
</li>
<li class="menu-item {{ request()->routeIs('users.*') ? 'active' : '' }}">
<a href="{{ route('users.index') }}" class="menu-link">
<i class="menu-icon icon-base ti tabler-users"></i><div data-i18n="Daftar Pengguna">Daftar Pengguna</div>
</a>
</li>
@endcanany
@canany(['super_admin', 'admin'])
<li class="menu-item {{ request()->routeIs(['program.*', 'framework.*']) ? 'active open' : '' }}">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-transform"></i><div data-i18n="Program Transformasi">Program Transformasi</div>
</a>
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('program.*') ? 'active' : '' }}">
<a href="{{ route('program.index') }}" class="menu-link"><div data-i18n="Program Transformasi">Program Transformasi</div></a>
</li>
<li class="menu-item {{ request()->routeIs('framework.*') ? 'active' : '' }}">
<a href="{{ route('framework.index') }}" class="menu-link"><div data-i18n="Framework">Framework</div></a>
</li>
</ul>
</li>
<li class="menu-item {{ request()->routeIs(['group.*', 'tabel.*']) && !request()->routeIs('tabel.data.*') ? 'active open' : '' }}">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon icon-base ti tabler-database"></i><div data-i18n="Basis Data Ekosistem">Basis Data Ekosistem</div>
</a>
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('group.*') ? 'active' : '' }}">
<a href="{{ route('group.index') }}" class="menu-link"><div data-i18n="Kelompok">Kelompok</div></a>
</li>
<li class="menu-item {{ request()->routeIs('tabel.*') && !request()->routeIs('tabel.data.*') ? 'active' : '' }}">
<a href="{{ route('tabel.index') }}" class="menu-link"><div data-i18n="Tabel">Tabel</div></a>
</li>
</ul>
</li>
@endcanany
</ul>
</aside>
<div class="menu-mobile-toggler d-xl-none rounded-1">
<a href="javascript:void(0);" class="layout-menu-toggle menu-link text-large text-bg-secondary p-2 rounded-1">
<i class="ti tabler-menu icon-base"></i>
<i class="ti tabler-chevron-right icon-base"></i>
</a>
</div>
+32 -1
View File
@@ -8,7 +8,38 @@
@csrf
<div class="mb-4 form-control-validation">
<label class="form-label" for="add-nama">Nama Komoditas<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="add-nama" name="nama" placeholder="Cth: Padi Sabrang" />
<input type="text" class="form-control" id="add-nama" name="nama" placeholder="Cth: Kopi" />
</div>
<div class="mb-4 form-control-validation">
<label class="form-label" for="add-kode">Kode Komoditas<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="add-kode" name="kode" placeholder="Cth: KP" />
</div>
<div class="mb-4 form-control-validation">
<label class="form-label d-block">Komoditas Utama <span class="text-danger">*</span></label>
<input type="hidden" name="is_utama" value="0">
<label class="switch switch-lg"><input type="checkbox" class="switch-input" id="add-is-utama" name="is_utama" value="1" @checked(old('is_utama', false))>
<span class="switch-toggle-slider">
<span class="switch-on">
<i class="icon-base ti tabler-check"></i>
</span>
<span class="switch-off">
<i class="icon-base ti tabler-x"></i>
</span>
</span>
<span class="switch-label" id="add-is-utama-label">
{{ old('is_utama', false) ? 'Komoditas Utama' : 'Tidak Termasuk' }}
</span>
</label>
@error('is_utama')
<div class="invalid-feedback d-block">
{{ $message }}
</div>
@enderror
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary me-sm-3 me-1 data-submit">Simpan</button>
@@ -6,6 +6,7 @@
<div class="offcanvas-body mx-0 flex-grow-0 p-6 h-100">
<form id="editKomoditasForm" class="pt-0" method="POST">
@csrf
@method('PUT')
<input type="hidden" name="_method" value="PUT">
<input type="hidden" id="edit-id" name="id">
@@ -13,6 +14,39 @@
<label class="form-label" for="edit-nama">Nama Komoditas<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="edit-nama" name="nama" />
</div>
<div class="mb-4 form-control-validation">
<label class="form-label" for="edit-kode">Kode Komoditas<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="edit-kode" name="kode" />
</div>
<div class="mb-4 form-control-validation">
<label class="form-label d-block" for="edit-is-utama">Komoditas Utama <span class="text-danger">*</span></label>
<input type="hidden" name="is_utama" value="0">
<label class="switch switch-lg">
<input
type="checkbox"
class="switch-input"
id="edit-is-utama"
name="is_utama"
value="1"
>
<span class="switch-toggle-slider">
<span class="switch-on">
<i class="icon-base ti tabler-check"></i>
</span>
<span class="switch-off">
<i class="icon-base ti tabler-x"></i>
</span>
</span>
<span class="switch-label" id="edit-is-utama-label">
Tidak Termasuk
</span>
</label>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary me-sm-3 me-1 data-submit">Update</button>
<button type="reset" class="btn btn-label-secondary" data-bs-dismiss="offcanvas">Batal</button>
@@ -49,6 +49,7 @@
<tr>
<th>No</th>
<th>Nama Komoditas</th>
<th>Kode Komoditas</th>
<th>Aksi</th>
</tr>
</thead>
@@ -57,6 +58,7 @@
<tr>
<td>{{ $komoditas->firstItem() + $index }}</td>
<td><span class="text-heading fw-medium">{{ $item->nama }}</span></td>
<td><span class="text-heading fw-medium">{{ $item->kode }}</span></td>
<td>
<div class="d-flex align-items-center">
<a href="javascript:;" class="btn btn-icon btn-text-secondary rounded-pill view-record" data-id="{{ $item->id }}"><i class="ti tabler-eye ti-md"></i></a>
@@ -144,6 +146,19 @@
if (res.status === 'success') {
$('#edit-id').val(res.data.id);
$('#edit-nama').val(res.data.nama);
$('#edit-kode').val(res.data.kode);
const isUtama =
res.data.is_utama === true ||
res.data.is_utama === 1 ||
res.data.is_utama === '1';
$('#edit-is-utama').prop('checked', isUtama);
$('#edit-is-utama-label').text(
isUtama ? 'Komoditas Utama' : 'Tidak Termasuk'
);
if (typeof fvEdit !== 'undefined') fvEdit.resetForm();
offcanvasEdit.show();
}
@@ -166,6 +181,15 @@
$btn.removeClass('disabled');
if (res.status === 'success') {
$('#view-nama').val(res.data.nama);
$('#view-kode').val(res.data.kode);
const isUtama =
res.data.is_utama === true ||
res.data.is_utama === 1 ||
res.data.is_utama === '1';
$('#view-is-utama').val(
isUtama ? 'Komoditas Utama' : 'Tidak Termasuk'
);
offcanvasView.show();
}
}).fail((xhr) => {
@@ -177,7 +201,9 @@
const editForm = document.getElementById('editKomoditasForm');
let fvEdit = FormValidation.formValidation(editForm, {
fields: { nama: { validators: { notEmpty: { message: 'Nama komoditas wajib diisi' } } } },
fields: { nama: { validators: { notEmpty: { message: 'Nama komoditas wajib diisi' } } } ,
kode: {validators: { notEmpty: { message: 'Kode komoditas wajib diisi' } } }
},
plugins: {
trigger: new FormValidation.plugins.Trigger(),
bootstrap5: new FormValidation.plugins.Bootstrap5({ eleValidClass: '', rowSelector: '.form-control-validation' }),
@@ -245,5 +271,20 @@
});
});
});
document.addEventListener('DOMContentLoaded', function () {
const switchInput = document.getElementById('add-is-utama');
const switchLabel = document.getElementById('add-is-utama-label');
function updateKomoditasLabel() {
switchLabel.textContent = switchInput.checked
? 'Komoditas Utama'
: 'Tidak Termasuk';
}
switchInput.addEventListener('change', updateKomoditasLabel);
updateKomoditasLabel();
});
</script>
@endpush
@@ -9,6 +9,14 @@
<label class="form-label" for="view-nama">Nama Komoditas</label>
<input type="text" class="form-control bg-lighter" id="view-nama" readonly />
</div>
<div class="mb-4">
<label class="form-label" for="view-kode">Kode Komoditas</label>
<input type="text" class="form-control bg-lighter" id="view-kode" readonly />
</div>
<div class="mb-4">
<label class="form-label" for="view-is-utama">Komoditas Utama</label>
<input type="text" class="form-control bg-lighter" id="view-is-utama" readonly>
</div>
<div class="mt-4">
<button type="button" class="btn btn-label-secondary d-grid w-100" data-bs-dismiss="offcanvas">Tutup</button>
</div>
@@ -27,7 +27,7 @@
<div class="row">
<div class="col-md-6 mb-4 form-control-validation">
<label class="form-label" for="edit-profile-telepon">No. Telepon<span class="text-danger">*</span></label>
<label class="form-label" for="edit-profile-telepon">No. Telepon</label>
<input type="text" class="form-control" id="edit-profile-telepon" name="telepon" value="{{ $profile->telepon }}" />
</div>
</div>
@@ -47,27 +47,6 @@
</div>
</div>
<div class="col-sm-6 col-md-4 col-xl-3">
<div class="card shadow-sm border-0 h-100">
<div class="card-body p-4">
<div class="d-flex justify-content-between">
<div>
<span class="text-muted d-block mb-2">Titik Penanaman</span>
<h2 class="mb-0 fw-bold text-dark" style="font-size: 2.5rem;">
{{ number_format($totalTitikTanam, 0, ',', '.') }}
</h2>
</div>
<div>
<div class="d-flex align-items-center justify-content-center bg-label-warning text-warning" style="width: 56px; height: 56px; border-radius: 12px;">
<i class="ti tabler-map-pin" style="font-size: 1.8rem;"></i>
</div>
</div>
</div>
<small class="text-muted d-block mt-3">Distribusi lahan aktif</small>
</div>
</div>
</div>
</div>
<div class="card">
@@ -1,3 +1,17 @@
@push('style')
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.5/croppie.min.css" />
<style>
#croppie-container {
width: 100%;
height: 350px;
}
</style>
@endpush
@push('scripts')
<script src="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.5/croppie.min.js"></script>
@extends('layout.main')
@section('content')
@@ -22,16 +36,19 @@
<!-- INFORMASI PETANI -->
<form id="addPetaniForm" action="{{ route('petani.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<input type="file" id="foto" name="foto" accept="image/png,image/jpeg,image/jpg" hidden>
<div class="row">
<div class="col-md-3">
<div class="user-avatar-section">
<div class=" d-flex align-items-center flex-column">
<img
<img id="fotoPreview"
class="img-fluid rounded mb-4"
src="../../assets/img/avatars/1.png"
height="120"
width="120"
alt="User avatar" />
src="{{ isset($petani) && $petani?->foto ? asset('storage/' . $petani->foto) : asset('assets/img/avatars/3.jpg') }}"
height="120" width="120"
alt="Foto profil petani"
data-bs-toggle="tooltip" data-bs-placement="top"
data-bs-original-title="Klik untuk menambahkan foto profil petani"
style="cursor:pointer; object-fit:cover;" />
<div class="user-info text-center">
<h5><i>Nama Petani</i></h5>
<span class="badge bg-label-secondary">Petani</span>
@@ -56,7 +73,7 @@
@error('ktp')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="add-petani-kk">No. KK<span class="text-danger">*</span></label>
<label class="form-label" for="add-petani-kk">No. KK</label>
<input type="text" class="form-control @error('kk') is-invalid @enderror" id="add-petani-kk" name="kk"
placeholder="Cth: 1234567890" value="{{ old('kk') }}" />
@error('kk')<div class="error invalid-feedback">{{ $message }}</div>@enderror
@@ -79,15 +96,15 @@
@error('tempat_lahir')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="add-petani-tanggal-lahir">Tanggal Lahir</label>
<input type="date" class="form-control @error('tanggal_lahir') is-invalid @enderror" id="add-petani-tanggal-lahir" name="tanggal_lahir"
<label class="form-label" for="add-petani-tanggal-lahir">Tanggal Lahir<span class="text-danger">*</span></label>
<input type="text" class="form-control @error('tanggal_lahir') is-invalid @enderror" id="add-petani-tanggal-lahir" name="tanggal_lahir"
value="{{ old('tanggal_lahir') }}" />
@error('tanggal_lahir')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
<div class="row">
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="add-petani-pendidikan-terakhir">Pendidikan Terakhir</label>
<label class="form-label" for="add-petani-pendidikan-terakhir">Pendidikan Terakhir<span class="text-danger">*</span></label>
<select class="form-control @error('pendidikan_terakhir') is-invalid @enderror" id="add-petani-pendidikan-terakhir" name="pendidikan_terakhir">
<option value="">Pilih Pendidikan Terakhir</option>
@foreach($pendidikan as $value)
@@ -108,11 +125,24 @@
</div>
</div>
<h5 class="pb-4 border-bottom mb-4 mt-4">Komoditas</h5>
<div class="row">
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label">Komoditas Utama <span class="text-danger">*</span></label>
<select id="add-petani-komoditas" name="komoditas_id" class="form-select @error('komoditas_id') is-invalid @enderror">
<option value="">Pilih Komoditas</option>
@foreach($komoditas as $k)
<option value="{{ $k->id }}">{{ $k->nama }}</option>
@endforeach
</select>
@error('komoditas_id')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
<h5 class="pb-4 border-bottom mb-4 mt-4">Domisili dan Kontak</h5>
<div class="row">
<div class="col-md-12 mb-4 form-control-validation">
<label class="form-label" for="add-petani-alamat">Alamat</label>
<label class="form-label" for="add-petani-alamat">Alamat<span class="text-danger">*</span></label>
<textarea class="form-control @error('alamat') is-invalid @enderror" id="add-petani-alamat" name="alamat"
rows="2" placeholder="Cth: Jl. Nama Jalan, Nama Dusun">{{ old('alamat') }}</textarea>
@error('alamat')<div class="error invalid-feedback">{{ $message }}</div>@enderror
@@ -120,7 +150,7 @@
</div>
<div class="row">
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="add-petani-provinsi">Provinsi</label>
<label class="form-label" for="add-petani-provinsi">Provinsi<span class="text-danger">*</span></label>
<select class="form-control @error('provinsi_id') is-invalid @enderror" id="add-petani-provinsi" name="provinsi_id">
<option value="">Pilih Provinsi</option>
@foreach($provinsi as $p)
@@ -130,21 +160,21 @@
@error('provinsi_id')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="add-petani-kabupaten">Kabupaten/Kota</label>
<label class="form-label" for="add-petani-kabupaten">Kabupaten/Kota<span class="text-danger">*</span></label>
<select class="form-control @error('kabupaten_id') is-invalid @enderror" id="add-petani-kabupaten" name="kabupaten_id" >
<option value="">Pilih Kabupaten/Kota</option>
</select>
@error('kabupaten_id')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="add-petani-kecamatan">Kecamatan</label>
<label class="form-label" for="add-petani-kecamatan">Kecamatan<span class="text-danger">*</span></label>
<select class="form-control @error('kecamatan_id') is-invalid @enderror" id="add-petani-kecamatan" name="kecamatan_id" >
<option value="">Pilih Kecamatan</option>
</select>
@error('kecamatan_id')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="add-petani-desa">Desa/Kelurahan</label>
<label class="form-label" for="add-petani-desa">Desa/Kelurahan<span class="text-danger">*</span></label>
<select class="form-control @error('desa_kelurahan_id') is-invalid @enderror" id="add-petani-desa" name="desa_kelurahan_id" >
<option value="">Pilih Desa/Kelurahan</option>
</select>
@@ -205,7 +235,7 @@
<div class="mt-4 text-end">
<a href="{{ route('petani.index') }}" class="btn btn-secondary me-2 wave-effect wave-light">Kembali</a>
<button type="submit" class="btn btn-success data-submit wave-effect wave-light">Simpan Profil</button>
<button type="submit" class="btn btn-success data-submit wave-effect wave-light"><i class="ti tabler-device-floppy me-2"></i> Simpan Profil</button>
</div>
</form>
@@ -214,6 +244,24 @@
</div>
</div>
</div>
<div class="modal fade" id="cropModal" tabindex="-1" aria-labelledby="cropModalLabel" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="cropModalLabel">Sesuaikan Foto Profil</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="croppie-container"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
<button type="button" class="btn btn-primary" id="cropImageBtn">Potong & Simpan</button>
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
@@ -222,7 +270,10 @@
$(document).ready(function () {
$('#add-petani-jenis-kelamin, #add-petani-pendidikan-terakhir, #add-petani-pekerjaan-utama, #add-petani-komoditas, #add-petani-pekerjaan-sampingan, #add-petani-komoditas-sampingan, #add-petani-status-pernikahan, #add-petani-status-keluarga, #add-petani-petani-pengumpul').select2();
$('#add-petani-tanggal-lahir').flatpickr({
dateFormat: 'd-m-Y'
});
$('#add-petani-provinsi').select2().change(function(e) {
e.preventDefault();
var provinsiId = $(this).val();
@@ -281,43 +332,118 @@
}
});
$('#add-petani-desa').select2();
let croppieInstance = null;
$('#editPetaniForm').validate({
$('#fotoPreview').on('click', function () {
$('#foto').val('');
$('#foto').click();
});
$('#foto').on('change', function (e) {
const file = e.target.files[0];
if (!file) return;
if(!file.type.match(/^image\/(png|jpeg|jpg)$/)) {
return;
}
const reader = new FileReader();
reader.onload = function (event) {
$('#cropModal').modal('show');
if (!croppieInstance) {
const el = document.getElementById('croppie-container');
croppieInstance = new Croppie(el, {
viewport: { width: 200, height: 200,},
boundary: { width: 300, height: 300 },
showZoomer: true,
enableOrientation: true
});
}
setTimeout(function() {
croppieInstance.bind({
url: event.target.result
});
}, 200);
};
reader.readAsDataURL(file);
});
$('#cropImageBtn').on('click', function() {
croppieInstance.result({
type: 'base64',
format: 'png',
size: 'viewport'
}).then(function(base64) {
$('#fotoPreview').attr('src', base64);
function dataURLtoFile(dataurl, filename) {
let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type: mime});
}
let croppedFile = dataURLtoFile(base64, 'foto_profil_crop.png');
let dataTransfer = new DataTransfer();
dataTransfer.items.add(croppedFile);
document.getElementById('foto').files = dataTransfer.files;
$('#cropModal').modal('hide');
});
});
// 1 MB = 1048576 bytes
$.validator.addMethod('maxfilesize', function (value, element, param) {
return this.optional(element) || (element.files[0] && element.files[0].size <= param);
}, 'File size must be less than {0} bytes.');
$('#addPetaniForm').validate({
rules: {
nama: { required: true },
ktp: { required: true, digits: true, minlength: 16, maxlength: 16 },
kk: { required: true, digits: true, minlength: 16, maxlength: 16 },
tempat_lahir: { required: true },
tanggal_lahir: { required: true, date: true },
tanggal_lahir: { required: true },
jenis_kelamin: { required: true },
pendidikan_terakhir: { required: true },
komoditas_id: { required: true },
alamat: { required: true },
provinsi_id: { required: true },
kabupaten_id: { required: true },
kecamatan_id: { required: true },
desa_kelurahan_id: { required: true },
status_perkawinan: { required: true },
file_ktp: { accept: "image/png, image/jpeg, image/jpg" },
file_kk: { accept: "image/png, image/jpeg, image/jpg" },
foto: { accept: "image/png, image/jpeg, image/jpg", maxfilesize: 2097152 },
file_ktp: { accept: "image/png, image/jpeg, image/jpg", maxfilesize: 2097152 },
file_kk: { accept: "image/png, image/jpeg, image/jpg", maxfilesize: 2097152 },
nomor_telepon: { required: false, digits: true, minlength: 11, maxlength: 13 }
},
messages: {
nama: { required: "Nama petani wajib diisi" },
ktp: { required: "NIK wajib diisi", digits: "NIK harus berupa angka", minlength: "NIK harus 16 digit", maxlength: "NIK harus 16 digit" },
kk: { required: "No. KK wajib diisi", digits: "No. KK harus berupa angka", minlength: "No. KK harus 16 digit", maxlength: "No. KK harus 16 digit" },
kk: { digits: "No. KK harus berupa angka", minlength: "No. KK harus 16 digit", maxlength: "No. KK harus 16 digit" },
tempat_lahir: { required: "Tempat lahir wajib diisi" },
tanggal_lahir: { required: "Tanggal lahir wajib diisi", date: "Format tanggal salah" },
tanggal_lahir: { required: "Tanggal lahir wajib diisi" },
jenis_kelamin: { required: "Jenis kelamin wajib diisi" },
pendidikan_terakhir: { required: "Pendidikan terakhir wajib diisi" },
komoditas_id: { required: "Komoditas wajib diisi" },
alamat: { required: "Alamat wajib diisi" },
provinsi_id: { required: "Provinsi wajib diisi" },
kabupaten_id: { required: "Kabupaten/Kota wajib diisi" },
kecamatan_id: { required: "Kecamatan wajib diisi" },
desa_kelurahan_id: { required: "Desa/Kelurahan wajib diisi" },
status_perkawinan: { required: "Status perkawinan wajib diisi" },
file_ktp: { accept: "Format file tidak valid. Harap unggah file berupa gambar (PNG, JPEG, JPG)" },
file_kk: { accept: "Format file tidak valid. Harap unggah file berupa gambar (PNG, JPEG, JPG)" },
foto: { accept: "Format file tidak valid. Harap unggah file berupa gambar (PNG, JPEG, JPG)", maxfilesize: "Ukuran file tidak boleh melebihi 2 MB" },
file_ktp: { accept: "Format file tidak valid. Harap unggah file berupa gambar (PNG, JPEG, JPG)", maxfilesize: "Ukuran file tidak boleh melebihi 2 MB" },
file_kk: { accept: "Format file tidak valid. Harap unggah file berupa gambar (PNG, JPEG, JPG)", maxfilesize: "Ukuran file tidak boleh melebihi 2 MB" },
nomor_telepon: {
digits: "Nomor telepon harus berupa angka",
minlength: "Nomor telepon minimal 11 digit",
@@ -335,6 +461,9 @@
},
unhighlight: function (element) {
$(element).removeClass('is-invalid');
},
submitHandler: function (form) {
form.submit();
}
});
});
@@ -93,34 +93,30 @@
</tr>
</thead>
<tbody>
@php($listBentukProduk = ['Buah segar hasil petik', 'Biji basah', 'Biji kering/Biji Kupas', 'Terfermentasi (Rp/kg)'])
@php($hargaJualPanen = $hargaJualPanen ?? collect())
@foreach ($listBentukProduk as $index => $bentuk)
@php($existingData = $hargaJualPanen->firstWhere('bentuk_produk', $bentuk))
@foreach ($hargaJualRows as $row)
<tr>
<td>
<input type="hidden" name="harga_jual[{{ $index }}][bentuk_produk]" value="{{ $bentuk }}">
<strong>{{ $bentuk }}:</strong>
<input type="hidden" name="harga_jual[{{ $row['index'] }}][bentuk_produk]" value="{{ $row['bentuk'] }}">
<strong>{{ $row['bentuk'] }}:</strong>
</td>
<td>
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="number" min="0" class="form-control" name="harga_jual[{{ $index }}][harga_panen_terakhir]" value="{{ old('harga_jual.' . $index . '.harga_panen_terakhir', $existingData?->harga_panen_terakhir) }}">
<input type="text" inputmode="numeric" class="form-control rupiah-input" name="harga_jual[{{ $row['index'] }}][harga_panen_terakhir]" value="{{ old('harga_jual.' . $row['index'] . '.harga_panen_terakhir', $row['harga_panen_terakhir']) }}" placeholder="Contoh: 12.000">
<span class="input-group-text">/kg</span>
</div>
</td>
<td>
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="number" min="0" class="form-control" name="harga_jual[{{ $index }}][harga_tahun_lalu]" value="{{ old('harga_jual.' . $index . '.harga_tahun_lalu', $existingData?->harga_tahun_lalu) }}">
<input type="text" inputmode="numeric" class="form-control rupiah-input" name="harga_jual[{{ $row['index'] }}][harga_tahun_lalu]" value="{{ old('harga_jual.' . $row['index'] . '.harga_tahun_lalu', $row['harga_tahun_lalu']) }}" placeholder="Contoh: 10.000">
<span class="input-group-text">/kg</span>
</div>
</td>
<td>
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="number" min="0" class="form-control" name="harga_jual[{{ $index }}][harga_dua_tahun_lalu]" value="{{ old('harga_jual.' . $index . '.harga_dua_tahun_lalu', $existingData?->harga_dua_tahun_lalu) }}">
<input type="text" inputmode="numeric" class="form-control rupiah-input" name="harga_jual[{{ $row['index'] }}][harga_dua_tahun_lalu]" value="{{ old('harga_jual.' . $row['index'] . '.harga_dua_tahun_lalu', $row['harga_dua_tahun_lalu']) }}" placeholder="Contoh: 8.000">
<span class="input-group-text">/kg</span>
</div>
</td>
@@ -232,6 +228,16 @@
const praktikBelumPernahValue = String(@json($praktikBelumPernahValue));
const skorPengalamanBerhentiValues = @json($skorPengalamanBerhentiValues ?? [2,3]).map(Number);
function onlyDigits(value) {
return String(value || '').replace(/\D/g, '');
}
function formatRupiah(value) {
const digits = onlyDigits(value);
return digits.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
}
function syncAlasanBerhenti() {
const val = Number($('input[name="skor_pengalaman"]:checked').val());
const isBerhenti = skorPengalamanBerhentiValues.includes(val);
@@ -256,10 +262,21 @@
$('input[name="skor_pengalaman"]').on('change', syncAlasanBerhenti);
$('input[name="saluran_terdahulu[]"]').on('change', syncSaluranLainnya);
$('input[name="praktik_fermentasi"]').on('change', syncPraktikFermentasi);
$(document).on('input', '.rupiah-input', function () {
const cursorAtEnd = this.selectionStart === this.value.length;
this.value = formatRupiah(this.value);
if (cursorAtEnd) {
this.setSelectionRange(this.value.length, this.value.length);
}
});
$('.rupiah-input').each(function () {
this.value = formatRupiah(this.value);
});
syncAlasanBerhenti();
syncSaluranLainnya();
syncPraktikFermentasi();
});
</script>
@endpush
@endpush
@@ -1,5 +1,19 @@
@extends('layout.main')
@push('style')
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.5/croppie.min.css" />
<style>
#croppie-container {
width: 100%;
height: 350px;
}
</style>
@endpush
@push('scripts')
<script src="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.5/croppie.min.js"></script>
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
@if ($errors->any())
@@ -23,19 +37,26 @@
<form id="editPetaniForm" action="{{ route('petani.update', $petani->id) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
<input type="hidden" name="hapus_foto" id="hapus_foto" value="0">
<input type="file" id="foto" name="foto" accept="image/png,image/jpeg,image/jpg" hidden>
<div class="row">
<div class="col-md-3">
<div class="user-avatar-section">
<div class=" d-flex align-items-center flex-column">
<img
class="img-fluid rounded mb-4"
src="../../assets/img/avatars/1.png"
height="120"
width="120"
alt="User avatar" />
<div class="user-info text-center">
<h5><i>Nama Petani</i></h5>
<span class="badge bg-label-secondary">Petani</span>
<img id="fotoPreview"
class="mb-3 shadow-sm rounded-3"
src="{{ $petani->foto ? route('petani.show-image', ['id' => $petani->id, 'field' => 'foto']) : asset('assets/img/avatars/3.jpg') }}"
alt="Foto profil petani"
data-bs-toggle="tooltip" data-bs-placement="top"
data-bs-original-title="Klik untuk mengganti foto profil petani"
style="width: 120px !important; height: 120px !important; cursor:pointer; object-fit:cover; display:block; margin: 0 auto;" />
<button type="button" id="btnHapusFoto" class="btn btn-sm btn-outline-danger mb-4" style="display: {{ $petani->foto ? 'block' : 'none' }};">
Hapus Foto
</button>
<div class="user-info text-center">
<h5><i>{{ $petani->nama }}</i></h5>
<span class="badge bg-label-secondary">Petani {{ $petani->komoditas?->nama }}</span>
</div>
</div>
</div>
@@ -57,7 +78,7 @@
@error('ktp')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="edit-petani-kk">No. KK<span class="text-danger">*</span></label>
<label class="form-label" for="edit-petani-kk">No. KK</label>
<input type="text" class="form-control @error('kk') is-invalid @enderror" id="edit-petani-kk" name="kk"
placeholder="Cth: 1234567890" value="{{ old('kk', $petani->kk) }}" />
@error('kk')<div class="error invalid-feedback">{{ $message }}</div>@enderror
@@ -81,14 +102,14 @@
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="edit-petani-tanggal-lahir">Tanggal Lahir</label>
<input type="date" class="form-control @error('tanggal_lahir') is-invalid @enderror" id="edit-petani-tanggal-lahir" name="tanggal_lahir"
value="{{ old('tanggal_lahir', $petani->tanggal_lahir?->format('Y-m-d')) }}" />
<input type="text" class="form-control @error('tanggal_lahir') is-invalid @enderror" id="edit-petani-tanggal-lahir" name="tanggal_lahir"
value="{{ old('tanggal_lahir', $petani->tanggal_lahir?->format('d-m-Y')) }}" />
@error('tanggal_lahir')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
<div class="row">
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="edit-petani-pendidikan-terakhir">Pendidikan Terakhir</label>
<label class="form-label" for="edit-petani-pendidikan-terakhir">Pendidikan Terakhir<span class="text-danger">*</span></label>
<select class="form-control @error('pendidikan_terakhir') is-invalid @enderror" id="edit-petani-pendidikan-terakhir" name="pendidikan_terakhir">
<option value="">Pilih Pendidikan Terakhir</option>
@foreach($pendidikan as $value)
@@ -109,11 +130,24 @@
</div>
</div>
<h5 class="pb-4 border-bottom mb-4 mt-4">Komoditas</h5>
<div class="row">
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label">Komoditas Utama <span class="text-danger">*</span></label>
<select id="edit-petani-komoditas" name="komoditas_id" class="form-select @error('komoditas_id') is-invalid @enderror">
<option value="">Pilih Komoditas</option>
@foreach($komoditas as $k)
<option value="{{ $k->id }}" {{ old('komoditas_id', $petani->komoditas_id) == $k->id ? 'selected' : '' }}>{{ $k->nama }}</option>
@endforeach
</select>
@error('komoditas_id')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
<h5 class="pb-4 border-bottom mb-4 mt-4">Domisili dan Kontak</h5>
<div class="row">
<div class="col-md-12 mb-4 form-control-validation">
<label class="form-label" for="edit-petani-alamat">Alamat</label>
<label class="form-label" for="edit-petani-alamat">Alamat<span class="text-danger">*</span></label>
<textarea class="form-control @error('alamat') is-invalid @enderror" id="edit-petani-alamat" name="alamat"
rows="2" placeholder="Cth: Jl. Nama Jalan, Nama Dusun">{{ old('alamat', $petani->alamat) }}</textarea>
@error('alamat')<div class="error invalid-feedback">{{ $message }}</div>@enderror
@@ -121,7 +155,7 @@
</div>
<div class="row">
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="edit-petani-provinsi">Provinsi</label>
<label class="form-label" for="edit-petani-provinsi">Provinsi<span class="text-danger">*</span></label>
<select class="form-control @error('provinsi_id') is-invalid @enderror" id="edit-petani-provinsi" name="provinsi_id">
<option value="">Pilih Provinsi</option>
@foreach($provinsi as $p)
@@ -131,7 +165,7 @@
@error('provinsi_id')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="edit-petani-kabupaten">Kabupaten/Kota</label>
<label class="form-label" for="edit-petani-kabupaten">Kabupaten/Kota<span class="text-danger">*</span></label>
<select class="form-control @error('kabupaten_id') is-invalid @enderror" id="edit-petani-kabupaten" name="kabupaten_id" >
<option value="">Pilih Kabupaten/Kota</option>
<option value="{{ $petani->desaKelurahan->kecamatan->kabupatenKota->id }}" selected>{{ $petani->desaKelurahan->kecamatan->kabupatenKota->nama }}</option>
@@ -139,7 +173,7 @@
@error('kabupaten_id')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="edit-petani-kecamatan">Kecamatan</label>
<label class="form-label" for="edit-petani-kecamatan">Kecamatan<span class="text-danger">*</span></label>
<select class="form-control @error('kecamatan_id') is-invalid @enderror" id="edit-petani-kecamatan" name="kecamatan_id" >
<option value="">Pilih Kecamatan</option>
<option value="{{ $petani->desaKelurahan->kecamatan->id }}" selected>{{ $petani->desaKelurahan->kecamatan->nama }}</option>
@@ -147,7 +181,7 @@
@error('kecamatan_id')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="edit-petani-desa">Desa/Kelurahan</label>
<label class="form-label" for="edit-petani-desa">Desa/Kelurahan<span class="text-danger">*</span></label>
<select class="form-control @error('desa_kelurahan_id') is-invalid @enderror" id="edit-petani-desa" name="desa_kelurahan_id" >
<option value="">Pilih Desa/Kelurahan</option>
<option value="{{ $petani->desaKelurahan->id }}" selected>{{ $petani->desaKelurahan->nama }}</option>
@@ -208,7 +242,8 @@
</div>
<div class="mt-4 text-end">
<button type="submit" class="btn btn-success data-submit wave-effect wave-light">Simpan Profil</button>
<a href="{{ route('petani.index') }}" class="btn btn-secondary me-2 wave-effect wave-light">Kembali</a>
<button type="submit" class="btn btn-success data-submit wave-effect wave-light"><i class="ti tabler-device-floppy me-2"></i> Simpan Profil</button>
</div>
</form>
@@ -217,6 +252,24 @@
</div>
</div>
</div>
<div class="modal fade" id="cropModal" tabindex="-1" aria-labelledby="cropModalLabel" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="cropModalLabel">Sesuaikan Foto Profil</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="croppie-container"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
<button type="button" class="btn btn-primary" id="cropImageBtn">Potong & Simpan</button>
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
@@ -225,7 +278,11 @@
$(document).ready(function () {
$('#edit-petani-jenis-kelamin, #edit-petani-pendidikan-terakhir, #edit-petani-pekerjaan-utama, #edit-petani-komoditas, #edit-petani-pekerjaan-sampingan, #edit-petani-komoditas-sampingan, #edit-petani-status-pernikahan, #edit-petani-status-keluarga, #edit-petani-petani-pengumpul').select2();
$('#edit-petani-tanggal-lahir').flatpickr({
dateFormat: 'd-m-Y'
});
$('#edit-petani-provinsi').select2().change(function(e) {
e.preventDefault();
var provinsiId = $(this).val();
@@ -285,6 +342,89 @@
});
$('#edit-petani-desa').select2();
let croppieInstance = null;
$('#fotoPreview').on('click', function () {
$('#foto').val('');
$('#foto').click();
});
$('#foto').on('change', function (e) {
const file = e.target.files[0];
if (!file) return;
if(!file.type.match(/^image\/(png|jpeg|jpg)$/)) {
return;
}
const reader = new FileReader();
reader.onload = function (event) {
$('#cropModal').modal('show');
if (!croppieInstance) {
const el = document.getElementById('croppie-container');
croppieInstance = new Croppie(el, {
viewport: { width: 200, height: 200 },
boundary: { width: '100%', height: 280 },
showZoomer: true,
enableOrientation: true
});
}
setTimeout(function() {
croppieInstance.bind({
url: event.target.result
});
}, 200);
};
reader.readAsDataURL(file);
});
// 1 MB = 1048576 bytes
$('#cropImageBtn').on('click', function() {
croppieInstance.result({
type: 'base64',
format: 'png',
size: 'viewport',
}).then(function(base64) {
$('#fotoPreview').attr('src', base64);
$('#hapus_foto').val('0');
$('#btnHapusFoto').show();
function dataURLtoFile(dataurl, filename) {
let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type: mime});
}
let croppedFile = dataURLtoFile(base64, 'foto_profil_crop.png');
let dataTransfer = new DataTransfer();
dataTransfer.items.add(croppedFile);
document.getElementById('foto').files = dataTransfer.files;
$('#cropModal').modal('hide');
});
});
$('#btnHapusFoto').on('click', function() {
$('#hapus_foto').val('1');
$('#foto').val('');
$('#fotoPreview').attr('src', "{{ asset('assets/img/avatars/3.jpg') }}");
$(this).hide();
});
$.validator.addMethod('maxfilesize', function (value, element, param) {
return this.optional(element) || (element.files[0] && element.files[0].size <= param);
}, 'File size must be less than {0} bytes.');
$('#editPetaniForm').validate({
rules: {
@@ -292,9 +432,10 @@
ktp: { required: true, digits: true, minlength: 16, maxlength: 16 },
kk: { required: true, digits: true, minlength: 16, maxlength: 16 },
tempat_lahir: { required: true },
tanggal_lahir: { required: true, date: true },
tanggal_lahir: { required: true },
jenis_kelamin: { required: true },
pendidikan_terakhir: { required: true },
komoditas_id: { required: true },
alamat: { required: true },
provinsi_id: { required: true },
kabupaten_id: { required: true },
@@ -303,6 +444,7 @@
status_perkawinan: { required: true },
file_ktp: { accept: "image/png, image/jpeg, image/jpg" },
file_kk: { accept: "image/png, image/jpeg, image/jpg" },
foto: { accept: "image/png, image/jpeg, image/jpg" },
nomor_telepon: { required: false, digits: true, minlength: 11, maxlength: 13 }
},
messages: {
@@ -310,7 +452,7 @@
ktp: { required: "NIK wajib diisi", digits: "NIK harus berupa angka", minlength: "NIK harus 16 digit", maxlength: "NIK harus 16 digit" },
kk: { required: "No. KK wajib diisi", digits: "No. KK harus berupa angka", minlength: "No. KK harus 16 digit", maxlength: "No. KK harus 16 digit" },
tempat_lahir: { required: "Tempat lahir wajib diisi" },
tanggal_lahir: { required: "Tanggal lahir wajib diisi", date: "Format tanggal salah" },
tanggal_lahir: { required: "Tanggal lahir wajib diisi" },
jenis_kelamin: { required: "Jenis kelamin wajib diisi" },
pendidikan_terakhir: { required: "Pendidikan terakhir wajib diisi" },
alamat: { required: "Alamat wajib diisi" },
@@ -319,8 +461,9 @@
kecamatan_id: { required: "Kecamatan wajib diisi" },
desa_kelurahan_id: { required: "Desa/Kelurahan wajib diisi" },
status_perkawinan: { required: "Status perkawinan wajib diisi" },
file_ktp: { accept: "Format file tidak valid. Harap unggah file berupa gambar (PNG, JPEG, JPG)" },
file_kk: { accept: "Format file tidak valid. Harap unggah file berupa gambar (PNG, JPEG, JPG)" },
foto: { accept: "Format file tidak valid. Harap unggah file berupa gambar (PNG, JPEG, JPG)", maxfilesize: "Ukuran file tidak boleh melebihi 2 MB" },
file_ktp: { accept: "Format file tidak valid. Harap unggah file berupa gambar (PNG, JPEG, JPG)", maxfilesize: "Ukuran file tidak boleh melebihi 2 MB" },
file_kk: { accept: "Format file tidak valid. Harap unggah file berupa gambar (PNG, JPEG, JPG)", maxfilesize: "Ukuran file tidak boleh melebihi 2 MB" },
nomor_telepon: {
digits: "Nomor telepon harus berupa angka",
minlength: "Nomor telepon minimal 11 digit",
@@ -1,3 +1,39 @@
<style>
@media (min-width: 768px) {
.nav-pills-custom-spacing {
display: flex;
width: 100%;
gap: 0.5rem;
flex-wrap: nowrap !important;
overflow-x: auto;
}
.nav-pills-custom-spacing::-webkit-scrollbar {
display: none;
}
.nav-pills-custom-spacing .nav-item {
margin-right: 0 !important;
flex: 1;
}
.nav-pills-custom-spacing .nav-link {
display: flex;
justify-content: center;
align-items: center;
padding-left: 0.5rem !important;
padding-right: 0.5rem !important;
width: 100%;
white-space: nowrap;
font-size: 0.9375rem !important;
}
.nav-pills-custom-spacing .nav-link i {
margin-right: 0.4rem !important;
}
}
</style>
<div class="row mb-4">
<div class="col-md-4 mb-2 mb-md-0">
@@ -6,7 +42,12 @@
<h6 class="card-title mb-2">Profil Petani</h6>
<div class="d-flex justify-content-start align-items-center mb-3">
<div class="avatar me-2">
<img src="../../assets/img/avatars/1.png" alt="Avatar" class="rounded-circle" />
@if (!isset($petani))
<img src="{{ asset('assets/img/avatars/3.jpg') }}" alt="Foto Petani"/>
@else
<img alt="Foto Petani"
src="{{ $petani->foto ? route('petani.show-image', ['id' => $petani->id, 'field' => 'foto']) : asset('assets/img/avatars/3.jpg') }}" class="rounded-3"/>
@endif
</div>
<div class="d-flex flex-column">
<h6 class="mb-0" style="font-size: 0.9rem;">{{ isset($petani) ? $petani->nama : 'Tambah Petani Baru' }}</h6>
@@ -50,9 +91,16 @@
$lahanPetani = isset($petani) && \Illuminate\Support\Facades\Schema::hasTable('map_lahan')
? $petani->lahans()->get()
: collect();
$totalLuasLahan = $lahanPetani->sum('luas_lahan');
$totalTanaman = $lahanPetani->sum('jumlah_tanaman');
$totalLuasLahan = $petani ? $lahanPetani->where('komoditas_id', $petani->komoditas_id)->sum('luas_lahan') : 0;
$totalLuasLahanHa = $totalLuasLahan / 10000;
$lahanKomoditasUtamaIds = $petani
? $lahanPetani->where('komoditas_id', $petani->komoditas_id)->pluck('id')
: collect();
$totalTanaman = $petani && \Illuminate\Support\Facades\Schema::hasTable('map_tanaman')
? \App\Models\Pertanian\Tanaman::whereIn('lahan_id', $lahanKomoditasUtamaIds)->count()
: 0;
$pendidikanLabel = isset($petani) ? $petani->pendidikan_terakhir?->label() : null;
@endphp
<div class="card mb-2 flex-grow-1">
@@ -62,18 +110,18 @@
<div class="d-flex justify-content-between align-items-center card-widget-1 border-end h-100 pe-3">
<div>
<p class="mb-0 text-muted" style="font-size: 0.75rem;">Segmen Petani</p>
<h5 class="mb-0">{{ $segmenPetani ?? '-' }}</h5>
<h5 class="mb-0">{{ $petani?->segmen() ?? '-' }}</h5>
<p class="mb-0" style="font-size: 0.75rem;">
@if(!is_null($skorSegmenPetani))
<span class="me-1">Skor {{ number_format($skorSegmenPetani, 1) }}</span>
@if(!is_null($petani?->skor))
<span class="me-1">Skor {{ number_format($petani?->skor->skor_kesiapan_adopsi, 1) }}</span>
@else
<span class="me-1">Belum isi</span>
<span class="me-1">Belum terisi</span>
@endif
</p>
</div>
<span class="avatar">
<span class="avatar-initial rounded">
<i class="icon-base ti tabler-user-star icon-22px"></i>
<i class="icon-base ti tabler-user-star icon-22px text-heading"></i>
</span>
</span>
</div>
@@ -84,22 +132,22 @@
<p class="mb-0 text-muted" style="font-size: 0.75rem;">Lahan & Tanaman</p>
<h5 class="mb-0">
@if($lahanPetani->isNotEmpty())
{{ number_format($totalLuasLahan, 0, ',', '.') }} m<sup>2</sup>
{{ number_format($totalLuasLahanHa, 2, ',', '.') }} ha
@else
-
@endif
</h5>
<p class="mb-0" style="font-size: 0.75rem;">
@if(!is_null($skorLahanTanaman))
<span class="me-1">Skor {{ number_format($skorLahanTanaman, 1) }}</span><span class="text-success fw-medium">{{ number_format($totalTanaman, 0, ',', '.') }} tanaman</span>
<span class="me-1">{{ number_format($totalTanaman, 0, ',', '.') }} tanaman {{ $petani?->komoditas->nama }}</span>
@else
<span class="me-1">Belum isi</span>
<span class="me-1">Belum terisi</span>
@endif
</p>
</div>
<span class="avatar">
<span class="avatar-initial rounded">
<i class="icon-base ti tabler-trees icon-22px"></i>
<i class="icon-base ti tabler-trees icon-22px text-heading"></i>
</span>
</span>
</div>
@@ -107,25 +155,21 @@
<div class="col-sm-6 col-lg-4">
<div class="d-flex justify-content-between align-items-center card-widget-1 h-100 ps-3">
<div>
<p class="mb-0 text-muted" style="font-size: 0.75rem;">Praktik Budidaya</p>
<h5 class="mb-0">
@if(!is_null($skorPraktikBudidaya))
{{ number_format(round($skorPraktikBudidaya), 0, ',', '.') }}%
@else
-
@endif
</h5>
<p class="mb-0 text-muted" style="font-size: 0.75rem;">Pendidikan & Pelatihan</p>
<h5 class="mb-0">{{ $pendidikanLabel ?? '-' }}</h5>
<p class="mb-0" style="font-size: 0.75rem;">
@if(!is_null($skorPraktikBudidaya))
<span class="me-1">Skor {{ number_format($skorPraktikBudidaya, 1) }}</span>
@if(!is_null($petani?->surveyPelatihan) && !is_null($petani?->surveySertifikasi))
<span class="me-1">
{{ $petani?->surveyPelatihan->count() }} pelatihan, {{ $petani?->surveySertifikasi->count() }} sertifikasi
</span>
@else
<span class="me-1">Belum isi</span>
<span class="me-1">Belum terisi</span>
@endif
</p>
</div>
<span class="avatar">
<span class="avatar-initial rounded">
<i class="icon-base ti tabler-seedling icon-22px"></i>
<i class="icon-base ti tabler-books icon-22px text-heading"></i>
</span>
</span>
</div>
@@ -141,20 +185,45 @@
<div class="row gy-2">
<div class="col-sm-6 col-lg-4">
<div class="d-flex justify-content-between align-items-center card-widget-1 border-end h-100 pe-3">
@php
$skorPraktik = isset($petani?->skor) ? $petani?->skor->skor_d2_sistem_praktik_budidaya : null;
if (!is_null($skorPraktik)) {
if ($skorPraktik >= 4) {
$praktik = 'Menjalankan GAP (' . number_format($skorPraktik, 1, ',', '.') . ')';
} else if ($skorPraktik >= 2) {
$praktik = 'Menjalankan sebagian GAP (' . number_format($skorPraktik, 1, ',', '.') . ')';
} else {
$praktik = 'Belum menjalankan GAP (' . number_format($skorPraktik, 1, ',', '.') . ')';
}
}
@endphp
@php
$produktivitas = isset($petani?->surveyProduktivitas) ? $petani?->surveyProduktivitas : null;
if (!is_null($produktivitas)) {
$produktivitas = $produktivitas->where('komoditas_id', $petani->komoditas_id);
}
@endphp
<div>
<p class="mb-0 text-muted" style="font-size: 0.75rem;">Pendidikan</p>
<h5 class="mb-0">{{ $pendidikanLabel ?? '-' }}</h5>
<p class="mb-0" style="font-size: 0.75rem;">
@if(!is_null($skorPendidikan))
<span class="me-1">Skor {{ number_format($skorPendidikan, 1) }}</span>
<p class="mb-0 text-muted" style="font-size: 0.75rem;">Praktik Budidaya</p>
<h5 class="mb-0">
@if($produktivitas && count($produktivitas) > 0)
{{ number_format($produktivitas->sum('kuantitas'), 0, ',', '.') }}
<small>{{ $produktivitas->first()->satuan == 'ha_tahun' ? 'Ha/Tahun' : 'Pohon/Tahun' }}</small>
@else
<span class="me-1">Belum isi</span>
-
@endif
</h5>
<p class="mb-0" style="font-size: 0.75rem;">
@if(!is_null($skorPraktik))
<span class="me-1">{{ $praktik }}</span>
@else
<span class="me-1">Belum terisi</span>
@endif
</p>
</div>
<span class="avatar">
<span class="avatar-initial rounded">
<i class="icon-base ti tabler-books icon-22px"></i>
<i class="icon-base ti tabler-seedling icon-22px text-heading"></i>
</span>
</span>
</div>
@@ -168,24 +237,44 @@
$skorSosialEkonomi = isset($petani) ? $petani->skorSosialEkonomi() : null;
$skorSosialEkonomiBulat = is_null($skorSosialEkonomi) ? null : (int) round($skorSosialEkonomi);
@endphp
@php
$pendapatanKomoditas = isset($sosialEkonomi) ? $sosialEkonomi->pendapatanKomoditas : null;
@endphp
@php
$ekonomi = null;
if ($sosialEkonomi?->status_rekening_tabungan && $sosialEkonomi?->pengalaman_kredit_kebun) {
if ($sosialEkonomi?->status_rekening_tabungan > 1 && $sosialEkonomi?->pengalaman_kredit_kebun > 3) {
$ekonomi = 'Memiliki rekening dan pengalaman kredit';
} elseif ($sosialEkonomi?->status_rekening_tabungan > 1 && $sosialEkonomi?->pengalaman_kredit_kebun <= 3) {
$ekonomi = 'Memiliki rekening';
} elseif ($sosialEkonomi?->status_rekening_tabungan == 1 && $sosialEkonomi?->pengalaman_kredit_kebun > 3) {
$ekonomi = 'Memiliki pengalaman kredit';
} else {
$ekonomi = 'Tidak memiliki akses keuangan';
}
} else {
$ekonomi = 'Tidak memiliki akses keuangan';
}
@endphp
<h5 class="mb-0">
@if(!is_null($skorSosialEkonomi))
{{ number_format($skorSosialEkonomiBulat, 0, ',', '.') }}%
@if(!is_null($pendapatanKomoditas))
{{ number_format($pendapatanKomoditas->sum('pendapatan'), 0, ',', '.') }}
<small>pendapatan (Rp)</small>
@else
-
@endif
</h5>
<p class="mb-0" style="font-size: 0.75rem;">
@if(!is_null($skorSosialEkonomi))
<span class="me-1">Skor {{ number_format($skorSosialEkonomi, 1) }}</span>
<span class="me-1">{{ $ekonomi }}</span>
@else
<span class="me-1">Belum isi</span>
<span class="me-1">Belum terisi</span>
@endif
</p>
</div>
<span class="avatar">
<span class="avatar-initial rounded">
<i class="icon-base ti tabler-social icon-22px"></i>
<i class="icon-base ti tabler-social icon-22px text-heading"></i>
</span>
</span>
</div>
@@ -203,24 +292,48 @@
$skorAksesPasarBulat = (int) round($skorAksesPasar);
}
@endphp
@php
$hargaJual = isset($petani) ? $petani->hargaJualPanen : null;
if ($hargaJual) {
$hargaJual = $hargaJual->whereNotNull('bentuk_produk')
->where('harga_panen_terakhir', '>', 0)
->sortByDesc('id')
->first();
}
@endphp
@php
$pengalaman = null;
if(!is_null($aksesPasar?->skor_pengalaman) && !is_null($aksesPasar->skor_kesadaran_premium)){
if($aksesPasar->skor_pengalaman > 1){
if ($aksesPasar->skor_kesadaran_premium == 5) {
$pengalaman = 'Akses saluran lain dan pasar premium';
} else {
$pengalaman = 'Akses saluran lain';
}
} else {
$pengalaman = 'Belum akses';
}
}
@endphp
<h5 class="mb-0">
@if(!is_null($skorAksesPasar))
{{ number_format($skorAksesPasarBulat, 0, ',', '.') }}%
@if(!is_null($hargaJual))
{{ number_format($hargaJual->harga_panen_terakhir, 0, ',', '.') }}
<small>{{ $hargaJual->bentuk_produk }}</small>
@else
-
@endif
</h5>
<p class="mb-0" style="font-size: 0.75rem;">
@if(!is_null($skorAksesPasar))
<span class="me-1">Skor {{ number_format($skorAksesPasar, 1) }}</span>
@if(!is_null($aksesPasar?->skor_pengalaman) && !is_null($aksesPasar->skor_kesadaran_premium))
<span class="me-1">{{ $pengalaman }}</span>
@else
<span class="me-1">Belum isi</span>
<span class="me-1">Belum terisi</span>
@endif
</p>
</div>
<span class="avatar">
<span class="avatar-initial rounded">
<i class="icon-base ti tabler-building-store icon-22px"></i>
<i class="icon-base ti tabler-building-store icon-22px text-heading"></i>
</span>
</span>
</div>
@@ -235,70 +348,80 @@
<div class="nav-align-top">
@if(!$petani)
<ul class="nav nav-pills flex-column flex-md-row mb-6 row-gap-2">
<ul class="nav nav-pills flex-column flex-md-row mb-6 row-gap-2 nav-pills-custom-spacing">
<li class="nav-item">
<a class="nav-link active" href="{{ route('petani.create') }}">
<i class="icon-base ti tabler-user-check me-1_5 icon-sm"></i>Profil
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" disabled tooltip="Lahan & Tanaman, isi profil terlebih dahulu" data-bs-toggle="tooltip" data-bs-placement="top">
<i class="icon-base ti tabler-trees me-1_5 icon-sm"></i>Lahan & Tanaman
<a class="nav-link" href="#" disabled data-bs-original-title="Lahan & Tanaman, isi profil terlebih dahulu" data-bs-toggle="tooltip" data-bs-placement="top">
<i class="icon-base ti tabler-trees me-1_5 icon-sm"></i>Lahan & Tanaman
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" disabled tooltip="Praktik Budidaya, isi profil terlebih dahulu" data-bs-toggle="tooltip" data-bs-placement="top">
<i class="icon-base ti tabler-seedling me-1_5 icon-sm"></i>Praktik Budidaya
<a class="nav-link" href="#" disabled data-bs-original-title="Praktik Budidaya, isi profil terlebih dahulu" data-bs-toggle="tooltip" data-bs-placement="top">
<i class="icon-base ti tabler-seedling me-1_5 icon-sm"></i>Praktik Budidaya
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" disabled tooltip="Pendidikan & Pelatihan, isi profil terlebih dahulu" data-bs-toggle="tooltip" data-bs-placement="top">
<i class="icon-base ti tabler-books me-1_5 icon-sm"></i>Pendidikan & Pelatihan
<a class="nav-link" href="#" disabled data-bs-original-title="Pendidikan & Pelatihan, isi profil terlebih dahulu" data-bs-toggle="tooltip" data-bs-placement="top">
<i class="icon-base ti tabler-books me-1_5 icon-sm"></i>Pendidikan & Pelatihan
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" disabled tooltip="Sosial Ekonomi, isi profil terlebih dahulu" data-bs-toggle="tooltip" data-bs-placement="top">
<i class="icon-base ti tabler-social me-1_5 icon-sm"></i>Sosial Ekonomi
<a class="nav-link" href="#" disabled data-bs-original-title="Sosial Ekonomi, isi profil terlebih dahulu" data-bs-toggle="tooltip" data-bs-placement="top">
<i class="icon-base ti tabler-social me-1_5 icon-sm"></i>Sosial Ekonomi
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" disabled tooltip="Akses Pasar, isi profil terlebih dahulu" data-bs-toggle="tooltip" data-bs-placement="top">
<a class="nav-link" href="#" disabled data-bs-original-title="Akses Pasar, isi profil terlebih dahulu" data-bs-toggle="tooltip" data-bs-placement="top">
<i class="icon-base ti tabler-building-store me-1_5 icon-sm"></i>Akses Pasar
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" disabled data-bs-original-title="Kesiapan Adopsi, isi profil terlebih dahulu" data-bs-toggle="tooltip" data-bs-placement="top">
<i class="icon-base ti tabler-star me-1_5 icon-sm"></i>Kesiapan Adopsi
</a>
</li>
</ul>
@else
<ul class="nav nav-pills flex-column flex-md-row mb-6 row-gap-2">
<ul class="nav nav-pills flex-column flex-md-row mb-6 row-gap-2 nav-pills-custom-spacing">
<li class="nav-item">
<a class="nav-link {{ request()->routeIs('petani.edit') ? 'active' : '' }}" href="{{ route('petani.edit', $petani->id) }}">
<i class="icon-base ti tabler-user-check me-1_5 icon-sm"></i>Profil
<i class="icon-base ti tabler-user-check icon-sm"></i>Profil
</a>
</li>
<li class="nav-item">
<a class="nav-link {{ request()->routeIs('petani.lahan-tanaman.*') ? 'active' : '' }}" href="{{ route('petani.lahan-tanaman.index', $petani->id) }}">
<i class="icon-base ti tabler-trees me-1_5 icon-sm"></i>Lahan & Tanaman
<i class="icon-base ti tabler-trees icon-sm"></i>Lahan & Tanaman
</a>
</li>
<li class="nav-item">
<a class="nav-link {{ request()->routeIs('petani.praktik-budidaya.*') ? 'active' : '' }}" href="{{ route('petani.praktik-budidaya.index', $petani->id) }}">
<i class="icon-base ti tabler-seedling me-1_5 icon-sm"></i>Praktik Budidaya
<i class="icon-base ti tabler-seedling icon-sm"></i>Praktik Budidaya
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('petani.edit', $petani->id) }}">
<i class="icon-base ti tabler-books me-1_5 icon-sm"></i>Pendidikan & Pelatihan
<a class="nav-link {{ request()->routeIs('petani.pendidikan-pelatihan.*') ? 'active' : '' }}" href="{{ route('petani.pendidikan-pelatihan.index', $petani->id) }}">
<i class="icon-base ti tabler-books icon-sm"></i>Pendidikan & Pelatihan
</a>
</li>
<li class="nav-item">
<a class="nav-link {{ request()->routeIs('petani.sosial-ekonomi.*') ? 'active' : '' }}" href="{{ route('petani.sosial-ekonomi.index', $petani->id) }}">
<i class="icon-base ti tabler-social me-1_5 icon-sm"></i>Sosial Ekonomi
<i class="icon-base ti tabler-social icon-sm"></i>Sosial Ekonomi
</a>
</li>
<li class="nav-item">
<a class="nav-link {{ request()->routeIs('petani.akses-pasar.*') ? 'active' : '' }}" href="{{ route('petani.akses-pasar.index', $petani->id) }}">
<i class="icon-base ti tabler-building-store me-1_5 icon-sm"></i>Akses Pasar
<i class="icon-base ti tabler-building-store icon-sm"></i>Akses Pasar
</a>
</li>
<li class="nav-item">
<a class="nav-link {{ request()->routeIs('petani.skor.*') ? 'active' : '' }}" href="{{ route('petani.skor.index', $petani->id) }}">
<i class="icon-base ti tabler-star icon-sm"></i>Kesiapan Adopsi
</a>
</li>
</ul>
@endif
@endif
</div>
@@ -2,6 +2,36 @@
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
<div class="d-flex flex-row gap-3 mb-4">
<div class="w-25">
<x-summary-card
title="Petani"
count="{{ $petani->count() }}"
subtitle="{{ $petani->where('jenis_kelamin', 1)->count() }} Laki-laki, {{ $petani->where('jenis_kelamin', 0)->count() }} Perempuan"
icon="user-check"
color="primary"
/>
</div>
<div class="w-25">
<x-summary-card
title="Lahan & Tanaman"
count="{{ number_format(($totalLuasLahan ?? 0) / 10000, 2, ',', '.') }} ha"
subtitle="{{ $totalTanaman ?? 0 }} tanaman dari {{ $komoditas?->count() }} komoditas utama"
icon="trees"
color="success"
/>
</div>
<div class="w-25">
<x-summary-card
title="Segmentasi"
count="{{ $skor->where('segmen', 'Penggerak')->count() }} Penggerak"
subtitle="{{ $skor->where('segmen', 'Perintis')->count() }} Perintis, {{ $skor->where('segmen', 'Pemerhati')->count() }} Pemerhati, {{ $skor->where('segmen', 'Pemula')->count() }} Pemula"
icon="star"
color="info"
/>
</div>
</div>
<div class="card">
<div class="card-header border-bottom">
<h5 class="card-title mb-0">Data Petani</h5>
@@ -40,6 +70,8 @@
<th>Jenis Kelamin</th>
<th>Usia</th>
<th>Desa/Kelurahan</th>
<th>Komoditas Utama</th>
<th>Segmentasi</th>
<th>Aksi</th>
</tr>
</thead>
@@ -51,10 +83,21 @@
<td><span class="text-muted">{{ $item->jenis_kelamin ? 'Laki-laki' : 'Perempuan' }}</span></td>
<td><span class="text-muted">{{ $item->umur }} tahun</span></td>
<td><span class="text-muted">{{ $item->desaKelurahan?->nama }}, {{ $item->desaKelurahan?->kecamatan?->nama }}, {{ $item->desaKelurahan?->kecamatan?->kabupatenKota?->nama }}, {{ $item->desaKelurahan?->kecamatan?->kabupatenKota?->provinsi?->nama }}</span></td>
<td>{{ $item->komoditas?->nama }}</td>
<td>
@if($item->segmen() == 'Penggerak')
<span class="badge bg-label-success">Penggerak</span>
@elseif($item->segmen() == 'Perintis')
<span class="badge bg-label-info">Perintis</span>
@elseif($item->segmen() == 'Pemerhati')
<span class="badge bg-label-warning">Pemerhati</span>
@elseif($item->segmen() == 'Pemula')
<span class="badge bg-label-danger">Pemula</span>
@endif
</td>
<td>
<div class="d-flex align-items-center">
<a href="{{ route('petani.show', $item->id) }}" class="btn btn-icon btn-text-secondary rounded-pill view-record"><i class="ti tabler-eye ti-md"></i></a>
<!-- <a href="{{ route('petani.show', $item->id) }}" class="btn btn-icon btn-text-secondary rounded-pill view-record"><i class="ti tabler-eye ti-md"></i></a> -->
<a href="{{ route('petani.edit', $item->id) }}" class="btn btn-icon btn-text-secondary rounded-pill edit-record"><i class="ti tabler-edit ti-md"></i></a>
<a href="javascript:;" class="btn btn-icon btn-text-secondary rounded-pill delete-record" data-id="{{ $item->id }}" data-nama="{{ $item->nama }}"><i class="ti tabler-trash ti-md"></i></a>
</div>
@@ -3,6 +3,7 @@
@push('style')
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
<link rel="stylesheet" href="https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" type="text/css" />
<style>
#map {
@@ -11,6 +12,161 @@
background-color: #f8f9fa;
z-index: 1;
}
.dropzone-custom-container {
display: flex;
flex-wrap: wrap;
gap: 15px;
padding: 15px;
border: 2px dashed #ced4da;
border-radius: 12px;
background-color: #f8f9fa;
min-height: 160px;
align-items: center;
}
.btn-tambah-foto {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 140px;
height: 160px;
border: 2px dashed #a8b1ba;
border-radius: 12px;
background: #fff;
color: #6c757d;
cursor: pointer;
transition: 0.2s;
order: 999;
}
.btn-tambah-foto:hover {
background: #e9ecef;
border-color: #6c757d;
color: #495057;
}
.dropzone-custom-container .dz-preview {
position: relative;
background: #fff;
border-radius: 12px;
box-shadow: 0 4px 10px rgba(0,0,0,0.08);
border: 1px solid #e2e8f0;
width: 140px;
display: flex;
flex-direction: column;
}
.dropzone-custom-container .dz-image {
width: 100%;
height: 110px;
background: #f1f5f9;
cursor: zoom-in;
display: flex;
align-items: center;
justify-content: center;
border-radius: 12px 12px 0 0;
overflow: hidden;
}
.dropzone-custom-container .dz-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.dropzone-custom-container .dz-details {
padding: 8px;
text-align: center;
background: #fff;
border-radius: 0 0 12px 12px;
border-top: 1px solid #e2e8f0;
}
.dropzone-custom-container .dz-filename {
font-size: 11px;
font-weight: 600;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #495057;
}
.dropzone-custom-container .dz-size {
font-size: 10px;
color: #adb5bd;
}
.dropzone-custom-container .dz-control-panel {
position: absolute;
top: -8px;
right: -8px;
display: flex;
gap: 5px;
z-index: 20;
}
.dropzone-custom-container .dz-btn-action {
display: flex;
align-items: center;
justify-content: center;
width: 26px;
height: 26px;
border-radius: 50%;
color: #fff !important;
text-decoration: none !important;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
cursor: pointer;
font-size: 14px;
}
.dropzone-custom-container .btn-edit { background: #ffc107; color: #000 !important; }
.dropzone-custom-container .btn-edit:hover { background: #7367f0; }
.dropzone-custom-container .btn-delete { background: #dc3545; }
.dropzone-custom-container .btn-delete:hover { background: #c82333; }
.dropzone-custom-container .dz-error-message,
.dropzone-custom-container .dz-success-mark,
.dropzone-custom-container .dz-error-mark,
.dropzone-custom-container .progress { display: none !important; }
.foto-lightbox {
display: none;
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
background: rgba(0, 0, 0, 0.85) !important;
z-index: 99999 !important;
align-items: center !important;
justify-content: center !important;
padding: 30px !important;
box-sizing: border-box !important;
}
.foto-lightbox.active {
display: flex !important;
}
.foto-lightbox img {
max-width: 90vw !important;
max-height: 85vh !important;
object-fit: contain !important;
border-radius: 8px !important;
box-shadow: 0 10px 40px rgba(0,0,0,0.5) !important;
}
.foto-lightbox-close {
position: absolute !important;
top: 20px !important;
right: 30px !important;
color: #fff !important;
font-size: 40px !important;
font-weight: bold !important;
cursor: pointer !important;
z-index: 100000 !important;
}
.foto-lightbox-close:hover { color: #dc3545 !important; }
.auto-pest-disease-field .form-check-label,
.auto-pest-disease-field .text-muted {
font-size: 0.875rem;
}
</style>
@endpush
@@ -41,7 +197,8 @@
<div class="col-12 col-lg-10 col-md-9 pt-6 pt-lg-0">
<form id="petani-lahan-tanaman" method="POST" action="{{ route('petani.lahan-tanaman.store', ['petani' => $petani->id, 'lahanSelected' => null]) }}">
<form id="petani-lahan-tanaman" method="POST" enctype="multipart/form-data"
action="{{ route('petani.lahan-tanaman.store', ['petani' => $petani->id, 'lahanSelected' => null]) }}">
@csrf
<input type="hidden" name="status_kepemilikan" value="sendiri">
<div class="row">
@@ -50,8 +207,8 @@
<div class="row">
<div class="col-md-3 mb-3 form-control-validation">
<label class="form-label">Luas Lahan (m2) <span class="text-danger">*</span></label>
<input type="number" step="0.01" id="luas_lahan" name="luas_lahan" class="form-control @error('luas_lahan') is-invalid @enderror" placeholder="Contoh: 1.5" required />
<label class="form-label">Luas Lahan (ha) <span class="text-danger">*</span></label>
<input type="number" id="luas_lahan" name="luas_lahan" class="form-control @error('luas_lahan') is-invalid @enderror" placeholder="Contoh: 1.5" required />
@error('luas_lahan')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-3 form-control-validation">
@@ -60,12 +217,12 @@
@error('umur_lahan')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-3 form-control-validation">
<label class="form-label">Jumlah Tanaman <span class="text-danger">*</span></label>
<input type="number" name="jumlah_tanaman" class="form-control @error('jumlah_tanaman') is-invalid @enderror" placeholder="Contoh: 1" required />
<label class="form-label">Jumlah Tanaman</label>
<input type="number" name="jumlah_tanaman" class="form-control @error('jumlah_tanaman') is-invalid @enderror" placeholder="Contoh: 1 (min 0)" />
@error('jumlah_tanaman')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-3 form-control-validation">
<label class="form-label">Umur Tanaman (rata-rata)</label>
<label class="form-label">Umur Tanaman (rata-rata dalam tahun) <span class="text-danger">*</span></label>
<input type="number" name="umur_tanaman" class="form-control @error('umur_tanaman') is-invalid @enderror" placeholder="Contoh: 1" />
@error('umur_tanaman')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
@@ -75,7 +232,7 @@
<label class="form-label">Komoditas Utama <span class="text-danger">*</span></label>
<select id="komoditas_id" name="komoditas_id" class="form-select @error('komoditas_id') is-invalid @enderror">
<option value="">Pilih Komoditas</option>
@foreach($komoditas as $k)
@foreach($komoditas->where('is_utama', '1') as $k)
<option value="{{ $k->id }}">{{ $k->nama }}</option>
@endforeach
</select>
@@ -94,17 +251,134 @@
</div>
</div>
<div class="row">
<div class="col-md-3 mb-3 form-control-validation">
<label class="form-label">Kondisi Umum Tanaman</label>
<div class="col-md-6 mb-3 form-control-validation">
<label class="form-label">Kondisi Umum Tanaman <span class="text-danger">*</span></label>
<select id="kondisi_tanaman" name="kondisi_tanaman" class="form-select @error('kondisi_tanaman') is-invalid @enderror">
<option value="">Pilih Kondisi Tanaman</option>
<option value="{{ \App\Enums\KondisiTanaman::BAIK }}" {{ old('kondisi_tanaman') == \App\Enums\KondisiTanaman::BAIK ? 'selected' : '' }}>Baik</option>
<option value="{{ \App\Enums\KondisiTanaman::SEDANG }}" {{ old('kondisi_tanaman') == \App\Enums\KondisiTanaman::SEDANG ? 'selected' : '' }}>Sedang</option>
<option value="{{ \App\Enums\KondisiTanaman::BURUK }}" {{ old('kondisi_tanaman') == \App\Enums\KondisiTanaman::BURUK ? 'selected' : '' }}>Buruk</option>
<option value="{{ \App\Enums\KondisiTanaman::BAIK }}" {{ old('kondisi_tanaman') == \App\Enums\KondisiTanaman::BAIK ? 'selected' : '' }}>{{ \App\Enums\KondisiTanaman::BAIK->label() }}</option>
<option value="{{ \App\Enums\KondisiTanaman::SEDANG }}" {{ old('kondisi_tanaman') == \App\Enums\KondisiTanaman::SEDANG ? 'selected' : '' }}>{{ \App\Enums\KondisiTanaman::SEDANG->label() }}</option>
<option value="{{ \App\Enums\KondisiTanaman::BURUK }}" {{ old('kondisi_tanaman') == \App\Enums\KondisiTanaman::BURUK ? 'selected' : '' }}>{{ \App\Enums\KondisiTanaman::BURUK->label() }}</option>
</select>
@error('kondisi_tanaman')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-3 form-control-validation">
</div>
<div class="row">
<div class="col-md-3 mb-4 form-control-validation auto-pest-disease-field">
<label class="form-label">Jenis Hama</label>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_hama') is-invalid @enderror" disabled
type="checkbox"
name="jenis_hama[]"
value="Penggerek buah"
id="jenis-hama-penggerek-buah"
{{ in_array('Penggerek buah', $jenisHamaOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-hama-bentuk">Penggerek buah</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_hama') is-invalid @enderror" disabled
type="checkbox"
name="jenis_hama[]"
value="Penggerek batang"
id="jenis-hama-penggerek-batang"
{{ in_array('Penggerek batang', $jenisHamaOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-hama-bentuk">Penggerek batang</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_hama') is-invalid @enderror" disabled
type="checkbox"
name="jenis_hama[]"
value="Kutu putih/kutu sisik"
id="jenis-hama-kutu"
{{ in_array('Kutu putih/kutu sisik', $jenisHamaOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-hama-bentuk">Kutu putih/kutu sisik</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_hama') is-invalid @enderror" disabled
type="checkbox"
name="jenis_hama[]"
value="Ulat pemakan daun"
id="jenis-hama-ulat"
{{ in_array('Ulat pemakan daun', $jenisHamaOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-hama-bentuk">Ulat pemakan daun</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_hama') is-invalid @enderror" disabled
type="checkbox"
name="jenis_hama[]"
value="Tikus"
id="jenis-hama-tikus"
{{ in_array('Tikus', $jenisHamaOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-hama-bentuk">Tikus</label>
</div>
<small class="text-muted text-secondary">* Tidak diisi, terisi otomatis di Praktik Budidaya</small>
@error('jenis_hama')
<div class="error invalid-feedback d-block">{{ $message }}</div>
@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation auto-pest-disease-field">
<label class="form-label">Jenis Penyakit</label>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_penyakit') is-invalid @enderror" disabled
type="checkbox"
name="jenis_penyakit[]"
value="Karat daun"
id="jenis-penyakit-karat-daun"
{{ in_array('Karat daun', $jenisPenyakitOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-penyakit-bentuk">Karat daun</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_penyakit') is-invalid @enderror" disabled
type="checkbox"
name="jenis_penyakit[]"
value="Busuk buah/antraknosa"
id="jenis-penyakit-busuk-buah"
{{ in_array('Busuk buah/antraknosa', $jenisPenyakitOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-penyakit-bentuk">Busuk buah/antraknosa</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_penyakit') is-invalid @enderror" disabled
type="checkbox"
name="jenis_penyakit[]"
value="Busuk akar"
id="jenis-penyakit-busuk-akar"
{{ in_array('Busuk akar', $jenisPenyakitOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-penyakit-bentuk">Busuk akar</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_penyakit') is-invalid @enderror" disabled
type="checkbox"
name="jenis_penyakit[]"
value="Bercak daun"
id="jenis-penyakit-bercak-daun"
{{ in_array('Bercak daun', $jenisPenyakitOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-penyakit-bentuk">Bercak daun</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_penyakit') is-invalid @enderror" disabled
type="checkbox"
name="jenis_penyakit[]"
value="Layu fusarium"
id="jenis-penyakit-layu-fusarium"
{{ in_array('Layu fusarium', $jenisPenyakitOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-penyakit-bentuk">Layu fusarium</label>
</div>
<small class="text-muted text-secondary">* Tidak diisi, terisi otomatis di praktik budidaya</small>
@error('jenis_penyakit')
<div class="error invalid-feedback d-block">{{ $message }}</div>
@enderror
</div>
<!-- <div class="col-md-3 mb-3 form-control-validation">
<label class="form-label">Serangan Hama</label>
<select id="serangan_hama" name="serangan_hama" class="form-select @error('serangan_hama') is-invalid @enderror">
<option value="">Pilih Serangan Hama</option>
@@ -123,14 +397,14 @@
<option value="{{ \App\Enums\PenyakitTanaman::DAUN_BERCAK }}" {{ old('penyakit_tanaman') == \App\Enums\PenyakitTanaman::DAUN_BERCAK ? 'selected' : '' }}>Daun Bercak</option>
<option value="{{ \App\Enums\PenyakitTanaman::TANAMAN_LAYU }}" {{ old('penyakit_tanaman') == \App\Enums\PenyakitTanaman::TANAMAN_LAYU ? 'selected' : '' }}>Tanaman Layu</option>
</select>
</div>
<div class="col-md-3 mb-3 form-control-validation">
</div> -->
<div class="col-md-6 mb-3 form-control-validation">
<label class="form-label">Keparahan Serangan Hama/Penyakit</label>
<select id="keparahan_serangan" name="keparahan_serangan" class="form-select @error('keparahan_serangan') is-invalid @enderror">
<option value="">Pilih Keparahan Serangan</option>
<option value="{{ \App\Enums\KeparahanSerangan::RINGAN }}" {{ old('keparahan_serangan') == \App\Enums\KeparahanSerangan::RINGAN ? 'selected' : '' }}>Ringan</option>
<option value="{{ \App\Enums\KeparahanSerangan::SEDANG }}" {{ old('keparahan_serangan') == \App\Enums\KeparahanSerangan::SEDANG ? 'selected' : '' }}>Sedang</option>
<option value="{{ \App\Enums\KeparahanSerangan::BERAT }}" {{ old('keparahan_serangan') == \App\Enums\KeparahanSerangan::BERAT ? 'selected' : '' }}>Berat</option>
<option value="{{ \App\Enums\KeparahanSerangan::RINGAN }}" {{ old('keparahan_serangan') == \App\Enums\KeparahanSerangan::RINGAN ? 'selected' : '' }}>{{ \App\Enums\KeparahanSerangan::RINGAN->label() }}</option>
<option value="{{ \App\Enums\KeparahanSerangan::SEDANG }}" {{ old('keparahan_serangan') == \App\Enums\KeparahanSerangan::SEDANG ? 'selected' : '' }}>{{ \App\Enums\KeparahanSerangan::SEDANG->label() }}</option>
<option value="{{ \App\Enums\KeparahanSerangan::BERAT }}" {{ old('keparahan_serangan') == \App\Enums\KeparahanSerangan::BERAT ? 'selected' : '' }}>{{ \App\Enums\KeparahanSerangan::BERAT->label() }}</option>
</select>
@error('keparahan_serangan')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
@@ -149,9 +423,9 @@
<div class="col-md-6 mb-3 form-control-validation">
<label class="form-label">Tanaman Penaung</label>
<select id="tanaman_penaung" name="tanaman_penaung[]" class="form-select @error('tanaman_penaung[]') is-invalid @enderror" multiple>
<option value="">Pilih Komoditas</option>
@foreach($komoditas as $k)
<option value="{{ $k->id }}">{{ $k->nama }}</option>
<option value="">Pilih Tanaman atau ketik jika tidak ada</option>
@foreach($tanamanPenaung as $k)
<option value="{{ $k->nama }}">{{ $k->nama }}</option>
@endforeach
</select>
@error('tanaman_penaung[]')<div class="error invalid-feedback">{{ $message }}</div>@enderror
@@ -206,7 +480,7 @@
<div class="row">
<div class="col-md-12 mb-3 form-control-validation">
<label class="form-label">Raw Data Koordinat Lahan (Auto-generated JSON) <span class="text-danger">*</span></label>
<label class="form-label">Raw Data Koordinat Lahan (Auto-generated JSON)</label>
<textarea name="path" id="path" class="form-control @error('path') is-invalid @enderror" rows="4" readonly placeholder="Koordinat akan terisi otomatis setelah Anda menggambar polygon di peta..."></textarea>
<small class="text-muted">Pastikan menggambar polygon di peta dengan menyambungkan titik akhir ke titik awal.</small>
@error('path')<div class="error invalid-feedback">{{ $message }}</div>@enderror
@@ -221,12 +495,30 @@
<div id="map" class="border rounded shadow-sm"></div>
</div>
</div>
<div class="row mt-3">
<div class="col-12 text-end">
<button type="reset" class="btn btn-label-secondary me-2">Reset</button>
<button type="submit" class="btn btn-success"><i class="ti tabler-device-floppy me-2"></i> Simpan Lahan</button>
<hr class="my-4">
<div class="row">
<div class="col-md-12 mb-3 form-control-validation">
<h6 class="mb-5">Foto</h6>
<div id="dropzone-container" class="dropzone-custom-container">
<div id="btn-tambah-foto" class="btn-tambah-foto">
<i class="ti tabler-plus" style="font-size: 32px; margin-bottom: 8px;"></i>
<span style="font-size: 13px; font-weight: 600;">Tambah Foto</span>
</div>
</div>
<input type="file" id="foto-input" multiple hidden>
@error('file')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
<div class="row mt-3">
<div class="col-12 text-end">
<a href="{{ route('petani.index') }}" class="btn btn-secondary me-2 wave-effect wave-light">Kembali</a>
<button type="submit" class="btn btn-success data-submit wave-effect wave-light"><i class="ti tabler-device-floppy me-2"></i> Simpan Lahan</button>
</div>
</div>
</form>
@@ -237,11 +529,17 @@
</div>
</div>
</div>
<div id="foto-lightbox" class="foto-lightbox">
<span class="foto-lightbox-close">&times;</span>
<img id="foto-lightbox-img" src="" alt="Preview Foto Besar">
</div>
@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 src="https://unpkg.com/dropzone@5/dist/min/dropzone.min.js"></script>
<script>
'use strict';
@@ -252,7 +550,9 @@
$('#penyakit_tanaman').select2();
$('#keparahan_serangan').select2();
$('#komoditas_lain').select2();
$('#tanaman_penaung').select2();
$('#tanaman_penaung').select2({
tags: true
});
$('#provinsi_id').select2().change(function(e) {
e.preventDefault();
@@ -478,29 +778,139 @@
let area = L.GeometryUtil.geodesicArea(latlngs);
console.log(area);
let areaHa = area / 10000;
$('#luas_lahan').val(area.toFixed(2));
$('#luas_lahan').val(areaHa.toFixed(4));
}
// FORM
const previewTemplate = `
<div class="dz-preview dz-file-preview">
<div class="dz-control-panel">
<a href="javascript:void(0);" class="dz-btn-action btn-edit" title="Ganti Foto">
<i class="ti tabler-pencil"></i>
</a>
<a href="javascript:void(0);" class="dz-btn-action btn-delete" data-dz-remove title="Hapus Foto">
<i class="ti tabler-x"></i>
</a>
</div>
<div class="dz-image"><img data-dz-thumbnail /></div>
<div class="dz-details">
<div class="dz-filename"><span data-dz-name></span></div>
<div class="dz-size"><span data-dz-size></span></div>
</div>
</div>`;
Dropzone.autoDiscover = false;
let myDropzone = null;
const dropzoneElement = document.querySelector("#dropzone-container");
if (dropzoneElement) {
myDropzone = new Dropzone(dropzoneElement, {
url: "/",
autoProcessQueue: false,
previewTemplate: previewTemplate,
clickable: "#btn-tambah-foto",
previewsContainer: "#dropzone-container",
parallelUploads: 10,
maxFilesize: 5,
addRemoveLinks: false,
acceptedFiles: "image/jpeg,image/jpg,image/png",
thumbnailWidth: null,
thumbnailHeight: null,
});
}
$(document).on('click', '.btn-edit', function(e) {
e.preventDefault();
e.stopPropagation();
let previewElement = $(this).closest('.dz-preview')[0];
let dz = myDropzone;
let fileToReplace = dz.files.find(f => f.previewElement === previewElement);
if (fileToReplace) {
let tempInput = document.createElement('input');
tempInput.type = 'file';
tempInput.accept = 'image/jpeg,image/jpg,image/png';
tempInput.onchange = function(event) {
let newFile = event.target.files[0];
if (newFile) {
dz.removeFile(fileToReplace);
dz.addFile(newFile);
}
};
tempInput.click();
}
});
$(document).on('click', '#dropzone-container .dz-image img', function (e) {
e.stopPropagation();
$('#foto-lightbox-img').attr('src', this.src);
$('#foto-lightbox').addClass('active');
});
$('#foto-lightbox').on('click', function (e) {
if (e.target === this || $(e.target).hasClass('foto-lightbox-close')) {
$(this).removeClass('active');
}
});
$(document).on('click', '.dz-edit', function(e) {
e.preventDefault();
e.stopPropagation();
let previewElement = $(this).closest('.dz-preview')[0];
let dz = $("#dropzone-foto")[0].dropzone;
let fileToReplace = dz.files.find(f => f.previewElement === previewElement);
if (fileToReplace) {
let tempInput = document.createElement('input');
tempInput.type = 'file';
tempInput.accept = 'image/jpeg,image/jpg,image/png';
tempInput.onchange = function(event) {
let newFile = event.target.files[0];
if (newFile) {
dz.removeFile(fileToReplace);
dz.addFile(newFile);
}
};
tempInput.click();
}
});
$('#petani-lahan-tanaman').validate({
rules: {
luas_lahan: { required: true },
luas_lahan: { required: true, number: true, min: 0 },
komoditas_id: { required: true },
jenis_komoditas_id: { required: true },
varietas_id: { required: true },
provinsi_id: { required: true },
kabupatenkota_id: { required: true },
kecamatan_id: { required: true },
desa_kelurahan_id: { required: true },
jumlah_tanaman: { required: true },
jumlah_tanaman: { number: true, min: 0 },
umur_lahan: { number: true, min: 1 },
umur_tanaman: { required: true, number: true, min: 1 },
kondisi_tanaman: { required: true },
},
messages: {
luas_lahan: { required: "Luas lahan wajib diisi" },
luas_lahan: { required: "Luas lahan wajib diisi", number: "Luas lahan harus berupa angka", min: "Luas lahan minimal 0" },
komoditas_id: { required: "Komoditas wajib diisi" },
jenis_komoditas_id: { required: "Jenis komoditas wajib diisi" },
varietas_id: { required: "Varietas wajib diisi" },
provinsi_id: { required: "Provinsi wajib diisi" },
kabupatenkota_id: { required: "Kabupaten/Kota wajib diisi" },
kecamatan_id: { required: "Kecamatan wajib diisi" },
desa_kelurahan_id: { required: "Desa/Kelurahan wajib diisi" },
jumlah_tanaman: { required: "Jumlah tanaman wajib diisi" },
jumlah_tanaman: { number: "Jumlah tanaman harus berupa angka", min: "Jumlah tanaman minimal 0" },
umur_lahan: { number: "Umur lahan harus berupa angka", min: "Umur lahan minimal 1 tahun" },
umur_tanaman: { required: "Umur tanaman wajib diisi", number: "Umur tanaman harus berupa angka", min: "Umur tanaman minimal 1 tahun" },
kondisi_tanaman: { required: "Kondisi tanaman wajib diisi" },
},
errorElement: 'div',
errorPlacement: function (error, element) {
@@ -512,8 +922,73 @@
},
unhighlight: function (element) {
$(element).removeClass('is-invalid');
},
submitHandler: function (form) {
const formData = new FormData(form);
if (myDropzone) {
myDropzone.files.forEach(function(file) {
formData.append("foto[]", file);
});
}
let submitBtn = $(form).find('button[type="submit"]');
let originalText = submitBtn.html();
submitBtn.prop('disabled', true).html('<i class="ti tabler-loader fa-spin me-2"></i> Menyimpan...');
$.ajax({
url: $(form).attr('action'),
type: "POST",
data: formData,
processData: false,
contentType: false,
headers: {
'X-CSRF-TOKEN': $('input[name="_token"]').val(),
'Accept': 'application/json'
},
success: function(res) {
Swal.fire({
icon: 'success',
title: 'Berhasil!',
text: 'Data lahan berhasil ditambahkan.',
showConfirmButton: false,
timer: 1500
}).then(() => {
window.location.href = res.redirect || window.location.href;
});
},
error: function(xhr) {
submitBtn.prop('disabled', false).html(originalText);
if (xhr.status === 422) {
let errors = xhr.responseJSON.errors;
let errorMsg = "";
$.each(errors, function(key, val) {
errorMsg += val[0] + "\n";
});
Swal.fire({
icon: 'warning',
title: 'Penyimpanan Gagal',
text: errorMsg,
confirmButtonColor: '#dc3545'
});
} else {
let errorDetail = xhr.responseJSON && xhr.responseJSON.message ? xhr.responseJSON.message : xhr.statusText;
Swal.fire({
icon: 'error',
title: 'Terjadi Kesalahan',
text: "Error " + xhr.status + ": " + errorDetail,
confirmButtonColor: '#dc3545'
});
console.error(xhr.responseText);
}
}
});
return false;
}
});
});
</script>
@endpush
@endpush
@@ -3,6 +3,7 @@
@push('style')
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
<link rel="stylesheet" href="https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" type="text/css" />
<style>
#map {
@@ -11,6 +12,32 @@
background-color: #f8f9fa;
z-index: 1;
}
.dropzone-custom-container { display: flex; flex-wrap: wrap; gap: 15px; padding: 15px; border: 2px dashed #ced4da; border-radius: 12px; background-color: #f8f9fa; min-height: 160px; align-items: center; }
.btn-tambah-foto { display: flex; flex-direction: column; align-items: center; justify-content: center; width: 140px; height: 160px; border: 2px dashed #a8b1ba; border-radius: 12px; background: #fff; color: #6c757d; cursor: pointer; transition: 0.2s; order: 999; }
.btn-tambah-foto:hover { background: #e9ecef; border-color: #6c757d; color: #495057; }
.dropzone-custom-container .dz-preview { position: relative; background: #fff; border-radius: 12px; box-shadow: 0 4px 10px rgba(0,0,0,0.08); border: 1px solid #e2e8f0; width: 140px; display: flex; flex-direction: column; }
.dropzone-custom-container .dz-image { width: 100%; height: 110px; background: #f1f5f9; cursor: zoom-in; display: flex; align-items: center; justify-content: center; border-radius: 12px 12px 0 0; overflow: hidden; }
.dropzone-custom-container .dz-image img { width: 100%; height: 100%; object-fit: cover; }
.dropzone-custom-container .dz-details { padding: 8px; text-align: center; background: #fff; border-radius: 0 0 12px 12px; border-top: 1px solid #e2e8f0; }
.dropzone-custom-container .dz-filename { font-size: 11px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: #495057; }
.dropzone-custom-container .dz-size { font-size: 10px; color: #adb5bd; }
.dropzone-custom-container .dz-control-panel { position: absolute; top: -8px; right: -8px; display: flex; gap: 5px; z-index: 20; }
.dropzone-custom-container .dz-btn-action { display: flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 50%; color: #fff !important; text-decoration: none !important; box-shadow: 0 2px 5px rgba(0,0,0,0.2); cursor: pointer; font-size: 14px; }
.dropzone-custom-container .btn-edit { background: #ffc107; color: #000 !important; }
.dropzone-custom-container .btn-edit:hover { background: #7367f0; }
.dropzone-custom-container .btn-delete { background: #dc3545; }
.dropzone-custom-container .btn-delete:hover { background: #c82333; }
.dropzone-custom-container .dz-error-message, .dropzone-custom-container .dz-success-mark, .dropzone-custom-container .dz-error-mark, .dropzone-custom-container .progress { display: none !important; }
.foto-lightbox { display: none; position: fixed !important; top: 0 !important; left: 0 !important; width: 100vw !important; height: 100vh !important; background: rgba(0, 0, 0, 0.85) !important; z-index: 99999 !important; align-items: center !important; justify-content: center !important; padding: 30px !important; box-sizing: border-box !important; }
.foto-lightbox.active { display: flex !important; }
.foto-lightbox img { max-width: 90vw !important; max-height: 85vh !important; object-fit: contain !important; border-radius: 8px !important; box-shadow: 0 10px 40px rgba(0,0,0,0.5) !important; }
.foto-lightbox-close { position: absolute !important; top: 20px !important; right: 30px !important; color: #fff !important; font-size: 40px !important; font-weight: bold !important; cursor: pointer !important; z-index: 100000 !important; }
.foto-lightbox-close:hover { color: #dc3545 !important; }
.auto-pest-disease-field .form-check-label,
.auto-pest-disease-field .text-muted {
font-size: 0.875rem;
}
</style>
@endpush
@@ -50,7 +77,7 @@
<div class="row">
<div class="col-md-3 mb-3 form-control-validation">
<label class="form-label">Luas Lahan (m2) <span class="text-danger">*</span></label>
<label class="form-label">Luas Lahan (ha) <span class="text-danger">*</span></label>
<input type="number" step="0.01" id="luas_lahan" name="luas_lahan" class="form-control @error('luas_lahan') is-invalid @enderror" placeholder="Contoh: 1.5" required
value="{{ old('luas_lahan', $lahanSelected->luas_lahan) }}" />
@error('luas_lahan')<div class="error invalid-feedback">{{ $message }}</div>@enderror
@@ -62,8 +89,8 @@
@error('umur_lahan')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-3 form-control-validation">
<label class="form-label">Jumlah Tanaman <span class="text-danger">*</span></label>
<input type="number" name="jumlah_tanaman" class="form-control @error('jumlah_tanaman') is-invalid @enderror" placeholder="Contoh: 1" required
<label class="form-label">Jumlah Tanaman</label>
<input type="number" name="jumlah_tanaman" class="form-control @error('jumlah_tanaman') is-invalid @enderror" placeholder="Contoh: 1 (min 0)"
value="{{ old('jumlah_tanaman', $lahanSelected->jumlah_tanaman) }}" />
@error('jumlah_tanaman')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
@@ -79,7 +106,7 @@
<label class="form-label">Komoditas Utama <span class="text-danger">*</span></label>
<select id="komoditas_id" name="komoditas_id" class="form-select @error('komoditas_id') is-invalid @enderror">
<option value="">Pilih Komoditas</option>
@foreach($komoditas as $k)
@foreach($komoditas->where('is_utama', '1') as $k)
<option value="{{ $k->id }}" {{ old('komoditas_id', $lahanSelected->komoditas_id) == $k->id ? 'selected' : '' }}>{{ $k->nama }}</option>
@endforeach
</select>
@@ -106,23 +133,25 @@
</div>
<div class="row">
<div class="col-md-3 mb-3 form-control-validation">
<label class="form-label">Kondisi Umum Tanaman {{ $lahanSelected->kondisi_tanaman }}</label>
<div class="col-md-6 mb-3 form-control-validation">
<label class="form-label">Kondisi Umum Tanaman</label>
<select id="kondisi_tanaman" name="kondisi_tanaman" class="form-select @error('kondisi_tanaman') is-invalid @enderror">
<option value="">Pilih Kondisi Tanaman</option>
<option value="{{ \App\Enums\KondisiTanaman::BAIK }}" {{ old('kondisi_tanaman', $lahanSelected->kondisi_tanaman) == \App\Enums\KondisiTanaman::BAIK->value ? 'selected' : '' }}>Baik</option>
<option value="{{ \App\Enums\KondisiTanaman::SEDANG }}" {{ old('kondisi_tanaman', $lahanSelected->kondisi_tanaman) == \App\Enums\KondisiTanaman::SEDANG->value ? 'selected' : '' }}>Sedang</option>
<option value="{{ \App\Enums\KondisiTanaman::BURUK }}" {{ old('kondisi_tanaman', $lahanSelected->kondisi_tanaman) == \App\Enums\KondisiTanaman::BURUK->value ? 'selected' : '' }}>Buruk</option>
<option value="{{ \App\Enums\KondisiTanaman::BAIK }}" {{ old('kondisi_tanaman', $lahanSelected->kondisi_tanaman) == \App\Enums\KondisiTanaman::BAIK ? 'selected' : '' }}>{{ \App\Enums\KondisiTanaman::BAIK->label() }}</option>
<option value="{{ \App\Enums\KondisiTanaman::SEDANG }}" {{ old('kondisi_tanaman', $lahanSelected->kondisi_tanaman) == \App\Enums\KondisiTanaman::SEDANG ? 'selected' : '' }}>{{ \App\Enums\KondisiTanaman::SEDANG->label() }}</option>
<option value="{{ \App\Enums\KondisiTanaman::BURUK }}" {{ old('kondisi_tanaman', $lahanSelected->kondisi_tanaman) == \App\Enums\KondisiTanaman::BURUK ? 'selected' : '' }}>{{ \App\Enums\KondisiTanaman::BURUK->label() }}</option>
</select>
@error('kondisi_tanaman')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-3 form-control-validation">
</div>
<div class="row">
<!-- <div class="col-md-3 mb-3 form-control-validation">
<label class="form-label">Serangan Hama</label>
<select id="serangan_hama" name="serangan_hama" class="form-select @error('serangan_hama') is-invalid @enderror">
<option value="">Pilih Serangan Hama</option>
<option value="{{ \App\Enums\SeranganHama::ULAT }}" {{ old('serangan_hama', $lahanSelected->serangan_hama) == \App\Enums\SeranganHama::ULAT->value ? 'selected' : '' }}>Ulat</option>
<option value="{{ \App\Enums\SeranganHama::BELALANG }}" {{ old('serangan_hama', $lahanSelected->serangan_hama) == \App\Enums\SeranganHama::BELALANG->value ? 'selected' : '' }}>Belalang</option>
<option value="{{ \App\Enums\SeranganHama::KUTU }}" {{ old('serangan_hama', $lahanSelected->serangan_hama) == \App\Enums\SeranganHama::KUTU->value ? 'selected' : '' }}>Kutu</option>
<option value="{{ \App\Enums\SeranganHama::ULAT }}" {{ old('serangan_hama', $lahanSelected->serangan_hama) == \App\Enums\SeranganHama::ULAT ? 'selected' : '' }}>Ulat</option>
<option value="{{ \App\Enums\SeranganHama::BELALANG }}" {{ old('serangan_hama', $lahanSelected->serangan_hama) == \App\Enums\SeranganHama::BELALANG ? 'selected' : '' }}>Belalang</option>
<option value="{{ \App\Enums\SeranganHama::KUTU }}" {{ old('serangan_hama', $lahanSelected->serangan_hama) == \App\Enums\SeranganHama::KUTU ? 'selected' : '' }}>Kutu</option>
</select>
@error('serangan_hama')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
@@ -130,19 +159,134 @@
<label class="form-label">Serangan Penyakit</label>
<select id="penyakit_tanaman" name="penyakit_tanaman" class="form-select @error('penyakit_tanaman') is-invalid @enderror">
<option value="">Pilih Penyakit</option>
<option value="{{ \App\Enums\PenyakitTanaman::BUSUK_BUAH }}" {{ old('penyakit_tanaman', $lahanSelected->penyakit_tanaman) == \App\Enums\PenyakitTanaman::BUSUK_BUAH->value ? 'selected' : '' }}>Busuk Buah</option>
<option value="{{ \App\Enums\PenyakitTanaman::DAUN_MENGUNING }}" {{ old('penyakit_tanaman', $lahanSelected->penyakit_tanaman) == \App\Enums\PenyakitTanaman::DAUN_MENGUNING->value ? 'selected' : '' }}>Daun Menguning</option>
<option value="{{ \App\Enums\PenyakitTanaman::DAUN_BERCAK }}" {{ old('penyakit_tanaman', $lahanSelected->penyakit_tanaman) == \App\Enums\PenyakitTanaman::DAUN_BERCAK->value ? 'selected' : '' }}>Daun Bercak</option>
<option value="{{ \App\Enums\PenyakitTanaman::TANAMAN_LAYU }}" {{ old('penyakit_tanaman', $lahanSelected->penyakit_tanaman) == \App\Enums\PenyakitTanaman::TANAMAN_LAYU->value ? 'selected' : '' }}>Tanaman Layu</option>
<option value="{{ \App\Enums\PenyakitTanaman::BUSUK_BUAH }}" {{ old('penyakit_tanaman', $lahanSelected->penyakit_tanaman) == \App\Enums\PenyakitTanaman::BUSUK_BUAH ? 'selected' : '' }}>Busuk Buah</option>
<option value="{{ \App\Enums\PenyakitTanaman::DAUN_MENGUNING }}" {{ old('penyakit_tanaman', $lahanSelected->penyakit_tanaman) == \App\Enums\PenyakitTanaman::DAUN_MENGUNING ? 'selected' : '' }}>Daun Menguning</option>
<option value="{{ \App\Enums\PenyakitTanaman::DAUN_BERCAK }}" {{ old('penyakit_tanaman', $lahanSelected->penyakit_tanaman) == \App\Enums\PenyakitTanaman::DAUN_BERCAK ? 'selected' : '' }}>Daun Bercak</option>
<option value="{{ \App\Enums\PenyakitTanaman::TANAMAN_LAYU }}" {{ old('penyakit_tanaman', $lahanSelected->penyakit_tanaman) == \App\Enums\PenyakitTanaman::TANAMAN_LAYU ? 'selected' : '' }}>Tanaman Layu</option>
</select>
</div> -->
<div class="col-md-3 mb-4 form-control-validation auto-pest-disease-field">
<label class="form-label">Jenis Hama</label>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_hama') is-invalid @enderror" disabled
type="checkbox"
name="jenis_hama[]"
value="Penggerek buah"
id="jenis-hama-penggerek-buah"
{{ in_array('Penggerek buah', $jenisHamaOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-hama-bentuk">Penggerek buah</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_hama') is-invalid @enderror" disabled
type="checkbox"
name="jenis_hama[]"
value="Penggerek batang"
id="jenis-hama-penggerek-batang"
{{ in_array('Penggerek batang', $jenisHamaOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-hama-bentuk">Penggerek batang</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_hama') is-invalid @enderror" disabled
type="checkbox"
name="jenis_hama[]"
value="Kutu putih/kutu sisik"
id="jenis-hama-kutu"
{{ in_array('Kutu putih/kutu sisik', $jenisHamaOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-hama-bentuk">Kutu putih/kutu sisik</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_hama') is-invalid @enderror" disabled
type="checkbox"
name="jenis_hama[]"
value="Ulat pemakan daun"
id="jenis-hama-ulat"
{{ in_array('Ulat pemakan daun', $jenisHamaOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-hama-bentuk">Ulat pemakan daun</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_hama') is-invalid @enderror" disabled
type="checkbox"
name="jenis_hama[]"
value="Tikus"
id="jenis-hama-tikus"
{{ in_array('Tikus', $jenisHamaOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-hama-bentuk">Tikus</label>
</div>
<small class="text-muted text-secondary">* Tidak diisi, terisi otomatis di praktik budidaya</small>
@error('jenis_hama')
<div class="error invalid-feedback d-block">{{ $message }}</div>
@enderror
</div>
<div class="col-md-3 mb-3 form-control-validation">
<div class="col-md-3 mb-4 form-control-validation auto-pest-disease-field">
<label class="form-label">Jenis Penyakit</label>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_penyakit') is-invalid @enderror" disabled
type="checkbox"
name="jenis_penyakit[]"
value="Karat daun"
id="jenis-penyakit-karat-daun"
{{ in_array('Karat daun', $jenisPenyakitOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-penyakit-bentuk">Karat daun</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_penyakit') is-invalid @enderror" disabled
type="checkbox"
name="jenis_penyakit[]"
value="Busuk buah/antraknosa"
id="jenis-penyakit-busuk-buah"
{{ in_array('Busuk buah/antraknosa', $jenisPenyakitOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-penyakit-bentuk">Busuk buah/antraknosa</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_penyakit') is-invalid @enderror" disabled
type="checkbox"
name="jenis_penyakit[]"
value="Busuk akar"
id="jenis-penyakit-busuk-akar"
{{ in_array('Busuk akar', $jenisPenyakitOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-penyakit-bentuk">Busuk akar</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_penyakit') is-invalid @enderror" disabled
type="checkbox"
name="jenis_penyakit[]"
value="Bercak daun"
id="jenis-penyakit-bercak-daun"
{{ in_array('Bercak daun', $jenisPenyakitOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-penyakit-bentuk">Bercak daun</label>
</div>
<div class="form-check mt-2">
<input class="form-check-input @error('jenis_penyakit') is-invalid @enderror" disabled
type="checkbox"
name="jenis_penyakit[]"
value="Layu fusarium"
id="jenis-penyakit-layu-fusarium"
{{ in_array('Layu fusarium', $jenisPenyakitOtomatis ?? [], true) ? 'checked' : '' }}>
<label class="form-check-label" for="jenis-penyakit-bentuk">Layu fusarium</label>
</div>
<small class="text-muted text-secondary">* Tidak diisi, terisi otomatis di Praktik Budidaya</small>
@error('jenis_penyakit')
<div class="error invalid-feedback d-block">{{ $message }}</div>
@enderror
</div>
<div class="col-md-6 mb-3 form-control-validation">
<label class="form-label">Keparahan Serangan Hama/Penyakit</label>
<select id="keparahan_serangan" name="keparahan_serangan" class="form-select @error('keparahan_serangan') is-invalid @enderror">
<option value="">Pilih Keparahan Serangan</option>
<option value="{{ \App\Enums\KeparahanSerangan::RINGAN }}" {{ old('keparahan_serangan', $lahanSelected->keparahan_serangan) == \App\Enums\KeparahanSerangan::RINGAN->value ? 'selected' : '' }}>Ringan</option>
<option value="{{ \App\Enums\KeparahanSerangan::SEDANG }}" {{ old('keparahan_serangan', $lahanSelected->keparahan_serangan) == \App\Enums\KeparahanSerangan::SEDANG->value ? 'selected' : '' }}>Sedang</option>
<option value="{{ \App\Enums\KeparahanSerangan::BERAT }}" {{ old('keparahan_serangan', $lahanSelected->keparahan_serangan) == \App\Enums\KeparahanSerangan::BERAT->value ? 'selected' : '' }}>Berat</option>
<option value="{{ \App\Enums\KeparahanSerangan::RINGAN }}" {{ old('keparahan_serangan', $lahanSelected->keparahan_serangan) == \App\Enums\KeparahanSerangan::RINGAN ? 'selected' : '' }}>{{ \App\Enums\KeparahanSerangan::RINGAN->label() }}</option>
<option value="{{ \App\Enums\KeparahanSerangan::SEDANG }}" {{ old('keparahan_serangan', $lahanSelected->keparahan_serangan) == \App\Enums\KeparahanSerangan::SEDANG ? 'selected' : '' }}>{{ \App\Enums\KeparahanSerangan::SEDANG->label() }}</option>
<option value="{{ \App\Enums\KeparahanSerangan::BERAT }}" {{ old('keparahan_serangan', $lahanSelected->keparahan_serangan) == \App\Enums\KeparahanSerangan::BERAT ? 'selected' : '' }}>{{ \App\Enums\KeparahanSerangan::BERAT->label() }}</option>
</select>
@error('keparahan_serangan')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
@@ -164,10 +308,10 @@
<div class="col-md-6 mb-3 form-control-validation">
<label class="form-label">Tanaman Penaung</label>
<select id="tanaman_penaung" name="tanaman_penaung[]" class="form-select @error('tanaman_penaung[]') is-invalid @enderror" multiple>
<option value="">Pilih Komoditas</option>
@foreach($komoditas as $k)
<option value="{{ $k->id }}"
{{ in_array($k->id, old('tanaman_penaung', $lahanSelected->tanaman_penaung ?? [])) ? 'selected' : '' }}>
<option value="">Pilih Tanaman atau ketik jika tidak ada</option>
@foreach($tanamanPenaung as $k)
<option value="{{ $k->nama }}"
{{ in_array($k->nama, old('tanaman_penaung', $lahanSelected->tanaman_penaung ?? [])) ? 'selected' : '' }}>
{{ $k->nama }}
</option>
@endforeach
@@ -224,9 +368,8 @@
<div class="row">
<div class="col-md-12 mb-3 form-control-validation">
<label class="form-label">Raw Data Koordinat Lahan (Auto-generated JSON) <span class="text-danger">*</span></label>
<textarea name="path" id="path" class="form-control @error('path') is-invalid @enderror" rows="4" readonly
placeholder="Koordinat akan terisi otomatis setelah Anda menggambar polygon di peta...">{{ old('path', $lahanSelected->path) }}</textarea>
<small class="text-muted">Gunakan tombol edit (pensil) atau hapus (tong sampah) di peta untuk mengubah bentuk lahan.</small>
<textarea name="path" id="path" class="form-control @error('path') is-invalid @enderror" rows="4" readonly
placeholder="Koordinat akan terisi otomatis setelah Anda menggambar polygon di peta...">{{ old('path', is_string($lahanSelected->path) ? $lahanSelected->path : json_encode($lahanSelected->path)) }}</textarea>
@error('path')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
@@ -240,11 +383,32 @@
<div id="map" class="border rounded shadow-sm"></div>
</div>
<div class="row mt-3">
<div class="col-12 text-end">
<button type="reset" class="btn btn-label-secondary me-2">Reset</button>
<button type="submit" class="btn btn-primary"><i class="ti tabler-device-floppy me-2"></i> Simpan Data</button>
</div>
<hr class="my-4">
<div class="row">
<div class="col-md-12 mb-3 form-control-validation">
<h6 class="mb-5">Foto</h6>
<div id="dropzone-container" class="dropzone-custom-container">
<div id="btn-tambah-foto" class="btn-tambah-foto">
<i class="ti tabler-plus" style="font-size: 32px; margin-bottom: 8px;"></i>
<span style="font-size: 13px; font-weight: 600;">Tambah Foto</span>
</div>
</div>
<div id="deleted-photos-container"></div>
<input type="file" id="foto-input" multiple hidden>
@error('file')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
<div class="row mt-3">
<div class="col-12 text-end">
<a href="{{ route('petani.index') }}" class="btn btn-secondary me-2 wave-effect wave-light">Kembali</a>
<button id="delete-lahan"type="button" class="btn btn-danger data-submit wave-effect wave-light"><i class="ti tabler-trash me-2"></i> Hapus Lahan</button>
<button type="submit" class="btn btn-success data-submit wave-effect wave-light"><i class="ti tabler-device-floppy me-2"></i> Simpan Lahan</button>
</div>
</div>
</form>
@@ -252,10 +416,13 @@
</div>
<br/>
<div class="row">
<div class="col-12 col-lg-2 col-md-3">
</div>
<div class="col-12 col-lg-10 col-md-9">
<hr class="my-4">
<h6 class="mb-3">Tanaman</h6>
<div class="table-responsive">
<table class="table table-hover table-sm" id="table-tanaman">
<thead class="border-top">
@@ -271,7 +438,7 @@
</tr>
</thead>
<tbody>
@forelse($lahanSelected->tanaman as $index => $item)
@foreach($lahanSelected->tanaman as $item)
<tr>
<td>{{ $loop->iteration }}</td>
<td>
@@ -315,12 +482,12 @@
@elseif($item->penyakit_tanaman == \App\Enums\PenyakitTanaman::DAUN_BERCAK)
<span class="badge bg-label-warning">Daun Bercak</span>
@elseif($item->penyakit_tanaman == \App\Enums\PenyakitTanaman::TANAMAN_LAYU)
<span class="badge bg-label-danger">Tanaman Layu</span>
<span class="badge bg-label-info">Tanaman Layu</span>
@endif
</td>
<td class="td-keparahan">
@if($item->keparahan_serangan == \App\Enums\KeparahanSerangan::RINGAN)
<span class="badge bg-label-success">Ringan</span>
<span class="badge bg-label-info">Ringan</span>
@elseif($item->keparahan_serangan == \App\Enums\KeparahanSerangan::SEDANG)
<span class="badge bg-label-warning">Sedang</span>
@elseif($item->keparahan_serangan == \App\Enums\KeparahanSerangan::BERAT)
@@ -334,9 +501,7 @@
</div>
</td>
</tr>
@empty
<tr><td colspan="6" class="text-center py-4">Tidak ada data ditemukan.</td></tr>
@endforelse
@endforeach
</tbody>
</table>
</div>
@@ -355,6 +520,7 @@
@endsection
@push('scripts')
<script src="https://unpkg.com/dropzone@5/dist/min/dropzone.min.js"></script>
<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>
@@ -376,7 +542,9 @@
$('#penyakit_tanaman').select2();
$('#keparahan_serangan').select2();
$('#komoditas_lain').select2();
$('#tanaman_penaung').select2();
$('#tanaman_penaung').select2({
tags: true
});
$('#table-tanaman').DataTable({
"paging": true,
@@ -543,7 +711,7 @@
let regionBoundaryLayer = L.featureGroup().addTo(map);
function focusToRegionBoundary(selectElement, shouldZoom = true) {
regionBoundaryLayer.clearLayers(); // Bersihkan garis wilayah sebelumnya
regionBoundaryLayer.clearLayers();
let selectedOption = selectElement.options[selectElement.selectedIndex];
if (!selectedOption || !selectedOption.hasAttribute('data-path')) return;
@@ -558,7 +726,7 @@
function formatCoordinates(coords) {
if (coords.length === 2 && typeof coords[0] === 'number') {
return [coords[0], coords[1]]; // JANGAN DIBALIK
return [coords[0], coords[1]];
}
return coords.map(formatCoordinates);
}
@@ -634,10 +802,8 @@
map.on(L.Draw.Event.CREATED, function (e) {
let layer = e.layer;
drawnItems.clearLayers();
drawnItems.addLayer(layer);
updatePathTextarea(layer);
});
@@ -657,15 +823,142 @@
return [latlng.lng, latlng.lat];
});
document.getElementById('path').value = JSON.stringify(pathData);
let area = L.GeometryUtil.geodesicArea(latlngs);
console.log(area);
$('#luas_lahan').val(area.toFixed(2));
let areaHa = area / 10000;
$('#luas_lahan').val(areaHa.toFixed(4));
}
// FORM
const previewTemplate = `
<div class="dz-preview dz-file-preview">
<div class="dz-control-panel">
<a href="javascript:void(0);" class="dz-btn-action btn-edit" title="Ganti Foto">
<i class="ti tabler-pencil"></i>
</a>
<a href="javascript:void(0);" class="dz-btn-action btn-delete" data-dz-remove title="Hapus Foto">
<i class="ti tabler-x"></i>
</a>
</div>
<div class="dz-image"><img data-dz-thumbnail /></div>
<div class="dz-details">
<div class="dz-filename"><span data-dz-name></span></div>
<div class="dz-size"><span data-dz-size></span></div>
</div>
</div>`;
Dropzone.autoDiscover = false;
let myDropzone = null;
const dropzoneElement = document.querySelector("#dropzone-container");
if (dropzoneElement) {
myDropzone = new Dropzone(dropzoneElement, {
url: "/",
autoProcessQueue: false,
previewTemplate: previewTemplate,
clickable: "#btn-tambah-foto",
previewsContainer: "#dropzone-container",
parallelUploads: 10,
maxFilesize: 5,
addRemoveLinks: false,
acceptedFiles: "image/jpeg,image/jpg,image/png",
init: function () {
let dz = this;
let rawPhotos = {!! json_encode($lahanSelected->foto ?? []) !!};
let existingPhotos = [];
if (typeof rawPhotos === 'string') {
try {
existingPhotos = JSON.parse(rawPhotos);
} catch(e) {
existingPhotos = [];
}
} else if (Array.isArray(rawPhotos)) {
existingPhotos = rawPhotos;
}
if (existingPhotos && existingPhotos.length > 0) {
existingPhotos.forEach(function (photo, index) {
let pathStr = typeof photo === 'object' ? (photo.path || photo[0] || '') : photo;
if (pathStr && pathStr !== '') {
let mockFile = {
name: "Foto Lahan " + (index + 1),
size: 1024,
id: index,
file_path: pathStr,
isServerFile: true,
accepted: true
};
dz.emit("addedfile", mockFile);
dz.emit("thumbnail", mockFile, "{{ asset('storage') }}/" + pathStr);
dz.emit("complete", mockFile);
dz.files.push(mockFile);
}
});
}
this.on("removedfile", function (file) {
if (file.isServerFile) {
let deleteInput = $('<input>').attr({
type: 'hidden',
name: 'deleted_photos[]',
value: file.file_path
});
$('#deleted-photos-container').append(deleteInput);
}
});
}
});
}
$(document).on('click', '.btn-edit', function(e) {
e.preventDefault();
e.stopPropagation();
let previewElement = $(this).closest('.dz-preview')[0];
let dz = myDropzone;
let fileToReplace = dz.files.find(f => f.previewElement === previewElement);
if (fileToReplace) {
let tempInput = document.createElement('input');
tempInput.type = 'file';
tempInput.accept = 'image/jpeg,image/jpg,image/png';
tempInput.onchange = function(event) {
let newFile = event.target.files[0];
if (newFile) {
if(fileToReplace.isServerFile){
let deleteInput = $('<input>').attr({
type: 'hidden',
name: 'deleted_photos[]',
value: fileToReplace.file_path
});
$('#deleted-photos-container').append(deleteInput);
}
dz.removeFile(fileToReplace);
dz.addFile(newFile);
}
};
tempInput.click();
}
});
$(document).on('click', '#dropzone-container .dz-image img', function (e) {
e.stopPropagation();
$('#foto-lightbox-img').attr('src', this.src);
$('#foto-lightbox').addClass('active');
});
$('#foto-lightbox').on('click', function (e) {
if (e.target === this || $(e.target).hasClass('foto-lightbox-close')) {
$(this).removeClass('active');
}
});
$('#petani-lahan-tanaman').validate({
rules: {
@@ -674,7 +967,7 @@
jenis_komoditas_id: { required: true },
varietas_id: { required: true },
desa_kelurahan_id: { required: true },
jumlah_tanaman: { required: true, min: @json($lahanSelected->jumlah_tanaman) },
jumlah_tanaman: { min: @json($lahanSelected->jumlah_tanaman) },
},
messages: {
luas_lahan: { required: "Luas lahan wajib diisi" },
@@ -682,7 +975,7 @@
jenis_komoditas_id: { required: "Jenis komoditas wajib diisi" },
varietas_id: { required: "Varietas wajib diisi" },
desa_kelurahan_id: { required: "Desa/Kelurahan wajib diisi" },
jumlah_tanaman: { required: "Jumlah tanaman wajib diisi", min: "Jumlah tanaman tidak boleh kurang dari @json($lahanSelected->jumlah_tanaman), hapus pada tanaman yang dimaksud" },
jumlah_tanaman: { min: "Jumlah tanaman tidak boleh kurang dari @json($lahanSelected->jumlah_tanaman), hapus pada tanaman yang dimaksud" },
},
errorElement: 'div',
errorPlacement: function (error, element) {
@@ -694,11 +987,104 @@
},
unhighlight: function (element) {
$(element).removeClass('is-invalid');
},
submitHandler: function (form) {
const formData = new FormData(form);
formData.append('_method', 'PUT');
if (myDropzone) {
myDropzone.files.forEach(function(file) {
if (!file.isServerFile) {
formData.append("foto[]", file);
}
});
}
let submitBtn = $(form).find('button[type="submit"]');
let originalText = submitBtn.html();
submitBtn.prop('disabled', true).html('<i class="ti tabler-loader fa-spin me-2"></i> Menyimpan...');
$.ajax({
url: $(form).attr('action'),
type: "POST",
data: formData,
processData: false,
contentType: false,
headers: {
'X-CSRF-TOKEN': $('input[name="_token"]').val(),
'Accept': 'application/json'
},
success: function(res) {
Swal.fire({
icon: 'success',
title: 'Berhasil!',
text: 'Data lahan berhasil disimpan.',
showConfirmButton: false,
timer: 1500
}).then(() => {
window.location.href = res.redirect || window.location.href;
});
},
error: function(xhr) {
submitBtn.prop('disabled', false).html(originalText);
if (xhr.status === 422) {
let errors = xhr.responseJSON.errors;
let errorMsg = "";
$.each(errors, function(key, val) {
errorMsg += val[0] + "\n";
});
Swal.fire({
icon: 'warning',
title: 'Penyimpanan Gagal',
text: errorMsg,
confirmButtonColor: '#dc3545'
});
} else {
let errorDetail = xhr.responseJSON && xhr.responseJSON.message ? xhr.responseJSON.message : xhr.statusText;
Swal.fire({
icon: 'error',
title: 'Terjadi Kesalahan',
text: "Error " + xhr.status + ": " + errorDetail,
confirmButtonColor: '#dc3545'
});
console.error(xhr.responseText);
}
}
});
return false;
}
});
$('#delete-lahan').click(function(e) {
e.preventDefault();
$.ajax({
url: "{{ route('petani.lahan-tanaman.destroy', ['petani' => $petani->id, 'lahan_tanaman' => $lahanSelected->id]) }}",
type: "POST",
data: {
_method: 'DELETE',
_token: $('input[name="_token"]').val()
},
success: function(res) {
Swal.fire({
icon: 'success',
title: 'Berhasil!',
text: 'Data lahan berhasil dihapus.',
showConfirmButton: false,
timer: 1500
}).then(() => {
window.location.href = "{{ route('petani.lahan-tanaman.index', ['petani' => $petani->id]) }}";
});
}
});
});
initWilayah();
initKomoditas();
});
</script>
@endpush
@endpush
@@ -32,40 +32,39 @@
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<div class="col-md-6 form-control-validation">
<label for="latitude" class="form-label">Latitude</label>
<input type="number" class="form-control" id="latitude" name="latitude">
</div>
<div class="col-md-6">
<div class="col-md-6 form-control-validation">
<label for="longitude" class="form-label">Longitude</label>
<input type="number" class="form-control" id="longitude" name="longitude">
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<div class="col-md-6 form-control-validation">
<label for="kondisi" class="form-label">Kondisi Tanaman</label>
<select class="form-select" id="kondisi" name="kondisi_tanaman" required>
<select class="form-select" id="tnm_kondisi_tanaman" name="kondisi_tanaman" required>
<option value="">Pilih Kondisi Tanaman</option>
<option value="{{ \App\Enums\KondisiTanaman::BAIK }}" {{ old('kondisi_tanaman', $lahanSelected->kondisi_tanaman) == \App\Enums\KondisiTanaman::BAIK->value ? 'selected' : '' }}>Baik</option>
<option value="{{ \App\Enums\KondisiTanaman::SEDANG }}" {{ old('kondisi_tanaman', $lahanSelected->kondisi_tanaman) == \App\Enums\KondisiTanaman::SEDANG->value ? 'selected' : '' }}>Sedang</option>
<option value="{{ \App\Enums\KondisiTanaman::BURUK }}" {{ old('kondisi_tanaman', $lahanSelected->kondisi_tanaman) == \App\Enums\KondisiTanaman::BURUK->value ? 'selected' : '' }}>Buruk</option>
<option value="{{ \App\Enums\KondisiTanaman::BAIK->value }}">Baik</option>
<option value="{{ \App\Enums\KondisiTanaman::SEDANG->value }}">Sedang</option>
<option value="{{ \App\Enums\KondisiTanaman::BURUK->value }}">Buruk</option>
</select>
</div>
<div class="col-md-6 form-control-validation">
<label class="form-label">Serangan Hama</label>
<select id="serangan_hama" name="serangan_hama" class="form-select @error('serangan_hama') is-invalid @enderror">
<select id="tnm_serangan_hama" name="serangan_hama" class="form-select">
<option value="">Pilih Serangan Hama</option>
<option value="{{ \App\Enums\SeranganHama::ULAT }}" {{ old('serangan_hama', $lahanSelected->serangan_hama) == \App\Enums\SeranganHama::ULAT->value ? 'selected' : '' }}>Ulat</option>
<option value="{{ \App\Enums\SeranganHama::BELALANG }}" {{ old('serangan_hama', $lahanSelected->serangan_hama) == \App\Enums\SeranganHama::BELALANG->value ? 'selected' : '' }}>Belalang</option>
<option value="{{ \App\Enums\SeranganHama::KUTU }}" {{ old('serangan_hama', $lahanSelected->serangan_hama) == \App\Enums\SeranganHama::KUTU->value ? 'selected' : '' }}>Kutu</option>
<option value="{{ \App\Enums\SeranganHama::ULAT }}">Ulat</option>
<option value="{{ \App\Enums\SeranganHama::BELALANG }}">Belalang</option>
<option value="{{ \App\Enums\SeranganHama::KUTU }}">Kutu</option>
</select>
@error('serangan_hama')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
<div class="row mb-3">
<div class="col-md-6 form-control-validation">
<label class="form-label">Penyakit Tanaman</label>
<select id="penyakit_tanaman" name="penyakit_tanaman" class="form-select @error('penyakit_tanaman') is-invalid @enderror">
<select id="tnm_penyakit_tanaman" name="penyakit_tanaman">
<option value="">Pilih Penyakit</option>
<option value="{{ \App\Enums\PenyakitTanaman::BUSUK_BUAH }}" {{ old('penyakit_tanaman', $lahanSelected->penyakit_tanaman) == \App\Enums\PenyakitTanaman::BUSUK_BUAH->value ? 'selected' : '' }}>Busuk Buah</option>
<option value="{{ \App\Enums\PenyakitTanaman::DAUN_MENGUNING }}" {{ old('penyakit_tanaman', $lahanSelected->penyakit_tanaman) == \App\Enums\PenyakitTanaman::DAUN_MENGUNING->value ? 'selected' : '' }}>Daun Menguning</option>
@@ -76,7 +75,7 @@
</div>
<div class="col-md-6 form-control-validation">
<label class="form-label">Keparahan Serangan</label>
<select id="keparahan_serangan" name="keparahan_serangan" class="form-select @error('keparahan_serangan') is-invalid @enderror">
<select id="tnm_keparahan_serangan" name="keparahan_serangan" class="form-select @error('keparahan_serangan') is-invalid @enderror">
<option value="">Pilih Keparahan Serangan</option>
<option value="{{ \App\Enums\KeparahanSerangan::RINGAN }}" {{ old('keparahan_serangan', $lahanSelected->keparahan_serangan) == \App\Enums\KeparahanSerangan::RINGAN->value ? 'selected' : '' }}>Ringan</option>
<option value="{{ \App\Enums\KeparahanSerangan::SEDANG }}" {{ old('keparahan_serangan', $lahanSelected->keparahan_serangan) == \App\Enums\KeparahanSerangan::SEDANG->value ? 'selected' : '' }}>Sedang</option>
@@ -110,15 +109,21 @@
type: 'GET',
success: function(response) {
console.log(response);
$('#tnm_kondisi_tanaman,#tnm_serangan_hama,#tnm_penyakit_tanaman,#tnm_keparahan_serangan')
.val(null)
.trigger('change');
$('#komoditas').val(response.data.komoditas.nama);
$('#jenis_komoditas').val(response.data.jenis_komoditas.nama);
$('#varietas').val(response.data.varietas.nama);
$('#latitude').val(response.data.latitude);
$('#longitude').val(response.data.longitude);
$('#kondisi').val(response.data.kondisi_tanaman);
$('#serangan_hama').val(response.data.serangan_hama);
$('#penyakit_tanaman').val(response.data.penyakit_tanaman);
$('#keparahan_serangan').val(response.data.keparahan_serangan);
$('#tnm_kondisi_tanaman').val(response.data.kondisi_tanaman).trigger('change');
$('#tnm_serangan_hama').val(response.data.serangan_hama).trigger('change');
$('#tnm_penyakit_tanaman').val(response.data.penyakit_tanaman).trigger('change');
$('#tnm_keparahan_serangan').val(response.data.keparahan_serangan).trigger('change');
$('#editTanamanFormId').val(response.data.id);
$('#tanamanModal').modal('show');
@@ -129,6 +134,13 @@
});
});
console.log(document.querySelectorAll('#serangan_hama'));
$('#tnm_kondisi_tanaman,#tnm_serangan_hama,#tnm_penyakit_tanaman,#tnm_keparahan_serangan').select2({
dropdownParent: $('#tanamanModal'),
width: '100%'
});
$('#editTanamanForm').validate({
rules: {
latitude: {
@@ -150,7 +162,6 @@
},
submitHandler: function(form) {
var url = form.action.replace(':id', $('#editTanamanFormId').val());
console.log(url);
$.ajax({
url: url,
@@ -177,6 +188,35 @@
currentRow.find('.td-kondisi').html('<span class="badge bg-label-dark">Mati</span>');
}
}
if (response.data.serangan_hama) {
if (response.data.serangan_hama === 'ulat') {
currentRow.find('.td-hama').html('<span class="badge bg-label-success">Ulat</span>');
} else if (response.data.serangan_hama === 'belalang') {
currentRow.find('.td-hama').html('<span class="badge bg-label-danger">Belalang</span>');
} else if (response.data.serangan_hama === 'kutu') {
currentRow.find('.td-hama').html('<span class="badge bg-label-warning">Kutu</span>');
}
}
if (response.data.penyakit_tanaman) {
if (response.data.penyakit_tanaman === 'busuk_buah') {
currentRow.find('.td-penyakit').html('<span class="badge bg-label-success">Busuk Buah</span>');
} else if (response.data.penyakit_tanaman === 'daun_menguning') {
currentRow.find('.td-penyakit').html('<span class="badge bg-label-danger">Daun Menguning</span>');
} else if (response.data.penyakit_tanaman === 'daun_bercak') {
currentRow.find('.td-penyakit').html('<span class="badge bg-label-warning">Daun Bercak</span>');
} else if (response.data.penyakit_tanaman === 'tanaman_layu') {
currentRow.find('.td-penyakit').html('<span class="badge bg-label-info">Tanaman Layu</span>');
}
}
if (response.data.keparahan_serangan) {
if (response.data.keparahan_serangan === 'baik') {
currentRow.find('.td-keparahan').html('<span class="badge bg-label-info">Ringan</span>');
} else if (response.data.keparahan_serangan === 'sedang') {
currentRow.find('.td-keparahan').html('<span class="badge bg-label-warning">Sedang</span>');
} else if (response.data.keparahan_serangan === 'buruk') {
currentRow.find('.td-keparahan').html('<span class="badge bg-label-danger">Berat</span>');
}
}
} else {
}
@@ -0,0 +1,548 @@
@extends('layout.main')
@push('style')
<style>
.status-switch-row {
display: flex !important;
align-items: center !important;
gap: 12px !important;
white-space: nowrap !important;
}
.status-switch-row .switch {
width: 52px !important;
min-width: 52px !important;
max-width: 52px !important;
padding-left: 0 !important;
margin: 0 !important;
position: relative !important;
display: inline-block !important;
flex: 0 0 52px !important;
}
.status-switch-row .switch-toggle-slider {
left: 0 !important;
}
.status-switch-row .status-text {
display: inline-block !important;
white-space: nowrap !important;
line-height: 1.5 !important;
}
#section-pelatihan,
#section-sertifikasi {
scroll-margin-top: 96px;
}
</style>
@endpush
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
@if ($errors->any())
<div class="alert alert-danger">
<ul class="mb-0">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div class="row">
<!-- PROFIL PETANI -->
<div class="col-md-12">
@include('produktivitas.petani.header', ['petani' => $petani])
<div class="card mb-6" id="section-pelatihan">
<div class="card-body pt-12">
<h5 class="pb-4 border-bottom mb-4">
Riwayat Pelatihan
</h5>
{{-- DATA LAMA --}}
@if ($petani->surveyPelatihan->count() > 0)
@foreach ($petani->surveyPelatihan as $row)
<div class="row align-items-end border-bottom pb-3 mb-3">
<div class="col-md-5">
<label class="form-label">Jenis Pelatihan</label>
<input type="text" class="form-control" value="{{ $row->jenis_pelatihan }}" disabled>
</div>
<div class="col-md-4">
<label class="form-label">Penyelenggara</label>
<input type="text" class="form-control" value="{{ $row->penyelenggara }}" disabled>
</div>
<div class="col-md-2">
<label class="form-label">Tahun</label>
<input type="text" class="form-control" value="{{ $row->tahun_pelaksanaan }}" disabled>
</div>
<div class="col-md-1">
<form
method="POST"
action="{{ route('petani.pendidikan-pelatihan.pelatihan.destroy', [$petani->id, $row->id]) }}"
class="delete-db-form">
@csrf
@method('DELETE')
<input type="hidden" name="redirect_fragment" value="section-pelatihan">
<button type="submit" class="btn btn-outline-danger">
<i class="icon-base ti tabler-trash icon-sm"></i>
</button>
</form>
</div>
</div>
@endforeach
@else
<p class="text-muted mb-4">Belum ada riwayat pelatihan.</p>
@endif
{{-- FORM TAMBAH DATA BARU --}}
<form
method="POST"
action="{{ route('petani.pendidikan-pelatihan.pelatihan.store', $petani->id) }}"
class="form-repeater-pelatihan">
@csrf
<input type="hidden" name="redirect_fragment" value="section-sertifikasi">
<div data-repeater-list="riwayat_pelatihan">
<div data-repeater-item>
<div class="row align-items-end">
<div class="col-md-5 mb-3">
<label class="form-label">Jenis Pelatihan</label>
<input
type="text"
class="form-control pelatihan-input"
name="jenis_pelatihan"
placeholder="Contoh: Pelatihan GAP">
</div>
<div class="col-md-4 mb-3">
<label class="form-label">Penyelenggara</label>
<input
type="text"
class="form-control pelatihan-input"
name="penyelenggara"
placeholder="Contoh: Dinas Pertanian">
</div>
<div class="col-md-2 mb-3">
<label class="form-label d-block">Tahun</label>
<input
type="number"
class="form-control pelatihan-input"
name="tahun"
placeholder="Contoh: 2024"
min="1900"
max="{{ date('Y') }}">
</div>
<div class="col-md-1 mb-3">
<button
type="button"
class="btn btn-outline-danger btn-delete-pelatihan"
data-repeater-delete
disabled>
<i class="icon-base ti tabler-trash icon-sm"></i>
</button>
</div>
</div>
<hr>
</div>
</div>
<div class="mt-4 d-flex justify-content-between">
<button
type="button"
class="btn btn-outline-success"
id="btn-tambah-pelatihan"
data-repeater-create
disabled>
<i class="icon-base ti tabler-plus me-1_5 icon-sm"></i>
Tambah Pelatihan
</button>
<button type="submit" class="btn btn-success">
<i class="icon-base ti tabler-check me-1_5 icon-sm"></i>
Simpan Riwayat Pelatihan
</button>
</div>
</form>
</div>
</div>
{{-- SERTIFIKASI KEAHLIAN --}}
<div class="card mb-6" id="section-sertifikasi">
<div class="card-body pt-12">
<h5 class="pb-4 border-bottom mb-4">
Sertifikasi Keahlian
</h5>
{{-- DATA LAMA --}}
@if ($petani->surveySertifikasi->count() > 0)
@foreach ($petani->surveySertifikasi as $row)
<div class="row align-items-end border-bottom pb-3 mb-3">
<div class="col-md-4">
<label class="form-label">Jenis Keahlian Yang Disertifikasi</label>
<input type="text" class="form-control" value="{{ $row->jenis_sertifikasi }}" disabled>
</div>
<div class="col-md-3">
<label class="form-label">Lembaga Penerbit</label>
<input type="text" class="form-control" value="{{ $row->lembaga_penerbit }}" disabled>
</div>
<div class="col-md-2">
<label class="form-label">Tahun</label>
<input type="text" class="form-control" value="{{ $row->tahun_pelaksanaan }}" disabled>
</div>
<div class="col-md-2">
<label class="form-label d-block mb-1">Status</label>
@php
$statusBerlaku = (bool) $row->is_aktif;
@endphp
<div class="status-switch-row">
<label class="switch switch-lg">
<input
type="checkbox"
class="switch-input"
{{ $statusBerlaku ? 'checked' : '' }}
onclick="return false;"
tabindex="-1">
<span class="switch-toggle-slider">
<span class="switch-on">
<i class="icon-base ti tabler-check"></i>
</span>
<span class="switch-off">
<i class="icon-base ti tabler-x"></i>
</span>
</span>
</label>
<span class="status-text">
{{ $statusBerlaku ? 'Masih Berlaku' : 'Tidak Berlaku' }}
</span>
</div>
</div>
<div class="col-md-1">
<form
method="POST"
action="{{ route('petani.pendidikan-pelatihan.sertifikasi.destroy', [$petani->id, $row->id]) }}"
class="delete-db-form">
@csrf
@method('DELETE')
<input type="hidden" name="redirect_fragment" value="section-sertifikasi">
<button type="submit" class="btn btn-outline-danger">
<i class="icon-base ti tabler-trash icon-sm"></i>
</button>
</form>
</div>
</div>
@endforeach
@else
<p class="text-muted mb-4">Belum ada data sertifikasi.</p>
@endif
{{-- FORM TAMBAH DATA BARU --}}
<form
method="POST"
action="{{ route('petani.pendidikan-pelatihan.sertifikasi.store', $petani->id) }}"
class="form-repeater-sertifikasi">
@csrf
<input type="hidden" name="redirect_fragment" value="section-sertifikasi">
<div data-repeater-list="sertifikasi">
<div data-repeater-item>
<div class="row align-items-end">
<div class="col-md-4 mb-3">
<label class="form-label">Jenis Keahlian Yang Disertifikasi</label>
<input
type="text"
class="form-control sertifikasi-input"
name="jenis_sertifikasi"
placeholder="Contoh: Sertifikasi GAP">
</div>
<div class="col-md-3 mb-3">
<label class="form-label">Lembaga Penerbit</label>
<input
type="text"
class="form-control sertifikasi-input"
name="lembaga_penerbit"
placeholder="Contoh: BNSP">
</div>
<div class="col-md-2 mb-3">
<label class="form-label d-block">Tahun</label>
<input
type="number"
class="form-control sertifikasi-input"
name="tahun"
placeholder="Contoh: 2024"
min="1900"
max="{{ date('Y') }}">
</div>
<div class="col-md-2 mb-3">
<label class="form-label d-block">Status</label>
<label class="switch switch-lg">
<input type="hidden" name="status_berlaku_sertifikat" value="0">
<input
type="checkbox"
class="switch-input sertifikasi-status-switch"
name="status_berlaku_sertifikat"
value="1">
<span class="switch-toggle-slider">
<span class="switch-on">
<i class="icon-base ti tabler-check"></i>
</span>
<span class="switch-off">
<i class="icon-base ti tabler-x"></i>
</span>
</span>
<span class="switch-label">
<span class="sertifikasi-switch-text">Tidak Berlaku</span>
</span>
</label>
</div>
<div class="col-md-1 mb-3">
<button
type="button"
class="btn btn-outline-danger btn-delete-sertifikasi"
data-repeater-delete
disabled>
<i class="icon-base ti tabler-trash icon-sm"></i>
</button>
</div>
</div>
<hr>
</div>
</div>
<div class="mt-4 d-flex justify-content-between">
<button
type="button"
class="btn btn-outline-success"
id="btn-tambah-sertifikasi"
data-repeater-create
disabled>
<i class="icon-base ti tabler-plus me-1_5 icon-sm"></i>
Tambah Sertifikasi
</button>
<button type="submit" class="btn btn-success">
<i class="icon-base ti tabler-check me-1_5 icon-sm"></i>
Simpan Sertifikasi Keahlian
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
'use strict';
$(function () {
function initRepeaterWithValidation(config) {
const $form = $(config.formSelector);
const $btnTambah = $(config.addButtonSelector);
if (!$form.length || !$btnTambah.length) {
return;
}
function getRows() {
return $form.find('[data-repeater-item]');
}
function rowAdaIsi($row) {
return $row.find(config.inputSelector).toArray().some(function (input) {
return String($(input).val() || '').trim() !== '';
});
}
function rowLengkap($row) {
const $inputs = $row.find(config.inputSelector);
if ($inputs.length === 0) {
return false;
}
return $inputs.toArray().every(function (input) {
return String($(input).val() || '').trim() !== '';
});
}
function updateSwitchText($switch) {
if (!config.switchSelector || !config.switchTextSelector) {
return;
}
const $row = $switch.closest('[data-repeater-item]');
const $text = $row.find(config.switchTextSelector);
if ($switch.is(':checked')) {
$text.text(config.switchTextOn || 'Ya');
} else {
$text.text(config.switchTextOff || 'Tidak');
}
}
function updateAllSwitchText() {
if (!config.switchSelector) {
return;
}
$form.find(config.switchSelector).each(function () {
updateSwitchText($(this));
});
}
function updateButtons() {
const $rows = getRows();
const $lastRow = $rows.last();
$rows.each(function () {
const $row = $(this);
const $deleteButton = $row.find(config.deleteButtonSelector);
$deleteButton.prop('disabled', !rowAdaIsi($row));
});
$btnTambah.prop('disabled', !rowLengkap($lastRow));
}
$form.repeater({
initEmpty: false,
show: function () {
const $row = $(this);
$row.find(config.inputSelector).val('');
$row.find(config.deleteButtonSelector).prop('disabled', true);
if (config.switchSelector) {
$row.find(config.switchSelector).prop('checked', false);
}
updateAllSwitchText();
$row.slideDown();
setTimeout(updateButtons, 50);
},
hide: function (deleteElement) {
const $row = $(this);
// Kalau baris kosong, jangan lakukan apa-apa
if (!rowAdaIsi($row)) {
return;
}
// Ini hanya hapus baris di form, tidak kirim ke DB
Swal.fire({
title: config.deleteTitle || 'Hapus baris ini?',
text: 'Baris ini hanya akan dihapus dari form.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Ya, hapus',
cancelButtonText: 'Batal',
customClass: {
confirmButton: 'btn btn-danger me-3',
cancelButton: 'btn btn-label-secondary'
},
buttonsStyling: false
}).then(function (result) {
if (result.isConfirmed) {
$row.slideUp(deleteElement);
setTimeout(updateButtons, 300);
}
});
}
});
$(document).on('input keyup change', config.formSelector + ' ' + config.inputSelector, function () {
updateButtons();
});
if (config.switchSelector) {
$(document).on('change', config.formSelector + ' ' + config.switchSelector, function () {
updateSwitchText($(this));
updateButtons();
});
}
updateAllSwitchText();
updateButtons();
}
initRepeaterWithValidation({
formSelector: '.form-repeater-pelatihan',
addButtonSelector: '#btn-tambah-pelatihan',
inputSelector: '.pelatihan-input',
deleteButtonSelector: '.btn-delete-pelatihan',
deleteTitle: 'Hapus baris pelatihan ini?'
});
initRepeaterWithValidation({
formSelector: '.form-repeater-sertifikasi',
addButtonSelector: '#btn-tambah-sertifikasi',
inputSelector: '.sertifikasi-input',
deleteButtonSelector: '.btn-delete-sertifikasi',
deleteTitle: 'Hapus baris sertifikasi ini?',
switchSelector: '.sertifikasi-status-switch',
switchTextSelector: '.sertifikasi-switch-text',
switchTextOn: 'Masih Berlaku',
switchTextOff: 'Tidak Berlaku'
});
// Ini khusus untuk data yang SUDAH ADA DI DATABASE
$(document).on('submit', '.delete-db-form', function (e) {
e.preventDefault();
const form = this;
Swal.fire({
title: 'Hapus data ini?',
text: 'Data yang sudah dihapus tidak bisa dikembalikan.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Ya, hapus',
cancelButtonText: 'Batal',
customClass: {
confirmButton: 'btn btn-danger me-3',
cancelButton: 'btn btn-label-secondary'
},
buttonsStyling: false
}).then(function (result) {
if (result.isConfirmed) {
form.submit();
}
});
});
});
</script>
@endpush
@@ -517,6 +517,57 @@
$(document).ready(function () {
$('#tenaga-kerja, #frekuensi-pemangkasan-komoditas-utama, #frekuensi-pemangkasan-pohon-penaung, #penyerbukan-manual, #pemberian-pupuk, #jenis-pupuk').select2();
function syncTeknikPemangkasanState() {
const tidakPernahMemangkas = $('#frekuensi-pemangkasan-komoditas-utama').val() === '{{ \App\Enums\PraktikBudidaya\FrekuensiPemangkasanUtama::TIDAK_PERNAH->value }}';
const $teknikInputs = $('input[name="teknik_pemangkasan[]"]');
const $lainnyaInput = $('#input-teknik-pemangkasan-lainnya');
$teknikInputs
.prop('disabled', tidakPernahMemangkas)
.closest('.form-check')
.toggleClass('opacity-50', tidakPernahMemangkas);
if (tidakPernahMemangkas) {
$teknikInputs.prop('checked', false);
$lainnyaInput.val('');
}
$lainnyaInput.prop('disabled', tidakPernahMemangkas || !$('#teknik-pemangkasan-lainnya').is(':checked'));
}
$('#frekuensi-pemangkasan-komoditas-utama, #teknik-pemangkasan-lainnya').on('change select2:select select2:clear', syncTeknikPemangkasanState);
syncTeknikPemangkasanState();
function syncPemupukanState() {
const tidakPernahMemberiPupuk = $('#pemberian-pupuk').val() === '{{ \App\Enums\PraktikBudidaya\PemberianPupuk::TIDAK_PERNAH->value }}';
const $pemupukanFields = $(
'#jenis-pupuk, ' +
'input[name="frekuensi_pemupukan"], #input-frekuensi-pemupukan-lainnya, ' +
'#estimasi-dosis-pupuk-organik, #estimasi-dosis-pupuk-anorganik, ' +
'input[name="waktu_pemberian_pupuk"], #input-waktu-pemberian-pupuk-lainnya, ' +
'input[name="cara_pemberian_pupuk"], #input-cara-pemberian-pupuk-lainnya'
);
$pemupukanFields
.prop('disabled', tidakPernahMemberiPupuk)
.closest('.form-check, .form-control-validation')
.toggleClass('opacity-50', tidakPernahMemberiPupuk);
if (tidakPernahMemberiPupuk) {
$('#jenis-pupuk').val('').trigger('change.select2');
$('input[name="frekuensi_pemupukan"], input[name="waktu_pemberian_pupuk"], input[name="cara_pemberian_pupuk"]').prop('checked', false);
$('#input-frekuensi-pemupukan-lainnya, #estimasi-dosis-pupuk-organik, #estimasi-dosis-pupuk-anorganik, #input-waktu-pemberian-pupuk-lainnya, #input-cara-pemberian-pupuk-lainnya').val('');
} else {
$('#input-frekuensi-pemupukan-lainnya').prop('disabled', !$('input[data-target="#input-frekuensi-pemupukan-lainnya"]').is(':checked'));
$('#input-waktu-pemberian-pupuk-lainnya').prop('disabled', !$('input[data-target="#input-waktu-pemberian-pupuk-lainnya"]').is(':checked'));
$('#input-cara-pemberian-pupuk-lainnya').prop('disabled', !$('input[data-target="#input-cara-pemberian-pupuk-lainnya"]').is(':checked'));
}
}
$('#pemberian-pupuk').on('change select2:select select2:clear', syncPemupukanState);
syncPemupukanState();
setTimeout(syncPemupukanState, 0);
const $switch = $('input[name="disimpan_untuk_diri_sendiri"]');
const $text = $('#switch-text');
@@ -636,6 +687,35 @@
trigger.addEventListener('change', toggleInput);
toggleInput();
});
const frekuensiPemangkasan = document.getElementById('frekuensi-pemangkasan-komoditas-utama');
const teknikPemangkasanInputs = document.querySelectorAll('input[name="teknik_pemangkasan[]"]');
const teknikPemangkasanLainnya = document.getElementById('input-teknik-pemangkasan-lainnya');
function toggleTeknikPemangkasan() {
const tidakPernahMemangkas = frekuensiPemangkasan && frekuensiPemangkasan.value === '{{ \App\Enums\PraktikBudidaya\FrekuensiPemangkasanUtama::TIDAK_PERNAH->value }}';
teknikPemangkasanInputs.forEach(function (input) {
input.disabled = tidakPernahMemangkas;
input.closest('.form-check')?.classList.toggle('opacity-50', tidakPernahMemangkas);
if (tidakPernahMemangkas) {
input.checked = false;
}
});
if (teknikPemangkasanLainnya) {
teknikPemangkasanLainnya.disabled = tidakPernahMemangkas || !document.getElementById('teknik-pemangkasan-lainnya')?.checked;
if (tidakPernahMemangkas) {
teknikPemangkasanLainnya.value = '';
}
}
}
frekuensiPemangkasan?.addEventListener('change', toggleTeknikPemangkasan);
document.getElementById('teknik-pemangkasan-lainnya')?.addEventListener('change', toggleTeknikPemangkasan);
toggleTeknikPemangkasan();
});
</script>
@endpush
@endpush
@@ -39,7 +39,8 @@
<form id="praktikBudidayaForm" action="{{ route('petani.praktik-budidaya.update', [$petani->id, $praktikBudidaya->id]) }}" method="POST">
@csrf
@method('PUT')
<div class="card mb-6">
<input type="hidden" name="redirect_fragment" value="section-opt">
<div class="card mb-6" id="section-praktik-pemupukan">
<div class="card-body pt-12">
<h5 class="pb-4 border-bottom mb-4">Persiapan Lahan & Tanaman</h5>
<div class="row">
@@ -541,8 +542,9 @@
<form id="praktikBudidayaForm" action="{{ route('petani.praktik-budidaya.update', [$petani->id, $praktikBudidaya->id]) }}" method="POST">
@csrf
@method('PUT')
<input type="hidden" name="redirect_fragment" value="section-biaya-produksi">
<div class="card mb-6">
<div class="card mb-6" id="section-opt">
<div class="card-body pt-12">
<!-- INFORMASI PETANI -->
<h5 class="pb-4 border-bottom mb-4">Pengendalian Organisme Pengganggu Tumbuhan (OPT)</h5>
@@ -1048,7 +1050,8 @@
<form id="praktikBudidayaForm" action="{{ route('petani.praktik-budidaya.update', [$petani->id, $praktikBudidaya->id]) }}" method="POST">
@csrf
@method('PUT')
<div class="card mb-6">
<input type="hidden" name="redirect_fragment" value="section-penanganan-panen">
<div class="card mb-6" id="section-biaya-produksi">
<div class="card-body pt-12">
<h5 class="pb-4 border-bottom mb-4">Struktur Biaya Produksi Permusim</h5>
<div class="row">
@@ -1360,7 +1363,8 @@
<form id="praktikBudidayaForm" action="{{ route('petani.praktik-budidaya.update', [$petani->id, $praktikBudidaya->id]) }}" method="POST">
@csrf
@method('PUT')
<div class="card mb-6">
<input type="hidden" name="redirect_fragment" value="section-produktivitas">
<div class="card mb-6" id="section-penanganan-panen">
<div class="card-body pt-12">
<h5 class="pb-4 border-bottom mb-4">Penanganan Awal Setelah Panen</h5>
<div class="row">
@@ -1546,7 +1550,7 @@
</div>
</div>
</form>
<div class="card mb-6">
<div class="card mb-6" id="section-produktivitas">
<div class="card-body pt-12">
<h5 class="pb-4 border-bottom mb-4">
Produktivitas Rata-rata 3 Musim Panen Terakhir per Komoditas
@@ -1579,6 +1583,7 @@
<form method="POST" action="{{ route('petani.survey-produktivitas.destroy', [$petani->id, $row->id]) }}">
@csrf
@method('DELETE')
<input type="hidden" name="redirect_fragment" value="section-produktivitas">
<button type="submit" class="btn btn-outline-danger">
<i class="icon-base ti tabler-trash icon-sm"></i>
</button>
@@ -1593,41 +1598,66 @@
action="{{ route('petani.survey-produktivitas.store', $petani->id) }}"
class="form-repeater">
@csrf
<input type="hidden" name="redirect_fragment" value="section-produktivitas">
@php
$produktivitasRows = old('produktivitas_komoditas');
if (!is_array($produktivitasRows) || count($produktivitasRows) === 0) {
$produktivitasRows = [
[
'komoditas_id' => null,
'hasil_panen_3_musim' => null,
'satuan' => null,
],
];
}
@endphp
<div data-repeater-list="produktivitas_komoditas">
@foreach ($produktivitasRows as $index => $produktivitasRow)
<div data-repeater-item>
<div class="row align-items-end">
<div class="col-md-4 mb-3">
<label class="form-label">Komoditas</label>
<select name="komoditas_id" class="form-select">
<select name="komoditas_id" class="form-select @error('produktivitas_komoditas.' . $index . '.komoditas_id') is-invalid @enderror">
<option value="">Pilih Komoditas</option>
@foreach ($komoditas as $item)
<option value="{{ $item->id }}">{{ $item->nama }}</option>
<option value="{{ $item->id }}" @selected((string) data_get($produktivitasRow, 'komoditas_id') === (string) $item->id)>{{ $item->nama }}</option>
@endforeach
</select>
@error('produktivitas_komoditas.' . $index . '.komoditas_id')
<div class="invalid-feedback d-block">{{ $message }}</div>
@enderror
</div>
<div class="col-md-3 mb-3">
<label class="form-label">Hasil</label>
<div class="input-group">
<input type="number" name="hasil_panen_3_musim" class="form-control" step="0.01" min="0">
<input type="number" name="hasil_panen_3_musim" class="form-control @error('produktivitas_komoditas.' . $index . '.hasil_panen_3_musim') is-invalid @enderror" step="0.01" min="0" value="{{ data_get($produktivitasRow, 'hasil_panen_3_musim') }}">
<span class="input-group-text">Kg</span>
</div>
@error('produktivitas_komoditas.' . $index . '.hasil_panen_3_musim')
<div class="invalid-feedback d-block">{{ $message }}</div>
@enderror
</div>
<div class="col-md-3 mb-3">
<label class="form-label d-block">Satuan</label>
<label class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="satuan" value="ha_tahun">
<input class="form-check-input @error('produktivitas_komoditas.' . $index . '.satuan') is-invalid @enderror" type="radio" name="satuan" value="ha_tahun" @checked(data_get($produktivitasRow, 'satuan') === 'ha_tahun')>
<span class="form-check-label">Ha/Tahun</span>
</label>
<label class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="satuan" value="pohon_tahun">
<input class="form-check-input @error('produktivitas_komoditas.' . $index . '.satuan') is-invalid @enderror" type="radio" name="satuan" value="pohon_tahun" @checked(data_get($produktivitasRow, 'satuan') === 'pohon_tahun')>
<span class="form-check-label">Pohon/Tahun</span>
</label>
@error('produktivitas_komoditas.' . $index . '.satuan')
<div class="invalid-feedback d-block">{{ $message }}</div>
@enderror
</div>
<div class="col-md-2 mb-3">
@@ -1639,6 +1669,7 @@
</div>
<hr>
</div>
@endforeach
</div>
<div class="mt-4 d-flex justify-content-between">
@@ -1657,7 +1688,8 @@
<form id="praktikBudidayaForm" action="{{ route('petani.praktik-budidaya.update', [$petani->id, $praktikBudidaya->id]) }}" method="POST">
@csrf
@method('PUT')
<div class="card mb-6">
<input type="hidden" name="redirect_fragment" value="section-kehilangan-hasil">
<div class="card mb-6" id="section-kehilangan-hasil">
<div class="card-body pt-12">
<h5 class="pb-4 border-bottom mb-4">Kehilangan Hasil Akibat Organisme Pengganggu Tumbuhan (OPT)</h5>
<div class="row">
@@ -1706,12 +1738,76 @@
</div>
@endsection
@push('scripts-head')
<style>
#section-praktik-pemupukan,
#section-opt,
#section-biaya-produksi,
#section-penanganan-panen,
#section-produktivitas,
#section-kehilangan-hasil {
scroll-margin-top: 96px;
}
</style>
@endpush
@push('scripts')
<script>
'use strict';
$(document).ready(function () {
$('#tenaga-kerja, #frekuensi-pemangkasan-komoditas-utama, #frekuensi-pemangkasan-pohon-penaung, #penyerbukan-manual, #pemberian-pupuk, #jenis-pupuk, #metode-penanganan-hama-penyakit, #intensitas-serangan, #waktu-kemunculan-terparah, #frekuensi-sanitasi-lahan, #penanganan-sisa-buah-ranting, #penanganan-gulma, #kondisi-pengelolaan-air-irigasi, #kebutuhan-air-permusim, #pemahaman-manfaat-konservasi, #dasar-penentuan-panen, #praktik-sortasi, #bentuk-sortasi, #estimasi-kehilangan-akibat-opt, #tingkat-reject, #tindakan-hasil-reject, #estimasi-kehilangan-akibat-hama, #komoditas-id').select2();
function syncTeknikPemangkasanState() {
const tidakPernahMemangkas = $('#frekuensi-pemangkasan-komoditas-utama').val() === '{{ \App\Enums\PraktikBudidaya\FrekuensiPemangkasanUtama::TIDAK_PERNAH->value }}';
const $teknikInputs = $('input[name="teknik_pemangkasan[]"]');
const $lainnyaInput = $('#input-teknik-pemangkasan-lainnya');
$teknikInputs
.prop('disabled', tidakPernahMemangkas)
.closest('.form-check')
.toggleClass('opacity-50', tidakPernahMemangkas);
if (tidakPernahMemangkas) {
$teknikInputs.prop('checked', false);
$lainnyaInput.val('');
}
$lainnyaInput.prop('disabled', tidakPernahMemangkas || !$('#teknik-pemangkasan-lainnya').is(':checked'));
}
$('#frekuensi-pemangkasan-komoditas-utama, #teknik-pemangkasan-lainnya').on('change select2:select select2:clear', syncTeknikPemangkasanState);
syncTeknikPemangkasanState();
function syncPemupukanState() {
const tidakPernahMemberiPupuk = $('#pemberian-pupuk').val() === '{{ \App\Enums\PraktikBudidaya\PemberianPupuk::TIDAK_PERNAH->value }}';
const $pemupukanFields = $(
'#jenis-pupuk, ' +
'input[name="frekuensi_pemupukan"], #input-frekuensi-pemupukan-lainnya, ' +
'#estimasi-dosis-pupuk-organik, #estimasi-dosis-pupuk-anorganik, ' +
'input[name="waktu_pemberian_pupuk"], #input-waktu-pemberian-pupuk-lainnya, ' +
'input[name="cara_pemberian_pupuk"], #input-cara-pemberian-pupuk-lainnya'
);
$pemupukanFields
.prop('disabled', tidakPernahMemberiPupuk)
.closest('.form-check, .form-control-validation')
.toggleClass('opacity-50', tidakPernahMemberiPupuk);
if (tidakPernahMemberiPupuk) {
$('#jenis-pupuk').val('').trigger('change.select2');
$('input[name="frekuensi_pemupukan"], input[name="waktu_pemberian_pupuk"], input[name="cara_pemberian_pupuk"]').prop('checked', false);
$('#input-frekuensi-pemupukan-lainnya, #estimasi-dosis-pupuk-organik, #estimasi-dosis-pupuk-anorganik, #input-waktu-pemberian-pupuk-lainnya, #input-cara-pemberian-pupuk-lainnya').val('');
} else {
$('#input-frekuensi-pemupukan-lainnya').prop('disabled', !$('input[data-target="#input-frekuensi-pemupukan-lainnya"]').is(':checked'));
$('#input-waktu-pemberian-pupuk-lainnya').prop('disabled', !$('input[data-target="#input-waktu-pemberian-pupuk-lainnya"]').is(':checked'));
$('#input-cara-pemberian-pupuk-lainnya').prop('disabled', !$('input[data-target="#input-cara-pemberian-pupuk-lainnya"]').is(':checked'));
}
}
$('#pemberian-pupuk').on('change select2:select select2:clear', syncPemupukanState);
syncPemupukanState();
setTimeout(syncPemupukanState, 0);
const $switch = $('input[name="disimpan_untuk_diri_sendiri"]');
const $text = $('#switch-text');
@@ -1822,6 +1918,35 @@
toggleInput();
});
const frekuensiPemangkasan = document.getElementById('frekuensi-pemangkasan-komoditas-utama');
const teknikPemangkasanInputs = document.querySelectorAll('input[name="teknik_pemangkasan[]"]');
const teknikPemangkasanLainnya = document.getElementById('input-teknik-pemangkasan-lainnya');
function toggleTeknikPemangkasan() {
const tidakPernahMemangkas = frekuensiPemangkasan && frekuensiPemangkasan.value === '{{ \App\Enums\PraktikBudidaya\FrekuensiPemangkasanUtama::TIDAK_PERNAH->value }}';
teknikPemangkasanInputs.forEach(function (input) {
input.disabled = tidakPernahMemangkas;
input.closest('.form-check')?.classList.toggle('opacity-50', tidakPernahMemangkas);
if (tidakPernahMemangkas) {
input.checked = false;
}
});
if (teknikPemangkasanLainnya) {
teknikPemangkasanLainnya.disabled = tidakPernahMemangkas || !document.getElementById('teknik-pemangkasan-lainnya')?.checked;
if (tidakPernahMemangkas) {
teknikPemangkasanLainnya.value = '';
}
}
}
frekuensiPemangkasan?.addEventListener('change', toggleTeknikPemangkasan);
document.getElementById('teknik-pemangkasan-lainnya')?.addEventListener('change', toggleTeknikPemangkasan);
toggleTeknikPemangkasan();
const biayaProduksiFields = [
'upah-tenaga-kerja',
'biaya-bibit',
@@ -1991,4 +2116,4 @@ $(function () {
});
});
</script>
@endpush
@endpush
@@ -0,0 +1,280 @@
@extends('layout.main')
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
@if (session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
@if ($errors->any())
<div class="alert alert-danger">
<ul class="mb-0">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div class="row">
<div class="col-md-12">
@include('produktivitas.petani.header', ['petani' => $petani])
<div class="row g-6">
<div class="col-lg-4 col-sm-6">
<div class="card card-border-shadow-primary h-100">
<div class="card-body">
@php
$segmen = 'Belum tersegmentasi';
@endphp
<div class="d-flex align-items-center mb-2">
<h4 class="mb-0">{{ $petani->segmen() }} ({{ number_format($skor->skor_kesiapan_adopsi, 1, ',', '.') }})</h4>
</div>
<p class="mb-1 text-wrapped">{{ $petani->keteranganSegmen() }}</p>
</div>
</div>
</div>
<div class="col-lg-8 col-sm-6">
<div class="card card-border-shadow-primary h-100">
<div class="card-body d-flex align-items-end">
<div class="w-100">
<div class="row gy-3">
<div class="col-md-4 col-12">
<div class="card-info">
<h5 class="mb-0">{{ number_format($skor->skor_d2_sistem_praktik_budidaya, 1, ',', '.') }}</h5></h5>
<small>Sistem & Praktik Budidaya</small>
</div>
</div>
<div class="col-md-4 col-12">
<div class="card-info">
<h5 class="mb-0">{{ number_format($skor->skor_d4_sosial_ekonomi, 1, ',', '.') }}</h5>
<small>Sosial Ekonomi Rumah Tangga</small>
</div>
</div>
<div class="col-md-4 col-12">
<div class="card-info">
<h5 class="mb-0">{{ number_format($skor->skor_d6_rantai_nilai_akses_pasar, 1, ',', '.') }}</h5>
<small>Rantai Nilai & Akses Pasar</small>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row g-6 pt-4">
<div class="col-lg-4 col-sm-6">
<div class="card card-border-shadow-primary">
<div class="card-body d-flex align-items-end">
<div class="w-100">
<div class="row gy-3">
<div class="col-12">
<div class="card-info">
<h5 class="mb-0">{{ number_format($skor->skor_komp_1_d4_k3_motivasi_kapasitas_adopsi, 1, ',', '.') }}</h5></h5>
<small>Motivasi & Kapasitas Adopsi</small><br/>
<small class="text-body-secondary">Kemauan dan kapasitas kognitif untuk mengadopsi perubahan</small>
</div>
</div>
</div>
<div class="row gy-3">
<div class="col-12">
<div class="card-info">
<h5 class="mb-0">{{ number_format($skor->skor_komp_2_d4_k2_ekonomi_rumah_tangga, 1, ',', '.') }}</h5></h5>
<small>Kondisi Ekonomi Rumah Tangga</small><br/>
<small class="text-body-secondary">Kapasitas material petani untuk berinvestasi dalam perubahan</small>
</div>
</div>
</div>
<div class="row gy-3">
<div class="col-12">
<div class="card-info">
<h5 class="mb-0">{{ number_format($skor->skor_komp_3_d2_praktik_budidaya_gap, 1, ',', '.') }}</h5></h5>
<small>Praktik Budidaya & Skor GAP</small><br/>
<small class="text-body-secondary">Kualitas praktik budidaya aktual petani dibandingkan praktik terbaik yang dituju</small>
</div>
</div>
</div>
<div class="row gy-3">
<div class="col-12">
<div class="card-info">
<h5 class="mb-0">{{ number_format($skor->skor_komp_4_d4_k4_keterlibatan_kelembagaan, 1, ',', '.') }}</h5></h5>
<small>Keterlibatan Kelembagaan</small><br/>
<small class="text-body-secondary">Kapasitas sosial petani untuk berubah</small>
</div>
</div>
</div>
<div class="row gy-3">
<div class="col-12">
<div class="card-info">
<h5 class="mb-0">{{ number_format($skor->skor_komp_5_d4_k5_k6_akses_kebebasan_keuangan, 1, ',', '.') }}</h5></h5>
<small>Akses & Kebebasan Keuangan</small><br/>
<small class="text-body-secondary">Akses yang memperluas ruang gerak investasi dan membatasi pengambilan keputusan</small>
</div>
</div>
</div>
<div class="row gy-3">
<div class="col-12">
<div class="card-info">
<h5 class="mb-0">{{ number_format($skor->skor_komp_6_d6_k1_k4_k5_rantai_nilai_akses_pasar, 1, ',', '.') }}</h5></h5>
<small>Posisi & Akses Pasar</small><br/>
<small class="text-body-secondary">Posisi petani dalam rantai nilai dan akses pasar</small>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-8 col-sm-6">
<div class="card card-border-shadow-primary">
<div class="card-body">
<div class="table-responsive">
<table class="table table-borderless">
<thead>
<tr>
<th scope="col">Variabel</th>
<th scope="col" class="w-10 text-end">Skor</th>
</tr>
</thead>
<tbody>
<tr>
<td class="text-wrapped">Kemampuan mencoba praktik baru</td>
<td class="text-end">{{ number_format($skor->skor_d4_k3_1_praktik_baru, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Pemahaman kaitan mutu dan harga</td>
<td class="text-end">{{ number_format($skor->skor_d4_k3_4_pemahaman_mutu_harga, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Keberadaan role model</td>
<td class="text-end">{{ number_format($skor->skor_d4_k3_5_role_model, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Kemauan terlibat dalam program</td>
<td class="text-end">{{ number_format($skor->skor_d4_k3_6_kemampuan_keterlibatan_program, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Orientasi jangka panjang</td>
<td class="text-end">{{ number_format($skor->skor_d4_k3_7_orientasi_jangka_panjang, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Stabilitas penghasilan</td>
<td class="text-end">{{ number_format($skor->skor_d4_k2_5_stabilitas_penghasilan, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Kemampuan menabung</td>
<td class="text-end">{{ number_format($skor->skor_d4_k2_8_kemampuan_menabung, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Persepsi kecukupan penghasilan</td>
<td class="text-end">{{ number_format($skor->skor_d4_k2_9_kecukupan_penghasilan, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Rasio biaya produksi terhadap pendapatan</td>
<td class="text-end">{{ number_format($skor->skor_d4_k2_3_k2_7_rasio_biaya_produksi_pendapatan, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Kejelasan hak kelola lahan</td>
<td class="text-end">{{ number_format($skor->skor_d4_k2_11_hak_kelola_lahan, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Praktik pemangkasan</td>
<td class="text-end">{{ number_format($skor->skor_d2_k2_3_praktik_pemangkasan, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Praktik pemupukan</td>
<td class="text-end">{{ number_format($skor->skor_d2_k2_4_praktik_pemupukan, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Pengendalian OPT</td>
<td class="text-end">{{ number_format($skor->skor_d2_k2_5_pengendalian_opt, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Sanitasi kebun</td>
<td class="text-end">{{ number_format($skor->skor_d2_k2_6_sanitasi_kebun, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Pengelolaan gulma</td>
<td class="text-end">{{ number_format($skor->skor_d2_k2_6b_pengelolaan_gulma, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Pengelolaan air & irigasi</td>
<td class="text-end">{{ number_format($skor->skor_d2_k2_7_penglolaan_air_irigasi, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Praktik konservasi tanah</td>
<td class="text-end">{{ number_format($skor->skor_d2_k2_8_praktik_konservasi_tanah, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Penentuan kematangan saat panen</td>
<td class="text-end">{{ number_format($skor->skor_d2_k3_1_penentuan_pematangan, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Sortasi awal dan pemisahan kualitas</td>
<td class="text-end">{{ number_format($skor->skor_d2_k3_5_sortasi_awal_pemisahan_kualitas, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Keaktifan menghadiri pertemuan</td>
<td class="text-end">{{ number_format($skor->skor_d4_k4_2_keaktifan_pertemuan, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Peran dalam kelompok</td>
<td class="text-end">{{ number_format($skor->skor_d4_k4_3_peran_dalam_kelompok, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Manfaat yang dirasakan dari kelompok</td>
<td class="text-end">{{ number_format($skor->skor_d4_k4_4_manfaat_dirasakan, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Kepemilikan rekening bank</td>
<td class="text-end">{{ number_format($skor->skor_d4_k5_1_kepemilikan_rekening, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Pengalaman kredit formal</td>
<td class="text-end">{{ number_format($skor->skor_d4_k5_2_pengalaman_kredit_formal, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Kepemilikan aset produktif</td>
<td class="text-end">{{ number_format($skor->skor_d4_k5_3_kepemilikan_aset_produktif, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Akses program bantuan</td>
<td class="text-end">{{ number_format($skor->skor_d4_k5_4_akses_program_bantuan, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Keberadaan hutang terkait panen</td>
<td class="text-end">{{ number_format($skor->skor_d4_k6_3_keberadaan_hutang_terkait_panen, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Praktik ijon</td>
<td class="text-end">{{ number_format($skor->skor_d4_k6_5a_praktik_ijon, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Kebebasan memilih pembeli</td>
<td class="text-end">{{ number_format($skor->skor_d4_k6_5b_kebebasan_memilih_pembeli, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Pengalaman menjual ke saluran yang berbeda</td>
<td class="text-end">{{ number_format($skor->skor_d6_k1_6_pengalaman_menjual_ke_saluran_berbeda, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Kesadaran dan akses pasar premium</td>
<td class="text-end">{{ number_format($skor->skor_d6_k4_1_kesadaran_akses_pasar_premium, 1, ',', '.') }}</td>
</tr>
<tr>
<td class="text-wrapped">Hambatan mutu sebagai penghalang pasar</td>
<td class="text-end">{{ number_format($skor->skor_d6_k5_1_hambatan_mutu, 1, ',', '.') }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@@ -1,5 +1,17 @@
@extends('layout.main')
@push('scripts-head')
<style>
#section-utama,
#section-sosial-budaya,
#section-keanggotaan-kelompok,
#section-akses-keuangan,
#section-keterikatan-hutang {
scroll-margin-top: 96px;
}
</style>
@endpush
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
@if (session('success'))
@@ -1062,6 +1074,20 @@
const pinjamanTokohAdatAda = @json($pinjamanTokohAdatAdaValue);
const tekananJualSegeraAda = @json($tekananJualSegeraAdaValue);
const kebebasanMemilihPembeliCukupBebas = Number(@json($kebebasanMemilihPembeliCukupBebasValue));
const sectionAnchors = {
utama: 'section-utama',
sosial_budaya: 'section-sosial-budaya',
keanggotaan_kelompok: 'section-keanggotaan-kelompok',
akses_keuangan: 'section-akses-keuangan',
keterikatan_hutang: 'section-keterikatan-hutang'
};
const nextSectionAnchors = {
utama: 'section-sosial-budaya',
sosial_budaya: 'section-keanggotaan-kelompok',
keanggotaan_kelompok: 'section-akses-keuangan',
akses_keuangan: 'section-keterikatan-hutang',
keterikatan_hutang: 'section-keterikatan-hutang'
};
const fieldExamples = {
jumlah_tanggungan: 'Contoh: 4',
anak_masih_sekolah: 'Contoh: 2',
@@ -1399,7 +1425,8 @@
}
function syncPihakMembantuFields() {
const isTidakAda = $('#pihak-membantu').val() === pihakMembantuTanpaBantuan;
const isAdaSengketa = $('input[name="ada_sengketa"]:checked').val() === '1';
const isTidakAda = !isAdaSengketa || $('#pihak-membantu').val() === pihakMembantuTanpaBantuan;
const $fields = $('#pihak-membantu-nama, #tahun-bantuan');
$fields.prop('disabled', isTidakAda);
@@ -1409,6 +1436,21 @@
}
}
function syncSengketaFields() {
const isAdaSengketa = $('input[name="ada_sengketa"]:checked').val() === '1';
const $fields = $('#keterangan-sengketa, #pihak-membantu, #status-konflik');
const $assistanceFields = $('#pihak-membantu-nama, #tahun-bantuan');
$fields.prop('disabled', !isAdaSengketa);
if (!isAdaSengketa) {
$fields.add($assistanceFields).val('');
$fields.filter('select').trigger('change.select2');
}
syncPihakMembantuFields();
}
function syncPernahJualHargaLebihTinggiFields() {
const isPernah = $('#pernah-jual-harga-lebih-tinggi').val() === pernahJualHargaLebihTinggiPernah;
const $field = $('#penyebab-harga-lebih-tinggi');
@@ -1601,6 +1643,37 @@
clearPendapatanRowValidation($row);
}
function setupSectionAnchors() {
$('input[name="form_section"]').each(function () {
const section = this.value;
const anchor = sectionAnchors[section];
const nextAnchor = nextSectionAnchors[section] || anchor;
const $form = $(this).closest('form');
if (anchor) {
$form.find('> .card').first().attr('id', anchor);
}
if (nextAnchor && !$form.find('input[name="redirect_fragment"]').length) {
$('<input>', {
type: 'hidden',
name: 'redirect_fragment',
value: nextAnchor
}).appendTo($form);
}
});
if (window.location.hash) {
const target = document.getElementById(window.location.hash.substring(1));
if (target) {
setTimeout(function () {
target.scrollIntoView({ block: 'start' });
}, 0);
}
}
}
$(document).on('change', '.sosial-ekonomi-komoditas-utama', syncKomoditasLainnyaOptions);
$(document).on('input change', '.pendapatan-row input, .pendapatan-row select', function () {
clearPendapatanRowValidation($(this).closest('.pendapatan-row'));
@@ -1636,6 +1709,7 @@
});
});
$('#pihak-membantu').on('change', syncPihakMembantuFields);
$('input[name="ada_sengketa"]').on('change', syncSengketaFields);
$('#pernah-jual-harga-lebih-tinggi').on('change', syncPernahJualHargaLebihTinggiFields);
$('input[name="panutan_petani_sukses"]').on('change', syncPanutanFields);
$('input[name="terdaftar_kelompok_tani"]').on('change', syncTerdaftarKelompokFields);
@@ -1650,10 +1724,12 @@
$('#total-hutang-tidak-bersedia').on('change', syncTotalHutangFields);
$('input[name="tekanan_jual_segera"]').on('change', syncTekananJualFields);
$('input[name="kebebasan_memilih_pembeli"]').on('change', syncKebebasanPembeliFields);
setupSectionAnchors();
applySosialEkonomiExamples();
syncKomoditasLainnyaOptions();
setupAllPendapatanRows();
syncPihakMembantuFields();
syncSengketaFields();
syncPernahJualHargaLebihTinggiFields();
syncPanutanFields();
syncTerdaftarKelompokFields();
@@ -1,5 +1,17 @@
@extends('layout.main')
@push('scripts-head')
<style>
#section-utama,
#section-sosial-budaya,
#section-keanggotaan-kelompok,
#section-akses-keuangan,
#section-keterikatan-hutang {
scroll-margin-top: 96px;
}
</style>
@endpush
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
@if (session('success'))
@@ -1058,6 +1070,20 @@
const pinjamanTokohAdatAda = @json($pinjamanTokohAdatAdaValue);
const tekananJualSegeraAda = @json($tekananJualSegeraAdaValue);
const kebebasanMemilihPembeliCukupBebas = Number(@json($kebebasanMemilihPembeliCukupBebasValue));
const sectionAnchors = {
utama: 'section-utama',
sosial_budaya: 'section-sosial-budaya',
keanggotaan_kelompok: 'section-keanggotaan-kelompok',
akses_keuangan: 'section-akses-keuangan',
keterikatan_hutang: 'section-keterikatan-hutang'
};
const nextSectionAnchors = {
utama: 'section-sosial-budaya',
sosial_budaya: 'section-keanggotaan-kelompok',
keanggotaan_kelompok: 'section-akses-keuangan',
akses_keuangan: 'section-keterikatan-hutang',
keterikatan_hutang: 'section-keterikatan-hutang'
};
const fieldExamples = {
jumlah_tanggungan: 'Contoh: 4',
anak_masih_sekolah: 'Contoh: 2',
@@ -1395,7 +1421,8 @@
}
function syncPihakMembantuFields() {
const isTidakAda = $('#pihak-membantu').val() === pihakMembantuTanpaBantuan;
const isAdaSengketa = $('input[name="ada_sengketa"]:checked').val() === '1';
const isTidakAda = !isAdaSengketa || $('#pihak-membantu').val() === pihakMembantuTanpaBantuan;
const $fields = $('#pihak-membantu-nama, #tahun-bantuan');
$fields.prop('disabled', isTidakAda);
@@ -1405,6 +1432,21 @@
}
}
function syncSengketaFields() {
const isAdaSengketa = $('input[name="ada_sengketa"]:checked').val() === '1';
const $fields = $('#keterangan-sengketa, #pihak-membantu, #status-konflik');
const $assistanceFields = $('#pihak-membantu-nama, #tahun-bantuan');
$fields.prop('disabled', !isAdaSengketa);
if (!isAdaSengketa) {
$fields.add($assistanceFields).val('');
$fields.filter('select').trigger('change.select2');
}
syncPihakMembantuFields();
}
function syncPernahJualHargaLebihTinggiFields() {
const isPernah = $('#pernah-jual-harga-lebih-tinggi').val() === pernahJualHargaLebihTinggiPernah;
const $field = $('#penyebab-harga-lebih-tinggi');
@@ -1597,6 +1639,37 @@
clearPendapatanRowValidation($row);
}
function setupSectionAnchors() {
$('input[name="form_section"]').each(function () {
const section = this.value;
const anchor = sectionAnchors[section];
const nextAnchor = nextSectionAnchors[section] || anchor;
const $form = $(this).closest('form');
if (anchor) {
$form.find('> .card').first().attr('id', anchor);
}
if (nextAnchor && !$form.find('input[name="redirect_fragment"]').length) {
$('<input>', {
type: 'hidden',
name: 'redirect_fragment',
value: nextAnchor
}).appendTo($form);
}
});
if (window.location.hash) {
const target = document.getElementById(window.location.hash.substring(1));
if (target) {
setTimeout(function () {
target.scrollIntoView({ block: 'start' });
}, 0);
}
}
}
$(document).on('change', '.sosial-ekonomi-komoditas-utama', syncKomoditasLainnyaOptions);
$(document).on('input change', '.pendapatan-row input, .pendapatan-row select', function () {
clearPendapatanRowValidation($(this).closest('.pendapatan-row'));
@@ -1632,6 +1705,7 @@
});
});
$('#pihak-membantu').on('change', syncPihakMembantuFields);
$('input[name="ada_sengketa"]').on('change', syncSengketaFields);
$('#pernah-jual-harga-lebih-tinggi').on('change', syncPernahJualHargaLebihTinggiFields);
$('input[name="panutan_petani_sukses"]').on('change', syncPanutanFields);
$('input[name="terdaftar_kelompok_tani"]').on('change', syncTerdaftarKelompokFields);
@@ -1646,10 +1720,12 @@
$('#total-hutang-tidak-bersedia').on('change', syncTotalHutangFields);
$('input[name="tekanan_jual_segera"]').on('change', syncTekananJualFields);
$('input[name="kebebasan_memilih_pembeli"]').on('change', syncKebebasanPembeliFields);
setupSectionAnchors();
applySosialEkonomiExamples();
syncKomoditasLainnyaOptions();
setupAllPendapatanRows();
syncPihakMembantuFields();
syncSengketaFields();
syncPernahJualHargaLebihTinggiFields();
syncPanutanFields();
syncTerdaftarKelompokFields();
@@ -1,12 +1,21 @@
@forelse($tujuan->aktivitas as $aktivitas)
@php
$aktivitasRowspan = max($aktivitas->target->count(), 1);
$firstAktivitasRow = true;
@endphp
@forelse($aktivitas->target as $targetAktivitas)
<tr>
<td><span class="text-heading">{{ $transformasi->kode }} {{ $transformasi->nama }} (ID: {{ $transformasi->id }})</span></td>
<td><span class="{{ $aktivitas->jenis_aktivitas == 'tujuan' ? 'text-heading' : 'text-muted' }}">{{ $aktivitas->kode }} {{ $aktivitas->nama }} (ID: {{ $aktivitas->id }})</span></td>
<td><span class="text-muted">{{ $aktivitas->deskripsi }}</span></td>
<td><span class="text-muted">{{ $aktivitas->indikator }}</span></td>
<td><span class="text-muted">{{ $targetAktivitas->variabel }} (ID: {{ $targetAktivitas->id }}, Tipe: {{ $targetAktivitas->tipe }}, Realiasasi: {{ $targetAktivitas->tipe_realisasi }})</span></td>
<td>
@if($firstAktivitasRow)
<td rowspan="{{ $aktivitasRowspan }}" class="align-top"><span class="{{ $aktivitas->jenis_aktivitas == 'tujuan' ? 'text-heading' : 'text-muted' }}">{{ $aktivitas->kode }} {{ $aktivitas->nama }}</span></td>
<td rowspan="{{ $aktivitasRowspan }}" class="align-top"><span class="text-muted">{{ $aktivitas->deskripsi }}</span></td>
<td rowspan="{{ $aktivitasRowspan }}" class="align-top"><span class="text-muted">{{ $aktivitas->indikator }}</span></td>
@php
$firstAktivitasRow = false;
@endphp
@endif
<td class="align-top"><span class="text-muted">{{ $targetAktivitas->variabel }}</span></td>
<td class="align-top">
@if($targetAktivitas->tipe === 'integer')
<span class="text-muted">{{ $targetAktivitas->target_integer }}</span>
@elseif($targetAktivitas->tipe === 'float')
@@ -15,7 +24,7 @@
<span class="text-muted">{{ $targetAktivitas->target_boolean ? 'Ya' : 'Tidak' }}</span>
@endif
</td>
<td>
<td class="align-top">
@if($targetAktivitas->tipe === 'integer')
<span class="text-muted">{{ $targetAktivitas->baseline_integer }}</span>
@elseif($targetAktivitas->tipe === 'float')
@@ -24,7 +33,7 @@
<span class="text-muted">{{ $targetAktivitas->baseline_boolean ? 'Ya' : 'Tidak' }}</span>
@endif
</td>
<td>
<td class="align-top">
<div class="dropdown">
<button type="button" class="btn p-0 dropdown-toggle hide-arrow" data-bs-toggle="dropdown">
<i class="icon-base ti tabler-dots-vertical"></i>
@@ -44,14 +53,13 @@
</tr>
@empty
<tr>
<td><span class="text-heading">{{ $transformasi->kode }} {{ $transformasi->nama }} (ID: {{ $transformasi->id }})</span></td>
<td><span class="{{ $aktivitas->jenis_aktivitas == 'tujuan' ? 'text-heading' : 'text-muted' }}">{{ $aktivitas->kode }} {{ $aktivitas->nama }} (ID: {{ $aktivitas->id }})</span></td>
<td><span class="text-muted">{{ $aktivitas->deskripsi }}</span></td>
<td><span class="text-muted">{{ $aktivitas->indikator }}</span></td>
<td></td>
<td></td>
<td></td>
<td>
<td class="align-top"><span class="{{ $aktivitas->jenis_aktivitas == 'tujuan' ? 'text-heading' : 'text-muted' }}">{{ $aktivitas->kode }} {{ $aktivitas->nama }}</span></td>
<td class="align-top"><span class="text-muted">{{ $aktivitas->deskripsi }}</span></td>
<td class="align-top"><span class="text-muted">{{ $aktivitas->indikator }}</span></td>
<td class="align-top"></td>
<td class="align-top"></td>
<td class="align-top"></td>
<td class="align-top">
<div class="dropdown">
<button type="button" class="btn p-0 dropdown-toggle hide-arrow" data-bs-toggle="dropdown">
<i class="icon-base ti tabler-dots-vertical"></i>
@@ -1,12 +1,40 @@
@php
$transformasiRowspan = 0;
foreach ($transformasi->tujuan as $tujuan) {
$transformasiRowspan += max($tujuan->target->count(), 1);
foreach ($tujuan->aktivitas as $aktivitas) {
$transformasiRowspan += max($aktivitas->target->count(), 1);
}
}
$firstTransformasiRow = true;
@endphp
@forelse($transformasi->tujuan as $tujuan)
@php
$tujuanRowspan = max($tujuan->target->count(), 1);
$firstTujuanRow = true;
@endphp
@forelse($tujuan->target as $target)
<tr>
<td><span class="text-heading">{{ $transformasi->kode }} {{ $transformasi->nama }} (ID: {{ $transformasi->id }})</span></td>
<td><span class="{{ $tujuan->jenis_aktivitas == 'tujuan' ? 'text-heading' : 'text-muted' }}">{{ $tujuan->kode }} {{ $tujuan->nama }} (ID: {{ $tujuan->id }})</span></td>
<td><span class="text-muted">{{ $tujuan->deskripsi }}</span></td>
<td><span class="text-muted">{{ $tujuan->indikator }}</span></td>
<td><span class="text-muted">{{ $target->variabel }} (ID: {{ $target->id }}, Tipe: {{ $target->tipe }}, Realiasasi: {{ $target->tipe_realisasi }})</span></td>
<td>
@if($firstTransformasiRow)
<td rowspan="{{ $transformasiRowspan }}" class="align-top">{{ $transformasi->kode }} {{ $transformasi->nama }}</td>
@php
$firstTransformasiRow = false;
@endphp
@endif
@if($firstTujuanRow)
<td rowspan="{{ $tujuanRowspan }}" class="align-top"><span class="{{ $tujuan->jenis_aktivitas == 'tujuan' ? 'text-heading' : 'text-muted' }}">{{ $tujuan->kode }} {{ $tujuan->nama }}</span></td>
<td rowspan="{{ $tujuanRowspan }}" class="align-top"><span class="text-muted">{{ $tujuan->deskripsi }}</span></td>
<td rowspan="{{ $tujuanRowspan }}" class="align-top"><span class="text-muted">{{ $tujuan->indikator }}</span></td>
@php
$firstTujuanRow = false;
@endphp
@endif
<td class="align-top"><span class="text-muted">{{ $target->variabel }}</span></td>
<td class="align-top">
@if($target->tipe === 'integer')
<span class="text-muted">{{ $target->target_integer }}</span>
@elseif($target->tipe === 'float')
@@ -15,7 +43,7 @@
<span class="text-muted">{{ $target->target_boolean ? 'Ya' : 'Tidak' }}</span>
@endif
</td>
<td>
<td class="align-top">
@if($target->tipe === 'integer')
<span class="text-muted">{{ $target->baseline_integer }}</span>
@elseif($target->tipe === 'float')
@@ -24,7 +52,7 @@
<span class="text-muted">{{ $target->baseline_boolean ? 'Ya' : 'Tidak' }}</span>
@endif
</td>
<td>
<td class="align-top">
<div class="dropdown">
<button type="button" class="btn p-0 dropdown-toggle hide-arrow" data-bs-toggle="dropdown">
<i class="icon-base ti tabler-dots-vertical"></i>
@@ -50,14 +78,14 @@
</tr>
@empty
<tr>
<td><span class="text-heading">{{ $transformasi->kode }} {{ $transformasi->nama }} (ID: {{ $transformasi->id }})</span></td>
<td><span class="{{ $tujuan->jenis_aktivitas == 'tujuan' ? 'text-heading' : 'text-muted' }}">{{ $tujuan->kode }} {{ $tujuan->nama }} (ID: {{ $tujuan->id }})</span></td>
<td><span class="text-muted">{{ $tujuan->deskripsi }}</span></td>
<td><span class="text-muted">{{ $tujuan->indikator }}</span></td>
<td></td>
<td></td>
<td></td>
<td>
<td class="align-top"><span class="text-heading">{{ $transformasi->kode }} {{ $transformasi->nama }}</span></td>
<td class="align-top"><span class="{{ $tujuan->jenis_aktivitas == 'tujuan' ? 'text-heading' : 'text-muted' }}">{{ $tujuan->kode }} {{ $tujuan->nama }} (ID: {{ $tujuan->id }})</span></td>
<td class="align-top"><span class="text-muted">{{ $tujuan->deskripsi }}</span></td>
<td class="align-top"><span class="text-muted">{{ $tujuan->indikator }}</span></td>
<td class="align-top"></td>
<td class="align-top"></td>
<td class="align-top"></td>
<td class="align-top">
<div class="dropdown">
<button type="button" class="btn p-0 dropdown-toggle hide-arrow" data-bs-toggle="dropdown">
<i class="icon-base ti tabler-dots-vertical"></i>
@@ -84,14 +112,14 @@
@include('program.framework.view-aktivitas')
@empty
<tr>
<td><span class="text-heading">{{ $transformasi->kode }} {{ $transformasi->nama }}</span></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>
<td class="align-top"><span class="text-heading">{{ $transformasi->kode }} {{ $transformasi->nama }}</span></td>
<td class="align-top"></td>
<td class="align-top"></td>
<td class="align-top"></td>
<td class="align-top"></td>
<td class="align-top"></td>
<td class="align-top"></td>
<td class="align-top">
<div class="dropdown">
<button type="button" class="btn p-0 dropdown-toggle hide-arrow" data-bs-toggle="dropdown">
<i class="icon-base ti tabler-dots-vertical"></i>
@@ -13,7 +13,7 @@
<h6 class="mb-3">Informasi Kerangka Kerja</h6>
<div class="row">
<div class="col-md-3 mb-4 form-control-validation">
<div class="col-md-6 mb-4 form-control-validation">
<label class="form-label" for="update-framework-nama">Nama Kerangka Kerja<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="update" name="nama" placeholder="Cth: Tabel Pertanian" value="{{ old('nama', $framework->nama) }}" readonly/>
</div>
@@ -21,7 +21,9 @@
<label class="form-label" for="update-framework-tahun">Tahun Implementasi<span class="text-danger">*</span></label>
<input type="number" step="1" min="2026" class="form-control" id="update-framework-tahun" name="tahun" placeholder="Cth: 2023" value="{{ old('tahun', $framework->tahun) ?? now()->year }}" readonly/>
</div>
<div class="col-md-6 mb-4 form-control-validation">
</div>
<div class="row">
<div class="col-md-12 mb-4 form-control-validation">
<label class="form-label" for="update-framework-program">Untuk Program<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="update-framework-tahun" name="tahun" placeholder="Cth: 2023" value="{{ old('program_id', $framework->program->nama) }}" readonly/>
</div>
@@ -41,8 +43,18 @@
<div class="row mb-4">
<div class="col-md-12 mb-4 form-control-validation">
<div class="table-responsive text-nowrap mb-4">
<div class="table-responsive mb-4">
<table class="table table-hover">
<colgroup>
<col style="width: 200px">
<col style="width: 300px">
<col style="width: 600px">
<col style="width: 300px">
<col style="width: 200px">
<col style="width: 25px; text-align: right">
<col style="width: 25px; text-align: right">
<col style="width: 10px'>
</colgroup>
<thead class="border-top">
<tr>
<th>Transformasi</th>
+29 -6
View File
@@ -13,12 +13,22 @@ Route::post('/logout', [App\Http\Controllers\Web\Konfigurasi\AuthController::cla
Route::view('/offline', 'offline')->name('offline');
Route::get('/', function() {
if (!auth()->check()) {
return redirect()->route('login');
}
if (auth()->user()->role->value === 'fasilitator') {
return redirect()->route('dashboard.survey-petani');
}
return redirect()->route('dashboard.produktivitas');
})->name('home');
Route::middleware('auth')
->group(function () {
Route::get('/dashboard/survey-petani', [App\Http\Controllers\Web\Dashboard\SurveyPetaniController::class, 'index'])->name('dashboard.survey-petani');
Route::get('/tekad', function () {
return view('dashboard.dashboard');
})->name('dashboard.survey');
@@ -33,12 +43,15 @@ Route::middleware('auth')
Route::get('/dashboard/produktivitas', [App\Http\Controllers\Web\Dashboard\SummaryController::class, 'produktivitas'])->name('dashboard.produktivitas');
// Dashboard
Route::get('/dashboard/petani', [App\Http\Controllers\Web\Dashboard\ProfilPetaniController::class, 'index'])->name('dashboard.petani');
Route::get('/UserProfile', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'index'])->name('userProfile.index');
Route::get('/UserProfile/security', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'security'])->name('userProfile.security');
Route::get('/UserProfile/activities', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'activities'])->name('userProfile.activities');
Route::patch('/UserProfile/password', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'updatePassword'])->name('userProfile.password.update');
Route::post('/UserProfile/logout-devices', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'logoutDevices'])->name('userProfile.logoutDevices');
Route::get('/user-profile', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'index'])->name('userProfile.index');
Route::get('/user-profile/security', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'security'])->name('userProfile.security');
Route::get('/user-profile/activities', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'activities'])->name('userProfile.activities');
Route::patch('/user-profile/password', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'updatePassword'])->name('userProfile.password.update');
Route::post('/user-profile/logout-devices', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'logoutDevices'])->name('userProfile.logoutDevices');
Route::get('/dashboard/summary', [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');
@@ -197,7 +210,17 @@ Route::middleware('auth')
Route::resource('petani.lahan-tanaman.tanaman', App\Http\Controllers\Web\Produktivitas\PetaniLahanTanamanController::class)->only(['show', 'update', 'destroy'])->whereNumber('petani');
Route::resource('petani.praktik-budidaya', App\Http\Controllers\Web\Produktivitas\PraktikBudidayaController::class)->whereNumber('petani');
Route::resource('petani.survey-produktivitas', App\Http\Controllers\Web\Produktivitas\SurveyProduktivitasController::class)->only(['store', 'destroy']);
Route::resource('petani.pendidikan-pelatihan', App\Http\Controllers\Web\Produktivitas\PendidikanPelatihanController::class);
Route::prefix('petani/{petani}/pendidikan-pelatihan')->name('petani.pendidikan-pelatihan.')->group(function () {
Route::get('/', [App\Http\Controllers\Web\Produktivitas\PendidikanPelatihanController::class, 'index'])->name('index');
Route::post('/pelatihan', [App\Http\Controllers\Web\Produktivitas\PendidikanPelatihanController::class, 'storePelatihan'])->name('pelatihan.store');
Route::delete('/pelatihan/{surveyPelatihan}', [App\Http\Controllers\Web\Produktivitas\PendidikanPelatihanController::class, 'destroyPelatihan'])->name('pelatihan.destroy');
Route::post('/sertifikasi', [App\Http\Controllers\Web\Produktivitas\PendidikanPelatihanController::class, 'storeSertifikasi'])->name('sertifikasi.store');
Route::delete('/sertifikasi/{surveySertifikasi}', [App\Http\Controllers\Web\Produktivitas\PendidikanPelatihanController::class, 'destroySertifikasi'])->name('sertifikasi.destroy');
});
Route::resource('petani.sosial-ekonomi', App\Http\Controllers\Web\Produktivitas\SosialEkonomiController::class)->whereNumber('petani');
Route::resource('petani.akses-pasar', App\Http\Controllers\Web\Produktivitas\AksesPasarController::class)->whereNumber('petani');
Route::resource('petani.skor', App\Http\Controllers\Web\Produktivitas\SkorPetaniController::class)->only(['index']);
});