artikel atau informasi by admin done

This commit is contained in:
E31232303evimr 2026-03-01 23:28:18 +07:00
parent 86c6a51401
commit 1c8fd53f16
18 changed files with 1144 additions and 221 deletions

View File

@ -0,0 +1,129 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\InformasiBudidaya;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class ArtikelBudidayaController extends Controller
{
public function index()
{
$artikels = InformasiBudidaya::latest()->paginate(10);
return view('admin.artikel-budidaya.index', compact('artikels'));
}
public function create()
{
return view('admin.artikel-budidaya.create');
}
public function store(Request $request)
{
$validated = $request->validate([
'judul' => 'required|string|max:200',
'deskripsi_singkat' => 'nullable|string',
'konten' => 'required|string',
'gambar_utama' => 'nullable|image|max:2048',
'galeri_gambar.*' => 'nullable|image|max:2048',
'file_pdf' => 'nullable|mimes:pdf|max:5120',
'tags' => 'nullable|string',
'is_published' => 'boolean',
]);
$validated['slug'] = Str::slug($request->judul);
$validated['created_by'] = auth()->id();
$validated['is_published'] = $request->has('is_published') ? 1 : 0;
if ($request->hasFile('gambar_utama')) {
$validated['gambar_utama'] = $request->file('gambar_utama')->store('budidaya/gambar', 'public');
}
if ($request->hasFile('file_pdf')) {
$validated['file_pdf'] = $request->file('file_pdf')->store('budidaya/pdf', 'public');
}
// Handle galeri gambar
if ($request->hasFile('galeri_gambar')) {
$galeri = [];
foreach ($request->file('galeri_gambar') as $foto) {
$galeri[] = $foto->store('budidaya/galeri', 'public');
}
$validated['galeri_gambar'] = $galeri; // otomatis di-cast ke JSON oleh model
}
// Handle tags
$tagsDecoded = json_decode($request->tags, true);
$validated['tags'] = (!empty($tagsDecoded)) ? $tagsDecoded : null;
if ($validated['is_published']) {
$validated['published_at'] = now();
}
InformasiBudidaya::create($validated);
return redirect()->route('admin.artikel-budidaya.index')
->with('success', 'Artikel budidaya berhasil ditambahkan!');
}
public function edit(InformasiBudidaya $artikelBudidaya)
{
return view('admin.artikel-budidaya.edit', compact('artikelBudidaya'));
}
public function update(Request $request, InformasiBudidaya $artikelBudidaya)
{
$validated = $request->validate([
'judul' => 'required|string|max:200',
'deskripsi_singkat'=> 'nullable|string',
'konten' => 'required|string',
'gambar_utama' => 'nullable|image|max:2048',
'galeri_gambar.*' => 'nullable|image|max:2048',
'file_pdf' => 'nullable|mimes:pdf|max:5120',
'tags' => 'nullable|string',
'is_published' => 'boolean',
]);
$validated['slug'] = Str::slug($request->judul);
$validated['is_published'] = $request->has('is_published') ? 1 : 0;
if ($request->hasFile('gambar_utama')) {
$validated['gambar_utama'] = $request->file('gambar_utama')->store('budidaya/gambar', 'public');
}
if ($request->hasFile('file_pdf')) {
$validated['file_pdf'] = $request->file('file_pdf')->store('budidaya/pdf', 'public');
}
// Handle galeri gambar
if ($request->hasFile('galeri_gambar')) {
$galeri = [];
foreach ($request->file('galeri_gambar') as $foto) {
$galeri[] = $foto->store('budidaya/galeri', 'public');
}
$validated['galeri_gambar'] = $galeri;
}
// Handle tags
$tagsDecoded = json_decode($request->tags, true);
$validated['tags'] = (!empty($tagsDecoded)) ? $tagsDecoded : null;
if ($validated['is_published'] && !$artikelBudidaya->published_at) {
$validated['published_at'] = now();
}
$artikelBudidaya->update($validated);
return redirect()->route('admin.artikel-budidaya.index')
->with('success', 'Artikel budidaya berhasil diupdate!');
}
public function destroy(InformasiBudidaya $artikelBudidaya)
{
$artikelBudidaya->delete();
return redirect()->route('admin.artikel-budidaya.index')
->with('success', 'Artikel budidaya berhasil dihapus!');
}
}

View File

@ -1,146 +0,0 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\InformasiBudidaya;
use App\Models\InformasiHamaPenyakit;
use Illuminate\Http\Request;
class ArtikelController extends Controller
{
/**
* Display a listing of artikel.
* Gabungan dari InformasiBudidaya dan InformasiHamaPenyakit
*/
public function index()
{
// Ambil artikel dari kedua tabel
$budidaya = InformasiBudidaya::latest()->get()->map(function($item) {
$item->kategori = 'Budidaya';
return $item;
});
$hamaPenyakit = InformasiHamaPenyakit::latest()->get()->map(function($item) {
$item->kategori = 'Hama & Penyakit';
return $item;
});
// Gabungkan dan paginate manual
$artikels = $budidaya->merge($hamaPenyakit)->sortByDesc('created_at');
// Convert ke paginator
$page = request()->get('page', 1);
$perPage = 10;
$artikels = new \Illuminate\Pagination\LengthAwarePaginator(
$artikels->forPage($page, $perPage),
$artikels->count(),
$perPage,
$page,
['path' => request()->url(), 'query' => request()->query()]
);
return view('admin.artikel.index', compact('artikels'));
}
/**
* Show the form for creating a new artikel.
*/
public function create()
{
return view('admin.artikel.create');
}
/**
* Store a newly created artikel.
*/
public function store(Request $request)
{
$validated = $request->validate([
'kategori' => ['required', 'in:budidaya,hama_penyakit'],
'judul' => ['required', 'string', 'max:255'],
'konten' => ['required', 'string'],
'gambar' => ['nullable', 'image', 'max:2048'],
]);
// Upload gambar jika ada
if ($request->hasFile('gambar')) {
$validated['gambar'] = $request->file('gambar')->store('artikel', 'public');
}
$validated['created_by'] = auth()->id();
// Simpan ke tabel yang sesuai
if ($validated['kategori'] === 'budidaya') {
InformasiBudidaya::create($validated);
} else {
InformasiHamaPenyakit::create($validated);
}
return redirect()->route('admin.artikel.index')
->with('success', 'Artikel berhasil ditambahkan!');
}
/**
* Show the form for editing artikel.
*/
public function edit($id)
{
// Cari di kedua tabel
$artikel = InformasiBudidaya::find($id);
$kategori = 'budidaya';
if (!$artikel) {
$artikel = InformasiHamaPenyakit::findOrFail($id);
$kategori = 'hama_penyakit';
}
return view('admin.artikel.edit', compact('artikel', 'kategori'));
}
/**
* Update the specified artikel.
*/
public function update(Request $request, $id)
{
$validated = $request->validate([
'kategori' => ['required', 'in:budidaya,hama_penyakit'],
'judul' => ['required', 'string', 'max:255'],
'konten' => ['required', 'string'],
'gambar' => ['nullable', 'image', 'max:2048'],
]);
// Upload gambar baru jika ada
if ($request->hasFile('gambar')) {
$validated['gambar'] = $request->file('gambar')->store('artikel', 'public');
}
// Update di tabel yang sesuai
if ($validated['kategori'] === 'budidaya') {
$artikel = InformasiBudidaya::findOrFail($id);
} else {
$artikel = InformasiHamaPenyakit::findOrFail($id);
}
$artikel->update($validated);
return redirect()->route('admin.artikel.index')
->with('success', 'Artikel berhasil diupdate!');
}
/**
* Remove the specified artikel.
*/
public function destroy($id)
{
// Coba hapus dari kedua tabel
$deleted = InformasiBudidaya::where('id', $id)->delete();
if (!$deleted) {
InformasiHamaPenyakit::where('id', $id)->delete();
}
return redirect()->route('admin.artikel.index')
->with('success', 'Artikel berhasil dihapus!');
}
}

View File

@ -0,0 +1,139 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\InformasiHamaPenyakit;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class ArtikelHamaPenyakitController extends Controller
{
public function index()
{
$artikels = InformasiHamaPenyakit::latest()->paginate(10);
return view('admin.artikel-hama-penyakit.index', compact('artikels'));
}
public function create()
{
return view('admin.artikel-hama-penyakit.create');
}
public function store(Request $request)
{
$validated = $request->validate([
'judul' => 'required|string|max:200',
'jenis' => 'required|in:Hama,Penyakit',
'deskripsi_singkat'=> 'nullable|string',
'konten' => 'required|string',
'gejala_visual' => 'nullable|string',
'cara_identifikasi'=> 'nullable|string',
'pencegahan' => 'nullable|string',
'pengendalian' => 'nullable|string',
'gambar_utama' => 'nullable|image|max:2048',
'galeri_gambar.*' => 'nullable|image|max:2048',
'file_pdf' => 'nullable|mimes:pdf|max:5120',
'tags' => 'nullable|string',
'is_published' => 'boolean',
]);
$validated['slug'] = Str::slug($request->judul);
$validated['created_by'] = auth()->id();
$validated['is_published'] = $request->has('is_published') ? 1 : 0;
if ($request->hasFile('gambar_utama')) {
$validated['gambar_utama'] = $request->file('gambar_utama')->store('hama-penyakit/gambar', 'public');
}
if ($request->hasFile('file_pdf')) {
$validated['file_pdf'] = $request->file('file_pdf')->store('hama-penyakit/pdf', 'public');
}
// Handle galeri gambar
if ($request->hasFile('galeri_gambar')) {
$galeri = [];
foreach ($request->file('galeri_gambar') as $foto) {
$galeri[] = $foto->store('hama-penyakit/galeri', 'public');
}
$validated['galeri_gambar'] = $galeri;
}
// Handle tags
$tagsDecoded = json_decode($request->tags, true);
$validated['tags'] = (!empty($tagsDecoded)) ? $tagsDecoded : null;
if ($validated['is_published']) {
$validated['published_at'] = now();
}
InformasiHamaPenyakit::create($validated);
return redirect()->route('admin.artikel-hama-penyakit.index')
->with('success', 'Artikel hama & penyakit berhasil ditambahkan!');
}
public function edit(InformasiHamaPenyakit $artikelHamaPenyakit)
{
return view('admin.artikel-hama-penyakit.edit', compact('artikelHamaPenyakit'));
}
public function update(Request $request, InformasiHamaPenyakit $artikelHamaPenyakit)
{
$validated = $request->validate([
'judul' => 'required|string|max:200',
'jenis' => 'required|in:Hama,Penyakit',
'deskripsi_singkat'=> 'nullable|string',
'konten' => 'required|string',
'gejala_visual' => 'nullable|string',
'cara_identifikasi'=> 'nullable|string',
'pencegahan' => 'nullable|string',
'pengendalian' => 'nullable|string',
'gambar_utama' => 'nullable|image|max:2048',
'galeri_gambar.*' => 'nullable|image|max:2048',
'file_pdf' => 'nullable|mimes:pdf|max:5120',
'tags' => 'nullable|string',
'is_published' => 'boolean',
]);
$validated['slug'] = Str::slug($request->judul);
$validated['is_published'] = $request->has('is_published') ? 1 : 0;
if ($request->hasFile('gambar_utama')) {
$validated['gambar_utama'] = $request->file('gambar_utama')->store('hama-penyakit/gambar', 'public');
}
if ($request->hasFile('file_pdf')) {
$validated['file_pdf'] = $request->file('file_pdf')->store('hama-penyakit/pdf', 'public');
}
// Handle galeri gambar
if ($request->hasFile('galeri_gambar')) {
$galeri = [];
foreach ($request->file('galeri_gambar') as $foto) {
$galeri[] = $foto->store('hama-penyakit/galeri', 'public');
}
$validated['galeri_gambar'] = $galeri;
}
// Handle tags
$tagsDecoded = json_decode($request->tags, true);
$validated['tags'] = (!empty($tagsDecoded)) ? $tagsDecoded : null;
if ($validated['is_published'] && !$artikelHamaPenyakit->published_at) {
$validated['published_at'] = now();
}
$artikelHamaPenyakit->update($validated);
return redirect()->route('admin.artikel-hama-penyakit.index')
->with('success', 'Artikel hama & penyakit berhasil diupdate!');
}
public function destroy(InformasiHamaPenyakit $artikelHamaPenyakit)
{
$artikelHamaPenyakit->delete();
return redirect()->route('admin.artikel-hama-penyakit.index')
->with('success', 'Artikel hama & penyakit berhasil dihapus!');
}
}

View File

@ -34,7 +34,7 @@ public function index(Request $request)
$rules = $query->orderBy('id_penyakit', 'asc') $rules = $query->orderBy('id_penyakit', 'asc')
->orderBy('id_gejala', 'asc') ->orderBy('id_gejala', 'asc')
->paginate(15); ->paginate(10);
// Statistics // Statistics
$totalRules = RuleBasis::count(); $totalRules = RuleBasis::count();

View File

@ -16,7 +16,6 @@ class InformasiBudidaya extends Model
'gambar_utama', 'gambar_utama',
'galeri_gambar', 'galeri_gambar',
'file_pdf', 'file_pdf',
'kategori',
'tags', 'tags',
'urutan', 'urutan',
'is_published', 'is_published',

View File

@ -12,43 +12,35 @@
*/ */
public function up(): void public function up(): void
{ {
// Step 1: Drop foreign key constraint sementara // Step 1: Drop foreign key dulu
$fk1 = DB::select("SELECT CONSTRAINT_NAME FROM information_schema.TABLE_CONSTRAINTS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'riwayat_diagnosis'
AND CONSTRAINT_NAME = 'riwayat_diagnosis_penyakit_final_foreign'
AND CONSTRAINT_TYPE = 'FOREIGN KEY'");
if (!empty($fk1)) {
Schema::table('riwayat_diagnosis', function (Blueprint $table) {
$table->dropForeign('riwayat_diagnosis_penyakit_final_foreign');
});
}
// Step 2: Ubah penyakit_final jadi VARCHAR(10) supaya cocok dengan id_penyakit
DB::statement('ALTER TABLE riwayat_diagnosis MODIFY penyakit_final VARCHAR(10) NULL');
// Step 3: Pasang foreign key lagi
Schema::table('riwayat_diagnosis', function (Blueprint $table) {
$table->foreign('penyakit_final')
->references('id_penyakit')
->on('master_penyakit')
->onDelete('set null');
});
}
public function down(): void
{
Schema::table('riwayat_diagnosis', function (Blueprint $table) { Schema::table('riwayat_diagnosis', function (Blueprint $table) {
$table->dropForeign('riwayat_diagnosis_penyakit_final_foreign'); $table->dropForeign('riwayat_diagnosis_penyakit_final_foreign');
}); });
// Step 2: Set id_penyakit jadi AUTO_INCREMENT
DB::statement('ALTER TABLE master_penyakit MODIFY id_penyakit BIGINT UNSIGNED NOT NULL AUTO_INCREMENT');
// Step 3: Ubah penyakit_final dari VARCHAR(10) jadi BIGINT UNSIGNED
DB::statement('ALTER TABLE riwayat_diagnosis MODIFY penyakit_final BIGINT UNSIGNED NULL'); DB::statement('ALTER TABLE riwayat_diagnosis MODIFY penyakit_final BIGINT UNSIGNED NULL');
// Step 4: Buat foreign key lagi dengan tipe data yang benar
Schema::table('riwayat_diagnosis', function (Blueprint $table) {
$table->foreign('penyakit_final')
->references('id_penyakit')
->on('master_penyakit')
->onDelete('set null');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Rollback: Drop foreign key
Schema::table('riwayat_diagnosis', function (Blueprint $table) {
$table->dropForeign(['penyakit_final']);
});
// Kembalikan penyakit_final jadi VARCHAR(10)
DB::statement('ALTER TABLE riwayat_diagnosis MODIFY penyakit_final VARCHAR(10) NULL');
// Hapus AUTO_INCREMENT dari id_penyakit
DB::statement('ALTER TABLE master_penyakit MODIFY id_penyakit BIGINT UNSIGNED NOT NULL');
// Buat foreign key lagi ke kode_penyakit (struktur lama)
// Note: Ini opsional, sesuaikan dengan struktur database awal kamu
} }
}; };

View File

@ -0,0 +1,25 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('informasi_budidaya', function (Blueprint $table) {
$table->dropColumn('kategori');
});
}
public function down(): void
{
Schema::table('informasi_budidaya', function (Blueprint $table) {
$table->string('kategori', 50)->nullable();
});
}
};

View File

@ -0,0 +1,133 @@
@extends('layouts.admin-app')
@section('page-title', 'Tambah Artikel Budidaya')
@section('page-subtitle', 'Tambah informasi budidaya kopi baru')
@section('content')
<div class="bg-white rounded-2xl shadow-lg">
<div class="p-8">
<form action="{{ route('admin.artikel-budidaya.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="space-y-6">
<!-- Judul -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Judul <span class="text-red-500">*</span></label>
<input type="text" name="judul" value="{{ old('judul') }}"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500 focus:border-transparent @error('judul') border-red-500 @enderror"
placeholder="Masukkan judul artikel...">
@error('judul') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<!-- Deskripsi Singkat -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Deskripsi Singkat</label>
<textarea name="deskripsi_singkat" rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500 focus:border-transparent"
placeholder="Ringkasan singkat artikel...">{{ old('deskripsi_singkat') }}</textarea>
</div>
<!-- Konten -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Konten <span class="text-red-500">*</span></label>
<textarea name="konten" rows="10"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500 focus:border-transparent @error('konten') border-red-500 @enderror"
placeholder="Tulis konten artikel di sini...">{{ old('konten') }}</textarea>
@error('konten') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<!-- Gambar Utama & PDF -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Gambar Utama</label>
<input type="file" name="gambar_utama" accept="image/*"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500">
<p class="text-xs text-gray-400 mt-1">Format: JPG, PNG. Maks 2MB</p>
</div>
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">File PDF</label>
<input type="file" name="file_pdf" accept=".pdf"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500">
<p class="text-xs text-gray-400 mt-1">Format: PDF. Maks 5MB</p>
</div>
</div>
<!-- Tags -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Tags</label>
<div id="tags-container" class="w-full px-4 py-3 border border-gray-300 rounded-xl flex flex-wrap gap-2 min-h-[50px]">
</div>
<input type="text" id="tags-input"
class="w-full mt-2 px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500"
placeholder="Ketik tag lalu tekan Enter...">
<p class="text-xs text-gray-400 mt-1">Tekan Enter atau koma untuk menambah tag</p>
<input type="hidden" name="tags" id="tags-hidden" value="[]">
</div>
<!-- Galeri Gambar -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Galeri Gambar</label>
<input type="file" name="galeri_gambar[]" accept="image/*" multiple
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500">
<p class="text-xs text-gray-400 mt-1">Bisa pilih beberapa foto sekaligus. Format: JPG, PNG. Maks 2MB per foto</p>
</div>
<!-- Status Publish -->
<div class="flex items-center space-x-3">
<input type="checkbox" name="is_published" value="1" id="is_published" {{ old('is_published') ? 'checked' : '' }}
class="w-5 h-5 text-green-600 rounded focus:ring-green-500">
<label for="is_published" class="text-sm font-bold text-gray-700">Publikasikan sekarang</label>
</div>
</div>
<!-- Buttons -->
<div class="flex justify-end space-x-3 mt-8 pt-6 border-t border-gray-200">
<a href="{{ route('admin.artikel-budidaya.index') }}" class="px-6 py-3 border border-gray-300 text-gray-700 font-semibold rounded-xl hover:bg-gray-50 transition">
Batal
</a>
<button type="submit" class="px-6 py-3 bg-gradient-to-r from-green-500 to-green-600 text-white font-bold rounded-xl hover:from-green-600 hover:to-green-700 transition shadow-lg">
Simpan Artikel
</button>
</div>
</form>
</div>
</div>
@endsection
@push('scripts')
<script>
const tagsInput = document.getElementById('tags-input');
const tagsContainer = document.getElementById('tags-container');
const tagsHidden = document.getElementById('tags-hidden');
let tags = [];
function renderTags() {
tagsContainer.innerHTML = '';
tags.forEach((tag, index) => {
tagsContainer.innerHTML += `
<span class="flex items-center px-3 py-1 bg-green-100 text-green-800 text-xs font-bold rounded-full">
${tag}
<button type="button" onclick="removeTag(${index})" class="ml-2 text-green-600 hover:text-red-500"></button>
</span>`;
});
tagsHidden.value = JSON.stringify(tags);
}
function removeTag(index) {
tags.splice(index, 1);
renderTags();
}
tagsInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter' || e.key === ',') {
e.preventDefault();
const val = tagsInput.value.trim();
if (val) {
tags.push(val);
tagsInput.value = '';
renderTags();
}
}
});
</script>
@endpush

