refactor: transaksi controller, cart dan filter wilayah lengkap
This commit is contained in:
parent
69a3234d0b
commit
f01c00fa87
|
|
@ -22,3 +22,6 @@
|
|||
Homestead.json
|
||||
Homestead.yaml
|
||||
Thumbs.db
|
||||
/storage/framework/views/*.php
|
||||
/storage/framework/cache/data/*
|
||||
/storage/framework/sessions/*
|
||||
11
README.md
11
README.md
|
|
@ -141,14 +141,21 @@ ### Step 6: Database Migration
|
|||
php artisan migrate --seed
|
||||
```
|
||||
|
||||
### Step 7: Konfigurasi Storage Link
|
||||
### Step 7: Import Data Wilayah Indonesia (Wajib)
|
||||
Jalankan perintah ini untuk mengisi data wilayah resmi Indonesia ke dalam database.
|
||||
|
||||
```bash
|
||||
php artisan laravolt:indonesia:seed
|
||||
```
|
||||
|
||||
### Step 8: Konfigurasi Storage Link
|
||||
Jalankan perintah untuk konfigurasi storage link untuk menyimpan gambar
|
||||
|
||||
```bash
|
||||
php artisan storage:link
|
||||
```
|
||||
|
||||
### Step 8: Start Application
|
||||
### Step 9: Start Application
|
||||
**Terminal (Laravel Server):**
|
||||
```bash
|
||||
php artisan serve
|
||||
|
|
|
|||
|
|
@ -12,15 +12,16 @@ class CartController extends Controller
|
|||
// Menampilkan Halaman Keranjang
|
||||
public function index()
|
||||
{
|
||||
// Cek Login Pembeli
|
||||
if (!Auth::guard('pembeli')->check()) {
|
||||
return redirect()->route('login')->with('error', 'Silakan login terlebih dahulu untuk melihat keranjang.');
|
||||
}
|
||||
|
||||
$pembeli_id = Auth::guard('pembeli')->id();
|
||||
|
||||
// Ambil data keranjang dari Database
|
||||
$cart = Cart::with('produk')->where('pembeli_id', $pembeli_id)->get();
|
||||
$cart = Cart::with('produk')
|
||||
->where('pembeli_id', $pembeli_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('landing.cart', compact('cart'));
|
||||
}
|
||||
|
|
@ -54,8 +55,8 @@ public function addToCart(Request $request)
|
|||
} else {
|
||||
Cart::create([
|
||||
'pembeli_id' => $pembeli_id,
|
||||
'produk_id' => $produk_id,
|
||||
'quantity' => $quantity
|
||||
'produk_id' => $produk_id,
|
||||
'quantity' => $quantity
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,11 +25,13 @@ public function index(Request $request)
|
|||
return view('landing.partials.product_list', compact('produks'))->render();
|
||||
}
|
||||
|
||||
$produkTerlaris = Produk::withSum(['detailTransaksis as total_terjual' => function ($query) {
|
||||
$query->whereHas('transaksi', function ($q) {
|
||||
$q->where('status', '!=', 'batal');
|
||||
});
|
||||
}], 'jumlah')
|
||||
$produkTerlaris = Produk::withSum([
|
||||
'detailTransaksis as total_terjual' => function ($query) {
|
||||
$query->whereHas('transaksi', function ($q) {
|
||||
$q->where('status', '!=', 'batal');
|
||||
});
|
||||
}
|
||||
], 'jumlah')
|
||||
->orderByDesc('total_terjual')
|
||||
->take(4)
|
||||
->get();
|
||||
|
|
@ -41,6 +43,21 @@ public function shop(Request $request)
|
|||
{
|
||||
$query = Produk::where('stok', '>', 0);
|
||||
|
||||
// --- FILTER LOKASI ---
|
||||
if ($request->filled('provinsi')) {
|
||||
$query->where('provinsi_code', $request->provinsi);
|
||||
}
|
||||
if ($request->filled('kota')) {
|
||||
$query->where('kota_code', $request->kota);
|
||||
}
|
||||
if ($request->filled('kecamatan')) {
|
||||
$query->where('kecamatan_code', $request->kecamatan);
|
||||
}
|
||||
if ($request->filled('desa')) {
|
||||
$query->where('desa_code', $request->desa);
|
||||
}
|
||||
|
||||
// Filter Search
|
||||
if ($request->has('search') && $request->search != '') {
|
||||
$query->where('nama_produk', 'like', '%' . $request->search . '%');
|
||||
}
|
||||
|
|
@ -91,4 +108,4 @@ public function detail($id)
|
|||
|
||||
return view('landing.detail', compact('produk', 'produk_terkait'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,38 +6,47 @@
|
|||
use Illuminate\Http\Request;
|
||||
use App\Models\Produk;
|
||||
use App\Models\ProdukImage;
|
||||
use App\Models\Kategori; // PENTING: Import Model Kategori
|
||||
use App\Models\Kategori;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Laravolt\Indonesia\Models\City;
|
||||
use Laravolt\Indonesia\Models\District;
|
||||
use Laravolt\Indonesia\Models\Province;
|
||||
use Laravolt\Indonesia\Models\Village;
|
||||
|
||||
class ProdukController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$produks = Produk::with('kategori')
|
||||
->where('petani_id', Auth::guard('petani')->id())
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
->where('petani_id', Auth::guard('petani')->id())
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('petani.produk.index', compact('produks'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$kategoris = Kategori::all();
|
||||
|
||||
return view('petani.produk.create', compact('kategoris'));
|
||||
$provinsis = Province::all();
|
||||
|
||||
return view('petani.produk.create', compact('kategoris', 'provinsis'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'nama_produk' => 'required|string|max:255',
|
||||
'kategori_id' => 'required|exists:kategoris,id',
|
||||
'harga' => 'required|numeric|min:0',
|
||||
'stok' => 'required|integer|min:0',
|
||||
'deskripsi' => 'required|string',
|
||||
'foto_produk' => 'required|image|mimes:jpeg,png,jpg|max:2048',
|
||||
'nama_produk' => 'required|string|max:255',
|
||||
'kategori_id' => 'required|exists:kategoris,id',
|
||||
'harga' => 'required|numeric|min:0',
|
||||
'stok' => 'required|integer|min:0',
|
||||
'deskripsi' => 'required|string',
|
||||
'provinsi_code' => 'required',
|
||||
'kota_code' => 'required',
|
||||
'kecamatan_code' => 'required',
|
||||
'desa_code' => 'required',
|
||||
'foto_produk' => 'required|image|mimes:jpeg,png,jpg|max:2048',
|
||||
'foto_tambahan.*' => 'nullable|image|mimes:jpeg,png,jpg|max:2048'
|
||||
]);
|
||||
|
||||
|
|
@ -49,12 +58,16 @@ public function store(Request $request)
|
|||
|
||||
// Simpan Data Produk
|
||||
$produk = Produk::create([
|
||||
'petani_id' => Auth::guard('petani')->id(),
|
||||
'kategori_id' => $request->kategori_id,
|
||||
'petani_id' => Auth::guard('petani')->id(),
|
||||
'kategori_id' => $request->kategori_id,
|
||||
'nama_produk' => $request->nama_produk,
|
||||
'harga' => $request->harga,
|
||||
'stok' => $request->stok,
|
||||
'deskripsi' => $request->deskripsi,
|
||||
'harga' => $request->harga,
|
||||
'provinsi_code' => $request->provinsi_code,
|
||||
'kota_code' => $request->kota_code,
|
||||
'kecamatan_code' => $request->kecamatan_code,
|
||||
'desa_code' => $request->desa_code,
|
||||
'stok' => $request->stok,
|
||||
'deskripsi' => $request->deskripsi,
|
||||
'foto_produk' => $fotoPath,
|
||||
]);
|
||||
|
||||
|
|
@ -64,7 +77,7 @@ public function store(Request $request)
|
|||
$path = $file->store('produk/gallery', 'public');
|
||||
ProdukImage::create([
|
||||
'produk_id' => $produk->id,
|
||||
'foto' => $path
|
||||
'foto' => $path
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -77,7 +90,12 @@ public function edit($id)
|
|||
$produk = Produk::with('images')->where('id', $id)->where('petani_id', Auth::guard('petani')->id())->firstOrFail();
|
||||
$kategoris = Kategori::all();
|
||||
|
||||
return view('petani.produk.edit', compact('produk', 'kategoris'));
|
||||
$provinsis = Province::all();
|
||||
$kotas = City::where('province_code', $produk->provinsi_code)->get();
|
||||
$kecamatans = District::where('city_code', $produk->kota_code)->get();
|
||||
$desas = Village::where('district_code', $produk->kecamatan_code)->get();
|
||||
|
||||
return view('petani.produk.edit', compact('produk', 'kategoris', 'provinsis', 'kotas', 'kecamatans', 'desas'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
|
|
@ -89,13 +107,17 @@ public function update(Request $request, $id)
|
|||
$sisaSlot = max(3 - $jumlahGambarLama, 0);
|
||||
|
||||
$request->validate([
|
||||
'nama_produk' => 'required|string|max:255',
|
||||
'kategori_id' => 'required|exists:kategoris,id',
|
||||
'harga' => 'required|numeric|min:0',
|
||||
'stok' => 'required|integer|min:0',
|
||||
'deskripsi' => 'required|string',
|
||||
'foto_produk' => 'nullable|image|mimes:jpeg,png,jpg|max:2048',
|
||||
'foto_tambahan' => 'array|max:' . $sisaSlot,
|
||||
'nama_produk' => 'required|string|max:255',
|
||||
'kategori_id' => 'required|exists:kategoris,id',
|
||||
'harga' => 'required|numeric|min:0',
|
||||
'provinsi_code' => 'required',
|
||||
'kota_code' => 'required',
|
||||
'kecamatan_code' => 'required',
|
||||
'desa_code' => 'required',
|
||||
'stok' => 'required|integer|min:0',
|
||||
'deskripsi' => 'required|string',
|
||||
'foto_produk' => 'nullable|image|mimes:jpeg,png,jpg|max:2048',
|
||||
'foto_tambahan' => 'array|max:' . $sisaSlot,
|
||||
'foto_tambahan.*' => 'image|mimes:jpeg,png,jpg|max:2048'
|
||||
], [
|
||||
'foto_tambahan.max' => "Anda hanya bisa menambah $sisaSlot foto lagi."
|
||||
|
|
@ -112,22 +134,27 @@ public function update(Request $request, $id)
|
|||
// Update Data
|
||||
$produk->update([
|
||||
'nama_produk' => $request->nama_produk,
|
||||
'kategori_id' => $request->kategori_id,
|
||||
'harga' => $request->harga,
|
||||
'stok' => $request->stok,
|
||||
'deskripsi' => $request->deskripsi,
|
||||
'foto_produk' => $produk->foto_produk
|
||||
'kategori_id' => $request->kategori_id,
|
||||
'harga' => $request->harga,
|
||||
'provinsi_code' => $request->provinsi_code,
|
||||
'kota_code' => $request->kota_code,
|
||||
'kecamatan_code' => $request->kecamatan_code,
|
||||
'desa_code' => $request->desa_code,
|
||||
'stok' => $request->stok,
|
||||
'deskripsi' => $request->deskripsi,
|
||||
'foto_produk' => $produk->foto_produk
|
||||
]);
|
||||
|
||||
|
||||
// Tambah Foto Galeri
|
||||
if ($request->hasFile('foto_tambahan')) {
|
||||
foreach ($request->file('foto_tambahan') as $file) {
|
||||
if ($produk->images()->count() >= 3) break;
|
||||
|
||||
if ($produk->images()->count() >= 3)
|
||||
break;
|
||||
|
||||
$path = $file->store('produk/gallery', 'public');
|
||||
ProdukImage::create([
|
||||
'produk_id' => $produk->id,
|
||||
'foto' => $path
|
||||
'foto' => $path
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -138,18 +165,18 @@ public function update(Request $request, $id)
|
|||
public function destroy($id)
|
||||
{
|
||||
$produk = Produk::where('id', $id)->where('petani_id', Auth::guard('petani')->id())->firstOrFail();
|
||||
|
||||
|
||||
if ($produk->foto_produk && Storage::disk('public')->exists($produk->foto_produk)) {
|
||||
Storage::disk('public')->delete($produk->foto_produk);
|
||||
}
|
||||
|
||||
foreach($produk->images as $img) {
|
||||
foreach ($produk->images as $img) {
|
||||
if (Storage::disk('public')->exists($img->foto)) {
|
||||
Storage::disk('public')->delete($img->foto);
|
||||
}
|
||||
}
|
||||
|
||||
$produk->images()->delete();
|
||||
|
||||
$produk->images()->delete();
|
||||
$produk->delete();
|
||||
|
||||
return redirect()->route('petani.produk.index')->with('success', 'Produk berhasil dihapus.');
|
||||
|
|
@ -158,7 +185,7 @@ public function destroy($id)
|
|||
public function deleteImage($id)
|
||||
{
|
||||
$image = ProdukImage::findOrFail($id);
|
||||
|
||||
|
||||
if ($image->produk->petani_id != Auth::guard('petani')->id()) {
|
||||
abort(403);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
use App\Models\Produk;
|
||||
use App\Models\Transaksi;
|
||||
use App\Models\DetailTransaksi;
|
||||
use App\Models\Cart;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
|
|
@ -13,10 +14,16 @@ class TransaksiController extends Controller
|
|||
{
|
||||
// --- FITUR PEMBELI ---
|
||||
|
||||
// Tampilkan Halaman Checkout
|
||||
/**
|
||||
* Tampilkan Halaman Checkout
|
||||
* Mendukung Beli Langsung dan Checkout dari Keranjang (Database)
|
||||
*/
|
||||
public function checkoutPage(Request $request)
|
||||
{
|
||||
// Beli Langsung (Buy Now)
|
||||
// Mendefinisikan ID Pembeli agar tidak error 'Undefined Variable'
|
||||
$pembeli_id = Auth::guard('pembeli')->id();
|
||||
|
||||
// 1. LOGIKA BELI LANGSUNG (Buy Now)
|
||||
if ($request->has('produk_id')) {
|
||||
$produk = Produk::with('petani')->findOrFail($request->produk_id);
|
||||
$items = collect([
|
||||
|
|
@ -34,32 +41,48 @@ public function checkoutPage(Request $request)
|
|||
return view('landing.checkout', compact('items', 'total_belanja'));
|
||||
}
|
||||
|
||||
// Checkout dari Keranjang
|
||||
$cart = session()->get('cart');
|
||||
if ($cart && count($cart) > 0) {
|
||||
$items = collect();
|
||||
foreach ($cart as $id => $details) {
|
||||
$produk = Produk::find($id);
|
||||
if ($produk) {
|
||||
$items->push((object) [
|
||||
'id' => $id,
|
||||
'produk' => $produk,
|
||||
'nama_produk' => $details['name'],
|
||||
'harga' => $details['price'],
|
||||
'jumlah' => $details['quantity'],
|
||||
'subtotal' => $details['price'] * $details['quantity'],
|
||||
'foto' => $details['photo']
|
||||
]);
|
||||
}
|
||||
}
|
||||
$total_belanja = $items->sum('subtotal');
|
||||
return view('landing.checkout', compact('items', 'total_belanja'));
|
||||
// 2. LOGIKA CHECKOUT DARI KERANJANG (Database)
|
||||
$cartIds = $request->query('cart_ids');
|
||||
|
||||
if (!$cartIds) {
|
||||
return redirect()->route('cart')->with('error', 'Pilih minimal satu produk di keranjang untuk dicheckout.');
|
||||
}
|
||||
|
||||
return redirect()->route('shop')->with('error', 'Keranjang Anda kosong, silakan belanja dulu.');
|
||||
$selectedIds = explode(',', $cartIds);
|
||||
|
||||
// Ambil data dari Tabel Cart yang ID-nya dicentang oleh user
|
||||
$cartItems = Cart::with('produk.petani')
|
||||
->where('pembeli_id', $pembeli_id)
|
||||
->whereIn('id', $selectedIds)
|
||||
->get();
|
||||
|
||||
if ($cartItems->isEmpty()) {
|
||||
return redirect()->route('cart')->with('error', 'Barang di keranjang tidak ditemukan atau sudah dihapus.');
|
||||
}
|
||||
|
||||
// Transformasi data agar sesuai dengan format yang dibaca di View Checkout
|
||||
$items = $cartItems->map(function ($item) {
|
||||
return (object) [
|
||||
'cart_id' => $item->id,
|
||||
'id' => $item->produk->id,
|
||||
'produk' => $item->produk,
|
||||
'nama_produk' => $item->produk->nama_produk,
|
||||
'harga' => $item->produk->harga,
|
||||
'jumlah' => $item->quantity,
|
||||
'subtotal' => $item->produk->harga * $item->quantity,
|
||||
'foto' => $item->produk->foto_produk
|
||||
];
|
||||
});
|
||||
|
||||
$total_belanja = $items->sum('subtotal');
|
||||
|
||||
return view('landing.checkout', compact('items', 'total_belanja'));
|
||||
}
|
||||
|
||||
// fungsi prosesCheckout
|
||||
/**
|
||||
* Proses Pembuatan Transaksi
|
||||
* Mengelompokkan pesanan berdasarkan Petani dan membersihkan keranjang
|
||||
*/
|
||||
public function prosesCheckout(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
|
|
@ -70,9 +93,9 @@ public function prosesCheckout(Request $request)
|
|||
$pembeli_id = Auth::guard('pembeli')->id();
|
||||
|
||||
DB::transaction(function () use ($request, $pembeli_id) {
|
||||
|
||||
|
||||
if ($request->has('produk_id')) {
|
||||
// --- LOGIKA BELI LANGSUNG (Single Item) ---
|
||||
// --- LOGIKA BELI LANGSUNG ---
|
||||
$produk = Produk::findOrFail($request->produk_id);
|
||||
$total_harga = $produk->harga * $request->jumlah;
|
||||
|
||||
|
|
@ -97,65 +120,64 @@ public function prosesCheckout(Request $request)
|
|||
$produk->decrement('stok', $request->jumlah);
|
||||
|
||||
} else {
|
||||
// --- LOGIKA KERANJANG (Cart) ---
|
||||
$cart = session()->get('cart');
|
||||
|
||||
// Kelompokkan produk berdasarkan Petani ID
|
||||
$cartItems = [];
|
||||
foreach ($cart as $id => $details) {
|
||||
$produk = Produk::find($id);
|
||||
if ($produk) {
|
||||
$cartItems[$produk->petani_id][] = [
|
||||
'produk' => $produk,
|
||||
'qty' => $details['quantity']
|
||||
];
|
||||
}
|
||||
// --- LOGIKA KERANJANG (DATABASE) ---
|
||||
if (!$request->cart_ids) {
|
||||
throw new \Exception("ID keranjang tidak ditemukan.");
|
||||
}
|
||||
|
||||
foreach ($cartItems as $petani_id => $items) {
|
||||
$subtotal_transaksi = 0;
|
||||
$kode_invoice = 'INV/' . date('Ymd') . '/' . rand(1000, 9999);
|
||||
$cartIds = explode(',', $request->cart_ids);
|
||||
|
||||
$cartItems = Cart::with('produk')
|
||||
->whereIn('id', $cartIds)
|
||||
->where('pembeli_id', $pembeli_id)
|
||||
->get();
|
||||
|
||||
// Membuat Header Transaksi per Petani
|
||||
// Kelompokkan produk berdasarkan Petani ID agar Invoice terpisah per toko
|
||||
$groupedByPetani = [];
|
||||
foreach ($cartItems as $item) {
|
||||
$groupedByPetani[$item->produk->petani_id][] = $item;
|
||||
}
|
||||
|
||||
foreach ($groupedByPetani as $petani_id => $items) {
|
||||
$transaksi = Transaksi::create([
|
||||
'pembeli_id' => $pembeli_id,
|
||||
'petani_id' => $petani_id,
|
||||
'tanggal_transaksi' => now(),
|
||||
'alamat_pengiriman' => $request->alamat_pengiriman,
|
||||
'total_harga' => 0,
|
||||
'total_harga' => 0, // Diupdate setelah menghitung subtotal
|
||||
'status' => 'menunggu konfirmasi',
|
||||
'kode_invoice' => $kode_invoice,
|
||||
'kode_invoice' => 'INV/' . date('Ymd') . '/' . rand(1000, 9999),
|
||||
]);
|
||||
|
||||
$subtotal_transaksi = 0;
|
||||
foreach ($items as $item) {
|
||||
$produk = $item['produk'];
|
||||
$qty = $item['qty'];
|
||||
$total_per_item = $produk->harga * $qty;
|
||||
$total_per_item = $item->produk->harga * $item->quantity;
|
||||
$subtotal_transaksi += $total_per_item;
|
||||
|
||||
DetailTransaksi::create([
|
||||
'transaksi_id' => $transaksi->id,
|
||||
'produk_id' => $produk->id,
|
||||
'jumlah' => $qty,
|
||||
'harga_satuan' => $produk->harga,
|
||||
'produk_id' => $item->produk->id,
|
||||
'jumlah' => $item->quantity,
|
||||
'harga_satuan' => $item->produk->harga,
|
||||
'subtotal' => $total_per_item,
|
||||
]);
|
||||
|
||||
$produk->decrement('stok', $qty);
|
||||
$item->produk->decrement('stok', $item->quantity);
|
||||
}
|
||||
|
||||
// Update total harga transaksi
|
||||
// Update total harga transaksi per petani
|
||||
$transaksi->update(['total_harga' => $subtotal_transaksi]);
|
||||
}
|
||||
|
||||
session()->forget('cart');
|
||||
// OTOMATIS BERSIHKAN ITEM KERANJANG YANG SUDAH DIBELI
|
||||
Cart::whereIn('id', $cartIds)->delete();
|
||||
}
|
||||
});
|
||||
|
||||
return redirect()->route('pesanan.saya')->with('success', 'Pesanan berhasil dibuat! Menunggu konfirmasi petani.');
|
||||
return redirect()->route('pesanan.saya')->with('success', 'Pesanan berhasil dibuat! Silakan pantau status pesanan Anda.');
|
||||
}
|
||||
|
||||
// Riwayat Pesanan
|
||||
// Riwayat Pesanan Pembeli
|
||||
public function pesananSaya()
|
||||
{
|
||||
$transaksis = Transaksi::with(['detailTransaksis.produk.petani'])
|
||||
|
|
@ -172,11 +194,10 @@ public function konfirmasiSelesai($id)
|
|||
$transaksi = Transaksi::where('pembeli_id', Auth::guard('pembeli')->id())
|
||||
->findOrFail($id);
|
||||
|
||||
// Hanya bisa selesai jika status sebelumnya 'dikirim'
|
||||
if ($transaksi->status == 'dikirim') {
|
||||
$transaksi->status = 'selesai';
|
||||
$transaksi->save();
|
||||
return back()->with('success', 'Terima kasih! Pesanan telah diselesaikan.');
|
||||
return back()->with('success', 'Terima kasih! Pesanan telah selesai.');
|
||||
}
|
||||
|
||||
return back()->with('error', 'Pesanan belum dikirim atau sudah selesai.');
|
||||
|
|
@ -185,7 +206,7 @@ public function konfirmasiSelesai($id)
|
|||
|
||||
// --- FITUR PETANI ---
|
||||
|
||||
// Daftar Pesanan Masuk
|
||||
// Daftar Pesanan Masuk untuk Dashboard Petani
|
||||
public function pesananMasuk()
|
||||
{
|
||||
$petaniId = Auth::guard('petani')->id();
|
||||
|
|
@ -200,7 +221,7 @@ public function pesananMasuk()
|
|||
return view('petani.pesanan.index', compact('pesanans'));
|
||||
}
|
||||
|
||||
// Update Status (Terima/Tolak/Kirim)
|
||||
// Update Status Pesanan oleh Petani
|
||||
public function updateStatus(Request $request, $id)
|
||||
{
|
||||
$transaksi = Transaksi::findOrFail($id);
|
||||
|
|
@ -212,8 +233,9 @@ public function updateStatus(Request $request, $id)
|
|||
$transaksi->status = $request->status;
|
||||
$transaksi->save();
|
||||
|
||||
// Jika dibatalkan, kembalikan stok produk
|
||||
if ($request->status == 'batal') {
|
||||
foreach ($transaksi->details as $detail) {
|
||||
foreach ($transaksi->detailTransaksis as $detail) {
|
||||
$detail->produk->increment('stok', $detail->jumlah);
|
||||
}
|
||||
}
|
||||
|
|
@ -221,12 +243,11 @@ public function updateStatus(Request $request, $id)
|
|||
return back()->with('success', 'Status pesanan berhasil diperbarui.');
|
||||
}
|
||||
|
||||
// Detail Pesanan (Petani)
|
||||
// Detail Pesanan untuk Sisi Petani
|
||||
public function pesananDetail($id)
|
||||
{
|
||||
$petaniId = Auth::guard('petani')->id();
|
||||
|
||||
// Ambil transaksi berdasarkan ID
|
||||
$pesanan = Transaksi::whereHas('detailTransaksis.produk', function ($q) use ($petaniId) {
|
||||
$q->where('petani_id', $petaniId);
|
||||
})
|
||||
|
|
@ -235,4 +256,4 @@ public function pesananDetail($id)
|
|||
|
||||
return view('petani.pesanan.detail', compact('pesanan'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Laravolt\Indonesia\Models\City;
|
||||
use Laravolt\Indonesia\Models\District;
|
||||
use Laravolt\Indonesia\Models\Village;
|
||||
|
||||
class WilayahController extends Controller
|
||||
{
|
||||
public function getKota(Request $request)
|
||||
{
|
||||
$kota = City::where('province_code', $request->code)->get();
|
||||
return response()->json($kota);
|
||||
}
|
||||
|
||||
public function getKecamatan(Request $request)
|
||||
{
|
||||
$kecamatan = District::where('city_code', $request->code)->get();
|
||||
return response()->json($kecamatan);
|
||||
}
|
||||
|
||||
public function getDesa(Request $request)
|
||||
{
|
||||
$desa = Village::where('district_code', $request->code)->get();
|
||||
return response()->json($desa);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,11 @@ class Produk extends Model
|
|||
'harga',
|
||||
'stok',
|
||||
'deskripsi',
|
||||
'foto_produk'
|
||||
'foto_produk',
|
||||
'provinsi_code',
|
||||
'kota_code',
|
||||
'kecamatan_code',
|
||||
'desa_code',
|
||||
];
|
||||
|
||||
public function petani()
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@
|
|||
"require": {
|
||||
"php": "^8.2",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/tinker": "^2.10.1"
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"laravolt/indonesia": "^0.39.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.23",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c514d8f7b9fc5970bdd94287905ef584",
|
||||
"content-hash": "766a52f13bbfa552b799835b6f5f3e18",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brick/math",
|
||||
|
|
@ -1457,6 +1457,88 @@
|
|||
},
|
||||
"time": "2025-01-27T14:24:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravolt/indonesia",
|
||||
"version": "v0.39",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravolt/indonesia.git",
|
||||
"reference": "351e1c0e69b9415b0a56e03677fcfe0bbeca513a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravolt/indonesia/zipball/351e1c0e69b9415b0a56e03677fcfe0bbeca513a",
|
||||
"reference": "351e1c0e69b9415b0a56e03677fcfe0bbeca513a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/support": "^8.0|^9.0|^10.0|^11.0|^12.0",
|
||||
"php": "^7.3|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"orchestra/testbench": "^6.0|^7.0|^8.0|^9.0|^10.0",
|
||||
"php-coveralls/php-coveralls": "^2.1",
|
||||
"phpunit/phpunit": "^9.0|^10.5|^11.5.3"
|
||||
},
|
||||
"suggest": {
|
||||
"laravolt/suitable": "Required if you want to access editor panel",
|
||||
"spatie/geocoder": "Synchronize latitude longitude data directly using Google's Geocoding Service"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"Indonesia": "Laravolt\\Indonesia\\Facade"
|
||||
},
|
||||
"providers": [
|
||||
"Laravolt\\Indonesia\\ServiceProvider"
|
||||
]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravolt\\Indonesia\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Bayu Hendra Winata",
|
||||
"email": "bayu.hendra@javan.co.id"
|
||||
},
|
||||
{
|
||||
"name": "Akbar Adhatama",
|
||||
"email": "am.adhatama@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Deri Ramdani",
|
||||
"email": "deri.ramdani1@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Package Laravel yang berisi data Provinsi, Kabupaten/Kota, Kecamatan, dan Keluarahan/Desa di seluruh Indonesia.",
|
||||
"keywords": [
|
||||
"desa",
|
||||
"indonesia",
|
||||
"kabupaten",
|
||||
"kecamatan",
|
||||
"kelurahan",
|
||||
"kota",
|
||||
"laravel",
|
||||
"laravolt",
|
||||
"provinsi"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/laravolt/indonesia/issues",
|
||||
"source": "https://github.com/laravolt/indonesia/tree/v0.39"
|
||||
},
|
||||
"time": "2026-01-03T13:26:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/commonmark",
|
||||
"version": "2.7.1",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'table_prefix' => 'indonesia_',
|
||||
'route' => [
|
||||
'enabled' => false,
|
||||
'middleware' => ['web', 'auth'],
|
||||
'prefix' => 'indonesia',
|
||||
],
|
||||
'view' => [
|
||||
'layout' => 'ui::layouts.app',
|
||||
],
|
||||
'menu' => [
|
||||
'enabled' => false,
|
||||
],
|
||||
'cache' => [
|
||||
'ttl' => env('INDONESIA_CACHE_TTL', 3600),
|
||||
'prefix' => env('INDONESIA_CACHE_PREFIX', 'indonesia_service'),
|
||||
'store' => env('INDONESIA_CACHE_STORE', 'redis'),
|
||||
],
|
||||
'database' => [
|
||||
'connection' => env('INDONESIA_DB_CONNECTION', null),
|
||||
],
|
||||
];
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateProvincesTable extends Migration
|
||||
{
|
||||
protected function connection()
|
||||
{
|
||||
// New config (optional)
|
||||
return config('indonesia.database.connection')
|
||||
// Backward compatibility
|
||||
?? config('database.default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::connection($this->connection())->create(config('laravolt.indonesia.table_prefix').'provinces', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->char('code', 2)->unique();
|
||||
$table->string('name', 255);
|
||||
$table->text('meta')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop(config('laravolt.indonesia.table_prefix').'provinces');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateCitiesTable extends Migration
|
||||
{
|
||||
protected function connection()
|
||||
{
|
||||
// New config (optional)
|
||||
return config('indonesia.database.connection')
|
||||
// Backward compatibility
|
||||
?? config('database.default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::connection($this->connection())->create(config('laravolt.indonesia.table_prefix').'cities', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->char('code', 4)->unique();
|
||||
$table->char('province_code', 2);
|
||||
$table->string('name', 255);
|
||||
$table->text('meta')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('province_code')
|
||||
->references('code')
|
||||
->on(config('laravolt.indonesia.table_prefix').'provinces')
|
||||
->onUpdate('cascade')->onDelete('restrict');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop(config('laravolt.indonesia.table_prefix').'cities');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateDistrictsTable extends Migration
|
||||
{
|
||||
protected function connection()
|
||||
{
|
||||
// New config (optional)
|
||||
return config('indonesia.database.connection')
|
||||
// Backward compatibility
|
||||
?? config('database.default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::connection($this->connection())->create(config('laravolt.indonesia.table_prefix').'districts', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->char('code', 7)->unique();
|
||||
$table->char('city_code', 4);
|
||||
$table->string('name', 255);
|
||||
$table->text('meta')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('city_code')
|
||||
->references('code')
|
||||
->on(config('laravolt.indonesia.table_prefix').'cities')
|
||||
->onUpdate('cascade')->onDelete('restrict');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop(config('laravolt.indonesia.table_prefix').'districts');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateVillagesTable extends Migration
|
||||
{
|
||||
protected function connection()
|
||||
{
|
||||
// New config (optional)
|
||||
return config('indonesia.database.connection')
|
||||
// Backward compatibility
|
||||
?? config('database.default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::connection($this->connection())->create(config('laravolt.indonesia.table_prefix').'villages', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->char('code', 10)->unique();
|
||||
$table->char('district_code', 7);
|
||||
$table->string('name', 255);
|
||||
$table->text('meta')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('district_code')
|
||||
->references('code')
|
||||
->on(config('laravolt.indonesia.table_prefix').'districts')
|
||||
->onUpdate('cascade')->onDelete('restrict');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop(config('laravolt.indonesia.table_prefix').'villages');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('produks', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('produks', 'lokasi')) {
|
||||
$table->dropColumn('lokasi');
|
||||
}
|
||||
|
||||
$table->char('provinsi_code', 2)->nullable()->after('deskripsi');
|
||||
$table->char('kota_code', 4)->nullable()->after('provinsi_code');
|
||||
$table->char('kecamatan_code', 7)->nullable()->after('kota_code');
|
||||
$table->char('desa_code', 10)->nullable()->after('kecamatan_code');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('produks', function (Blueprint $table) {
|
||||
$table->dropColumn(['provinsi_code', 'kota_code', 'kecamatan_code', 'desa_code']);
|
||||
$table->string('lokasi')->nullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -69,7 +69,7 @@ public function run(): void
|
|||
'kode_invoice' => 'INV-' . $tahunIni . '03-003',
|
||||
'pembeli_id' => 1,
|
||||
'petani_id' => 1,
|
||||
'tanggal_transaksi' => Carbon::create($tahunIni, 3, 5, 9, 15, 0),
|
||||
'tanggal_transaksi' => Carbon::create($tahunIni, 1, 5, 9, 15, 0),
|
||||
'alamat_pengiriman' => 'Perumahan Indah Blok C2, Surabaya',
|
||||
'total_harga' => 150000,
|
||||
'status' => 'selesai',
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
|
@ -79,6 +79,7 @@
|
|||
<a href="{{ route('cart') }}"
|
||||
class="btn btn-outline-secondary py-2 rounded-pill">Kembali</a>
|
||||
</div>
|
||||
<input type="hidden" name="cart_ids" value="{{ request('cart_ids') }}">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,45 +4,39 @@
|
|||
|
||||
@section('content')
|
||||
|
||||
<div class="container-fluid mb-5 bg-white">
|
||||
<div class="container">
|
||||
<div class="row align-items-center g-5 py-5">
|
||||
<div class="col-lg-6 order-2 order-lg-1">
|
||||
<div class="d-inline-block border border-secondary text-secondary rounded-pill px-3 py-2 mb-3 fw-bold">
|
||||
🌾 Mitra Petani Padi Indonesia
|
||||
</div>
|
||||
<h1 class="display-4 fw-bold text-dark mb-4">
|
||||
Pusat Jual Beli <br>
|
||||
<span class="text-tani">Gabah Panen Raya.</span>
|
||||
</h1>
|
||||
<p class="lead text-muted mb-5">
|
||||
Platform langsung yang menghubungkan petani padi lokal dengan pembeli.
|
||||
Dapatkan harga gabah terbaik dan gabah berkualitas.
|
||||
</p>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="{{ route('shop') }}" class="btn btn-primary border-0 rounded-pill py-3 px-5 shadow">
|
||||
<i class="fas fa-shopping-bag me-2"></i> Belanja
|
||||
</a>
|
||||
<a href="#katalog" class="btn btn-outline-secondary rounded-pill py-3 px-5">
|
||||
Lihat Stok
|
||||
</a>
|
||||
</div>
|
||||
<div class="container-fluid mb-5 bg-white">
|
||||
<div class="container">
|
||||
<div class="row align-items-center g-5 py-5">
|
||||
<div class="col-lg-6 order-2 order-lg-1">
|
||||
<div class="d-inline-block border border-secondary text-secondary rounded-pill px-3 py-2 mb-3 fw-bold">
|
||||
🌾 Mitra Petani Padi Indonesia
|
||||
</div>
|
||||
<div class="col-lg-6 order-1 order-lg-2 text-center">
|
||||
<div class="position-relative d-inline-block">
|
||||
<img src="{{ asset('images/banner.jpg') }}" class="img-fluid rounded-circle shadow-lg w-100"
|
||||
style="max-height: 450px; object-fit: cover;" alt="Padi Premium">
|
||||
<div class="position-absolute bg-white p-3 rounded-3 shadow d-none d-md-block"
|
||||
style="bottom: 30px; left: -30px;">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="bg-primary text-white rounded-circle p-2 d-flex align-items-center justify-content-center"
|
||||
style="width: 40px; height: 40px;">
|
||||
<i class="fas fa-check"></i>
|
||||
</div>
|
||||
<div class="text-start">
|
||||
<h6 class="mb-0 fw-bold">100% Panen Baru</h6>
|
||||
<small class="text-muted">Kualitas Terjamin</small>
|
||||
</div>
|
||||
<h1 class="display-4 fw-bold text-dark mb-4">
|
||||
Pusat Jual Beli <br>
|
||||
<span class="text-tani">Gabah Panen Raya.</span>
|
||||
</h1>
|
||||
<p class="lead text-muted mb-5">
|
||||
Platform langsung yang menghubungkan petani padi lokal dengan pembeli.
|
||||
Dapatkan harga gabah terbaik dan gabah berkualitas.
|
||||
</p>
|
||||
<a href="{{ route('shop') }}" class="btn btn-primary border-0 rounded-pill py-3 px-5 shadow">
|
||||
<i class="fas fa-shopping-bag me-2"></i> Belanja
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-lg-6 order-1 order-lg-2 text-center">
|
||||
<div class="position-relative d-inline-block">
|
||||
<img src="{{ asset('images/banner.jpg') }}" class="img-fluid rounded-circle shadow-lg w-100"
|
||||
style="max-height: 450px; object-fit: cover;" alt="Padi Premium">
|
||||
<div class="position-absolute bg-white p-3 rounded-3 shadow d-none d-md-block"
|
||||
style="bottom: 30px; left: -30px;">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="bg-primary text-white rounded-circle p-2 d-flex align-items-center justify-content-center"
|
||||
style="width: 40px; height: 40px;">
|
||||
<i class="fas fa-check"></i>
|
||||
</div>
|
||||
<div class="text-start">
|
||||
<h6 class="mb-0 fw-bold">100% Panen Baru</h6>
|
||||
<small class="text-muted">Kualitas Terjamin</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -50,197 +44,198 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container py-5">
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="h-100 p-4 text-center bg-white border rounded-4 shadow-sm">
|
||||
<div class="d-inline-flex align-items-center justify-content-center bg-secondary text-white rounded-circle mb-4"
|
||||
style="width: 70px; height: 70px;">
|
||||
<i class="fas fa-truck fa-2x"></i>
|
||||
</div>
|
||||
<h5 class="fw-bold mb-3">Siap Antar</h5>
|
||||
<p class="mb-0 text-muted">Armada pickup siap kirim langsung ke lokasi Anda.</p>
|
||||
<div class="container py-5">
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="h-100 p-4 text-center bg-white border rounded-4 shadow-sm">
|
||||
<div class="d-inline-flex align-items-center justify-content-center bg-secondary text-white rounded-circle mb-4"
|
||||
style="width: 70px; height: 70px;">
|
||||
<i class="fas fa-truck fa-2x"></i>
|
||||
</div>
|
||||
<h5 class="fw-bold mb-3">Siap Antar</h5>
|
||||
<p class="mb-0 text-muted">Armada pickup siap kirim langsung ke lokasi Anda.</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="h-100 p-4 text-center bg-white border rounded-4 shadow-sm">
|
||||
<div class="d-inline-flex align-items-center justify-content-center bg-secondary text-white rounded-circle mb-4"
|
||||
style="width: 70px; height: 70px;">
|
||||
<i class="fas fa-hand-holding-usd fa-2x"></i>
|
||||
</div>
|
||||
<h5 class="fw-bold mb-3">Harga Petani</h5>
|
||||
<p class="mb-0 text-muted">Harga tangan pertama langsung tanpa tengkulak.</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="h-100 p-4 text-center bg-white border rounded-4 shadow-sm">
|
||||
<div class="d-inline-flex align-items-center justify-content-center bg-secondary text-white rounded-circle mb-4"
|
||||
style="width: 70px; height: 70px;">
|
||||
<i class="fas fa-hand-holding-usd fa-2x"></i>
|
||||
</div>
|
||||
<h5 class="fw-bold mb-3">Harga Petani</h5>
|
||||
<p class="mb-0 text-muted">Harga tangan pertama langsung tanpa tengkulak.</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="h-100 p-4 text-center bg-white border rounded-4 shadow-sm">
|
||||
<div class="d-inline-flex align-items-center justify-content-center bg-secondary text-white rounded-circle mb-4"
|
||||
style="width: 70px; height: 70px;">
|
||||
<i class="fas fa-certificate fa-2x"></i>
|
||||
</div>
|
||||
<h5 class="fw-bold mb-3">Kualitas Super</h5>
|
||||
<p class="mb-0 text-muted">Jaminan padi berkualitas, bulir utuh, bersih, dan bebas campuran.</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="h-100 p-4 text-center bg-white border rounded-4 shadow-sm">
|
||||
<div class="d-inline-flex align-items-center justify-content-center bg-secondary text-white rounded-circle mb-4"
|
||||
style="width: 70px; height: 70px;">
|
||||
<i class="fas fa-certificate fa-2x"></i>
|
||||
</div>
|
||||
<h5 class="fw-bold mb-3">Kualitas Super</h5>
|
||||
<p class="mb-0 text-muted">Jaminan padi berkualitas, bulir utuh, bersih, dan bebas campuran.</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="h-100 p-4 text-center bg-white border rounded-4 shadow-sm">
|
||||
<div class="d-inline-flex align-items-center justify-content-center bg-secondary text-white rounded-circle mb-4"
|
||||
style="width: 70px; height: 70px;">
|
||||
<i class="fas fa-shield-alt fa-2x"></i>
|
||||
</div>
|
||||
<h5 class="fw-bold mb-3">Transaksi Aman</h5>
|
||||
<p class="mb-0 text-muted">Pembayaran fleksibel, bisa transfer atau COD.</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="h-100 p-4 text-center bg-white border rounded-4 shadow-sm">
|
||||
<div class="d-inline-flex align-items-center justify-content-center bg-secondary text-white rounded-circle mb-4"
|
||||
style="width: 70px; height: 70px;">
|
||||
<i class="fas fa-shield-alt fa-2x"></i>
|
||||
</div>
|
||||
<h5 class="fw-bold mb-3">Transaksi Aman</h5>
|
||||
<p class="mb-0 text-muted">Pembayaran fleksibel, bisa transfer atau COD.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Produk terlaris --}}
|
||||
<div class="container py-5">
|
||||
<div class="text-center mx-auto mb-5" style="max-width: 700px;">
|
||||
<h1 class="display-6 fw-bold">Produk Terlaris</h1>
|
||||
<p class="text-muted">Pilihan favorit pelanggan kami minggu ini.</p>
|
||||
</div>
|
||||
<div class="row g-4">
|
||||
{{-- Produk terlaris --}}
|
||||
<div class="container py-5">
|
||||
<div class="text-center mx-auto mb-5" style="max-width: 700px;">
|
||||
<h1 class="display-6 fw-bold">Produk Terlaris</h1>
|
||||
<p class="text-muted">Pilihan favorit pelanggan kami minggu ini.</p>
|
||||
</div>
|
||||
<div class="row g-4">
|
||||
|
||||
@forelse($produkTerlaris as $item)
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="rounded position-relative border border-secondary shadow-sm overflow-hidden h-100">
|
||||
<div class="fruit-img">
|
||||
<img src="{{ $item->foto_produk ? asset('storage/' . $item->foto_produk) : asset('template/frontend/img/fruite-item-5.jpg') }}"
|
||||
class="img-fluid w-100" style="height: 200px; object-fit: cover;"
|
||||
alt="{{ $item->nama_produk }}">
|
||||
</div>
|
||||
@forelse($produkTerlaris as $item)
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="rounded position-relative border border-secondary shadow-sm overflow-hidden h-100">
|
||||
<div class="fruit-img">
|
||||
<img src="{{ $item->foto_produk ? asset('storage/' . $item->foto_produk) : asset('template/frontend/img/fruite-item-5.jpg') }}"
|
||||
class="img-fluid w-100" style="height: 200px; object-fit: cover;"
|
||||
alt="{{ $item->nama_produk }}">
|
||||
</div>
|
||||
|
||||
<div class="text-white bg-danger px-3 py-1 rounded position-absolute" style="top: 10px; left: 10px;">
|
||||
Terjual {{ $item->total_terjual ?? 0 }}
|
||||
</div>
|
||||
<div class="text-white bg-danger px-3 py-1 rounded position-absolute" style="top: 10px; left: 10px;">
|
||||
Terjual {{ $item->total_terjual ?? 0 }}
|
||||
</div>
|
||||
|
||||
<div class="p-4 border-top border-secondary bg-white d-flex flex-column"
|
||||
style="height: calc(100% - 200px);">
|
||||
<h4>{{ $item->nama_produk }}</h4>
|
||||
<p class="text-muted small mb-2 flex-grow-1">
|
||||
{{ Str::limit($item->deskripsi, 50) }}
|
||||
<div class="p-4 border-top border-secondary bg-white d-flex flex-column"
|
||||
style="height: calc(100% - 200px);">
|
||||
<h4>{{ $item->nama_produk }}</h4>
|
||||
<p class="text-muted small mb-2 flex-grow-1">
|
||||
{{ Str::limit($item->deskripsi, 50) }}
|
||||
</p>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<div>
|
||||
<p class="text-dark fs-5 fw-bold mb-0">Rp {{ number_format($item->harga, 0, ',', '.') }}
|
||||
</p>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<div>
|
||||
<p class="text-dark fs-5 fw-bold mb-0">Rp {{ number_format($item->harga, 0, ',', '.') }}
|
||||
</p>
|
||||
<small class="text-muted">/ kg</small>
|
||||
</div>
|
||||
<a href="{{ route('produk.detail', $item->id) }}"
|
||||
class="btn btn-outline-primary rounded-pill px-3">
|
||||
<i class="fa fa-shopping-bag"></i>
|
||||
</a>
|
||||
</div>
|
||||
<small class="text-muted">/ kg</small>
|
||||
</div>
|
||||
<a href="{{ route('produk.detail', $item->id) }}"
|
||||
class="btn btn-outline-primary rounded-pill px-3">
|
||||
<i class="fa fa-shopping-bag"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="col-12 text-center">
|
||||
<p class="text-muted">Belum ada data penjualan.</p>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="col-12 text-center">
|
||||
<p class="text-muted">Belum ada data penjualan.</p>
|
||||
</div>
|
||||
@endforelse
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid py-5 bg-light">
|
||||
<div class="container">
|
||||
<div class="row g-5">
|
||||
<div class="col-md-6 col-lg-3 text-center">
|
||||
<i class="fas fa-users fa-3x text-primary mb-3"></i>
|
||||
<h2 class="fw-bold mb-0 text-secondary" data-toggle="counter-up">150+</h2>
|
||||
<p class="mb-0 text-muted text-uppercase fw-bold">Petani Mitra</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 text-center">
|
||||
<i class="fas fa-shopping-cart fa-3x text-primary mb-3"></i>
|
||||
<h2 class="fw-bold mb-0 text-secondary" data-toggle="counter-up">2,500+</h2>
|
||||
<p class="mb-0 text-muted text-uppercase fw-bold">Transaksi</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 text-center">
|
||||
<i class="fas fa-star fa-3x text-primary mb-3"></i>
|
||||
<h2 class="fw-bold mb-0 text-secondary" data-toggle="counter-up">4.8</h2>
|
||||
<p class="mb-0 text-muted text-uppercase fw-bold">Rating Rata-rata</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 text-center">
|
||||
<i class="fas fa-check-circle fa-3x text-primary mb-3"></i>
|
||||
<h2 class="fw-bold mb-0 text-secondary" data-toggle="counter-up">100%</h2>
|
||||
<p class="mb-0 text-muted text-uppercase fw-bold">Garansi Kualitas</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid py-5 bg-light">
|
||||
<div class="container">
|
||||
<div class="row g-5">
|
||||
<div class="col-md-6 col-lg-3 text-center">
|
||||
<i class="fas fa-users fa-3x text-primary mb-3"></i>
|
||||
<h2 class="fw-bold mb-0 text-secondary" data-toggle="counter-up">150+</h2>
|
||||
<p class="mb-0 text-muted text-uppercase fw-bold">Petani Mitra</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 text-center">
|
||||
<i class="fas fa-shopping-cart fa-3x text-primary mb-3"></i>
|
||||
<h2 class="fw-bold mb-0 text-secondary" data-toggle="counter-up">2,500+</h2>
|
||||
<p class="mb-0 text-muted text-uppercase fw-bold">Transaksi</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 text-center">
|
||||
<i class="fas fa-star fa-3x text-primary mb-3"></i>
|
||||
<h2 class="fw-bold mb-0 text-secondary" data-toggle="counter-up">4.8</h2>
|
||||
<p class="mb-0 text-muted text-uppercase fw-bold">Rating Rata-rata</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 text-center">
|
||||
<i class="fas fa-check-circle fa-3x text-primary mb-3"></i>
|
||||
<h2 class="fw-bold mb-0 text-secondary" data-toggle="counter-up">100%</h2>
|
||||
<p class="mb-0 text-muted text-uppercase fw-bold">Garansi Kualitas</p>
|
||||
</div>
|
||||
{{-- Katalog --}}
|
||||
<div class="container py-5" id="katalog">
|
||||
<div class="text-center mx-auto mb-5" style="max-width: 700px;">
|
||||
<h2 class="fw-bold display-6 text-dark">Stok Gudang Kami</h2>
|
||||
<p class="text-muted">Pilih varietas gabah yang Anda butuhkan hari ini.</p>
|
||||
</div>
|
||||
|
||||
@php
|
||||
$kategoriList = \App\Models\Kategori::all();
|
||||
@endphp
|
||||
|
||||
<div class="row justify-content-center mb-5">
|
||||
<div class="col-12 text-center">
|
||||
<div class="d-flex justify-content-center flex-wrap gap-2">
|
||||
<a href="#" data-kategori="Semua"
|
||||
class="btn {{ request('kategori') == '' || request('kategori') == 'Semua' ? 'btn-primary' : 'btn-outline-primary' }} rounded-pill px-4 py-2 m-1 btn-category">
|
||||
Semua
|
||||
</a>
|
||||
|
||||
{{-- 2. Looping Kategori dari Database --}}
|
||||
@foreach($kategoriList as $kat)
|
||||
<a href="#" data-kategori="{{ $kat->slug }}"
|
||||
class="btn {{ request('kategori') == $kat->slug ? 'btn-primary' : 'btn-outline-primary' }} rounded-pill px-4 py-2 m-1 btn-category">
|
||||
<span>{{ $kat->nama_kategori }}</span>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Katalog --}}
|
||||
<div class="container py-5" id="katalog">
|
||||
<div class="text-center mx-auto mb-5" style="max-width: 700px;">
|
||||
<h2 class="fw-bold display-6 text-dark">Stok Gudang Kami</h2>
|
||||
<p class="text-muted">Pilih varietas gabah yang Anda butuhkan hari ini.</p>
|
||||
</div>
|
||||
|
||||
@php
|
||||
$kategoriList = \App\Models\Kategori::all();
|
||||
@endphp
|
||||
|
||||
<div class="row justify-content-center mb-5">
|
||||
<div class="col-12 text-center">
|
||||
<div class="d-flex justify-content-center flex-wrap gap-2">
|
||||
<a href="#" data-kategori="Semua"
|
||||
class="btn {{ request('kategori') == '' || request('kategori') == 'Semua' ? 'btn-primary' : 'btn-outline-primary' }} rounded-pill px-4 py-2 m-1 btn-category">
|
||||
Semua
|
||||
</a>
|
||||
|
||||
{{-- 2. Looping Kategori dari Database --}}
|
||||
@foreach($kategoriList as $kat)
|
||||
<a href="#" data-kategori="{{ $kat->slug }}"
|
||||
class="btn {{ request('kategori') == $kat->slug ? 'btn-primary' : 'btn-outline-primary' }} rounded-pill px-4 py-2 m-1 btn-category">
|
||||
<span>{{ $kat->nama_kategori }}</span>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4" id="product-container">
|
||||
@include('landing.partials.product_list')
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-5">
|
||||
<a href="{{ route('shop') }}" class="btn btn-primary border-0 rounded-pill px-5 py-3 shadow">
|
||||
Lihat Semua Produk
|
||||
</a>
|
||||
</div>
|
||||
<div class="row g-4" id="product-container">
|
||||
@include('landing.partials.product_list')
|
||||
</div>
|
||||
|
||||
{{-- Banner --}}
|
||||
<div class="container-fluid bg-primary py-5 mt-5">
|
||||
<div class="container py-5">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-8 text-center text-lg-start mb-4 mb-lg-0">
|
||||
<h2 class="display-5 fw-bold text-white mb-3">Butuh Suplai Besar?</h2>
|
||||
<p class="fs-5 text-white mb-4 opacity-75">
|
||||
Kami melayani kerjasama untuk penggilingan padi, restoran, dan toko
|
||||
kelontong dengan harga grosir spesial.
|
||||
</p>
|
||||
<a href="https://wa.me/6281234567890" target="_blank"
|
||||
class="btn btn-light rounded-pill px-5 py-3 text-success fw-bold shadow">
|
||||
<i class="fab fa-whatsapp me-2"></i> Hubungi Kami
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-lg-4 text-center">
|
||||
<i class="fas fa-warehouse text-white opacity-25" style="font-size: 10rem;"></i>
|
||||
</div>
|
||||
<div class="text-center mt-5">
|
||||
<a href="{{ route('shop') }}" class="btn btn-primary border-0 rounded-pill px-5 py-3 shadow">
|
||||
Lihat Semua Produk
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Banner --}}
|
||||
<div class="container-fluid bg-primary py-5 mt-5">
|
||||
<div class="container py-5">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-8 text-center text-lg-start mb-4 mb-lg-0">
|
||||
<h2 class="display-5 fw-bold text-white mb-3">Butuh Suplai Besar?</h2>
|
||||
<p class="fs-5 text-white mb-4 opacity-75">
|
||||
Kami melayani kerjasama untuk penggilingan padi, restoran, dan toko
|
||||
kelontong dengan harga grosir spesial.
|
||||
</p>
|
||||
<a href="https://wa.me/6281234567890" target="_blank"
|
||||
class="btn btn-light rounded-pill px-5 py-3 text-success fw-bold shadow">
|
||||
<i class="fab fa-whatsapp me-2"></i> Hubungi Kami
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-lg-4 text-center">
|
||||
<i class="fas fa-warehouse text-white opacity-25" style="font-size: 10rem;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('js')
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.btn-category').click(function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
|
|
@ -275,5 +270,5 @@ class="btn btn-light rounded-pill px-5 py-3 text-success fw-bold shadow">
|
|||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -5,17 +5,18 @@
|
|||
<style>
|
||||
/* Layout Utama Chat */
|
||||
.chat-layout {
|
||||
height: 60vh;
|
||||
height: 60vh;
|
||||
background-color: #fff;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* --- Sidebar Kiri --- */
|
||||
.chat-sidebar {
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
border-right: 1px solid #dee2e6;
|
||||
border-right: 1px solid #dee2e6;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
|
@ -40,8 +41,8 @@
|
|||
}
|
||||
|
||||
.chat-item:hover {
|
||||
background-color: #f9fdf0;
|
||||
border-left: 4px solid #81c408;
|
||||
background-color: #f9fdf0;
|
||||
border-left: 4px solid #81c408;
|
||||
}
|
||||
|
||||
/* --- Area Kanan --- */
|
||||
|
|
@ -56,74 +57,92 @@
|
|||
}
|
||||
|
||||
/* Custom Scrollbar */
|
||||
::-webkit-scrollbar { width: 5px; }
|
||||
::-webkit-scrollbar-track { background: transparent; }
|
||||
::-webkit-scrollbar-thumb { background: #ccc; border-radius: 10px; }
|
||||
::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #ccc;
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container py-5">
|
||||
<h2 class="mb-4 fw-bold text-dark">Pesan Saya</h2>
|
||||
<div class="container py-5">
|
||||
<h2 class="mb-4 fw-bold text-dark">Pesan Saya</h2>
|
||||
|
||||
{{-- Container Utama --}}
|
||||
<div class="row g-0 chat-layout shadow-sm">
|
||||
|
||||
{{-- KOLOM KIRI: DAFTAR PESAN --}}
|
||||
<div class="col-md-4 chat-sidebar">
|
||||
<div class="sidebar-header">
|
||||
<input type="text" class="form-control bg-light border-0 rounded-pill px-3" placeholder="Cari pesan...">
|
||||
</div>
|
||||
{{-- Container Utama --}}
|
||||
<div class="row g-0 chat-layout shadow-sm">
|
||||
|
||||
<div class="chat-list-container">
|
||||
<div class="list-group list-group-flush">
|
||||
@forelse($chatList as $chat)
|
||||
<a href="{{ route('pembeli.pesan.show', $chat['lawan_id']) }}"
|
||||
class="list-group-item list-group-item-action chat-item py-3 border-0">
|
||||
<div class="d-flex align-items-center">
|
||||
{{-- Avatar --}}
|
||||
<div class="position-relative">
|
||||
<img src="{{ asset('template/frontend/img/avatar.jpg') }}" class="rounded-circle shadow-sm"
|
||||
width="50" height="50" style="object-fit: cover;">
|
||||
@if ($chat['unread'] > 0)
|
||||
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger border border-white">
|
||||
{{ $chat['unread'] }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Info Pesan --}}
|
||||
<div class="ms-3 flex-grow-1 overflow-hidden">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<h6 class="mb-0 text-dark fw-bold text-truncate">{{ $chat['nama'] }}</h6>
|
||||
<small class="text-muted" style="font-size: 0.75rem;">{{ $chat['time'] }}</small>
|
||||
</div>
|
||||
<p class="mb-0 text-muted text-truncate small">
|
||||
{{ Str::limit($chat['last_message'], 35) }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@empty
|
||||
<div class="text-center py-5 px-3">
|
||||
<i class="far fa-comment-dots fa-3x text-muted mb-3 opacity-50"></i>
|
||||
<p class="text-muted small">Belum ada percakapan.</p>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
{{-- KOLOM KIRI: DAFTAR PESAN --}}
|
||||
<div class="col-md-4 chat-sidebar">
|
||||
{{-- Header Sidebar --}}
|
||||
<div class="p-3 border-bottom">
|
||||
<h6 class="fw-bold text-dark mb-3">Pesan Masuk</h6>
|
||||
<input type="text" class="form-control bg-light border-0 rounded-pill px-3"
|
||||
placeholder="Cari percakapan...">
|
||||
</div>
|
||||
|
||||
{{-- KOLOM KANAN: PLACEHOLDER --}}
|
||||
<div class="col-md-8 d-none d-md-flex chat-placeholder">
|
||||
<div class="text-center">
|
||||
<div class="bg-white p-4 rounded-circle shadow-sm d-inline-block mb-3">
|
||||
<i class="fas fa-comments fa-4x text-success"></i>
|
||||
{{-- List Chat --}}
|
||||
<div class="flex-grow-1 overflow-auto">
|
||||
@forelse ($chatList as $chat)
|
||||
<a href="{{ route('pembeli.pesan.show', $chat['lawan_id']) }}"
|
||||
class="d-flex align-items-center p-3 text-decoration-none text-dark chat-item">
|
||||
|
||||
<div class="position-relative">
|
||||
<img src="{{ asset('template/frontend/img/avatar.jpg') }}" class="rounded-circle shadow-sm"
|
||||
width="45" height="45" style="object-fit: cover;">
|
||||
|
||||
{{-- Badge Merah Notifikasi --}}
|
||||
@if($chat['unread'] > 0)
|
||||
<span
|
||||
class="position-absolute top-0 start-100 translate-middle p-1 bg-danger border border-light rounded-circle"></span>
|
||||
@endif
|
||||
</div>
|
||||
<h5 class="fw-bold text-dark">Selamat Datang di Chat</h5>
|
||||
<p class="small">Pilih salah satu percakapan di sebelah kiri<br>untuk mulai berdiskusi dengan Petani.</p>
|
||||
|
||||
<div class="ms-3 flex-grow-1 overflow-hidden">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="fw-bold small">{{ $chat['nama'] }}</span>
|
||||
<span class="text-muted" style="font-size: 0.7rem;">{{ $chat['time'] }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mt-1">
|
||||
<p class="mb-0 text-muted small text-truncate" style="max-width: 85%;">
|
||||
{{ Str::limit($chat['last_message'], 25) }}
|
||||
</p>
|
||||
|
||||
{{-- Angka Merah Notifikasi --}}
|
||||
@if($chat['unread'] > 0)
|
||||
<span class="badge bg-danger rounded-pill" style="font-size: 0.6rem;">{{ $chat['unread']
|
||||
}}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@empty
|
||||
<div class="text-center py-5 px-3">
|
||||
<i class="far fa-comment-dots fa-3x text-muted mb-3 opacity-50"></i>
|
||||
<p class="text-muted small">Belum ada percakapan.</p>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- KOLOM KANAN: PLACEHOLDER --}}
|
||||
<div class="col-md-8 d-none d-md-flex chat-placeholder">
|
||||
<div class="text-center">
|
||||
<div class="bg-white p-4 rounded-circle shadow-sm d-inline-block mb-3">
|
||||
<i class="fas fa-comments fa-4x text-success"></i>
|
||||
</div>
|
||||
<h5 class="fw-bold text-dark">Selamat Datang di Chat</h5>
|
||||
<p class="small">Pilih salah satu percakapan di sebelah kiri<br>untuk mulai berdiskusi dengan Petani.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -107,6 +107,7 @@
|
|||
|
||||
@section('content')
|
||||
<div class="container py-5">
|
||||
<h2 class="mb-4 fw-bold text-dark">Pesan Saya</h2>
|
||||
<div class="row g-0 chat-layout shadow-lg">
|
||||
|
||||
{{-- SIDEBAR KIRI --}}
|
||||
|
|
|
|||
|
|
@ -3,186 +3,268 @@
|
|||
@section('title', 'Belanja Padi & Beras')
|
||||
|
||||
@section('content')
|
||||
{{-- Header Halaman --}}
|
||||
<div class="container-fluid py-5 bg-light border-bottom mb-5">
|
||||
<div class="container text-center">
|
||||
<h1 class="display-5 fw-bold text-dark mb-3">Belanja Produk Kami</h1>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb justify-content-center mb-0">
|
||||
<li class="breadcrumb-item"><a href="{{ route('home') }}" class="text-decoration-none">Home</a></li>
|
||||
<li class="breadcrumb-item active text-muted">Shop</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
{{-- Header Halaman --}}
|
||||
<div class="container-fluid py-5 bg-light border-bottom mb-5">
|
||||
<div class="container text-center">
|
||||
<h1 class="display-5 fw-bold text-dark mb-3">Belanja Produk Kami</h1>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb justify-content-center mb-0">
|
||||
<li class="breadcrumb-item"><a href="{{ route('home') }}" class="text-decoration-none">Home</a></li>
|
||||
<li class="breadcrumb-item active text-muted">Shop</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Konten Utama --}}
|
||||
<div class="container pb-5">
|
||||
<div class="row g-4">
|
||||
{{-- Konten Utama --}}
|
||||
<div class="container pb-5">
|
||||
<div class="row g-4">
|
||||
|
||||
{{-- SIDEBAR FILTER --}}
|
||||
<div class="col-lg-3">
|
||||
{{-- SIDEBAR FILTER --}}
|
||||
<div class="col-lg-3">
|
||||
|
||||
{{-- Card Kategori --}}
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
<div class="card-body p-4">
|
||||
<h6 class="fw-bold mb-3 text-uppercase small text-muted">Kategori</h6>
|
||||
<div class="d-flex flex-column gap-2">
|
||||
|
||||
@php
|
||||
$kategoriList = \App\Models\Kategori::all();
|
||||
$currentKat = request('kategori');
|
||||
@endphp
|
||||
|
||||
{{-- Tombol Semua Kategori --}}
|
||||
<a href="{{ route('shop', array_merge(request()->query(), ['kategori' => null])) }}"
|
||||
class="d-flex justify-content-between align-items-center text-decoration-none {{ !$currentKat ? 'fw-bold text-primary' : 'text-secondary' }}">
|
||||
<span>Semua Kategori</span>
|
||||
</a>
|
||||
|
||||
{{-- Looping Kategori Database --}}
|
||||
@foreach($kategoriList as $kat)
|
||||
<a href="{{ route('shop', array_merge(request()->query(), ['kategori' => $kat->slug])) }}"
|
||||
class="d-flex justify-content-between align-items-center text-decoration-none {{ $currentKat == $kat->slug ? 'fw-bold text-primary' : 'text-secondary' }}">
|
||||
|
||||
<span>{{ $kat->nama_kategori }}</span>
|
||||
|
||||
@if($currentKat == $kat->slug)
|
||||
<i class="fas fa-check small"></i>
|
||||
@endif
|
||||
</a>
|
||||
@endforeach
|
||||
{{-- Filter Wilayah Lengkap--}}
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
<div class="card-body p-4">
|
||||
<h6 class="fw-bold mb-3 text-uppercase small text-muted">Filter Wilayah Lengkap</h6>
|
||||
<form action="{{ route('shop') }}" method="GET">
|
||||
@foreach(request()->only(['search', 'kategori', 'sort']) as $key => $val)
|
||||
<input type="hidden" name="{{ $key }}" value="{{ $val }}">
|
||||
@endforeach
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="small fw-bold">Provinsi</label>
|
||||
<select name="provinsi" id="filter_provinsi" class="form-select form-select-sm">
|
||||
<option value="">Semua Provinsi</option>
|
||||
@foreach(\Laravolt\Indonesia\Models\Province::all() as $prov)
|
||||
<option value="{{ $prov->code }}" {{ request('provinsi')==$prov->code ? 'selected' : ''
|
||||
}}>{{ $prov->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Banner Info Kecil --}}
|
||||
<div class="card border-0 shadow-sm bg-primary text-white">
|
||||
<div class="card-body p-4">
|
||||
<h5 class="fw-bold mb-2"><i class="fas fa-leaf me-2"></i>Produk Segar</h5>
|
||||
<p class="small mb-0 opacity-75">Semua produk kami diambil langsung dari petani lokal terpercaya.
|
||||
</p>
|
||||
<div class="mb-2">
|
||||
<label class="small fw-bold">Kota/Kabupaten</label>
|
||||
<select name="kota" id="filter_kota" class="form-select form-select-sm" {{
|
||||
!request('provinsi') ? 'disabled' : '' }}>
|
||||
<option value="">Semua Kota</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="small fw-bold">Kecamatan</label>
|
||||
<select name="kecamatan" id="filter_kecamatan" class="form-select form-select-sm" {{
|
||||
!request('kota') ? 'disabled' : '' }}>
|
||||
<option value="">Semua Kecamatan</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="small fw-bold">Desa</label>
|
||||
<select name="desa" id="filter_desa" class="form-select form-select-sm" {{
|
||||
!request('kecamatan') ? 'disabled' : '' }}>
|
||||
<option value="">Semua Desa</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-sm w-100 rounded-pill shadow-sm">
|
||||
<i class="fas fa-search me-1"></i> Cari Produk
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Card Kategori --}}
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
<div class="card-body p-4">
|
||||
<h6 class="fw-bold mb-3 text-uppercase small text-muted">Kategori</h6>
|
||||
<div class="d-flex flex-column gap-2">
|
||||
|
||||
@php
|
||||
$kategoriList = \App\Models\Kategori::all();
|
||||
$currentKat = request('kategori');
|
||||
@endphp
|
||||
|
||||
{{-- Tombol Semua Kategori --}}
|
||||
<a href="{{ route('shop', array_merge(request()->query(), ['kategori' => null])) }}"
|
||||
class="d-flex justify-content-between align-items-center text-decoration-none {{ !$currentKat ? 'fw-bold text-primary' : 'text-secondary' }}">
|
||||
<span>Semua Kategori</span>
|
||||
</a>
|
||||
|
||||
{{-- Looping Kategori Database --}}
|
||||
@foreach($kategoriList as $kat)
|
||||
<a href="{{ route('shop', array_merge(request()->query(), ['kategori' => $kat->slug])) }}"
|
||||
class="d-flex justify-content-between align-items-center text-decoration-none {{ $currentKat == $kat->slug ? 'fw-bold text-primary' : 'text-secondary' }}">
|
||||
|
||||
<span>{{ $kat->nama_kategori }}</span>
|
||||
|
||||
@if($currentKat == $kat->slug)
|
||||
<i class="fas fa-check small"></i>
|
||||
@endif
|
||||
</a>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- LIST PRODUK --}}
|
||||
<div class="col-lg-9">
|
||||
{{-- Banner Info Kecil --}}
|
||||
<div class="card border-0 shadow-sm bg-primary text-white">
|
||||
<div class="card-body p-4">
|
||||
<h5 class="fw-bold mb-2"><i class="fas fa-leaf me-2"></i>Produk Segar</h5>
|
||||
<p class="small mb-0 opacity-75">Semua produk kami diambil langsung dari petani lokal terpercaya.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Top Bar (Info Jumlah & Sorting) --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4 bg-white p-3 rounded shadow-sm border">
|
||||
<div class="d-none d-md-block text-muted small">
|
||||
Menampilkan <span class="fw-bold text-dark">{{ $produks->firstItem() ?? 0 }}-{{ $produks->lastItem() ?? 0 }}</span>
|
||||
dari <span class="fw-bold text-dark">{{ $produks->total() }}</span> produk
|
||||
</div>
|
||||
{{-- LIST PRODUK --}}
|
||||
<div class="col-lg-9">
|
||||
|
||||
<div class="d-flex align-items-center">
|
||||
<label class="small text-muted me-2 text-nowrap">Urutkan:</label>
|
||||
<form id="sortForm" action="{{ route('shop') }}" method="GET">
|
||||
{{-- Pertahankan query lain (search/kategori) saat sorting --}}
|
||||
@foreach(request()->except('sort') as $key => $value)
|
||||
<input type="hidden" name="{{ $key }}" value="{{ $value }}">
|
||||
@endforeach
|
||||
|
||||
<select name="sort" class="form-select form-select-sm border-0 bg-light fw-bold text-dark"
|
||||
onchange="document.getElementById('sortForm').submit()"
|
||||
style="width: 160px; cursor: pointer;">
|
||||
<option value="terbaru" {{ request('sort') == 'terbaru' ? 'selected' : '' }}>Paling Baru
|
||||
</option>
|
||||
<option value="termurah" {{ request('sort') == 'termurah' ? 'selected' : '' }}>Harga Terendah
|
||||
</option>
|
||||
<option value="termahal" {{ request('sort') == 'termahal' ? 'selected' : '' }}>Harga Tertinggi
|
||||
</option>
|
||||
<option value="terlaris" {{ request('sort') == 'terlaris' ? 'selected' : '' }}>Paling Laris
|
||||
</option>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
{{-- Top Bar (Info Jumlah & Sorting) --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4 bg-white p-3 rounded shadow-sm border">
|
||||
<div class="d-none d-md-block text-muted small">
|
||||
Menampilkan <span class="fw-bold text-dark">{{ $produks->firstItem() ?? 0 }}-{{ $produks->lastItem()
|
||||
?? 0 }}</span>
|
||||
dari <span class="fw-bold text-dark">{{ $produks->total() }}</span> produk
|
||||
</div>
|
||||
|
||||
{{-- Grid Produk --}}
|
||||
<div class="row g-4">
|
||||
@forelse($produks as $produk)
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<a href="{{ route('produk.detail', $produk->id) }}" class="text-decoration-none">
|
||||
<div class="card border-0 shadow-sm h-100 product-card">
|
||||
<div class="position-absolute top-0 end-0 m-2 z-1">
|
||||
<span class="badge bg-warning text-dark">
|
||||
Stok: {{ $produk->stok }} Kg
|
||||
</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<label class="small text-muted me-2 text-nowrap">Urutkan:</label>
|
||||
<form id="sortForm" action="{{ route('shop') }}" method="GET">
|
||||
{{-- Pertahankan query lain (search/kategori) saat sorting --}}
|
||||
@foreach(request()->except('sort') as $key => $value)
|
||||
<input type="hidden" name="{{ $key }}" value="{{ $value }}">
|
||||
@endforeach
|
||||
|
||||
<div class="overflow-hidden" style="height: 200px;">
|
||||
<img src="{{ $produk->foto_produk ? asset('storage/' . $produk->foto_produk) : 'https://images.unsplash.com/photo-1586201375761-83865001e31c?q=80&w=800&auto=format&fit=crop' }}"
|
||||
class="card-img-top w-100 h-100" alt="{{ $produk->nama_produk }}"
|
||||
style="object-fit: cover;">
|
||||
</div>
|
||||
<select name="sort" class="form-select form-select-sm border-0 bg-light fw-bold text-dark"
|
||||
onchange="document.getElementById('sortForm').submit()"
|
||||
style="width: 160px; cursor: pointer;">
|
||||
<option value="terbaru" {{ request('sort')=='terbaru' ? 'selected' : '' }}>Paling Baru
|
||||
</option>
|
||||
<option value="termurah" {{ request('sort')=='termurah' ? 'selected' : '' }}>Harga Terendah
|
||||
</option>
|
||||
<option value="termahal" {{ request('sort')=='termahal' ? 'selected' : '' }}>Harga Tertinggi
|
||||
</option>
|
||||
<option value="terlaris" {{ request('sort')=='terlaris' ? 'selected' : '' }}>Paling Laris
|
||||
</option>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body d-flex justify-content-between flex-column p-3">
|
||||
<div>
|
||||
<span class="badge bg-primary mb-2">{{ $produk->kategori->nama_kategori ?? 'Umum' }}</span>
|
||||
<h6 class="fw-bold mb-2 text-dark">{{ $produk->nama_produk }}</h6>
|
||||
<p class="text-muted small mb-3">{{ Str::limit($produk->deskripsi, 60) }}</p>
|
||||
</div>
|
||||
{{-- Grid Produk --}}
|
||||
<div class="row g-4">
|
||||
@forelse($produks as $produk)
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<a href="{{ route('produk.detail', $produk->id) }}" class="text-decoration-none">
|
||||
<div class="card border-0 shadow-sm h-100 product-card">
|
||||
<div class="position-absolute top-0 end-0 m-2 z-1">
|
||||
<span class="badge bg-warning text-dark">
|
||||
Stok: {{ $produk->stok }} Kg
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center pt-2 border-top">
|
||||
<div>
|
||||
<small class="text-muted">Harga/Kg</small>
|
||||
<h6 class="fw-bold text-primary mb-0">
|
||||
Rp {{ number_format($produk->harga, 0, ',', '.') }}
|
||||
</h6>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-sm rounded-pill">
|
||||
<i class="fa fa-eye"></i> Detail
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-hidden" style="height: 200px;">
|
||||
<img src="{{ $produk->foto_produk ? asset('storage/' . $produk->foto_produk) : 'https://images.unsplash.com/photo-1586201375761-83865001e31c?q=80&w=800&auto=format&fit=crop' }}"
|
||||
class="card-img-top w-100 h-100" alt="{{ $produk->nama_produk }}"
|
||||
style="object-fit: cover;">
|
||||
</div>
|
||||
|
||||
<div class="card-body d-flex justify-content-between flex-column p-3">
|
||||
<div>
|
||||
<span class="badge bg-primary mb-2">{{ $produk->kategori->nama_kategori ?? 'Umum'
|
||||
}}</span>
|
||||
<h6 class="fw-bold mb-2 text-dark">{{ $produk->nama_produk }}</h6>
|
||||
<p class="text-muted small mb-3">{{ Str::limit($produk->deskripsi, 60) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center pt-2 border-top">
|
||||
<div>
|
||||
<small class="text-muted">Harga/Kg</small>
|
||||
<h6 class="fw-bold text-primary mb-0">
|
||||
Rp {{ number_format($produk->harga, 0, ',', '.') }}
|
||||
</h6>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-sm rounded-pill">
|
||||
<i class="fa fa-eye"></i> Detail
|
||||
</button>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@empty
|
||||
<div class="col-12">
|
||||
<div class="text-center py-5 bg-white rounded-3 shadow-sm border border-dashed">
|
||||
<i class="fas fa-search fa-3x text-muted opacity-50 mb-3"></i>
|
||||
<h5 class="fw-bold text-dark">Produk Tidak Ditemukan</h5>
|
||||
<p class="text-muted mb-4">Coba ubah kata kunci pencarian atau reset filter Anda.</p>
|
||||
<a href="{{ route('shop') }}" class="btn btn-outline-primary rounded-pill px-4">
|
||||
<i class="fas fa-sync-alt me-2"></i> Reset Filter
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endforelse
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{-- Pagination --}}
|
||||
@if ($produks->hasPages())
|
||||
<div class="d-flex justify-content-center mt-5">
|
||||
{{ $produks->withQueryString()->links() }}
|
||||
@empty
|
||||
<div class="col-12">
|
||||
<div class="text-center py-5 bg-white rounded-3 shadow-sm border border-dashed">
|
||||
<i class="fas fa-search fa-3x text-muted opacity-50 mb-3"></i>
|
||||
<h5 class="fw-bold text-dark">Produk Tidak Ditemukan</h5>
|
||||
<p class="text-muted mb-4">Coba ubah kata kunci pencarian atau reset filter Anda.</p>
|
||||
<a href="{{ route('shop') }}" class="btn btn-outline-primary rounded-pill px-4">
|
||||
<i class="fas fa-sync-alt me-2"></i> Reset Filter
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
{{-- Pagination --}}
|
||||
@if ($produks->hasPages())
|
||||
<div class="d-flex justify-content-center mt-5">
|
||||
{{ $produks->withQueryString()->links() }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Hover Effect */
|
||||
.product-card {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
function setupCascading(source, target, routeName, placeholder) {
|
||||
$(source).on('change', function() {
|
||||
let code = $(this).val();
|
||||
$(target).html('<option value="">Memuat...</option>').prop('disabled', true);
|
||||
|
||||
if(target === '#filter_kota') {
|
||||
$('#filter_kecamatan, #filter_desa').html('<option value="">Semua...</option>').prop('disabled', true);
|
||||
}
|
||||
|
||||
.product-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1) !important;
|
||||
}
|
||||
if (code) {
|
||||
$.post("{{ url('/') }}/" + routeName, {code: code, _token: '{{ csrf_token() }}'}, function(data) {
|
||||
$(target).html('<option value="">' + placeholder + '</option>').prop('disabled', false);
|
||||
$.each(data, function(key, val) {
|
||||
$(target).append(`<option value="${val.code}">${val.name}</option>`);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Zoom Image on Hover */
|
||||
.product-card:hover img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.overflow-hidden img {
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
</style>
|
||||
setupCascading('#filter_provinsi', '#filter_kota', 'get-kota', 'Semua Kota');
|
||||
setupCascading('#filter_kota', '#filter_kecamatan', 'get-kecamatan', 'Semua Kecamatan');
|
||||
setupCascading('#filter_kecamatan', '#filter_desa', 'get-desa', 'Semua Desa');
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Hover Effect */
|
||||
.product-card {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.product-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1) !important;
|
||||
}
|
||||
|
||||
/* Zoom Image on Hover */
|
||||
.product-card:hover img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.overflow-hidden img {
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
|
@ -231,12 +231,7 @@
|
|||
</a>
|
||||
</li>
|
||||
|
||||
{{-- VERIFIKASI PETANI --}}
|
||||
<li class="sidebar-item {{ request()->is('admin/verifikasi*') ? 'active' : '' }}">
|
||||
<a href="{{ route('admin.verifikasi.index') }}" class='sidebar-link'>
|
||||
<i class="bi bi-person-badge-fill"></i> <span>Verifikasi Petani</span>
|
||||
</a>
|
||||
</li>
|
||||
{{-- MENU VERIFIKASI PETANI DIHAPUS SESUAI REVISI --}}
|
||||
|
||||
{{-- GAPOKTAN --}}
|
||||
<li class="sidebar-item {{ request()->is('admin/gapoktan*') ? 'active' : '' }}">
|
||||
|
|
@ -256,6 +251,23 @@
|
|||
|
||||
{{-- Menu Dashboard Petani --}}
|
||||
@if (Auth::guard('petani')->check())
|
||||
{{-- LOGIC UNTUK MENGHITUNG NOTIFIKASI BADGE MERAH --}}
|
||||
@php
|
||||
$petaniId = Auth::guard('petani')->id();
|
||||
|
||||
// Hitung pesanan dengan status 'menunggu konfirmasi'
|
||||
$notifPesanan = \App\Models\Transaksi::where('petani_id', $petaniId)
|
||||
->where('status', 'menunggu konfirmasi')
|
||||
->count();
|
||||
|
||||
// Hitung chat yang belum dibaca (sudah_dibaca = false)
|
||||
// Asumsi penerima_type menggunakan namespace model penuh 'App\Models\Petani'
|
||||
$notifPesan = \App\Models\Pesan::where('penerima_id', $petaniId)
|
||||
->where('penerima_type', 'App\Models\Petani')
|
||||
->where('sudah_dibaca', false)
|
||||
->count();
|
||||
@endphp
|
||||
|
||||
<li class="sidebar-item {{ request()->is('petani/dashboard') ? 'active' : '' }}">
|
||||
<a href="{{ route('petani.dashboard') }}" class='sidebar-link'>
|
||||
<i class="bi bi-grid-fill"></i> <span>Dashboard</span>
|
||||
|
|
@ -266,15 +278,28 @@
|
|||
<i class="bi bi-basket-fill"></i> <span>Kelola Produk</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{{-- Menu Pesanan Masuk (Dengan Badge) --}}
|
||||
<li class="sidebar-item {{ request()->is('petani/pesanan*') ? 'active' : '' }}">
|
||||
<a href="{{ route('petani.pesanan.index') }}" class='sidebar-link'>
|
||||
<i class="bi bi-receipt"></i> <span>Pesanan Masuk</span>
|
||||
<a href="{{ route('petani.pesanan.index') }}" class='sidebar-link d-flex justify-content-between align-items-center'>
|
||||
<div>
|
||||
<i class="bi bi-receipt"></i> <span>Pesanan Masuk</span>
|
||||
</div>
|
||||
@if($notifPesanan > 0)
|
||||
<span class="badge bg-danger rounded-pill">{{ $notifPesanan }}</span>
|
||||
@endif
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
class="sidebar-item {{ request()->is('petani/pesan') || request()->is('petani/pesan/*') ? 'active' : '' }}">
|
||||
<a href="{{ route('petani.pesan.index') }}" class='sidebar-link'>
|
||||
<i class="bi bi-chat-dots-fill"></i> <span>Kotak Masuk</span>
|
||||
|
||||
{{-- Menu Kotak Masuk (Dengan Badge) --}}
|
||||
<li class="sidebar-item {{ request()->is('petani/pesan') || request()->is('petani/pesan/*') ? 'active' : '' }}">
|
||||
<a href="{{ route('petani.pesan.index') }}" class='sidebar-link d-flex justify-content-between align-items-center'>
|
||||
<div>
|
||||
<i class="bi bi-chat-dots-fill"></i> <span>Kotak Masuk</span>
|
||||
</div>
|
||||
@if($notifPesan > 0)
|
||||
<span class="badge bg-danger rounded-pill">{{ $notifPesan }}</span>
|
||||
@endif
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -38,7 +38,12 @@
|
|||
line-height: 1.6;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-weight: 700;
|
||||
color: var(--dark-text);
|
||||
|
|
@ -46,9 +51,17 @@
|
|||
}
|
||||
|
||||
/* Utility Colors */
|
||||
.text-primary { color: var(--primary-color) !important; }
|
||||
.bg-primary { background-color: var(--primary-color) !important; }
|
||||
.border-primary { border-color: var(--primary-color) !important; }
|
||||
.text-primary {
|
||||
color: var(--primary-color) !important;
|
||||
}
|
||||
|
||||
.bg-primary {
|
||||
background-color: var(--primary-color) !important;
|
||||
}
|
||||
|
||||
.border-primary {
|
||||
border-color: var(--primary-color) !important;
|
||||
}
|
||||
|
||||
/* BUTTON */
|
||||
.btn {
|
||||
|
|
@ -144,7 +157,8 @@
|
|||
|
||||
<body>
|
||||
|
||||
<div id="spinner" class="show w-100 vh-100 bg-white position-fixed translate-middle top-50 start-50 d-flex align-items-center justify-content-center">
|
||||
<div id="spinner"
|
||||
class="show w-100 vh-100 bg-white position-fixed translate-middle top-50 start-50 d-flex align-items-center justify-content-center">
|
||||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"></div>
|
||||
</div>
|
||||
|
||||
|
|
@ -153,7 +167,8 @@
|
|||
<div class="container">
|
||||
<div class="d-flex justify-content-start text-white" style="font-size: 0.85rem;">
|
||||
<div>
|
||||
<span class="me-3"><i class="fas fa-map-marker-alt me-2"></i> Desa Mancon, Kecamatan Wilangan, Kabupaten Nganjuk</span>
|
||||
<span class="me-3"><i class="fas fa-map-marker-alt me-2"></i> Desa Mancon, Kecamatan Wilangan,
|
||||
Kabupaten Nganjuk</span>
|
||||
<span class="me-3"><i class="fas fa-envelope me-2"></i> info@tanidesa.com</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -164,22 +179,27 @@
|
|||
<div class="container">
|
||||
<nav class="navbar navbar-light navbar-expand-xl py-3">
|
||||
<a href="{{ url('/') }}" class="navbar-brand d-flex align-items-center">
|
||||
<h1 class="text-primary m-0 fw-bold" style="font-size: 1.8rem; letter-spacing: -1px;">GriyaPadi.id</h1>
|
||||
<h1 class="text-primary m-0 fw-bold" style="font-size: 1.8rem; letter-spacing: -1px;">
|
||||
GriyaPadi.id</h1>
|
||||
</a>
|
||||
|
||||
<button class="navbar-toggler border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse">
|
||||
<button class="navbar-toggler border-0" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarCollapse">
|
||||
<span class="fa fa-bars text-primary"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<div class="navbar-nav mx-auto">
|
||||
<a href="{{ url('/') }}" class="nav-item nav-link mx-2 {{ request()->is('/') ? 'active' : '' }}">Home</a>
|
||||
<a href="{{ route('shop') }}" class="nav-item nav-link mx-2 {{ request()->is('shop*') ? 'active' : '' }}">Belanja</a>
|
||||
<a href="{{ url('/') }}"
|
||||
class="nav-item nav-link mx-2 {{ request()->is('/') ? 'active' : '' }}">Home</a>
|
||||
<a href="{{ route('shop') }}"
|
||||
class="nav-item nav-link mx-2 {{ request()->is('shop*') ? 'active' : '' }}">Belanja</a>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center mt-3 mt-xl-0">
|
||||
|
||||
<form action="{{ route('shop') }}" method="GET" class="me-3 d-flex w-100 w-xl-auto mb-3 mb-xl-0">
|
||||
|
||||
<form action="{{ route('shop') }}" method="GET"
|
||||
class="me-3 d-flex w-100 w-xl-auto mb-3 mb-xl-0">
|
||||
<div class="input-group w-100">
|
||||
<input type="search" name="search" class="form-control border-end-0"
|
||||
placeholder="Cari produk..." value="{{ request('search') }}"
|
||||
|
|
@ -193,34 +213,64 @@
|
|||
|
||||
<a href="{{ route('cart') }}" class="position-relative me-3 text-dark">
|
||||
<i class="bi bi-bag fs-4"></i>
|
||||
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger" style="font-size: 0.6rem;">
|
||||
|
||||
<span
|
||||
class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger"
|
||||
style="font-size: 0.6rem;">
|
||||
|
||||
{{-- PERBAIKAN LOGIKA HITUNG CART --}}
|
||||
@if(Auth::guard('pembeli')->check())
|
||||
@if (Auth::guard('pembeli')->check())
|
||||
{{ \App\Models\Cart::where('pembeli_id', Auth::guard('pembeli')->id())->count() }}
|
||||
@else
|
||||
0
|
||||
@endif
|
||||
|
||||
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@if (Auth::guard('pembeli')->check())
|
||||
<div class="nav-item dropdown ms-2">
|
||||
<a href="#" class="nav-link dropdown-toggle text-dark fw-bold d-flex align-items-center" data-bs-toggle="dropdown">
|
||||
<div class="bg-light rounded-circle d-flex align-items-center justify-content-center me-2" style="width: 35px; height: 35px;">
|
||||
<a href="#"
|
||||
class="nav-link dropdown-toggle text-dark fw-bold d-flex align-items-center"
|
||||
data-bs-toggle="dropdown">
|
||||
<div class="bg-light rounded-circle d-flex align-items-center justify-content-center me-2"
|
||||
style="width: 35px; height: 35px;">
|
||||
<i class="fas fa-user text-primary"></i>
|
||||
</div>
|
||||
<span class="d-none d-xl-inline small">{{ Auth::guard('pembeli')->user()->nama_lengkap }}</span>
|
||||
<span
|
||||
class="d-none d-xl-inline small">{{ Auth::guard('pembeli')->user()->nama_lengkap }}</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end border-0 shadow-sm m-0 rounded-3">
|
||||
<a href="{{ route('pembeli.profile') }}" class="dropdown-item py-2"><i class="bi bi-person me-2"></i> Profil</a>
|
||||
<a href="{{ route('pembeli.pesan.index') }}" class="dropdown-item py-2"><i class="bi bi-chat-dots me-2"></i> Pesan</a>
|
||||
<a href="{{ route('pesanan.saya') }}" class="dropdown-item py-2"><i class="bi bi-bag-check me-2"></i> Riwayat Pesanan</a>
|
||||
<a href="{{ route('pembeli.profile') }}" class="dropdown-item py-2"><i
|
||||
class="bi bi-person me-2"></i> Profil</a>
|
||||
<a href="{{ route('pembeli.pesan.index') }}"
|
||||
class="dropdown-item py-2 d-flex justify-content-between align-items-center">
|
||||
<span><i class="bi bi-chat-dots me-2"></i> Pesan</span>
|
||||
|
||||
{{-- Logika Badge Notifikasi Pembeli --}}
|
||||
@if (Auth::guard('pembeli')->check())
|
||||
@php
|
||||
$notifPesanPembeli = \App\Models\Pesan::where(
|
||||
'penerima_id',
|
||||
Auth::guard('pembeli')->id(),
|
||||
)
|
||||
->where('penerima_type', 'App\Models\Pembeli')
|
||||
->where('sudah_dibaca', false)
|
||||
->count();
|
||||
@endphp
|
||||
|
||||
@if ($notifPesanPembeli > 0)
|
||||
<span class="badge bg-danger rounded-pill"
|
||||
style="font-size: 0.7rem;">{{ $notifPesanPembeli }}</span>
|
||||
@endif
|
||||
@endif
|
||||
</a>
|
||||
<a href="{{ route('pesanan.saya') }}" class="dropdown-item py-2"><i
|
||||
class="bi bi-bag-check me-2"></i> Riwayat Pesanan</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<form action="{{ route('logout') }}" method="POST">
|
||||
@csrf
|
||||
<button type="submit" class="dropdown-item py-2 text-danger"><i class="bi bi-box-arrow-right me-2"></i> Logout</button>
|
||||
<button type="submit" class="dropdown-item py-2 text-danger"><i
|
||||
class="bi bi-box-arrow-right me-2"></i> Logout</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -237,10 +287,12 @@
|
|||
<div style="margin-top: 170px;">
|
||||
@if (session('success'))
|
||||
<div class="container mt-4">
|
||||
<div class="alert alert-success border-0 shadow-sm rounded-3 d-flex align-items-center" role="alert">
|
||||
<div class="alert alert-success border-0 shadow-sm rounded-3 d-flex align-items-center"
|
||||
role="alert">
|
||||
<i class="bi bi-check-circle-fill fs-4 me-3"></i>
|
||||
<div>{{ session('success') }}</div>
|
||||
<button type="button" class="btn-close ms-auto" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
<button type="button" class="btn-close ms-auto" data-bs-dismiss="alert"
|
||||
aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
|
@ -253,27 +305,37 @@
|
|||
<div class="row g-5">
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<h3 class="text-white mb-4">GriyaPadi.id</h3>
|
||||
<p class="mb-4 small">Menghubungkan petani lokal langsung dengan pembeli untuk harga yang adil dan produk berkualitas tinggi.</p>
|
||||
<p class="mb-4 small">Menghubungkan petani lokal langsung dengan pembeli untuk harga yang adil dan
|
||||
produk berkualitas tinggi.</p>
|
||||
<div class="d-flex pt-2">
|
||||
<a class="btn btn-outline-light btn-sm rounded-circle me-2" href=""><i class="fab fa-twitter"></i></a>
|
||||
<a class="btn btn-outline-light btn-sm rounded-circle me-2" href=""><i class="fab fa-facebook-f"></i></a>
|
||||
<a class="btn btn-outline-light btn-sm rounded-circle" href=""><i class="fab fa-youtube"></i></a>
|
||||
<a class="btn btn-outline-light btn-sm rounded-circle me-2" href=""><i
|
||||
class="fab fa-twitter"></i></a>
|
||||
<a class="btn btn-outline-light btn-sm rounded-circle me-2" href=""><i
|
||||
class="fab fa-facebook-f"></i></a>
|
||||
<a class="btn btn-outline-light btn-sm rounded-circle" href=""><i
|
||||
class="fab fa-youtube"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<h5 class="text-white mb-4">Tautan Cepat</h5>
|
||||
<div class="d-flex flex-column justify-content-start">
|
||||
<a class="text-white-50 mb-2 text-decoration-none" href="{{ route('shop') }}"><i class="bi bi-chevron-right me-2 small"></i>Belanja</a>
|
||||
<a class="text-white-50 mb-2 text-decoration-none" href="#"><i class="bi bi-chevron-right me-2 small"></i>Tentang Kami</a>
|
||||
<a class="text-white-50 text-decoration-none" href="#"><i class="bi bi-chevron-right me-2 small"></i>Hubungi Kami</a>
|
||||
<a class="text-white-50 mb-2 text-decoration-none" href="{{ route('shop') }}"><i
|
||||
class="bi bi-chevron-right me-2 small"></i>Belanja</a>
|
||||
<a class="text-white-50 mb-2 text-decoration-none" href="#"><i
|
||||
class="bi bi-chevron-right me-2 small"></i>Tentang Kami</a>
|
||||
<a class="text-white-50 text-decoration-none" href="#"><i
|
||||
class="bi bi-chevron-right me-2 small"></i>Hubungi Kami</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<h5 class="text-white mb-4">Akun Saya</h5>
|
||||
<div class="d-flex flex-column justify-content-start">
|
||||
<a class="text-white-50 mb-2 text-decoration-none" href="{{ route('pembeli.profile') }}"><i class="bi bi-chevron-right me-2 small"></i>Profil</a>
|
||||
<a class="text-white-50 mb-2 text-decoration-none" href="{{ route('cart') }}"><i class="bi bi-chevron-right me-2 small"></i>Keranjang</a>
|
||||
<a class="text-white-50 text-decoration-none" href="{{ route('pesanan.saya') }}"><i class="bi bi-chevron-right me-2 small"></i>Riwayat Pesanan</a>
|
||||
<a class="text-white-50 mb-2 text-decoration-none" href="{{ route('pembeli.profile') }}"><i
|
||||
class="bi bi-chevron-right me-2 small"></i>Profil</a>
|
||||
<a class="text-white-50 mb-2 text-decoration-none" href="{{ route('cart') }}"><i
|
||||
class="bi bi-chevron-right me-2 small"></i>Keranjang</a>
|
||||
<a class="text-white-50 text-decoration-none" href="{{ route('pesanan.saya') }}"><i
|
||||
class="bi bi-chevron-right me-2 small"></i>Riwayat Pesanan</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
|
|
@ -286,12 +348,15 @@
|
|||
</div>
|
||||
<div class="container-fluid copyright bg-dark py-4 border-top border-secondary">
|
||||
<div class="container text-center">
|
||||
<span class="text-white-50 small">© <a href="#" class="text-white">GriyaPadi.id</a>, All Right Reserved.</span>
|
||||
<span class="text-white-50 small">© <a href="#" class="text-white">GriyaPadi.id</a>, All
|
||||
Right
|
||||
Reserved.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href="#" class="btn btn-primary btn-lg-square rounded-circle back-to-top shadow"><i class="bi bi-arrow-up"></i></a>
|
||||
<a href="#" class="btn btn-primary btn-lg-square rounded-circle back-to-top shadow"><i
|
||||
class="bi bi-arrow-up"></i></a>
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
|
@ -304,4 +369,4 @@
|
|||
@yield('js')
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -4,232 +4,343 @@
|
|||
@section('page-title', 'Tambah Produk Baru')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body">
|
||||
<form action="{{ route('petani.produk.store') }}" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body">
|
||||
<form action="{{ route('petani.produk.store') }}" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
|
||||
<div class="row">
|
||||
{{-- DATA PRODUK --}}
|
||||
<div class="col-lg-8">
|
||||
<h5 class="mb-4">Informasi Produk</h5>
|
||||
<div class="form-group mb-3">
|
||||
<label class="fw-bold">Nama Produk</label>
|
||||
<input type="text" name="nama_produk" class="form-control"
|
||||
placeholder="Contoh: Beras Pandan Wangi Super" required>
|
||||
<div class="row">
|
||||
{{-- DATA PRODUK --}}
|
||||
<div class="col-lg-8">
|
||||
<h5 class="mb-4">Informasi Produk</h5>
|
||||
<div class="form-group mb-3">
|
||||
<label class="fw-bold">Nama Produk</label>
|
||||
<input type="text" name="nama_produk" class="form-control"
|
||||
placeholder="Contoh: Beras Pandan Wangi Super" required>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="fw-bold">Kategori</label>
|
||||
<select name="kategori_id" class="form-select" required>
|
||||
<option value="" disabled selected>Pilih Kategori</option>
|
||||
@foreach($kategoris as $kat)
|
||||
<option value="{{ $kat->id }}" {{ old('kategori_id')==$kat->id ? 'selected' : ''
|
||||
}}>
|
||||
{{ $kat->nama_kategori }}
|
||||
</option>
|
||||
@endforeach
|
||||
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="fw-bold">Kategori</label>
|
||||
<select name="kategori_id" class="form-select" required>
|
||||
<option value="" disabled selected>Pilih Kategori</option>
|
||||
@foreach($kategoris as $kat)
|
||||
<option value="{{ $kat->id }}" {{ old('kategori_id') == $kat->id ? 'selected' : '' }}>
|
||||
{{ $kat->nama_kategori }}
|
||||
</option>
|
||||
@endforeach
|
||||
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="fw-bold">Stok (Kg)</label>
|
||||
<input type="number" name="stok" class="form-control" placeholder="0" required
|
||||
min="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label class="fw-bold">Harga (Rp)</label>
|
||||
<input type="number" name="harga" class="form-control" placeholder="0" required min="0">
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label class="fw-bold">Deskripsi</label>
|
||||
<textarea name="deskripsi" class="form-control" rows="4"
|
||||
placeholder="Jelaskan kualitas produk Anda..." required></textarea>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="fw-bold">Stok (Kg)</label>
|
||||
<input type="number" name="stok" class="form-control" placeholder="0" required
|
||||
min="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- UPLOAD GAMBAR --}}
|
||||
<div class="col-lg-4">
|
||||
<h5 class="mb-4">Media Produk</h5>
|
||||
<div class="form-group mb-3">
|
||||
<label class="fw-bold">Harga (Rp)</label>
|
||||
<input type="number" name="harga" class="form-control" placeholder="0" required min="0">
|
||||
</div>
|
||||
|
||||
{{-- FOTO UTAMA --}}
|
||||
<div class="card bg-light border-0 mb-4">
|
||||
<div class="card-body">
|
||||
<label class="fw-bold mb-2">Foto Utama</label>
|
||||
<div class="form-group mb-3">
|
||||
<label class="fw-bold">Deskripsi</label>
|
||||
<textarea name="deskripsi" class="form-control" rows="4"
|
||||
placeholder="Jelaskan kualitas produk Anda..." required></textarea>
|
||||
</div>
|
||||
|
||||
{{-- AREA PREVIEW --}}
|
||||
<div class="mb-2 bg-white border rounded d-flex align-items-center justify-content-center position-relative overflow-hidden"
|
||||
style="height: 150px;">
|
||||
|
||||
{{-- Ikon Upload --}}
|
||||
<div id="placeholder-utama" class="text-center text-muted">
|
||||
<i class="bi bi-cloud-arrow-up fs-1"></i>
|
||||
<div class="small mt-1">Klik untuk upload</div>
|
||||
</div>
|
||||
|
||||
{{-- Tampilan Gambar --}}
|
||||
<img id="preview-utama" src="#"
|
||||
class="img-fluid w-100 h-100 object-fit-contain d-none">
|
||||
</div>
|
||||
|
||||
<input type="file" name="foto_produk" class="form-control form-control-sm"
|
||||
accept="image/*" required onchange="previewMainImage(this)">
|
||||
<small class="text-muted">Wajib. Tampil di halaman depan.</small>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Provinsi</label>
|
||||
<select name="provinsi_code" id="provinsi" class="form-select" required>
|
||||
<option value="">Pilih Provinsi</option>
|
||||
@foreach ($provinsis as $prov)
|
||||
<option value="{{ $prov->code }}">{{ $prov->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- GALERI TAMBAHAN --}}
|
||||
<div class="card bg-light border-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<label class="fw-bold m-0">Galeri Tambahan</label>
|
||||
<span class="badge bg-primary rounded-pill" id="count-badge">0/3</span>
|
||||
</div>
|
||||
|
||||
{{-- Container Preview Grid --}}
|
||||
<div id="gallery-preview-container" class="row g-2 mb-3">
|
||||
{{-- Gambar preview --}}
|
||||
</div>
|
||||
|
||||
{{-- Input File Visual --}}
|
||||
<div class="mb-2">
|
||||
<input type="file" id="input-gallery-visual"
|
||||
class="form-control form-control-sm" accept="image/*" multiple>
|
||||
</div>
|
||||
|
||||
{{-- Input File Hidden --}}
|
||||
<input type="file" name="foto_tambahan[]" id="real-input-gallery" class="d-none"
|
||||
multiple>
|
||||
|
||||
<small class="text-muted d-block" style="font-size: 0.8rem;">
|
||||
<i class="bi bi-info-circle me-1"></i>Maksimal 3 foto. Bisa dihapus sebelum
|
||||
upload.
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Kota / Kabupaten</label>
|
||||
<select name="kota_code" id="kota" class="form-select" required disabled>
|
||||
<option value="">Pilih Kota/Kabupaten</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Kecamatan</label>
|
||||
<select name="kecamatan_code" id="kecamatan" class="form-select" required disabled>
|
||||
<option value="">Pilih Kecamatan</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Desa / Kelurahan</label>
|
||||
<select name="desa_code" id="desa" class="form-select" required disabled>
|
||||
<option value="">Pilih Desa</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-top pt-3 mt-4 text-end">
|
||||
<a href="{{ route('petani.produk.index') }}" class="btn btn-secondary me-2">Batal</a>
|
||||
<button type="submit" class="btn btn-primary px-4">Simpan Produk</button>
|
||||
{{-- UPLOAD GAMBAR --}}
|
||||
<div class="col-lg-4">
|
||||
<h5 class="mb-4">Media Produk</h5>
|
||||
|
||||
{{-- FOTO UTAMA --}}
|
||||
<div class="card bg-light border-0 mb-4">
|
||||
<div class="card-body">
|
||||
<label class="fw-bold mb-2">Foto Utama</label>
|
||||
|
||||
{{-- AREA PREVIEW --}}
|
||||
<div class="mb-2 bg-white border rounded d-flex align-items-center justify-content-center position-relative overflow-hidden"
|
||||
style="height: 150px;">
|
||||
|
||||
{{-- Ikon Upload --}}
|
||||
<div id="placeholder-utama" class="text-center text-muted">
|
||||
<i class="bi bi-cloud-arrow-up fs-1"></i>
|
||||
<div class="small mt-1">Klik untuk upload</div>
|
||||
</div>
|
||||
|
||||
{{-- Tampilan Gambar --}}
|
||||
<img id="preview-utama" src="#"
|
||||
class="img-fluid w-100 h-100 object-fit-contain d-none">
|
||||
</div>
|
||||
|
||||
<input type="file" name="foto_produk" class="form-control form-control-sm"
|
||||
accept="image/*" required onchange="previewMainImage(this)">
|
||||
<small class="text-muted">Wajib. Tampil di halaman depan.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- GALERI TAMBAHAN --}}
|
||||
<div class="card bg-light border-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<label class="fw-bold m-0">Galeri Tambahan</label>
|
||||
<span class="badge bg-primary rounded-pill" id="count-badge">0/3</span>
|
||||
</div>
|
||||
|
||||
{{-- Container Preview Grid --}}
|
||||
<div id="gallery-preview-container" class="row g-2 mb-3">
|
||||
{{-- Gambar preview --}}
|
||||
</div>
|
||||
|
||||
{{-- Input File Visual --}}
|
||||
<div class="mb-2">
|
||||
<input type="file" id="input-gallery-visual"
|
||||
class="form-control form-control-sm" accept="image/*" multiple>
|
||||
</div>
|
||||
|
||||
{{-- Input File Hidden --}}
|
||||
<input type="file" name="foto_tambahan[]" id="real-input-gallery" class="d-none"
|
||||
multiple>
|
||||
|
||||
<small class="text-muted d-block" style="font-size: 0.8rem;">
|
||||
<i class="bi bi-info-circle me-1"></i>Maksimal 3 foto. Bisa dihapus sebelum
|
||||
upload.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-top pt-3 mt-4 text-end">
|
||||
<a href="{{ route('petani.produk.index') }}" class="btn btn-secondary me-2">Batal</a>
|
||||
<button type="submit" class="btn btn-primary px-4">Simpan Produk</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// ----------------------------------------------------
|
||||
// PREVIEW FOTO UTAMA
|
||||
// ----------------------------------------------------
|
||||
function previewMainImage(input) {
|
||||
const preview = document.getElementById('preview-utama');
|
||||
const placeholder = document.getElementById('placeholder-utama');
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// When Provinsi changes, fetch Kota
|
||||
$('#provinsi').on('change', function() {
|
||||
let code = $(this).val();
|
||||
$('#kota').html('<option value="">Memuat...</option>').prop('disabled', true);
|
||||
$('#kecamatan').html('<option value="">== Pilih Kecamatan ==</option>').prop('disabled', true);
|
||||
$('#desa').html('<option value="">== Pilih Desa ==</option>').prop('disabled', true);
|
||||
|
||||
if (input.files && input.files[0]) {
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.onload = function (e) {
|
||||
preview.src = e.target.result;
|
||||
|
||||
// Tampilkan Gambar, Sembunyikan Ikon
|
||||
preview.classList.remove('d-none');
|
||||
placeholder.classList.add('d-none');
|
||||
}
|
||||
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
} else {
|
||||
preview.src = '#';
|
||||
preview.classList.add('d-none');
|
||||
placeholder.classList.remove('d-none');
|
||||
if (code) {
|
||||
$.ajax({
|
||||
url: "{{ route('get.kota') }}"
|
||||
, type: "POST"
|
||||
, data: {
|
||||
code: code
|
||||
, _token: '{{ csrf_token() }}'
|
||||
}
|
||||
, success: function(data) {
|
||||
$('#kota').html('<option value="">== Pilih Kota/Kabupaten ==</option>');
|
||||
$.each(data, function(key, value) {
|
||||
$('#kota').append('<option value="' + value.code + '">' + value.name + '</option>');
|
||||
});
|
||||
$('#kota').prop('disabled', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// When Kota changes, fetch Kecamatan
|
||||
$('#kota').on('change', function() {
|
||||
let code = $(this).val();
|
||||
$('#kecamatan').html('<option value="">Memuat...</option>').prop('disabled', true);
|
||||
$('#desa').html('<option value="">== Pilih Desa ==</option>').prop('disabled', true);
|
||||
|
||||
if (code) {
|
||||
$.ajax({
|
||||
url: "{{ route('get.kecamatan') }}"
|
||||
, type: "POST"
|
||||
, data: {
|
||||
code: code
|
||||
, _token: '{{ csrf_token() }}'
|
||||
}
|
||||
, success: function(data) {
|
||||
$('#kecamatan').html('<option value="">== Pilih Kecamatan ==</option>');
|
||||
$.each(data, function(key, value) {
|
||||
$('#kecamatan').append('<option value="' + value.code + '">' + value.name + '</option>');
|
||||
});
|
||||
$('#kecamatan').prop('disabled', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// When Kecamatan changes, fetch Desa
|
||||
$('#kecamatan').on('change', function() {
|
||||
let code = $(this).val();
|
||||
$('#desa').html('<option value="">Memuat...</option>').prop('disabled', true);
|
||||
|
||||
if (code) {
|
||||
$.ajax({
|
||||
url: "{{ route('get.desa') }}"
|
||||
, type: "POST"
|
||||
, data: {
|
||||
code: code
|
||||
, _token: '{{ csrf_token() }}'
|
||||
}
|
||||
, success: function(data) {
|
||||
$('#desa').html('<option value="">== Pilih Desa ==</option>');
|
||||
$.each(data, function(key, value) {
|
||||
$('#desa').append('<option value="' + value.code + '">' + value.name + '</option>');
|
||||
});
|
||||
$('#desa').prop('disabled', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
// ----------------------------------------------------
|
||||
// PREVIEW FOTO UTAMA
|
||||
// ----------------------------------------------------
|
||||
function previewMainImage(input) {
|
||||
const preview = document.getElementById('preview-utama');
|
||||
const placeholder = document.getElementById('placeholder-utama');
|
||||
|
||||
if (input.files && input.files[0]) {
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
preview.src = e.target.result;
|
||||
|
||||
// Tampilkan Gambar, Sembunyikan Ikon
|
||||
preview.classList.remove('d-none');
|
||||
placeholder.classList.add('d-none');
|
||||
}
|
||||
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
} else {
|
||||
preview.src = '#';
|
||||
preview.classList.add('d-none');
|
||||
placeholder.classList.remove('d-none');
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// LOGIC GALERI TAMBAHAN (KERANJANG UPLOAD)
|
||||
// ----------------------------------------------------
|
||||
const inputVisual = document.getElementById('input-gallery-visual');
|
||||
const inputReal = document.getElementById('real-input-gallery');
|
||||
const container = document.getElementById('gallery-preview-container');
|
||||
const countBadge = document.getElementById('count-badge');
|
||||
|
||||
// "Keranjang" virtual untuk menampung file
|
||||
let dt = new DataTransfer();
|
||||
|
||||
inputVisual.addEventListener('change', function() {
|
||||
const newFiles = this.files;
|
||||
|
||||
// Cek Limit Total
|
||||
if (dt.items.length + newFiles.length > 3) {
|
||||
alert('Maksimal hanya boleh 3 gambar tambahan!');
|
||||
this.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// LOGIC GALERI TAMBAHAN (KERANJANG UPLOAD)
|
||||
// ----------------------------------------------------
|
||||
const inputVisual = document.getElementById('input-gallery-visual');
|
||||
const inputReal = document.getElementById('real-input-gallery');
|
||||
const container = document.getElementById('gallery-preview-container');
|
||||
const countBadge = document.getElementById('count-badge');
|
||||
// Loop file baru
|
||||
for (let i = 0; i < newFiles.length; i++) {
|
||||
const file = newFiles[i];
|
||||
|
||||
// "Keranjang" virtual untuk menampung file
|
||||
let dt = new DataTransfer();
|
||||
dt.items.add(file);
|
||||
|
||||
inputVisual.addEventListener('change', function () {
|
||||
const newFiles = this.files;
|
||||
// Buat HTML Preview
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
const col = document.createElement('div');
|
||||
col.className = 'col-4 position-relative new-image-preview';
|
||||
|
||||
// Cek Limit Total
|
||||
if (dt.items.length + newFiles.length > 3) {
|
||||
alert('Maksimal hanya boleh 3 gambar tambahan!');
|
||||
this.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop file baru
|
||||
for (let i = 0; i < newFiles.length; i++) {
|
||||
const file = newFiles[i];
|
||||
|
||||
dt.items.add(file);
|
||||
|
||||
// Buat HTML Preview
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
const col = document.createElement('div');
|
||||
col.className = 'col-4 position-relative new-image-preview';
|
||||
|
||||
col.innerHTML = `
|
||||
col.innerHTML = `
|
||||
<img src="${e.target.result}" class="rounded w-100 border bg-white" style="height: 70px; object-fit: cover;">
|
||||
<span class="position-absolute top-0 end-0 badge bg-secondary text-white rounded-circle m-1 shadow-sm remove-btn"
|
||||
style="cursor: pointer;">×</span>
|
||||
`;
|
||||
|
||||
// Event Listener Tombol Hapus (X)
|
||||
col.querySelector('.remove-btn').addEventListener('click', function () {
|
||||
// Event Listener Tombol Hapus (X)
|
||||
col.querySelector('.remove-btn').addEventListener('click', function() {
|
||||
|
||||
// Hapus file dari keranjang berdasarkan nama & size
|
||||
for (let j = 0; j < dt.items.length; j++) {
|
||||
if (dt.files[j].name === file.name && dt.files[j].size === file.size) {
|
||||
dt.items.remove(j);
|
||||
break;
|
||||
}
|
||||
// Hapus file dari keranjang berdasarkan nama & size
|
||||
for (let j = 0; j < dt.items.length; j++) {
|
||||
if (dt.files[j].name === file.name && dt.files[j].size === file.size) {
|
||||
dt.items.remove(j);
|
||||
break;
|
||||
}
|
||||
inputReal.files = dt.files;
|
||||
col.remove();
|
||||
updateBadge();
|
||||
});
|
||||
}
|
||||
inputReal.files = dt.files;
|
||||
col.remove();
|
||||
updateBadge();
|
||||
});
|
||||
|
||||
container.appendChild(col);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
inputReal.files = dt.files;
|
||||
this.value = '';
|
||||
updateBadge();
|
||||
});
|
||||
|
||||
function updateBadge() {
|
||||
let total = dt.items.length;
|
||||
countBadge.innerText = total + '/3';
|
||||
|
||||
// Visual Feedback jika penuh
|
||||
if (total >= 3) {
|
||||
inputVisual.disabled = true;
|
||||
inputVisual.setAttribute('title', 'Slot penuh (Maks 3)');
|
||||
countBadge.className = 'badge bg-danger rounded-pill';
|
||||
} else {
|
||||
inputVisual.disabled = false;
|
||||
inputVisual.removeAttribute('title');
|
||||
countBadge.className = 'badge bg-primary rounded-pill';
|
||||
}
|
||||
container.appendChild(col);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
</script>
|
||||
|
||||
inputReal.files = dt.files;
|
||||
this.value = '';
|
||||
updateBadge();
|
||||
});
|
||||
|
||||
function updateBadge() {
|
||||
let total = dt.items.length;
|
||||
countBadge.innerText = total + '/3';
|
||||
|
||||
// Visual Feedback jika penuh
|
||||
if (total >= 3) {
|
||||
inputVisual.disabled = true;
|
||||
inputVisual.setAttribute('title', 'Slot penuh (Maks 3)');
|
||||
countBadge.className = 'badge bg-danger rounded-pill';
|
||||
} else {
|
||||
inputVisual.disabled = false;
|
||||
inputVisual.removeAttribute('title');
|
||||
countBadge.className = 'badge bg-primary rounded-pill';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -4,263 +4,363 @@
|
|||
@section('page-title', 'Edit Produk')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body">
|
||||
{{-- Form Utama --}}
|
||||
<form action="{{ route('petani.produk.update', $produk->id) }}" method="POST"
|
||||
enctype="multipart/form-data">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body">
|
||||
{{-- Form Utama --}}
|
||||
<form action="{{ route('petani.produk.update', $produk->id) }}" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="row">
|
||||
{{-- DATA PRODUK --}}
|
||||
<div class="col-lg-8">
|
||||
<h5 class="mb-4">Informasi Produk</h5>
|
||||
<div class="form-group mb-3">
|
||||
<label class="fw-bold">Nama Produk</label>
|
||||
<input type="text" name="nama_produk" class="form-control"
|
||||
value="{{ $produk->nama_produk }}" required>
|
||||
<div class="row">
|
||||
{{-- DATA PRODUK --}}
|
||||
<div class="col-lg-8">
|
||||
<h5 class="mb-4">Informasi Produk</h5>
|
||||
<div class="form-group mb-3">
|
||||
<label class="fw-bold">Nama Produk</label>
|
||||
<input type="text" name="nama_produk" class="form-control" value="{{ $produk->nama_produk }}" required>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="fw-bold">Kategori</label>
|
||||
<select name="kategori_id" class="form-select" required>
|
||||
<option value="" disabled>Pilih Kategori</option>
|
||||
@foreach($kategoris as $kat)
|
||||
<option value="{{ $kat->id }}" {{ (old('kategori_id', $produk->kategori_id) ==
|
||||
$kat->id) ? 'selected' : '' }}>
|
||||
{{ $kat->nama_kategori }}
|
||||
</option>
|
||||
@endforeach
|
||||
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="fw-bold">Kategori</label>
|
||||
<select name="kategori_id" class="form-select" required>
|
||||
<option value="" disabled>Pilih Kategori</option>
|
||||
@foreach($kategoris as $kat)
|
||||
<option value="{{ $kat->id }}" {{ (old('kategori_id', $produk->kategori_id) == $kat->id) ? 'selected' : '' }}>
|
||||
{{ $kat->nama_kategori }}
|
||||
</option>
|
||||
@endforeach
|
||||
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="fw-bold">Stok</label>
|
||||
<input type="number" name="stok" class="form-control" value="{{ $produk->stok }}"
|
||||
required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label class="fw-bold">Harga (Rp)</label>
|
||||
<input type="number" name="harga" class="form-control" value="{{ $produk->harga }}"
|
||||
required>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label class="fw-bold">Deskripsi</label>
|
||||
<textarea name="deskripsi" class="form-control" rows="4"
|
||||
required>{{ $produk->deskripsi }}</textarea>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="fw-bold">Stok</label>
|
||||
<input type="number" name="stok" class="form-control" value="{{ $produk->stok }}" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- KELOLA GAMBAR --}}
|
||||
<div class="col-lg-4">
|
||||
<h5 class="mb-4">Kelola Gambar</h5>
|
||||
<div class="form-group mb-3">
|
||||
<label class="fw-bold">Harga (Rp)</label>
|
||||
<input type="number" name="harga" class="form-control" value="{{ $produk->harga }}" required>
|
||||
</div>
|
||||
|
||||
{{-- FOTO UTAMA --}}
|
||||
<div class="card bg-light border-0 mb-4">
|
||||
<div class="card-body">
|
||||
<label class="fw-bold mb-2">Foto Utama</label>
|
||||
<div class="form-group mb-3">
|
||||
<label class="fw-bold">Deskripsi</label>
|
||||
<textarea name="deskripsi" class="form-control" rows="4" required>{{ $produk->deskripsi }}</textarea>
|
||||
</div>
|
||||
|
||||
{{-- AREA PREVIEW --}}
|
||||
<div class="mb-2 bg-white border rounded d-flex align-items-center justify-content-center position-relative overflow-hidden"
|
||||
style="height: 150px;">
|
||||
|
||||
<div id="placeholder-utama"
|
||||
class="text-center text-muted {{ $produk->foto_produk ? 'd-none' : '' }}">
|
||||
<i class="bi bi-cloud-arrow-up fs-1"></i>
|
||||
<div class="small mt-1">Upload foto baru</div>
|
||||
</div>
|
||||
|
||||
<img id="preview-utama"
|
||||
src="{{ $produk->foto_produk ? asset('storage/' . $produk->foto_produk) : '#' }}"
|
||||
class="img-fluid w-100 h-100 object-fit-contain {{ $produk->foto_produk ? '' : 'd-none' }}">
|
||||
</div>
|
||||
|
||||
{{-- Input File --}}
|
||||
<input type="file" name="foto_produk" class="form-control form-control-sm"
|
||||
accept="image/*" onchange="previewMainImage(this)">
|
||||
<small class="text-muted">Biarkan kosong jika tidak ingin mengganti foto.</small>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Provinsi</label>
|
||||
<select name="provinsi_code" id="provinsi" class="form-select" required>
|
||||
<option value="">Pilih Provinsi</option>
|
||||
@foreach ($provinsis as $prov)
|
||||
<option value="{{ $prov->code }}" {{ $produk->provinsi_code == $prov->code ?
|
||||
'selected' : '' }}>{{ $prov->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- GALERI TAMBAHAN --}}
|
||||
<div class="card bg-light border-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<label class="fw-bold m-0">Galeri Tambahan</label>
|
||||
<span class="badge bg-primary rounded-pill" id="count-badge">0/3</span>
|
||||
</div>
|
||||
|
||||
{{-- CONTAINER PREVIEW --}}
|
||||
<div id="gallery-preview-container" class="row g-2 mb-3">
|
||||
|
||||
{{-- Gambar Lama dari Database --}}
|
||||
@foreach($produk->images as $img)
|
||||
<div class="col-4 position-relative existing-image-wrapper"
|
||||
id="existing-img-{{ $img->id }}">
|
||||
<img src="{{ asset('storage/' . $img->foto) }}"
|
||||
class="rounded w-100 border bg-white"
|
||||
style="height: 70px; object-fit: cover;">
|
||||
|
||||
{{-- Tombol Hapus Gambar Lama --}}
|
||||
<a href="javascript:void(0)"
|
||||
class="position-absolute top-0 end-0 badge bg-danger text-white rounded-circle text-decoration-none m-1 shadow-sm"
|
||||
onclick="if(confirm('Hapus foto ini?')) deleteExistingImage({{ $img->id }});"
|
||||
style="cursor: pointer;">×</a>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
{{-- INPUT FILE --}}
|
||||
<div class="mb-3">
|
||||
<input type="file" id="input-gallery-visual"
|
||||
class="form-control form-control-sm" accept="image/*" multiple>
|
||||
</div>
|
||||
|
||||
{{-- INPUT FILE HIDDEN --}}
|
||||
<input type="file" name="foto_tambahan[]" id="real-input-gallery" class="d-none"
|
||||
multiple>
|
||||
|
||||
<small class="text-muted d-block" style="font-size: 0.8rem;">
|
||||
<i class="bi bi-info-circle me-1"></i>Maksimal 3 foto tambahan total.
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Kota / Kabupaten</label>
|
||||
<select name="kota_code" id="kota" class="form-select" required>
|
||||
<option value="">Pilih Kota/Kabupaten</option>
|
||||
@foreach ($kotas as $kota)
|
||||
<option value="{{ $kota->code }}" {{ $produk->kota_code == $kota->code ?
|
||||
'selected' : '' }}>{{ $kota->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Kecamatan</label>
|
||||
<select name="kecamatan_code" id="kecamatan" class="form-select" required>
|
||||
<option value="">Pilih Kecamatan</option>
|
||||
@foreach ($kecamatans as $kec)
|
||||
<option value="{{ $kec->code }}" {{ $produk->kecamatan_code == $kec->code ?
|
||||
'selected' : '' }}>{{ $kec->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Desa / Kelurahan</label>
|
||||
<select name="desa_code" id="desa" class="form-select" required>
|
||||
<option value="">Pilih Desa</option>
|
||||
@foreach ($desas as $desa)
|
||||
<option value="{{ $desa->code }}" {{ $produk->desa_code == $desa->code ?
|
||||
'selected' : '' }}>{{ $desa->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-top pt-3 mt-4 text-end">
|
||||
<a href="{{ route('petani.produk.index') }}" class="btn btn-secondary me-2">Batal</a>
|
||||
<button type="submit" class="btn btn-primary px-4">Update Produk</button>
|
||||
</div>
|
||||
</form>
|
||||
{{-- KELOLA GAMBAR --}}
|
||||
<div class="col-lg-4">
|
||||
<h5 class="mb-4">Kelola Gambar</h5>
|
||||
|
||||
{{-- FORM TERSEMBUNYI UNTUK HAPUS GAMBAR LAMA --}}
|
||||
@foreach($produk->images as $img)
|
||||
<form id="form-del-img-{{ $img->id }}" action="{{ route('petani.produk.image.delete', $img->id) }}"
|
||||
method="POST" style="display: none;">
|
||||
@csrf @method('DELETE')
|
||||
</form>
|
||||
@endforeach
|
||||
</div>
|
||||
{{-- FOTO UTAMA --}}
|
||||
<div class="card bg-light border-0 mb-4">
|
||||
<div class="card-body">
|
||||
<label class="fw-bold mb-2">Foto Utama</label>
|
||||
|
||||
{{-- AREA PREVIEW --}}
|
||||
<div class="mb-2 bg-white border rounded d-flex align-items-center justify-content-center position-relative overflow-hidden" style="height: 150px;">
|
||||
|
||||
<div id="placeholder-utama" class="text-center text-muted {{ $produk->foto_produk ? 'd-none' : '' }}">
|
||||
<i class="bi bi-cloud-arrow-up fs-1"></i>
|
||||
<div class="small mt-1">Upload foto baru</div>
|
||||
</div>
|
||||
|
||||
<img id="preview-utama" src="{{ $produk->foto_produk ? asset('storage/' . $produk->foto_produk) : '#' }}" class="img-fluid w-100 h-100 object-fit-contain {{ $produk->foto_produk ? '' : 'd-none' }}">
|
||||
</div>
|
||||
|
||||
{{-- Input File --}}
|
||||
<input type="file" name="foto_produk" class="form-control form-control-sm" accept="image/*" onchange="previewMainImage(this)">
|
||||
<small class="text-muted">Biarkan kosong jika tidak ingin mengganti foto.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- GALERI TAMBAHAN --}}
|
||||
<div class="card bg-light border-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<label class="fw-bold m-0">Galeri Tambahan</label>
|
||||
<span class="badge bg-primary rounded-pill" id="count-badge">0/3</span>
|
||||
</div>
|
||||
|
||||
{{-- CONTAINER PREVIEW --}}
|
||||
<div id="gallery-preview-container" class="row g-2 mb-3">
|
||||
|
||||
{{-- Gambar Lama dari Database --}}
|
||||
@foreach($produk->images as $img)
|
||||
<div class="col-4 position-relative existing-image-wrapper" id="existing-img-{{ $img->id }}">
|
||||
<img src="{{ asset('storage/' . $img->foto) }}" class="rounded w-100 border bg-white" style="height: 70px; object-fit: cover;">
|
||||
|
||||
{{-- Tombol Hapus Gambar Lama --}}
|
||||
<a href="javascript:void(0)" class="position-absolute top-0 end-0 badge bg-danger text-white rounded-circle text-decoration-none m-1 shadow-sm" onclick="if(confirm('Hapus foto ini?')) deleteExistingImage({{ $img->id }});" style="cursor: pointer;">×</a>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
{{-- INPUT FILE --}}
|
||||
<div class="mb-3">
|
||||
<input type="file" id="input-gallery-visual" class="form-control form-control-sm" accept="image/*" multiple>
|
||||
</div>
|
||||
|
||||
{{-- INPUT FILE HIDDEN --}}
|
||||
<input type="file" name="foto_tambahan[]" id="real-input-gallery" class="d-none" multiple>
|
||||
|
||||
<small class="text-muted d-block" style="font-size: 0.8rem;">
|
||||
<i class="bi bi-info-circle me-1"></i>Maksimal 3 foto tambahan total.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-top pt-3 mt-4 text-end">
|
||||
<a href="{{ route('petani.produk.index') }}" class="btn btn-secondary me-2">Batal</a>
|
||||
<button type="submit" class="btn btn-primary px-4">Update Produk</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{{-- FORM TERSEMBUNYI UNTUK HAPUS GAMBAR LAMA --}}
|
||||
@foreach($produk->images as $img)
|
||||
<form id="form-del-img-{{ $img->id }}" action="{{ route('petani.produk.image.delete', $img->id) }}" method="POST" style="display: none;">
|
||||
@csrf @method('DELETE')
|
||||
</form>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// ----------------------------------------------------
|
||||
// PREVIEW FOTO UTAMA
|
||||
// ----------------------------------------------------
|
||||
function previewMainImage(input) {
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#provinsi').on('change', function() {
|
||||
let code = $(this).val();
|
||||
$('#kota').html('<option value="">Memuat...</option>').prop('disabled', true);
|
||||
$('#kecamatan').html('<option value="">== Pilih Kecamatan ==</option>').prop('disabled', true);
|
||||
$('#desa').html('<option value="">== Pilih Desa ==</option>').prop('disabled', true);
|
||||
|
||||
if (code) {
|
||||
$.ajax({
|
||||
url: "{{ route('get.kota') }}"
|
||||
, type: "POST"
|
||||
, data: {
|
||||
code: code
|
||||
, _token: '{{ csrf_token() }}'
|
||||
}
|
||||
, success: function(data) {
|
||||
$('#kota').html('<option value="">== Pilih Kota/Kabupaten ==</option>');
|
||||
$.each(data, function(key, value) {
|
||||
$('#kota').append('<option value="' + value.code + '">' + value.name + '</option>');
|
||||
});
|
||||
$('#kota').prop('disabled', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#kota').on('change', function() {
|
||||
let code = $(this).val();
|
||||
$('#kecamatan').html('<option value="">Memuat...</option>').prop('disabled', true);
|
||||
$('#desa').html('<option value="">== Pilih Desa ==</option>').prop('disabled', true);
|
||||
|
||||
if (code) {
|
||||
$.ajax({
|
||||
url: "{{ route('get.kecamatan') }}"
|
||||
, type: "POST"
|
||||
, data: {
|
||||
code: code
|
||||
, _token: '{{ csrf_token() }}'
|
||||
}
|
||||
, success: function(data) {
|
||||
$('#kecamatan').html('<option value="">== Pilih Kecamatan ==</option>');
|
||||
$.each(data, function(key, value) {
|
||||
$('#kecamatan').append('<option value="' + value.code + '">' + value.name + '</option>');
|
||||
});
|
||||
$('#kecamatan').prop('disabled', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#kecamatan').on('change', function() {
|
||||
let code = $(this).val();
|
||||
$('#desa').html('<option value="">Memuat...</option>').prop('disabled', true);
|
||||
|
||||
if (code) {
|
||||
$.ajax({
|
||||
url: "{{ route('get.desa') }}"
|
||||
, type: "POST"
|
||||
, data: {
|
||||
code: code
|
||||
, _token: '{{ csrf_token() }}'
|
||||
}
|
||||
, success: function(data) {
|
||||
$('#desa').html('<option value="">== Pilih Desa ==</option>');
|
||||
$.each(data, function(key, value) {
|
||||
$('#desa').append('<option value="' + value.code + '">' + value.name + '</option>');
|
||||
});
|
||||
$('#desa').prop('disabled', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
// ----------------------------------------------------
|
||||
// PREVIEW FOTO UTAMA
|
||||
// ----------------------------------------------------
|
||||
function previewMainImage(input) {
|
||||
const preview = document.getElementById('preview-utama');
|
||||
const placeholder = document.getElementById('placeholder-utama');
|
||||
|
||||
if (input.files && input.files[0]) {
|
||||
var reader = new FileReader();
|
||||
|
||||
|
||||
reader.onload = function(e) {
|
||||
preview.src = e.target.result;
|
||||
preview.classList.remove('d-none');
|
||||
placeholder.classList.add('d-none');
|
||||
}
|
||||
|
||||
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// LOGIC HAPUS GAMBAR LAMA (DATABASE)
|
||||
// ----------------------------------------------------
|
||||
function deleteExistingImage(id) {
|
||||
document.getElementById('form-del-img-' + id).submit();
|
||||
// ----------------------------------------------------
|
||||
// LOGIC HAPUS GAMBAR LAMA (DATABASE)
|
||||
// ----------------------------------------------------
|
||||
function deleteExistingImage(id) {
|
||||
document.getElementById('form-del-img-' + id).submit();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// LOGIC PREVIEW + ACCUMULATE
|
||||
// ----------------------------------------------------
|
||||
const inputVisual = document.getElementById('input-gallery-visual');
|
||||
const inputReal = document.getElementById('real-input-gallery');
|
||||
const container = document.getElementById('gallery-preview-container');
|
||||
const countBadge = document.getElementById('count-badge');
|
||||
|
||||
let dt = new DataTransfer();
|
||||
let existingCount = document.querySelectorAll('.existing-image-wrapper').length;
|
||||
updateBadge();
|
||||
|
||||
inputVisual.addEventListener('change', function() {
|
||||
const newFiles = this.files;
|
||||
|
||||
if (existingCount + dt.items.length + newFiles.length > 3) {
|
||||
alert('Maksimal total hanya boleh 3 gambar tambahan!');
|
||||
this.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// LOGIC PREVIEW + ACCUMULATE
|
||||
// ----------------------------------------------------
|
||||
const inputVisual = document.getElementById('input-gallery-visual');
|
||||
const inputReal = document.getElementById('real-input-gallery');
|
||||
const container = document.getElementById('gallery-preview-container');
|
||||
const countBadge = document.getElementById('count-badge');
|
||||
// Loop file yang baru dipilih
|
||||
for (let i = 0; i < newFiles.length; i++) {
|
||||
const file = newFiles[i];
|
||||
|
||||
let dt = new DataTransfer();
|
||||
let existingCount = document.querySelectorAll('.existing-image-wrapper').length;
|
||||
updateBadge();
|
||||
// Tambahkan ke keranjang DataTransfer
|
||||
dt.items.add(file);
|
||||
|
||||
inputVisual.addEventListener('change', function () {
|
||||
const newFiles = this.files;
|
||||
// Buat Preview Element
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
const col = document.createElement('div');
|
||||
col.className = 'col-4 position-relative new-image-preview';
|
||||
|
||||
if (existingCount + dt.items.length + newFiles.length > 3) {
|
||||
alert('Maksimal total hanya boleh 3 gambar tambahan!');
|
||||
this.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop file yang baru dipilih
|
||||
for (let i = 0; i < newFiles.length; i++) {
|
||||
const file = newFiles[i];
|
||||
|
||||
// Tambahkan ke keranjang DataTransfer
|
||||
dt.items.add(file);
|
||||
|
||||
// Buat Preview Element
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
const col = document.createElement('div');
|
||||
col.className = 'col-4 position-relative new-image-preview';
|
||||
|
||||
// HTML Preview
|
||||
col.innerHTML = `
|
||||
// HTML Preview
|
||||
col.innerHTML = `
|
||||
<img src="${e.target.result}" class="rounded w-100 border bg-white" style="height: 70px; object-fit: cover;">
|
||||
<span class="position-absolute top-0 end-0 badge bg-secondary text-white rounded-circle m-1 shadow-sm remove-btn"
|
||||
style="cursor: pointer;">×</span>
|
||||
`;
|
||||
|
||||
// Event Hapus Preview
|
||||
col.querySelector('.remove-btn').addEventListener('click', function () {
|
||||
for (let j = 0; j < dt.items.length; j++) {
|
||||
if (dt.files[j].name === file.name && dt.files[j].size === file.size) {
|
||||
dt.items.remove(j);
|
||||
break;
|
||||
}
|
||||
// Event Hapus Preview
|
||||
col.querySelector('.remove-btn').addEventListener('click', function() {
|
||||
for (let j = 0; j < dt.items.length; j++) {
|
||||
if (dt.files[j].name === file.name && dt.files[j].size === file.size) {
|
||||
dt.items.remove(j);
|
||||
break;
|
||||
}
|
||||
// Sinkronisasi ke Input Real
|
||||
inputReal.files = dt.files;
|
||||
col.remove();
|
||||
updateBadge();
|
||||
});
|
||||
}
|
||||
// Sinkronisasi ke Input Real
|
||||
inputReal.files = dt.files;
|
||||
col.remove();
|
||||
updateBadge();
|
||||
});
|
||||
|
||||
container.appendChild(col);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
inputReal.files = dt.files;
|
||||
this.value = '';
|
||||
updateBadge();
|
||||
});
|
||||
|
||||
function updateBadge() {
|
||||
let total = existingCount + dt.items.length;
|
||||
countBadge.innerText = total + '/3';
|
||||
|
||||
if (total >= 3) {
|
||||
inputVisual.disabled = true;
|
||||
countBadge.classList.remove('bg-primary');
|
||||
countBadge.classList.add('bg-danger');
|
||||
inputVisual.setAttribute('title', 'Kapasitas penuh');
|
||||
} else {
|
||||
inputVisual.disabled = false;
|
||||
countBadge.classList.remove('bg-danger');
|
||||
countBadge.classList.add('bg-primary');
|
||||
inputVisual.removeAttribute('title');
|
||||
}
|
||||
container.appendChild(col);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
inputReal.files = dt.files;
|
||||
this.value = '';
|
||||
updateBadge();
|
||||
});
|
||||
|
||||
function updateBadge() {
|
||||
let total = existingCount + dt.items.length;
|
||||
countBadge.innerText = total + '/3';
|
||||
|
||||
if (total >= 3) {
|
||||
inputVisual.disabled = true;
|
||||
countBadge.classList.remove('bg-primary');
|
||||
countBadge.classList.add('bg-danger');
|
||||
inputVisual.setAttribute('title', 'Kapasitas penuh');
|
||||
} else {
|
||||
inputVisual.disabled = false;
|
||||
countBadge.classList.remove('bg-danger');
|
||||
countBadge.classList.add('bg-primary');
|
||||
inputVisual.removeAttribute('title');
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -123,6 +123,11 @@
|
|||
Route::put('/petani/profile', [ProfileController::class, 'updatePetani'])->name('petani.profile.update');
|
||||
});
|
||||
|
||||
// Route untuk Dropdown Wilayah Laravolt
|
||||
Route::post('/get-kota', [\App\Http\Controllers\WilayahController::class, 'getKota'])->name('get.kota');
|
||||
Route::post('/get-kecamatan', [\App\Http\Controllers\WilayahController::class, 'getKecamatan'])->name('get.kecamatan');
|
||||
Route::post('/get-desa', [\App\Http\Controllers\WilayahController::class, 'getDesa'])->name('get.desa');
|
||||
|
||||
|
||||
// --- CEK NIK GAPOKTAN AJAX ---
|
||||
Route::post('/cek-nik-gapoktan', function (Request $request) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue