feat: validasi AJAX NIK, relasi master Gapoktan, dan grafik pendapatan Chart.js di dashboard petani

This commit is contained in:
sayasilvi 2026-02-15 14:31:58 +07:00
parent c04507dfb4
commit 69a3234d0b
17 changed files with 579 additions and 78 deletions

View File

@ -48,7 +48,7 @@ public function loginProcess(Request $request)
Auth::guard('petani')->login($petani);
$request->session()->regenerate();
return redirect()->intended('petani/dashboard');
}
@ -70,38 +70,49 @@ public function showRegisterForm()
public function registerProcess(Request $request)
{
$request->validate([
'role' => 'required|in:petani,pembeli',
'nama_lengkap' => 'required',
'email' => 'required|email',
'username' => 'required|unique:petanis,username|unique:pembelis,username|alpha_dash',
'password' => 'required|min:6',
'no_hp' => 'required|numeric',
'alamat' => 'required',
$rules = [
'role' => 'required|in:petani,pembeli',
'nama_lengkap' => 'required',
'email' => 'required|email',
'username' => 'required|unique:petanis,username|unique:pembelis,username|alpha_dash',
'password' => 'required|min:8',
'no_hp' => 'required|numeric',
'alamat' => 'required',
];
if ($request->role == 'petani') {
$rules['nik'] = 'required|exists:gapoktans,nik|unique:petanis,nik';
}
$request->validate($rules, [
'nik.required' => 'NIK wajib diisi untuk pendaftaran Petani.',
'nik.exists' => 'NIK tidak terdaftar di sistem Admin/Gapoktan.',
'nik.unique' => 'NIK ini sudah terdaftar pada akun lain.'
]);
if ($request->role == 'petani') {
Petani::create([
'nik' => $request->nik,
'nama_lengkap' => $request->nama_lengkap,
'email' => $request->email,
'username' => $request->username,
'password' => Hash::make($request->password),
'no_hp' => $request->no_hp,
'alamat' => $request->alamat,
'nama_usaha' => $request->nama_usaha ?? 'Toko Tani ' . $request->nama_lengkap,
'status_akun' => 'menunggu'
'email' => $request->email,
'username' => $request->username,
'password' => Hash::make($request->password),
'no_hp' => $request->no_hp,
'alamat' => $request->alamat,
'nama_usaha' => $request->nama_usaha ?? 'Toko Tani ' . $request->nama_lengkap,
'status_akun' => 'menunggu'
]);
return redirect('/login')->with('success', 'Registrasi Petani Berhasil! Mohon tunggu verifikasi Admin.');
} else {
Pembeli::create([
'nama_lengkap' => $request->nama_lengkap,
'email' => $request->email,
'username' => $request->username,
'password' => Hash::make($request->password),
'no_hp' => $request->no_hp,
'alamat' => $request->alamat,
'email' => $request->email,
'username' => $request->username,
'password' => Hash::make($request->password),
'no_hp' => $request->no_hp,
'alamat' => $request->alamat,
]);
return redirect('/login')->with('success', 'Registrasi Berhasil! Silakan Login.');
@ -111,9 +122,12 @@ public function registerProcess(Request $request)
public function logout(Request $request)
{
// Logout semua guard untuk keamanan
if (Auth::guard('admin')->check()) Auth::guard('admin')->logout();
if (Auth::guard('petani')->check()) Auth::guard('petani')->logout();
if (Auth::guard('pembeli')->check()) Auth::guard('pembeli')->logout();
if (Auth::guard('admin')->check())
Auth::guard('admin')->logout();
if (Auth::guard('petani')->check())
Auth::guard('petani')->logout();
if (Auth::guard('pembeli')->check())
Auth::guard('pembeli')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();

View File

@ -0,0 +1,39 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Gapoktan;
class GapoktanController extends Controller
{
public function index()
{
$gapoktan = Gapoktan::with('petanis')->get();
return view('admin.gapoktan.index', compact('gapoktan'));
}
public function store(Request $request)
{
$request->validate([
'nik' => 'required|unique:gapoktans,nik|max:16',
'nama' => 'required|string|max:255',
], [
'nik.unique' => 'NIK ini sudah terdaftar di sistem.',
]);
Gapoktan::create([
'nik' => $request->nik,
'nama' => $request->nama,
]);
return redirect()->back()->with('success', 'Data Gapoktan berhasil ditambahkan!');
}
// Menghapus data
public function destroy($id)
{
Gapoktan::findOrFail($id)->delete();
return redirect()->back()->with('success', 'Data berhasil dihapus!');
}
}

View File

@ -5,39 +5,43 @@
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use App\Models\Produk;
use App\Models\DetailTransaksi;
use App\Models\Transaksi;
class DashboardController extends Controller
{
public function index()
{
$petaniId = Auth::guard('petani')->id();
// 1. Hitung Total Produk Aktif
$totalProduk = Produk::where('petani_id', $petaniId)->count();
$pesananBaru = Transaksi::where('petani_id', $petaniId)
->where('status', 'dibayar')
->count();
// 2. Hitung Pesanan Baru (Yang statusnya 'dibayar' / perlu diproses)
$pesananBaru = DetailTransaksi::whereHas('produk', function($q) use ($petaniId) {
$q->where('petani_id', $petaniId);
})->whereHas('transaksi', function($q) {
$q->where('status', 'dibayar');
})->count();
$totalPemesanan = Transaksi::where('petani_id', $petaniId)
->where('status', '!=', 'batal')
->count();
// 3. Hitung TOTAL SEMUA PEMESANAN (Valid)
// Menghitung semua transaksi masuk (Dibayar, Dikirim, Selesai) kecuali yang Batal
$totalPemesanan = DetailTransaksi::whereHas('produk', function($q) use ($petaniId) {
$q->where('petani_id', $petaniId);
})->whereHas('transaksi', function($q) {
$q->where('status', '!=', 'batal'); // Ambil semua kecuali yang batal
})->count();
$totalPendapatan = Transaksi::where('petani_id', $petaniId)
->where('status', 'selesai')
->sum('total_harga');
// 4. Hitung Total Pendapatan (Hanya yang status 'selesai')
$totalPendapatan = DetailTransaksi::whereHas('produk', function($q) use ($petaniId) {
$q->where('petani_id', $petaniId);
})->whereHas('transaksi', function($q) {
$q->where('status', 'selesai');
})->sum('subtotal');
$pendapatanPerBulan = Transaksi::where('petani_id', $petaniId)
->where('status', 'selesai')
->whereYear('tanggal_transaksi', date('Y'))
->selectRaw('MONTH(tanggal_transaksi) as bulan, SUM(total_harga) as total')
->groupBy('bulan')
->pluck('total', 'bulan')
->toArray();
return view('petani.dashboard', compact('totalProduk', 'pesananBaru', 'totalPemesanan', 'totalPendapatan'));
$labels = ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agt', 'Sep', 'Okt', 'Nov', 'Des'];
$dataGrafik = [];
for ($i = 1; $i <= 12; $i++) {
$dataGrafik[] = $pendapatanPerBulan[$i] ?? 0;
}
return view('petani.dashboard', compact(
'totalProduk', 'pesananBaru', 'totalPemesanan', 'totalPendapatan', 'labels', 'dataGrafik'
));
}
}

23
app/Models/Gapoktan.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Gapoktan extends Model
{
use HasFactory;
protected $table = 'gapoktans';
protected $fillable = [
'nik',
'nama',
];
public function petanis()
{
return $this->hasOne(Petani::class, 'nik', 'nik');
}
}

View File

@ -14,6 +14,7 @@ class Petani extends Authenticatable implements CanResetPassword
protected $table = 'petanis';
protected $fillable = [
'nik',
'nama_lengkap',
'username',
'email',

View File

@ -13,6 +13,7 @@ public function up(): void
{
Schema::create('petanis', function (Blueprint $table) {
$table->id();
$table->string('nik', 16)->nullable()->unique();
$table->string('nama_lengkap');
$table->string('username')->unique();
$table->string('email')->unique();

View File

@ -0,0 +1,23 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up()
{
Schema::create('gapoktans', function (Blueprint $table) {
$table->id();
$table->string('nik', 16)->unique();
$table->string('nama');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('gapoktans');
}
};

View File

@ -19,9 +19,10 @@ public function run(): void
// User::factory(10)->create();
$this->call([
GapoktanSeeder::class,
PetaniSeeder::class,
AdminSeeder::class,
PembeliSeeder::class,
PetaniSeeder::class,
ProdukSeeder::class,
]);
}

View File

@ -0,0 +1,33 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class GapoktanSeeder extends Seeder
{
public function run(): void
{
DB::table('gapoktans')->insert([
[
'nik' => '3518012345678901',
'nama' => 'Gapoktan Makmur Jaya',
'created_at' => now(),
'updated_at' => now(),
],
[
'nik' => '3518012345678902',
'nama' => 'Kelompok Tani Sumber Rejeki',
'created_at' => now(),
'updated_at' => now(),
],
[
'nik' => '3518012345678903',
'nama' => 'Gapoktan Suka Maju',
'created_at' => now(),
'updated_at' => now(),
],
]);
}
}

View File

@ -13,11 +13,12 @@ class PetaniSeeder extends Seeder
*/
public function run(): void
{
// Petani SUDAH AKTIF -> Bisa login & jualan
// Petani SUDAH AKTIF
DB::table('petanis')->insert([
'nik' => '3518012345678901',
'nama_lengkap' => 'Siti Aminah',
'username' => 'siti_sayur',
'email' => 'siti@gmail.com',
'email' => 'siti@gmail.com',
'password' => Hash::make('password123'),
'no_hp' => '085678901234',
'alamat' => 'Dusun Krajan RT 02 RW 01',
@ -26,11 +27,13 @@ public function run(): void
'created_at' => now(),
'updated_at' => now(),
]);
// Petani BARU DAFTAR menunggu verifikasi
DB::table('petanis')->insert([
'nik' => '3518012345678902',
'nama_lengkap' => 'Budi Santoso',
'username' => 'budi_tani',
'email' => 'budisantoso@gmail.com',
'email' => 'budisantoso@gmail.com',
'password' => Hash::make('password123'),
'no_hp' => '081234567890',
'alamat' => 'Jl. Raya Desa Sukamaju No. 12',
@ -40,12 +43,12 @@ public function run(): void
'updated_at' => now(),
]);
// Petani DITOLAK
DB::table('petanis')->insert([
'nik' => '3518012345678903',
'nama_lengkap' => 'Joko Widodo',
'username' => 'joko_tani',
'email' => 'wiwokdetok@gmail.com',
'email' => 'wiwokdetok@gmail.com',
'password' => Hash::make('password123'),
'no_hp' => '089876543210',
'alamat' => 'Jl. Buntu No. 99',

View File

@ -0,0 +1,90 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
class TransaksiSeeder extends Seeder
{
public function run(): void
{
$tahunIni = date('Y');
// ==========================================
// TRANSAKSI 1: BULAN JANUARI (Selesai)
// ==========================================
$trx1 = DB::table('transaksis')->insertGetId([
'kode_invoice' => 'INV-' . $tahunIni . '01-001',
'pembeli_id' => 1,
'petani_id' => 1,
'tanggal_transaksi' => Carbon::create($tahunIni, 1, 15, 10, 0, 0),
'alamat_pengiriman' => 'Jl. Raya Nganjuk No. 123, Jawa Timur',
'total_harga' => 250000,
'status' => 'selesai',
'created_at' => Carbon::create($tahunIni, 1, 15, 10, 0, 0),
'updated_at' => Carbon::create($tahunIni, 1, 15, 10, 0, 0),
]);
DB::table('detail_transaksis')->insert([
'transaksi_id' => $trx1,
'produk_id' => 1,
'jumlah' => 5,
'harga_satuan' => 50000,
'subtotal' => 250000,
'created_at' => Carbon::create($tahunIni, 1, 15, 10, 0, 0),
'updated_at' => Carbon::create($tahunIni, 1, 15, 10, 0, 0),
]);
// ==========================================
// TRANSAKSI 2: BULAN FEBRUARI (Selesai)
// ==========================================
$trx2 = DB::table('transaksis')->insertGetId([
'kode_invoice' => 'INV-' . $tahunIni . '02-002',
'pembeli_id' => 1,
'petani_id' => 1,
'tanggal_transaksi' => Carbon::create($tahunIni, 2, 10, 14, 30, 0),
'alamat_pengiriman' => 'Jl. Sudirman No. 45, Jakarta',
'total_harga' => 400000,
'status' => 'selesai',
'created_at' => Carbon::create($tahunIni, 2, 10, 14, 30, 0),
'updated_at' => Carbon::create($tahunIni, 2, 10, 14, 30, 0),
]);
DB::table('detail_transaksis')->insert([
'transaksi_id' => $trx2,
'produk_id' => 1,
'jumlah' => 8,
'harga_satuan' => 50000,
'subtotal' => 400000,
'created_at' => Carbon::create($tahunIni, 2, 10, 14, 30, 0),
'updated_at' => Carbon::create($tahunIni, 2, 10, 14, 30, 0),
]);
// ==========================================
// TRANSAKSI 3: BULAN MARET (Selesai)
// ==========================================
$trx3 = DB::table('transaksis')->insertGetId([
'kode_invoice' => 'INV-' . $tahunIni . '03-003',
'pembeli_id' => 1,
'petani_id' => 1,
'tanggal_transaksi' => Carbon::create($tahunIni, 3, 5, 9, 15, 0),
'alamat_pengiriman' => 'Perumahan Indah Blok C2, Surabaya',
'total_harga' => 150000,
'status' => 'selesai',
'created_at' => Carbon::create($tahunIni, 3, 5, 9, 15, 0),
'updated_at' => Carbon::create($tahunIni, 3, 5, 9, 15, 0),
]);
DB::table('detail_transaksis')->insert([
'transaksi_id' => $trx3,
'produk_id' => 1,
'jumlah' => 3,
'harga_satuan' => 50000,
'subtotal' => 150000,
'created_at' => Carbon::create($tahunIni, 3, 5, 9, 15, 0),
'updated_at' => Carbon::create($tahunIni, 3, 5, 9, 15, 0),
]);
}
}

View File

@ -0,0 +1,86 @@
@extends('layouts.admin')
@section('content')
<div class="container-fluid">
<h3>Data Master Gapoktan</h3>
{{-- Pesan Sukses/Error --}}
@if (session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
@if ($errors->any())
<div class="alert alert-danger">{{ $errors->first() }}</div>
@endif
<div class="row">
{{-- Form Tambah Data --}}
<div class="col-md-4">
<div class="card">
<div class="card-header">Tambah Data</div>
<div class="card-body">
<form action="{{ route('admin.gapoktan.store') }}" method="POST">
@csrf
<div class="form-group mb-3">
<label>NIK</label>
<input type="number" name="nik" class="form-control" required
placeholder="Masukkan 16 digit NIK">
</div>
<div class="form-group mb-3">
<label>Nama Petani / Kelompok</label>
<input type="text" name="nama" class="form-control" required
placeholder="Masukkan Nama">
</div>
<button type="submit" class="btn btn-primary">Simpan</button>
</form>
</div>
</div>
</div>
{{-- Tabel Data --}}
<div class="col-md-8">
<div class="card">
<div class="card-header">Daftar NIK Terdaftar</div>
<div class="card-body">
<table class="table table-bordered">
<thead>
<tr>
<th>No</th>
<th>Tanggal Dibuat</th>
<th>NIK</th>
<th>Nama Petani/Kelompok</th>
<th>Status Akun</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
@foreach ($gapoktan as $key => $item)
<tr>
<td>{{ $key + 1 }}</td>
<td>{{ \Carbon\Carbon::parse($item->created_at)->translatedFormat('d F Y') }}</td>
<td>{{ $item->nik }}</td>
<td>{{ $item->nama }}</td>
<td>
@if ($item->petanis)
<span class="badge bg-primary-green">Digunakan oleh
{{ $item->petanis->nama_lengkap }}</span>
@else
<span class="badge bg-warning text-dark">Belum Digunakan</span>
@endif
</td>
<td>
<form action="{{ route('admin.gapoktan.destroy', $item->id) }}" method="POST"
onsubmit="return confirm('Yakin hapus data ini?')">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger btn-sm">Hapus</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@ -41,15 +41,23 @@
<table class="table table-borderless align-middle mb-0">
<tr>
<td class="text-muted small text-uppercase fw-bold pt-3" width="30%">Nama Lengkap</td>
<td class="pt-3 fw-bold text-dark fs-5">{{ $petani->nama_lengkap }}</td>
<td class="pt-3 fw-medium">: {{ $petani->nama_lengkap }}</td>
</tr>
<tr>
<td class="text-muted small text-uppercase fw-bold">Username</td>
<td class="fw-medium">{{ $petani->username }}</td>
<td class="fw-medium">: {{ $petani->username }}</td>
</tr>
<tr>
<td class="text-muted small text-uppercase fw-bold">Email</td>
<td class="fw-medium">: {{ $petani->email }}</td>
</tr>
<tr>
<td class="text-muted small text-uppercase fw-bold">NIK Gapoktan</td>
<td class="fw-medium">: {{ $petani->nik }}</td>
</tr>
<tr>
<td class="text-muted small text-uppercase fw-bold">Nomor WhatsApp</td>
<td>
<td>:
<span
class="bg-light px-2 py-1 rounded fw-bold text-dark font-monospace">{{ $petani->no_hp }}</span>
<a href="https://wa.me/{{ $petani->no_hp }}" target="_blank"
@ -60,15 +68,15 @@ class="ms-2 text-decoration-none small text-success fw-bold">
</tr>
<tr>
<td class="text-muted small text-uppercase fw-bold">Nama Usaha Tani</td>
<td class="fw-medium">{{ $petani->nama_usaha }}</td>
<td class="fw-medium">: {{ $petani->nama_usaha }}</td>
</tr>
<tr>
<td class="text-muted small text-uppercase fw-bold">Alamat Lengkap</td>
<td class="text-secondary" style="line-height: 1.6;">{{ $petani->alamat }}</td>
<td class="text-secondary" style="line-height: 1.6;">: {{ $petani->alamat }}</td>
</tr>
<tr>
<td class="text-muted small text-uppercase fw-bold">Terdaftar Sejak</td>
<td class="text-secondary">{{ $petani->created_at->format('d F Y, H:i') }} WIB</td>
<td class="text-secondary">: {{ $petani->created_at->format('d F Y, H:i') }} WIB</td>
</tr>
</table>
</div>

View File

@ -85,6 +85,7 @@
<p class="text-muted small">Gabung komunitas GriyaPadi.id</p>
</div>
<form action="{{ route('register.proses') }}" method="POST">
@csrf
<div class="mb-3">
@ -112,6 +113,13 @@
<input type="email" name="email" class="form-control" required>
</div>
<div class="mb-3" id="wrapper-nik" style="display: none;">
<label class="form-label small text-muted">NIK (Khusus Petani)</label>
<input type="number" name="nik" id="nik" class="form-control"
placeholder="Masukkan 16 digit NIK">
<small id="pesan-nik" class="form-text d-block mt-1"></small>
</div>
{{-- PASSWORD DENGAN VALIDASI --}}
<div class="mb-2">
<label class="form-label small text-muted">Password</label>
@ -150,7 +158,7 @@
</div>
<div class="d-grid mt-4">
<button type="submit" class="btn btn-tani rounded-pill py-2">Register</button>
<button type="submit" id="btn-daftar" class="btn btn-tani rounded-pill py-2">Register</button>
</div>
</form>
@ -161,8 +169,9 @@ class="text-tani fw-bold text-decoration-none">Login</a></small>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
// Toggle Show/Hide Password
// 1. Toggle Show/Hide Password
function togglePassword(inputId, iconId) {
const input = document.getElementById(inputId);
const icon = document.getElementById(iconId);
@ -177,14 +186,7 @@ function togglePassword(inputId, iconId) {
}
}
// Toggle Form Petani
function toggleForm() {
var role = document.getElementById('role').value;
var formPetani = document.getElementById('form-petani');
formPetani.style.display = (role === 'petani') ? 'block' : 'none';
}
// Real-time Password Validator
// 2. Real-time Password Validator (Yang tadi sempat hilang)
function checkPassword() {
const password = document.getElementById('password').value;
@ -212,6 +214,77 @@ function updateRequirement(id, isValid) {
icon.classList.add('fa-times');
}
}
// 3. Toggle Form Petani
function toggleForm() {
var role = document.getElementById('role').value;
var formPetani = document.getElementById('form-petani');
var wrapperNik = document.getElementById('wrapper-nik');
var inputNik = document.getElementById('nik');
var btnDaftar = document.getElementById('btn-daftar');
if (role === 'petani') {
formPetani.style.display = 'block';
wrapperNik.style.display = 'block';
inputNik.setAttribute('required', 'required');
} else {
formPetani.style.display = 'none';
wrapperNik.style.display = 'none';
inputNik.removeAttribute('required');
inputNik.value = '';
$('#pesan-nik').text('');
btnDaftar.disabled = false;
}
}
// 4. AJAX Cek NIK
$(document).ready(function() {
toggleForm(); // Panggil saat web pertama dimuat
$('#nik').on('blur', function() {
var currentRole = $('#role').val();
if (currentRole !== 'petani') return; // Cuma jalan kalau rolenya petani
let nikValue = $(this).val();
if (nikValue === '') {
$('#pesan-nik').text('');
$('#btn-daftar').prop('disabled', false);
return;
}
$('#pesan-nik').text('Mengecek NIK...').css('color', 'blue');
// Jalankan AJAX
$.ajax({
url: "{{ route('cek.nik') }}",
type: "POST",
data: {
_token: "{{ csrf_token() }}",
nik: nikValue
},
success: function(response) {
if (response.status === 'tersedia') {
$('#pesan-nik').text('NIK valid dan terdaftar.').css('color',
'green');
$('#btn-daftar').prop('disabled', false);
} else if (response.status === 'sudah_dipakai') {
$('#pesan-nik').text('NIK ini sudah terdaftar pada akun lain!').css(
'color', 'orange');
$('#btn-daftar').prop('disabled', true);
} else {
$('#pesan-nik').text(
'NIK tidak terdaftar di Gapoktan! Anda tidak bisa mendaftar.'
).css('color', 'red');
$('#btn-daftar').prop('disabled', true);
}
},
error: function() {
$('#pesan-nik').text('Terjadi kesalahan server.').css('color', 'red');
}
});
});
});
</script>
</body>

View File

@ -238,6 +238,13 @@
</a>
</li>
{{-- GAPOKTAN --}}
<li class="sidebar-item {{ request()->is('admin/gapoktan*') ? 'active' : '' }}">
<a href="{{ route('admin.gapoktan.index') }}" class='sidebar-link'>
<i class="bi bi-people-fill"></i> <span>Data Gapoktan</span>
</a>
</li>
{{-- MONITORING --}}
<li class="sidebar-item {{ request()->is('admin/monitoring*') ? 'active' : '' }}">
<a href="{{ route('admin.monitoring') }}" class='sidebar-link'>
@ -323,6 +330,8 @@ class='sidebar-link border-0 bg-transparent text-danger w-100 text-start'>
</div>
</div>
@stack('scripts')
<script src="https://cdn.jsdelivr.net/gh/zuramai/mazer@docs/demo/assets/static/js/components/dark.js"></script>
<script
src="https://cdn.jsdelivr.net/gh/zuramai/mazer@docs/demo/assets/extensions/perfect-scrollbar/perfect-scrollbar.min.js">

View File

@ -6,6 +6,8 @@
@section('content')
<section class="row">
<div class="col-12 col-lg-12">
{{-- ROW 1: Card Ringkasan --}}
<div class="row">
{{-- Card 1: Produk Saya --}}
<div class="col-6 col-lg-4 col-md-6">
@ -24,7 +26,7 @@
</div>
</div>
{{-- Card Pemesanan --}}
{{-- Card 2: Pemesanan --}}
<div class="col-6 col-lg-4 col-md-6">
<div class="card">
<div class="card-body px-3 py-4-5">
@ -43,7 +45,7 @@
</div>
</div>
{{-- Card Total Pendapatan --}}
{{-- Card 3: Total Pendapatan --}}
<div class="col-6 col-lg-4 col-md-6">
<div class="card">
<div class="card-body px-3 py-4-5">
@ -64,6 +66,20 @@
</div>
</div>
{{-- ROW 2: Grafik Pendapatan --}}
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h4>Grafik Pendapatan Tahun {{ date('Y') }}</h4>
</div>
<div class="card-body">
<canvas id="revenueChart" width="100%" height="30"></canvas>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="card">
@ -77,6 +93,65 @@
</div>
</div>
</div>
</div>
</section>
@endsection
@endsection
@push('scripts')
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
var ctx = document.getElementById("revenueChart").getContext('2d');
var revenueChart = new Chart(ctx, {
type: 'bar',
data: {
labels: {!! json_encode($labels) !!},
datasets: [{
label: 'Pendapatan (Rp)',
data: {!! json_encode($dataGrafik) !!},
backgroundColor: '#57ca22',
borderColor: '#4fac1d',
borderWidth: 1,
borderRadius: 5
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value, index, values) {
if(parseInt(value) >= 1000){
return 'Rp ' + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
} else {
return 'Rp ' + value;
}
}
}
}
},
plugins: {
tooltip: {
callbacks: {
label: function(context) {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += 'Rp ' + context.parsed.y.toLocaleString('id-ID');
}
return label;
}
}
}
}
}
});
});
</script>
@endpush

View File

@ -6,12 +6,16 @@
use App\Http\Controllers\Admin\AdminController;
use App\Http\Controllers\CartController;
use App\Http\Controllers\ForgotPasswordController;
use App\Http\Controllers\GapoktanController;
use App\Http\Controllers\LandingController;
use App\Http\Controllers\PesanController;
use App\Http\Controllers\Petani\DashboardController;
use App\Http\Controllers\Petani\ProdukController;
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\TransaksiController;
use Illuminate\Http\Request;
use App\Models\Gapoktan;
use App\Models\Petani;
/*
|--------------------------------------------------------------------------
@ -82,20 +86,18 @@
Route::middleware(['auth:admin'])->group(function () {
Route::get('/admin/dashboard', [AdminController::class, 'dashboard'])->name('admin.dashboard');
Route::get('/admin/monitoring', [AdminController::class, 'monitoring'])->name('admin.monitoring');
// Petani Verification Logic
Route::controller(AdminController::class)->prefix('admin/verifikasi')->group(function () {
Route::get('/', 'verifikasiIndex')->name('admin.verifikasi.index');
Route::get('/{id}', 'verifikasiShow')->name('admin.verifikasi.show');
Route::post('/{id}/approve', 'verifikasiApprove');
Route::post('/{id}/reject', 'verifikasiReject');
});
// CRUD Kategori
Route::resource('admin/kategori', KategoriController::class)->names('admin.kategori');
Route::get('/admin/transaksi/{id}', [AdminController::class, 'transaksiDetail'])
->name('admin.transaksi.detail');
Route::get('/admin/gapoktan', [GapoktanController::class, 'index'])->name('admin.gapoktan.index');
Route::post('/admin/gapoktan', [GapoktanController::class, 'store'])->name('admin.gapoktan.store');
Route::delete('/admin/gapoktan/{id}', [GapoktanController::class, 'destroy'])->name('admin.gapoktan.destroy');
});
@ -120,3 +122,19 @@
Route::get('/petani/profile', [ProfileController::class, 'editPetani'])->name('petani.profile');
Route::put('/petani/profile', [ProfileController::class, 'updatePetani'])->name('petani.profile.update');
});
// --- CEK NIK GAPOKTAN AJAX ---
Route::post('/cek-nik-gapoktan', function (Request $request) {
$nik = $request->nik;
$adaDiGapoktan = Gapoktan::where('nik', $nik)->exists();
$sudahDipakai = Petani::where('nik', $nik)->exists();
if (!$adaDiGapoktan) {
return response()->json(['status' => 'tidak_ditemukan']);
} elseif ($sudahDipakai) {
return response()->json(['status' => 'sudah_dipakai']);
} else {
return response()->json(['status' => 'tersedia']);
}
})->name('cek.nik');