View File

@ -0,0 +1,148 @@
@extends('layouts.admin-app')
@section('page-title', 'Edit Artikel Budidaya')
@section('page-subtitle', 'Edit informasi budidaya kopi')
@section('content')
<div class="bg-white rounded-2xl shadow-lg">
<div class="p-8">
<form action="{{ route('admin.artikel-budidaya.update', $artikelBudidaya) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
<div class="space-y-6">
<!-- Judul -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Judul <span class="text-red-500">*</span></label>
<input type="text" name="judul" value="{{ old('judul', $artikelBudidaya->judul) }}"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500 focus:border-transparent @error('judul') border-red-500 @enderror">
@error('judul') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<!-- Deskripsi Singkat -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Deskripsi Singkat</label>
<textarea name="deskripsi_singkat" rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500 focus:border-transparent">{{ old('deskripsi_singkat', $artikelBudidaya->deskripsi_singkat) }}</textarea>
</div>
<!-- Konten -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Konten <span class="text-red-500">*</span></label>
<textarea name="konten" rows="10"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500 focus:border-transparent @error('konten') border-red-500 @enderror">{{ old('konten', $artikelBudidaya->konten) }}</textarea>
@error('konten') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<!-- Gambar Utama -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Gambar Utama</label>
@if($artikelBudidaya->gambar_utama)
<img src="{{ Storage::url($artikelBudidaya->gambar_utama) }}" class="w-32 h-24 object-cover rounded-lg mb-2">
@endif
<input type="file" name="gambar_utama" accept="image/*"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500">
<p class="text-xs text-gray-400 mt-1">Kosongkan jika tidak ingin mengubah gambar</p>
</div>
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">File PDF</label>
@if($artikelBudidaya->file_pdf)
<a href="{{ Storage::url($artikelBudidaya->file_pdf) }}" target="_blank" class="text-xs text-blue-500 underline mb-2 block">Lihat PDF saat ini</a>
@endif
<input type="file" name="file_pdf" accept=".pdf"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500">
<p class="text-xs text-gray-400 mt-1">Kosongkan jika tidak ingin mengubah PDF</p>
</div>
</div>
<!-- Tags -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Tags</label>
<div id="tags-container" class="w-full px-4 py-3 border border-gray-300 rounded-xl flex flex-wrap gap-2 min-h-[50px]">
</div>
<input type="text" id="tags-input"
class="w-full mt-2 px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500"
placeholder="Ketik tag lalu tekan Enter...">
<p class="text-xs text-gray-400 mt-1">Tekan Enter atau koma untuk menambah tag</p>
<input type="hidden" name="tags" id="tags-hidden" value="[]">
</div>
<!-- Galeri Gambar -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Galeri Gambar</label>
@if($artikelBudidaya->galeri_gambar)
<div class="flex flex-wrap gap-2 mb-3">
@foreach($artikelBudidaya->galeri_gambar as $foto)
<img src="{{ Storage::url($foto) }}" class="w-24 h-20 object-cover rounded-lg">
@endforeach
</div>
@endif
<input type="file" name="galeri_gambar[]" accept="image/*" multiple
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-green-500">
<p class="text-xs text-gray-400 mt-1">Upload foto baru akan menggantikan galeri yang lama</p>
</div>
<!-- Status Publish -->
<div class="flex items-center space-x-3">
<input type="checkbox" name="is_published" value="1" id="is_published" {{ old('is_published', $artikelBudidaya->is_published) ? 'checked' : '' }}
class="w-5 h-5 text-green-600 rounded focus:ring-green-500">
<label for="is_published" class="text-sm font-bold text-gray-700">Publikasikan</label>
</div>
</div>
<!-- Buttons -->
<div class="flex justify-end space-x-3 mt-8 pt-6 border-t border-gray-200">
<a href="{{ route('admin.artikel-budidaya.index') }}" class="px-6 py-3 border border-gray-300 text-gray-700 font-semibold rounded-xl hover:bg-gray-50 transition">
Batal
</a>
<button type="submit" class="px-6 py-3 bg-gradient-to-r from-green-500 to-green-600 text-white font-bold rounded-xl hover:from-green-600 hover:to-green-700 transition shadow-lg">
Update Artikel
</button>
</div>
</form>
</div>
</div>
@endsection
@push('scripts')
<script>
const tagsInput = document.getElementById('tags-input');
const tagsContainer = document.getElementById('tags-container');
const tagsHidden = document.getElementById('tags-hidden');
// Load tags yang sudah ada
let tags = {!! json_encode($artikelBudidaya->tags ?? []) !!};
function renderTags() {
tagsContainer.innerHTML = '';
tags.forEach((tag, index) => {
tagsContainer.innerHTML += `
<span class="flex items-center px-3 py-1 bg-green-100 text-green-800 text-xs font-bold rounded-full">
${tag}
<button type="button" onclick="removeTag(${index})" class="ml-2 text-green-600 hover:text-red-500"></button>
</span>`;
});
tagsHidden.value = JSON.stringify(tags);
}
function removeTag(index) {
tags.splice(index, 1);
renderTags();
}
tagsInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter' || e.key === ',') {
e.preventDefault();
const val = tagsInput.value.trim();
if (val) {
tags.push(val);
tagsInput.value = '';
renderTags();
}
}
});
// Render tags awal
renderTags();
</script>
@endpush

View File

@ -1,7 +1,7 @@
@extends('layouts.admin-app') @extends('layouts.admin-app')
@section('page-title', '📰 Manajemen Artikel') @section('page-title', 'Artikel Budidaya')
@section('page-subtitle', 'Kelola artikel edukasi') @section('page-subtitle', 'Kelola informasi budidaya kopi')
@section('content') @section('content')
@if (session('success')) @if (session('success'))
@ -17,14 +17,14 @@
<div class="p-8"> <div class="p-8">
<div class="flex justify-between items-center mb-6"> <div class="flex justify-between items-center mb-6">
<div class="flex items-center"> <div class="flex items-center">
<div class="bg-gradient-to-r from-yellow-500 to-yellow-600 rounded-xl p-3 mr-4"> <div class="bg-gradient-to-r from-green-500 to-green-600 rounded-xl p-3 mr-4">
<svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"></path>
</svg> </svg>
</div> </div>
<h3 class="text-xl font-bold text-gray-800">Daftar Artikel Edukasi</h3> <h3 class="text-xl font-bold text-gray-800">Daftar Artikel Budidaya</h3>
</div> </div>
<a href="{{ route('admin.artikel.create') }}" class="flex items-center px-5 py-3 bg-gradient-to-r from-yellow-500 to-yellow-600 text-white font-bold rounded-xl hover:from-yellow-600 hover:to-yellow-700 transition-all shadow-lg hover:shadow-xl transform hover:scale-105"> <a href="{{ route('admin.artikel-budidaya.create') }}" class="flex items-center px-5 py-3 bg-gradient-to-r from-green-500 to-green-600 text-white font-bold rounded-xl hover:from-green-600 hover:to-green-700 transition-all shadow-lg hover:shadow-xl transform hover:scale-105">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg> </svg>
@ -38,7 +38,7 @@
<tr> <tr>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">No</th> <th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">No</th>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">Judul</th> <th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">Judul</th>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">Kategori</th> <th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">Status</th>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">Penulis</th> <th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">Penulis</th>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">Tanggal</th> <th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">Tanggal</th>
<th class="px-6 py-4 text-center text-xs font-bold text-gray-600 uppercase">Aksi</th> <th class="px-6 py-4 text-center text-xs font-bold text-gray-600 uppercase">Aksi</th>
@ -50,23 +50,28 @@
<td class="px-6 py-4 text-sm">{{ $artikels->firstItem() + $index }}</td> <td class="px-6 py-4 text-sm">{{ $artikels->firstItem() + $index }}</td>
<td class="px-6 py-4"> <td class="px-6 py-4">
<div class="text-sm font-semibold text-gray-900">{{ $artikel->judul }}</div> <div class="text-sm font-semibold text-gray-900">{{ $artikel->judul }}</div>
@if($artikel->deskripsi_singkat)
<div class="text-xs text-gray-400 mt-1">{{ Str::limit($artikel->deskripsi_singkat, 60) }}</div>
@endif
</td> </td>
<td class="px-6 py-4"> <td class="px-6 py-4">
<span class="px-3 py-1 text-xs font-bold rounded-full bg-yellow-100 text-yellow-800"> @if($artikel->is_published)
{{ $artikel->kategori }} <span class="px-3 py-1 text-xs font-bold rounded-full bg-green-100 text-green-800">Published</span>
</span> @else
<span class="px-3 py-1 text-xs font-bold rounded-full bg-gray-100 text-gray-600">Draft</span>
@endif
</td> </td>
<td class="px-6 py-4 text-sm text-gray-600">{{ $artikel->penulis ?? 'Admin' }}</td> <td class="px-6 py-4 text-sm text-gray-600">{{ $artikel->author->nama ?? 'Admin' }}</td>
<td class="px-6 py-4 text-sm text-gray-600">{{ $artikel->created_at->format('d M Y') }}</td> <td class="px-6 py-4 text-sm text-gray-600">{{ $artikel->created_at->format('d M Y') }}</td>
<td class="px-6 py-4 text-center"> <td class="px-6 py-4 text-center">
<div class="flex justify-center space-x-2"> <div class="flex justify-center space-x-2">
<a href="{{ route('admin.artikel.edit', $artikel) }}" class="inline-flex items-center px-3 py-2 bg-blue-500 text-white text-xs font-semibold rounded-lg hover:bg-blue-600 transition"> <a href="{{ route('admin.artikel-budidaya.edit', $artikel) }}" class="inline-flex items-center px-3 py-2 bg-blue-500 text-white text-xs font-semibold rounded-lg hover:bg-blue-600 transition">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
</svg> </svg>
Edit Edit
</a> </a>
<form action="{{ route('admin.artikel.destroy', $artikel) }}" method="POST" onsubmit="return confirm('Yakin ingin menghapus artikel ini?')"> <form action="{{ route('admin.artikel-budidaya.destroy', $artikel) }}" method="POST" onsubmit="return confirm('Yakin ingin menghapus artikel ini?')">
@csrf @csrf
@method('DELETE') @method('DELETE')
<button type="submit" class="inline-flex items-center px-3 py-2 bg-red-500 text-white text-xs font-semibold rounded-lg hover:bg-red-600 transition"> <button type="submit" class="inline-flex items-center px-3 py-2 bg-red-500 text-white text-xs font-semibold rounded-lg hover:bg-red-600 transition">
@ -81,13 +86,11 @@
</tr> </tr>
@empty @empty
<tr> <tr>
<td colspan="6" class="px-6 py-12 text-center"> <td colspan="6" class="px-6 py-12 text-center text-gray-400">
<div class="text-gray-400"> <svg class="w-16 h-16 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg class="w-16 h-16 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 006.586 13H4"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"></path> </svg>
</svg> <p class="text-xl font-semibold mb-2">Belum ada artikel budidaya</p>
<p class="text-xl font-semibold mb-2">Belum ada artikel</p>
</div>
</td> </td>
</tr> </tr>
@endforelse @endforelse

View File

@ -0,0 +1,176 @@
@extends('layouts.admin-app')
@section('page-title', 'Tambah Artikel Hama & Penyakit')
@section('page-subtitle', 'Tambah informasi hama dan penyakit kopi baru')
@section('content')
<div class="bg-white rounded-2xl shadow-lg">
<div class="p-8">
<form action="{{ route('admin.artikel-hama-penyakit.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="space-y-6">
<!-- Judul & Jenis -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Judul <span class="text-red-500">*</span></label>
<input type="text" name="judul" value="{{ old('judul') }}"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 focus:border-transparent @error('judul') border-red-500 @enderror"
placeholder="Masukkan judul artikel...">
@error('judul') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Jenis <span class="text-red-500">*</span></label>
<select name="jenis" class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 focus:border-transparent @error('jenis') border-red-500 @enderror">
<option value="">-- Pilih Jenis --</option>
<option value="Hama" {{ old('jenis') === 'Hama' ? 'selected' : '' }}>Hama</option>
<option value="Penyakit" {{ old('jenis') === 'Penyakit' ? 'selected' : '' }}>Penyakit</option>
</select>
@error('jenis') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
</div>
<!-- Deskripsi Singkat -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Deskripsi Singkat</label>
<textarea name="deskripsi_singkat" rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 focus:border-transparent"
placeholder="Ringkasan singkat...">{{ old('deskripsi_singkat') }}</textarea>
</div>
<!-- Konten -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Konten <span class="text-red-500">*</span></label>
<textarea name="konten" rows="8"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 focus:border-transparent @error('konten') border-red-500 @enderror"
placeholder="Tulis konten artikel...">{{ old('konten') }}</textarea>
@error('konten') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<!-- Info Spesifik Hama Penyakit -->
<div class="border border-gray-200 rounded-xl p-6 bg-gray-50">
<h4 class="font-bold text-gray-700 mb-4">📋 Informasi Teknis</h4>
<div class="space-y-4">
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Gejala Visual</label>
<textarea name="gejala_visual" rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 bg-white"
placeholder="Deskripsikan gejala yang terlihat...">{{ old('gejala_visual') }}</textarea>
</div>
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Cara Identifikasi</label>
<textarea name="cara_identifikasi" rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 bg-white"
placeholder="Cara mengidentifikasi...">{{ old('cara_identifikasi') }}</textarea>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Pencegahan</label>
<textarea name="pencegahan" rows="4"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 bg-white"
placeholder="Langkah pencegahan...">{{ old('pencegahan') }}</textarea>
</div>
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Pengendalian</label>
<textarea name="pengendalian" rows="4"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 bg-white"
placeholder="Cara pengendalian...">{{ old('pengendalian') }}</textarea>
</div>
</div>
</div>
</div>
<!-- Gambar & PDF -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Gambar Utama</label>
<input type="file" name="gambar_utama" accept="image/*"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500">
<p class="text-xs text-gray-400 mt-1">Format: JPG, PNG. Maks 2MB</p>
</div>
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">File PDF</label>
<input type="file" name="file_pdf" accept=".pdf"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500">
<p class="text-xs text-gray-400 mt-1">Format: PDF. Maks 5MB</p>
</div>
</div>
<!-- Tags -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Tags</label>
<div id="tags-container" class="w-full px-4 py-3 border border-gray-300 rounded-xl flex flex-wrap gap-2 min-h-[50px]"></div>
<input type="text" id="tags-input"
class="w-full mt-2 px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500"
placeholder="Ketik tag lalu tekan Enter...">
<p class="text-xs text-gray-400 mt-1">Tekan Enter atau koma untuk menambah tag</p>
<input type="hidden" name="tags" id="tags-hidden" value="[]">
</div>
<!-- Galeri Gambar -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Galeri Gambar</label>
<input type="file" name="galeri_gambar[]" accept="image/*" multiple
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500">
<p class="text-xs text-gray-400 mt-1">Bisa pilih beberapa foto sekaligus. Format: JPG, PNG. Maks 2MB per foto</p>
</div>
<!-- Status Publish -->
<div class="flex items-center space-x-3">
<input type="checkbox" name="is_published" value="1" id="is_published" {{ old('is_published') ? 'checked' : '' }}
class="w-5 h-5 text-red-600 rounded focus:ring-red-500">
<label for="is_published" class="text-sm font-bold text-gray-700">Publikasikan sekarang</label>
</div>
</div>
<!-- Buttons -->
<div class="flex justify-end space-x-3 mt-8 pt-6 border-t border-gray-200">
<a href="{{ route('admin.artikel-hama-penyakit.index') }}" class="px-6 py-3 border border-gray-300 text-gray-700 font-semibold rounded-xl hover:bg-gray-50 transition">
Batal
</a>
<button type="submit" class="px-6 py-3 bg-gradient-to-r from-red-500 to-red-600 text-white font-bold rounded-xl hover:from-red-600 hover:to-red-700 transition shadow-lg">
Simpan Artikel
</button>
</div>
</form>
</div>
</div>
@endsection
@push('scripts')
<script>
const tagsInput = document.getElementById('tags-input');
const tagsContainer = document.getElementById('tags-container');
const tagsHidden = document.getElementById('tags-hidden');
let tags = [];
function renderTags() {
tagsContainer.innerHTML = '';
tags.forEach((tag, index) => {
tagsContainer.innerHTML += `
<span class="flex items-center px-3 py-1 bg-red-100 text-red-800 text-xs font-bold rounded-full">
${tag}
<button type="button" onclick="removeTag(${index})" class="ml-2 text-red-600 hover:text-red-900"></button>
</span>`;
});
tagsHidden.value = JSON.stringify(tags);
}
function removeTag(index) {
tags.splice(index, 1);
renderTags();
}
tagsInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter' || e.key === ',') {
e.preventDefault();
const val = tagsInput.value.trim();
if (val) {
tags.push(val);
tagsInput.value = '';
renderTags();
}
}
});
</script>
@endpush

View File

@ -0,0 +1,186 @@
@extends('layouts.admin-app')
@section('page-title', 'Edit Artikel Hama & Penyakit')
@section('page-subtitle', 'Edit informasi hama dan penyakit kopi')
@section('content')
<div class="bg-white rounded-2xl shadow-lg">
<div class="p-8">
<form action="{{ route('admin.artikel-hama-penyakit.update', $artikelHamaPenyakit) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
<div class="space-y-6">
<!-- Judul & Jenis -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Judul <span class="text-red-500">*</span></label>
<input type="text" name="judul" value="{{ old('judul', $artikelHamaPenyakit->judul) }}"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 focus:border-transparent @error('judul') border-red-500 @enderror">
@error('judul') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Jenis <span class="text-red-500">*</span></label>
<select name="jenis" class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 focus:border-transparent">
<option value="Hama" {{ old('jenis', $artikelHamaPenyakit->jenis) === 'Hama' ? 'selected' : '' }}>Hama</option>
<option value="Penyakit" {{ old('jenis', $artikelHamaPenyakit->jenis) === 'Penyakit' ? 'selected' : '' }}>Penyakit</option>
</select>
</div>
</div>
<!-- Deskripsi Singkat -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Deskripsi Singkat</label>
<textarea name="deskripsi_singkat" rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 focus:border-transparent">{{ old('deskripsi_singkat', $artikelHamaPenyakit->deskripsi_singkat) }}</textarea>
</div>
<!-- Konten -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Konten <span class="text-red-500">*</span></label>
<textarea name="konten" rows="8"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 focus:border-transparent @error('konten') border-red-500 @enderror">{{ old('konten', $artikelHamaPenyakit->konten) }}</textarea>
@error('konten') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<!-- Info Teknis -->
<div class="border border-gray-200 rounded-xl p-6 bg-gray-50">
<h4 class="font-bold text-gray-700 mb-4">📋 Informasi Teknis</h4>
<div class="space-y-4">
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Gejala Visual</label>
<textarea name="gejala_visual" rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 bg-white">{{ old('gejala_visual', $artikelHamaPenyakit->gejala_visual) }}</textarea>
</div>
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Cara Identifikasi</label>
<textarea name="cara_identifikasi" rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 bg-white">{{ old('cara_identifikasi', $artikelHamaPenyakit->cara_identifikasi) }}</textarea>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Pencegahan</label>
<textarea name="pencegahan" rows="4"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 bg-white">{{ old('pencegahan', $artikelHamaPenyakit->pencegahan) }}</textarea>
</div>
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Pengendalian</label>
<textarea name="pengendalian" rows="4"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500 bg-white">{{ old('pengendalian', $artikelHamaPenyakit->pengendalian) }}</textarea>
</div>
</div>
</div>
</div>
<!-- Gambar & PDF -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Gambar Utama</label>
@if($artikelHamaPenyakit->gambar_utama)
<img src="{{ Storage::url($artikelHamaPenyakit->gambar_utama) }}" class="w-32 h-24 object-cover rounded-lg mb-2">
@endif
<input type="file" name="gambar_utama" accept="image/*"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500">
<p class="text-xs text-gray-400 mt-1">Kosongkan jika tidak ingin mengubah</p>
</div>
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">File PDF</label>
@if($artikelHamaPenyakit->file_pdf)
<a href="{{ Storage::url($artikelHamaPenyakit->file_pdf) }}" target="_blank" class="text-xs text-blue-500 underline mb-2 block">Lihat PDF saat ini</a>
@endif
<input type="file" name="file_pdf" accept=".pdf"
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500">
<p class="text-xs text-gray-400 mt-1">Kosongkan jika tidak ingin mengubah</p>
</div>
</div>
<!-- Tags -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Tags</label>
<div id="tags-container" class="w-full px-4 py-3 border border-gray-300 rounded-xl flex flex-wrap gap-2 min-h-[50px]"></div>
<input type="text" id="tags-input"
class="w-full mt-2 px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500"
placeholder="Ketik tag lalu tekan Enter...">
<p class="text-xs text-gray-400 mt-1">Tekan Enter atau koma untuk menambah tag</p>
<input type="hidden" name="tags" id="tags-hidden" value="[]">
</div>
<!-- Galeri Gambar -->
<div>
<label class="block text-sm font-bold text-gray-700 mb-2">Galeri Gambar</label>
@if($artikelHamaPenyakit->galeri_gambar)
<div class="flex flex-wrap gap-2 mb-3">
@foreach($artikelHamaPenyakit->galeri_gambar as $foto)
<img src="{{ Storage::url($foto) }}" class="w-24 h-20 object-cover rounded-lg">
@endforeach
</div>
@endif
<input type="file" name="galeri_gambar[]" accept="image/*" multiple
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-red-500">
<p class="text-xs text-gray-400 mt-1">Upload foto baru akan menggantikan galeri yang lama</p>
</div>
<!-- Status Publish -->
<div class="flex items-center space-x-3">
<input type="checkbox" name="is_published" value="1" id="is_published" {{ old('is_published', $artikelHamaPenyakit->is_published) ? 'checked' : '' }}
class="w-5 h-5 text-red-600 rounded focus:ring-red-500">
<label for="is_published" class="text-sm font-bold text-gray-700">Publikasikan</label>
</div>
</div>
<!-- Buttons -->
<div class="flex justify-end space-x-3 mt-8 pt-6 border-t border-gray-200">
<a href="{{ route('admin.artikel-hama-penyakit.index') }}" class="px-6 py-3 border border-gray-300 text-gray-700 font-semibold rounded-xl hover:bg-gray-50 transition">
Batal
</a>
<button type="submit" class="px-6 py-3 bg-gradient-to-r from-red-500 to-red-600 text-white font-bold rounded-xl hover:from-red-600 hover:to-red-700 transition shadow-lg">
Update Artikel
</button>
</div>
</form>
</div>
</div>
@endsection
@push('scripts')
<script>
const tagsInput = document.getElementById('tags-input');
const tagsContainer = document.getElementById('tags-container');
const tagsHidden = document.getElementById('tags-hidden');
// Load tags yang sudah ada
let tags = {!! json_encode($artikelHamaPenyakit->tags ?? []) !!};
function renderTags() {
tagsContainer.innerHTML = '';
tags.forEach((tag, index) => {
tagsContainer.innerHTML += `
<span class="flex items-center px-3 py-1 bg-red-100 text-red-800 text-xs font-bold rounded-full">
${tag}
<button type="button" onclick="removeTag(${index})" class="ml-2 text-red-600 hover:text-red-900"></button>
</span>`;
});
tagsHidden.value = JSON.stringify(tags);
}
function removeTag(index) {
tags.splice(index, 1);
renderTags();
}
tagsInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter' || e.key === ',') {
e.preventDefault();
const val = tagsInput.value.trim();
if (val) {
tags.push(val);
tagsInput.value = '';
renderTags();
}
}
});
// Render tags awal
renderTags();
</script>
@endpush

View File

@ -0,0 +1,110 @@
@extends('layouts.admin-app')
@section('page-title', 'Artikel Hama & Penyakit')
@section('page-subtitle', 'Kelola informasi hama dan penyakit kopi')
@section('content')
@if (session('success'))
<div class="mb-6 bg-green-100 border-l-4 border-green-500 text-green-700 p-4 rounded-lg flex items-center">
<svg class="w-6 h-6 mr-3" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
</svg>
<span class="font-semibold">{{ session('success') }}</span>
</div>
@endif
<div class="bg-white rounded-2xl shadow-lg">
<div class="p-8">
<div class="flex justify-between items-center mb-6">
<div class="flex items-center">
<div class="bg-gradient-to-r from-red-500 to-red-600 rounded-xl p-3 mr-4">
<svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
</svg>
</div>
<h3 class="text-xl font-bold text-gray-800">Daftar Artikel Hama & Penyakit</h3>
</div>
<a href="{{ route('admin.artikel-hama-penyakit.create') }}" class="flex items-center px-5 py-3 bg-gradient-to-r from-red-500 to-red-600 text-white font-bold rounded-xl hover:from-red-600 hover:to-red-700 transition-all shadow-lg hover:shadow-xl transform hover:scale-105">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
Tambah Artikel
</a>
</div>
<div class="overflow-x-auto rounded-xl border border-gray-200">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">No</th>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">Judul</th>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">Jenis</th>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">Status</th>
<th class="px-6 py-4 text-left text-xs font-bold text-gray-600 uppercase">Tanggal</th>
<th class="px-6 py-4 text-center text-xs font-bold text-gray-600 uppercase">Aksi</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
@forelse ($artikels as $index => $artikel)
<tr class="hover:bg-gray-50 transition-colors">
<td class="px-6 py-4 text-sm">{{ $artikels->firstItem() + $index }}</td>
<td class="px-6 py-4">
<div class="text-sm font-semibold text-gray-900">{{ $artikel->judul }}</div>
@if($artikel->deskripsi_singkat)
<div class="text-xs text-gray-400 mt-1">{{ Str::limit($artikel->deskripsi_singkat, 60) }}</div>
@endif
</td>
<td class="px-6 py-4">
@if($artikel->jenis === 'Hama')
<span class="px-3 py-1 text-xs font-bold rounded-full bg-orange-100 text-orange-800">Hama</span>
@else
<span class="px-3 py-1 text-xs font-bold rounded-full bg-red-100 text-red-800">Penyakit</span>
@endif
</td>
<td class="px-6 py-4">
@if($artikel->is_published)
<span class="px-3 py-1 text-xs font-bold rounded-full bg-green-100 text-green-800">Published</span>
@else
<span class="px-3 py-1 text-xs font-bold rounded-full bg-gray-100 text-gray-600">Draft</span>
@endif
</td>
<td class="px-6 py-4 text-sm text-gray-600">{{ $artikel->created_at->format('d M Y') }}</td>
<td class="px-6 py-4 text-center">
<div class="flex justify-center space-x-2">
<a href="{{ route('admin.artikel-hama-penyakit.edit', $artikel) }}" class="inline-flex items-center px-3 py-2 bg-blue-500 text-white text-xs font-semibold rounded-lg hover:bg-blue-600 transition">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
</svg>
Edit
</a>
<form action="{{ route('admin.artikel-hama-penyakit.destroy', $artikel) }}" method="POST" onsubmit="return confirm('Yakin ingin menghapus artikel ini?')">
@csrf
@method('DELETE')
<button type="submit" class="inline-flex items-center px-3 py-2 bg-red-500 text-white text-xs font-semibold rounded-lg hover:bg-red-600 transition">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
</svg>
Hapus
</button>
</form>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="6" class="px-6 py-12 text-center text-gray-400">
<svg class="w-16 h-16 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 006.586 13H4"></path>
</svg>
<p class="text-xl font-semibold mb-2">Belum ada artikel hama & penyakit</p>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<div class="mt-6">{{ $artikels->links() }}</div>
</div>
</div>
@endsection

View File

@ -1,6 +1,6 @@
@extends('layouts.admin-app') @extends('layouts.admin-app')
@section('page-title', ' Tambah Rule Basis') @section('page-title', 'Tambah Rule Basis')
@section('page-subtitle', 'Tambah aturan diagnosa baru') @section('page-subtitle', 'Tambah aturan diagnosa baru')
@section('content') @section('content')

View File

@ -1,6 +1,6 @@
@extends('layouts.admin-app') @extends('layouts.admin-app')
@section('page-title', '✏️ Edit Rule Basis') @section('page-title', 'Edit Rule Basis')
@section('page-subtitle', 'Edit aturan diagnosa') @section('page-subtitle', 'Edit aturan diagnosa')
@section('content') @section('content')

View File

@ -1,6 +1,6 @@
@extends('layouts.admin-app') @extends('layouts.admin-app')
@section('page-title', '🧠 Manajemen Rule Basis') @section('page-title', 'Manajemen Rule Basis')
@section('page-subtitle', 'Kelola aturan diagnosa sistem pakar') @section('page-subtitle', 'Kelola aturan diagnosa sistem pakar')
@section('content') @section('content')

View File

@ -198,18 +198,48 @@ class="menu-item flex items-center px-4 py-3 rounded-xl hover:bg-gray-700 {{ req
</div> </div>
</a> </a>
<!-- Artikel Management --> <!-- Informasi Management (Dropdown) -->
<a href="{{ route('admin.artikel.index') }}" <div x-data="{ informasiOpen: {{ request()->routeIs('admin.artikel-budidaya.*') || request()->routeIs('admin.artikel-hama-penyakit.*') ? 'true' : 'false' }} }">
class="menu-item flex items-center px-4 py-3 rounded-xl hover:bg-gray-700 {{ request()->routeIs('admin.artikel.*') ? 'active bg-gray-700' : '' }} group">
<div class="flex items-center flex-1"> <!-- Dropdown Toggle -->
<div class="w-10 h-10 flex items-center justify-center rounded-lg bg-yellow-500/20 group-hover:bg-yellow-500/30 transition-colors"> <button @click="informasiOpen = !informasiOpen"
<svg class="w-5 h-5 text-yellow-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> class="menu-item w-full flex items-center px-4 py-3 rounded-xl hover:bg-gray-700 {{ request()->routeIs('admin.artikel-budidaya.*') || request()->routeIs('admin.artikel-hama-penyakit.*') ? 'active bg-gray-700' : '' }} group">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"></path> <div class="flex items-center flex-1">
</svg> <div class="w-10 h-10 flex items-center justify-center rounded-lg bg-yellow-500/20 group-hover:bg-yellow-500/30 transition-colors">
<svg class="w-5 h-5 text-yellow-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"></path>
</svg>
</div>
<span x-show="sidebarOpen" class="ml-3 font-semibold">Artikel</span>
</div> </div>
<span x-show="sidebarOpen" class="ml-3 font-semibold">Artikel</span> <svg x-show="sidebarOpen" :class="informasiOpen ? 'rotate-180' : ''"
class="w-4 h-4 text-gray-400 transition-transform duration-200"
fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
</svg>
</button>
<!-- Sub Menu -->
<div x-show="informasiOpen && sidebarOpen"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 -translate-y-2"
x-transition:enter-end="opacity-100 translate-y-0"
class="mt-1 ml-6 pl-4 border-l-2 border-gray-600 space-y-1">
<!-- Budidaya -->
<a href="{{ route('admin.artikel-budidaya.index') }}"
class="flex items-center px-3 py-2 rounded-lg hover:bg-gray-700 {{ request()->routeIs('admin.artikel-budidaya.*') ? 'bg-gray-700 text-white' : 'text-gray-400' }} group transition-colors">
<span class="text-sm font-medium group-hover:text-white">Budidaya</span>
</a>
<!-- Hama & Penyakit -->
<a href="{{ route('admin.artikel-hama-penyakit.index') }}"
class="flex items-center px-3 py-2 rounded-lg hover:bg-gray-700 {{ request()->routeIs('admin.artikel-hama-penyakit.*') ? 'bg-gray-700 text-white' : 'text-gray-400' }} group transition-colors">
<span class="text-sm font-medium group-hover:text-white">Hama & Penyakit</span>
</a>
</div> </div>
</a> </div>
</nav> </nav>

View File

@ -3,11 +3,12 @@
use App\Http\Controllers\ProfileController; use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use App\Http\Controllers\SuperAdmin\UserManagementController; use App\Http\Controllers\SuperAdmin\UserManagementController;
use App\Http\Controllers\Admin\AdminDashboardController; // ← TAMBAHKAN INI use App\Http\Controllers\Admin\AdminDashboardController;
use App\Http\Controllers\Admin\PenyakitController; // ← DAN INI use App\Http\Controllers\Admin\PenyakitController;
use App\Http\Controllers\Admin\GejalaController; use App\Http\Controllers\Admin\GejalaController;
use App\Http\Controllers\Admin\RuleBasisController; // ← DAN INI use App\Http\Controllers\Admin\RuleBasisController;
use App\Http\Controllers\Admin\ArtikelController; // ← DAN INI use App\Http\Controllers\Admin\ArtikelBudidayaController;
use App\Http\Controllers\Admin\ArtikelHamaPenyakitController;
Route::get('/', function () { Route::get('/', function () {
return view('welcome'); return view('welcome');
@ -55,11 +56,9 @@
]); ]);
// Artikel Management // Artikel Management
Route::resource('artikel', ArtikelController::class); Route::resource('artikel-budidaya', ArtikelBudidayaController::class);
Route::resource('artikel-hama-penyakit', ArtikelHamaPenyakitController::class);
// Bisa tambah route lain di sini:
// Route::resource('diagnosa', DiagnosaController::class);
// Route::resource('aturan', AturanController::class);
}); });
// Profile Routes // Profile Routes