diff --git a/apps/web/src/assets/images/dashboard-bg.png b/apps/web/src/assets/images/dashboard-bg.png deleted file mode 100644 index 613383d..0000000 Binary files a/apps/web/src/assets/images/dashboard-bg.png and /dev/null differ diff --git a/apps/web/src/assets/images/dashboard-bg.webp b/apps/web/src/assets/images/dashboard-bg.webp new file mode 100644 index 0000000..56d93fd Binary files /dev/null and b/apps/web/src/assets/images/dashboard-bg.webp differ diff --git a/apps/web/src/assets/images/scan-guide-bg.png b/apps/web/src/assets/images/scan-guide-bg.png deleted file mode 100644 index 7a3d888..0000000 Binary files a/apps/web/src/assets/images/scan-guide-bg.png and /dev/null differ diff --git a/apps/web/src/assets/images/scan-guide-bg.webp b/apps/web/src/assets/images/scan-guide-bg.webp new file mode 100644 index 0000000..8480f2f Binary files /dev/null and b/apps/web/src/assets/images/scan-guide-bg.webp differ diff --git a/apps/web/src/components/diagnose-result-view.tsx b/apps/web/src/components/diagnose-result-view.tsx new file mode 100644 index 0000000..091e8ab --- /dev/null +++ b/apps/web/src/components/diagnose-result-view.tsx @@ -0,0 +1,205 @@ +import { useState } from "react"; +import { ChevronDown, ChevronUp, AlertTriangle, BookOpen, ShieldCheck, Pill, RefreshCcw } from "lucide-react"; + +// Spesifikasi data yang dibutuhkan oleh cetakan ini +type Props = { + imageUrl: string; + confidence: number; // contoh: 0.95 + diseaseName: string; + scientificName: string; + riskLevel: string; + description: string; + symptoms: string[]; + preventions: string[]; + medicines: string[]; + onRescan?: () => void; // Tombol opsional untuk Scan Ulang +}; + +export function DiagnosisResultView({ + imageUrl, + confidence, + diseaseName, + scientificName, + riskLevel, + description, + symptoms, + preventions, + medicines, + onRescan, +}: Props) { + // Ingatan untuk laci (accordion) sebelah kanan + const [openSection, setOpenSection] = useState("detail"); + + const toggleSection = (section: string) => { + setOpenSection(openSection === section ? "" : section); + }; + + const confidencePercent = Math.round(confidence * 100); + + return ( +
+ + {/* KIRI: Area Gambar & Hasil Deteksi ML */} +
+ {/* Gambar Daun */} +
+ Daun yang dianalisis +
+ 📷 + Gambar yang dianalisis +
+
+ + {/* Kartu Hasil Deteksi ML */} +
+
+ + HASIL DETEKSI ML +
+ +

{diseaseName}

+

{scientificName}

+ + {/* Bar Tingkat Keyakinan AI */} +
+
+ Tingkat Keyakinan AI + {confidencePercent}% +
+
+
+
+

+ Di atas ambang batas minimum (75%) +

+
+ +
+ Tingkat Keparahan: + + {riskLevel.toUpperCase()} + +
+
+
+ + {/* KANAN: Area Edukasi (Accordion) & Referensi */} +
+ + {/* Tombol Header (Jika ada fungsi onRescan) */} + {onRescan && ( +
+ +
+ )} + + {/* Laci 1: Detail Penyakit */} +
+
toggleSection("detail")} + className="flex items-center justify-between p-4 cursor-pointer hover:bg-slate-50" + > +
+
+ +
+ Detail Penyakit +
+ {openSection === "detail" ? : } +
+ {openSection === "detail" && ( +
+

{description}

+
Gejala Umum:
+
    + {symptoms.map((sym, i) =>
  • {sym}
  • )} +
+
+ )} +
+ + {/* Laci 2: Panduan Pencegahan */} +
+
toggleSection("cegah")} + className="flex items-center justify-between p-4 cursor-pointer hover:bg-slate-50" + > +
+
+ +
+ Panduan Pencegahan +
+ {openSection === "cegah" ? : } +
+ {openSection === "cegah" && ( +
+
    + {preventions.map((prev, i) => ( +
  • + {prev} +
  • + ))} +
+
+ )} +
+ + {/* Laci 3: Rekomendasi Obat */} +
+
toggleSection("obat")} + className="flex items-center justify-between p-4 cursor-pointer hover:bg-slate-50" + > +
+
+ +
+ Rekomendasi Obat +
+ {openSection === "obat" ? : } +
+ {openSection === "obat" && ( +
+
    + {medicines.map((med, i) => ( +
  • + ⚕️ {med} +
  • + ))} +
+
+ )} +
+ + {/* Kotak Disclaimer Penting */} +
+
+ Disclaimer Penting +
+

+ ZeaVis Edu adalah alat bantu edukasi awal, bukan pengganti diagnosis profesional. Hasil ini tidak dapat dijadikan dasar keputusan agronomis tanpa konfirmasi dari ahli pertanian atau Petugas Pengamat Organisme Pengganggu Tanaman (POPT) yang berwenang. +

+
+ +
+
+ ); +} + +// Ikon bantuan untuk persentase +function CheckCircle2(props: any) { + return +} \ No newline at end of file diff --git a/apps/web/src/pages/catalog-page.tsx b/apps/web/src/pages/catalog-page.tsx index 11620b1..46606ca 100644 --- a/apps/web/src/pages/catalog-page.tsx +++ b/apps/web/src/pages/catalog-page.tsx @@ -1,174 +1,268 @@ -import { useState, useEffect } from 'react'; -import { useQuery } from '@tanstack/react-query'; -import { Link, useSearchParams } from 'react-router-dom'; -import { AlertCircle } from 'lucide-react'; -import type { RiskLevel } from '@zeavis/shared'; -import { Card, CardContent } from '@/components/ui/card'; -import { RiskBadge } from '@/components/risk-badge'; -import { apiClient } from '@/lib/api-client'; +import { useState, useMemo } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { + ChevronDown, + ChevronUp, + AlertTriangle, + CheckCircle2, + Pill, + ShieldCheck, + Search, + Leaf, +} from "lucide-react"; +import { apiClient } from "@/lib/api-client"; +import { RiskBadge } from "@/components/risk-badge"; +import { diseaseCatalogSeed } from "@zeavis/shared/diseases"; + export function CatalogPage() { - const [searchParams, setSearchParams] = useSearchParams(); - const initialRisk = searchParams.get('risk') as RiskLevel | null; + const [expandedId, setExpandedId] = useState(null); + const [searchQuery, setSearchQuery] = useState(""); + const [riskFilter, setRiskFilter] = useState("all"); - const [searchQuery, setSearchQuery] = useState(''); - const [riskFilter, setRiskFilter] = useState(initialRisk ?? 'all'); - - // Sync URL params with state - useEffect(() => { - if (initialRisk && initialRisk !== riskFilter) { - setRiskFilter(initialRisk); - } - }, [initialRisk]); - - const { data: diseases, isLoading, error } = useQuery({ - queryKey: ['diseases'], + const { data: diseases, isLoading } = useQuery({ + queryKey: ["diseases"], queryFn: () => apiClient.getDiseases(), }); - const filteredDiseases = (diseases || []) - .sort((a, b) => a.displayOrder - b.displayOrder) - .filter((disease) => { + const filteredDiseases = useMemo(() => { + if (!diseases) return []; + + return diseases.filter((disease) => { const matchesSearch = disease.commonName.toLowerCase().includes(searchQuery.toLowerCase()) || - disease.label.toLowerCase().includes(searchQuery.toLowerCase()) || - disease.summary.toLowerCase().includes(searchQuery.toLowerCase()) || - disease.symptoms.some((s) => s.toLowerCase().includes(searchQuery.toLowerCase())); + disease.symptoms.some((symptom) => + symptom.toLowerCase().includes(searchQuery.toLowerCase()), + ); - const matchesRisk = riskFilter === 'all' || disease.riskLevel === riskFilter; + const matchesRisk = + riskFilter === "all" || disease.riskLevel === riskFilter; return matchesSearch && matchesRisk; }); + }, [diseases, searchQuery, riskFilter]); + + if (isLoading) { + return ( +
+ Memuat pustaka penyakit... +
+ ); + } return ( -
-
-
-

Pustaka Penyakit

-

- Referensi lengkap penyakit dan kondisi daun jagung yang dapat dideteksi oleh sistem AI ZeaVis Edu -

+
+ {/* Page Title */} +
+

+ Pustaka Penyakit +

+

+ Referensi lengkap penyakit dan kondisi daun jagung yang dapat + dideteksi oleh sistem AI ZeaVis Edu. +

+
+ + {/* Search and Filter */} +
+
+ +
+ + setSearchQuery(e.target.value)} + className="w-full pl-9 pr-4 py-2 border border-slate-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-[#214B11]/20 focus:border-[#214B11] transition-all" + /> +
+
+ +
+ +
- {/* Filters */} -
-
- -
- - setSearchQuery(e.target.value)} - className="w-full rounded-md border border-border bg-background pl-10 pr-3 py-2 text-sm" - /> -
+ {/* Accordion List */} +
+ {filteredDiseases.length === 0 ? ( +
+

+ Tidak ada penyakit yang sesuai dengan pencarianmu. +

-
- - -
-
+ ) : ( + filteredDiseases.map((disease) => { + const isExpanded = expandedId === disease.slug; + + const seedData = diseaseCatalogSeed.find(seed => seed.slug === disease.slug); + const finalImageUrl = disease.imageUrl || seedData?.imageUrl || "https://placehold.co/100x100?text=Daun"; + const finalMedicines = disease.medicineRecommendations || seedData?.medicineRecommendations; - {isLoading && ( - - Memuat katalog... - - )} - {error && ( - - Katalog belum tersedia - - )} - - {!isLoading && !error && filteredDiseases.length === 0 && ( - - Tidak ada penyakit yang cocok dengan filter ini. - - )} - - {!isLoading && !error && filteredDiseases.length > 0 && ( -
- {filteredDiseases.map((disease) => ( - + setExpandedId(isExpanded ? null : disease.slug) + } + className={`bg-white rounded-2xl border transition-all duration-300 ${ + isExpanded + ? "border-[#214B11]/30 shadow-md ring-1 ring-[#214B11]/5" + : "border-slate-200 hover:border-slate-300 hover:shadow-sm" + }`} > - - -
-
+ {/* Accordion Header */} +
+
+ {disease.commonName} +
+

{disease.commonName}

-

- {disease.label} -

+
+ +
+
+

+ {disease.label} +

+
+
+ +
+ {isExpanded ? ( + + ) : ( + + )} +
+
+ + {/* Accordion Content */} + {isExpanded && ( +
+
+ Detail Penyakit + +
+
+

+ Deskripsi +

+

+ {disease.description || disease.summary} +

+
+ +
+

+ + Gejala +

+
    + {disease.symptoms?.map((symptom, idx) => ( +
  • +
    + {symptom} +
  • + ))} +
+
-
-

- {disease.summary} -

- - {disease.symptoms.length > 0 && ( -
-

- Gejala: +
+
+

+ + Panduan Pencegahan

-
    - {disease.symptoms.slice(0, 2).map((symptom, index) => ( -
  • - - {symptom} +
      + {disease.recommendations?.map((rec, idx) => ( +
    • + + {rec}
    • ))}
- )} -
-
- - Lihat detail → - +
+

+ + Rekomendasi Obat +

+
    + {finalMedicines ? ( + finalMedicines.map((obat, idx) => ( +
  • + + {obat} +
  • + )) + ) : ( +
  • + Belum ada data rekomendasi obat spesifik. +
  • + )} +
+
- - - - ))} -
+
+ )} +

+ ); + }) )} +
+ + {/* Warning Box */} +
+ +

+ Disclaimer: Informasi dalam pustaka ini bersifat + edukatif dan disarikan dari literatur ilmiah. ZeaVis Edu bukan + pengganti diagnosis lapangan oleh{" "} + Petugas Pengamat Organisme Pengganggu Tanaman (POPT){" "} + atau ahli pertanian berlisensi. Selalu konsultasikan kondisi tanaman + Anda kepada dinas pertanian atau balai penelitian tanaman terkait. +

+
); } diff --git a/apps/web/src/pages/dashboard-page.tsx b/apps/web/src/pages/dashboard-page.tsx index a5cdbc3..ebe71ea 100644 --- a/apps/web/src/pages/dashboard-page.tsx +++ b/apps/web/src/pages/dashboard-page.tsx @@ -6,7 +6,7 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { useUiStore } from "@/store/ui-store"; import { apiClient } from "@/lib/api-client"; -import bg from "@/assets/images/dashboard-bg.png"; +import bg from "@/assets/images/dashboard-bg.webp"; export function DashboardPage() { const { dashboardCompact } = useUiStore(); diff --git a/apps/web/src/pages/diagnosis-detail-page.tsx b/apps/web/src/pages/diagnosis-detail-page.tsx index c2c56ff..fe23342 100644 --- a/apps/web/src/pages/diagnosis-detail-page.tsx +++ b/apps/web/src/pages/diagnosis-detail-page.tsx @@ -1,102 +1,139 @@ -import { Link, useParams } from 'react-router-dom'; -import { useQuery } from '@tanstack/react-query'; -import { Button } from '@/components/ui/button'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { DiagnosisStatusBadge } from '@/components/diagnosis-status-badge'; -import { RiskBadge } from '@/components/risk-badge'; -import { apiClient } from '@/lib/api-client'; +import { Link, useParams } from "react-router-dom"; +import { useQuery } from "@tanstack/react-query"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { apiClient } from "@/lib/api-client"; +import { DiagnosisResultView } from "../components/diagnose-result-view"; export function DiagnosisDetailPage() { const { id } = useParams(); const query = useQuery({ - queryKey: ['diagnosis', id], + queryKey: ["diagnosis", id], queryFn: () => apiClient.getDiagnosis(id!), enabled: Boolean(id), }); - if (query.isLoading) return
Memuat diagnosis...
; - if (query.error || !query.data) return
Diagnosis tidak ditemukan
; + if (query.isLoading) + return ( +
+ Memuat diagnosis... +
+ ); + if (query.error || !query.data) + return ( +
+ Diagnosis tidak ditemukan +
+ ); const diagnosis = query.data; + const finalImageUrl = + diagnosis.imageUrl || "/src/assets/images/placeholder-image.png"; return (
+ {/* Header Page */}
-
-

Detail Diagnosis

-

{diagnosis.disease?.commonName ?? 'Diagnosis gagal'}

-
- +
+

+ Analisis & Modul Edukasi +

+

+ Hasil deteksi AI dan panduan edukasi berdasarkan gambar yang + diunggah +

+ +
-
- - - Daun jagung - - + {/* Warning if expert review is needed */} + {diagnosis.status === "needs_review" && ( +
+ Catatan: Hasil ini masih sementara karena tingkat + keyakinan (confidence) di bawah standar minimum dan sedang menunggu + ulasan pakar. +
+ )} - - -
- Hasil AI - -
- - {diagnosis.confidence === null ? 'Model gagal memproses gambar.' : `Confidence ${(diagnosis.confidence * 100).toFixed(1)}%`} - -
- - {diagnosis.status === 'needs_review' && ( -
- Hasil ini masih sementara karena confidence di bawah 70% dan sedang menunggu review pakar. + {/* Message if AI failed to process */} + {diagnosis.failureReason && ( +
+ Gagal Memproses: {diagnosis.failureReason} +
+ )} + + {/* Diagnosis Result View */} + + + {/* List of Alternative Predictions */} + {diagnosis.predictions && diagnosis.predictions.length > 0 && ( +
+

+ Semua Prediksi Model +

+

+ Tebakan alternatif lain dari sistem AI ZeaVis +

+
+ {diagnosis.predictions + .sort((a, b) => a.rank - b.rank) + .map((pred) => ( +
+ + {pred.modelLabel} + + + {(pred.confidence * 100).toFixed(1)}% +
- )} - {diagnosis.failureReason &&

{diagnosis.failureReason}

} - {diagnosis.disease && ( -
-
-

{diagnosis.disease.label}

- -
-

{diagnosis.disease.summary}

-
-

Rekomendasi

-
    - {diagnosis.disease.recommendations.map((item) =>
  • {item}
  • )} -
-
-
- )} - - -
+ ))} +
+
+ )} - + {/* Expert Notes (Only shown if already reviewed by human) */} + {diagnosis.latestReview && ( + - Top Predictions + + Catatan Pakar Agronomi + + + Ditinjau oleh: {diagnosis.latestReview.expert.name} + - - {diagnosis.predictions.map((prediction) => ( -
- {prediction.rank}. {prediction.modelLabel} - {(prediction.confidence * 100).toFixed(1)}% -
- ))} + +

+ "{diagnosis.latestReview.notes}" +

- - {diagnosis.latestReview && ( - - - Catatan Pakar - {diagnosis.latestReview.expert.name} - - -

{diagnosis.latestReview.notes}

-
-
- )} -
- ); - } + )} +
+ ); +} diff --git a/apps/web/src/pages/scan-page.tsx b/apps/web/src/pages/scan-page.tsx index f94ba4d..7ffabe4 100644 --- a/apps/web/src/pages/scan-page.tsx +++ b/apps/web/src/pages/scan-page.tsx @@ -15,10 +15,10 @@ import { import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Modal } from "@/components/ui/modal"; -import { DiagnosisStatusBadge } from "@/components/diagnosis-status-badge"; import type { DiagnosisRecord } from "@zeavis/shared"; import { apiClient } from "@/lib/api-client"; import { trackScan, trackDiagnosisResult } from "@/lib/telemetry"; +import { DiagnosisResultView } from "../components/diagnose-result-view"; export function ScanPage() { const [fileName, setFileName] = useState(null); @@ -36,8 +36,6 @@ export function ScanPage() { queryClient.invalidateQueries({ queryKey: ["diagnoses"] }); setDiagnosisPreview(diagnosis); setPreviewOpen(true); - setFileName(null); - setPreviewUrl(null); if (inputRef.current) inputRef.current.value = ""; }, onError: () => { @@ -55,7 +53,6 @@ export function ScanPage() { const url = URL.createObjectURL(f); setPreviewUrl(url); - // Detect image dimensions const img = new Image(); img.onload = () => { setImageDimensions({ width: img.width, height: img.height }); @@ -71,8 +68,7 @@ export function ScanPage() { }; const [previewOpen, setPreviewOpen] = useState(false); - const [diagnosisPreview, setDiagnosisPreview] = - useState(null); + const [diagnosisPreview, setDiagnosisPreview] = useState(null); const diagnosesQuery = useQuery({ queryKey: ["diagnoses"], @@ -82,12 +78,12 @@ export function ScanPage() { return (
+ {/* Main Header */}

Scan Tanaman

- Unggah foto daun jagung untuk dianalisis oleh sistem AI kami secara - real-time. + Unggah foto daun jagung untuk dianalisis oleh sistem AI kami secara real-time.

+ {/* Main Content */}
+ {/* Left Column: Upload Area */}
- {/* Left Sidebar */}
Area Unggah Gambar
- {/* Upload area */} {!previewUrl ? (
inputRef.current?.click()} > -

- Seret & Lepas Foto Daun -

-

- atau klik untuk memilih file berkas dari perangkat Anda -

+

Seret & Lepas Foto Daun

+

atau klik untuk memilih file berkas dari perangkat Anda

- - PNG, JPG, JPEG + PNG, JPG, JPEG, WEBP
- - Maks. 5 MB + Maks. 5 MB
-
) : ( @@ -150,19 +138,12 @@ export function ScanPage() { className="w-full max-h-80 object-contain" onLoad={(e) => { const img = e.currentTarget; - setImageDimensions({ - width: img.naturalWidth, - height: img.naturalHeight, - }); + setImageDimensions({ width: img.naturalWidth, height: img.naturalHeight }); }} /> - {/* Scanner area detection overlay */} {imageDimensions && (
- {/* Outer dark overlay */}
- - {/* Scan area frame - responsive to image */}
- {/* Corner markers */}
- - {/* Center text */}
AREA SCAN @@ -186,7 +164,6 @@ export function ScanPage() {
)} -
- {/* Right Sidebar */} + {/* Right Column: Guidelines */}
- {/* Result Modal */} + {/* Modal Preview Diagnosis */} { setPreviewOpen(false); setDiagnosisPreview(null); }} - title={diagnosisPreview?.disease?.commonName ?? "Hasil Diagnosis"} - size="md" + title="Hasil Analisis AI" + size="lg" footer={ diagnosisPreview && ( -
+
) } > {diagnosisPreview ? ( -
-
- - {diagnosisPreview.confidence !== null && ( - - Confidence: {(diagnosisPreview.confidence * 100).toFixed(1)}% - - )} -
- - {diagnosisPreview.disease && ( -
-

- {diagnosisPreview.disease.commonName} -

-

- {diagnosisPreview.disease.summary} -

+
+ + {/* Warning if expert review is needed */} + {diagnosisPreview.status === "needs_review" && ( +
+ Catatan: Hasil ini masih sementara karena tingkat keyakinan (confidence) di bawah standar minimum.
)} + {/* Message if AI fails to process */} {diagnosisPreview.failureReason && ( -
- {diagnosisPreview.failureReason} +
+ Gagal Memproses: {diagnosisPreview.failureReason}
)} - {diagnosisPreview.predictions.length > 0 && ( -
-

Semua Prediksi

-
+ + + {/* All Model Predictions */} + {diagnosisPreview.predictions && diagnosisPreview.predictions.length > 0 && ( +
+

Semua Prediksi Model

+

Tebakan alternatif lain dari sistem AI ZeaVis

+
{diagnosisPreview.predictions .sort((a, b) => a.rank - b.rank) .map((pred) => (
- {pred.modelLabel} - + {pred.modelLabel} + {(pred.confidence * 100).toFixed(1)}%
@@ -443,52 +368,9 @@ export function ScanPage() {
)} - -
-

- Riwayat Diagnosis Terbaru -

- {diagnosesQuery.isLoading && ( -
- Memuat riwayat... -
- )} - {!diagnosesQuery.isLoading && !diagnosesQuery.isError && ( -
- {(diagnosesQuery.data ?? []).slice(0, 5).map((d) => ( -
-
- thumb -
-
- {d.disease?.commonName ?? "Unknown"} -
-
- {new Date(d.createdAt).toLocaleString("id-ID")} -
-
-
- - Lihat - -
- ))} -
- )} -
) : null}
); -} +} \ No newline at end of file diff --git a/packages/shared/src/diseases.ts b/packages/shared/src/diseases.ts index 547aa43..cc5bd9e 100644 --- a/packages/shared/src/diseases.ts +++ b/packages/shared/src/diseases.ts @@ -1,10 +1,20 @@ -export const diseaseLabels = ['Bercak Daun', 'Hawar Daun', 'Karat Daun', 'Daun Sehat'] as const; +export const diseaseLabels = [ + "Bercak Daun", + "Hawar Daun", + "Karat Daun", + "Daun Sehat", +] as const; export type DiseaseLabel = (typeof diseaseLabels)[number]; -export const diseaseSlugs = ['bercak-daun', 'hawar-daun', 'karat-daun', 'daun-sehat'] as const; +export const diseaseSlugs = [ + "bercak-daun", + "hawar-daun", + "karat-daun", + "daun-sehat", +] as const; export type DiseaseSlug = (typeof diseaseSlugs)[number]; -export const riskLevels = ['low', 'medium', 'high'] as const; +export const riskLevels = ["low", "medium", "high"] as const; export type RiskLevel = (typeof riskLevels)[number]; export type DiseaseCatalogItem = { @@ -15,6 +25,8 @@ export type DiseaseCatalogItem = { description: string; symptoms: string[]; recommendations: string[]; + medicineRecommendations: string[]; + imageUrl: string; riskLevel: RiskLevel; accentColor: string; displayOrder: number; @@ -22,100 +34,133 @@ export type DiseaseCatalogItem = { export const diseaseCatalogSeed: DiseaseCatalogItem[] = [ { - slug: 'bercak-daun', - label: 'Bercak Daun', - commonName: 'Gray Leaf Spot', - summary: 'Penyakit jamur yang menyebabkan bercak abu-abu pada daun jagung.', + slug: "bercak-daun", + label: "Bercak Daun", + commonName: "Gray Leaf Spot", + summary: "Penyakit jamur yang menyebabkan bercak abu-abu pada daun jagung.", description: - 'Bercak Daun adalah penyakit jamur yang disebabkan oleh Cercospora zeae-maydis. Penyakit ini ditandai dengan munculnya bercak berbentuk persegi panjang berwarna abu-abu dengan tepi coklat pada daun jagung. Penyakit ini berkembang pesat dalam kondisi lembab dan dapat mengurangi hasil panen secara signifikan.', + "Bercak Daun adalah penyakit jamur yang disebabkan oleh Cercospora zeae-maydis. Penyakit ini ditandai dengan munculnya bercak berbentuk persegi panjang berwarna abu-abu dengan tepi coklat pada daun jagung. Penyakit ini berkembang pesat dalam kondisi lembab dan dapat mengurangi hasil panen secara signifikan.", symptoms: [ - 'Bercak berbentuk persegi panjang berwarna abu-abu', - 'Tepi bercak berwarna coklat atau merah', - 'Bercak biasanya muncul pada daun bagian bawah terlebih dahulu', - 'Dalam kondisi lembab, bercak dapat berkembang dengan cepat', + "Bercak berbentuk persegi panjang berwarna abu-abu", + "Tepi bercak berwarna coklat atau merah", + "Bercak biasanya muncul pada daun bagian bawah terlebih dahulu", + "Dalam kondisi lembab, bercak dapat berkembang dengan cepat", ], recommendations: [ - 'Gunakan varietas jagung yang tahan terhadap penyakit ini', - 'Terapkan rotasi tanaman dengan tanaman non-inang', - 'Kurangi kelembaban dengan meningkatkan jarak tanam', - 'Aplikasikan fungisida jika diperlukan', - 'Buang sisa tanaman yang terinfeksi setelah panen', + "Gunakan varietas jagung yang tahan terhadap penyakit ini", + "Terapkan rotasi tanaman dengan tanaman non-inang", + "Kurangi kelembaban dengan meningkatkan jarak tanam", + "Aplikasikan fungisida jika diperlukan", + "Buang sisa tanaman yang terinfeksi setelah panen", ], - riskLevel: 'high', - accentColor: '#9CA3AF', + medicineRecommendations: [ + "Azoksistrobin 250 SC: fungisida strobilurin sistemik", + "Piraklostrobin (Headline 250 EC): 1 mL/L air", + "Kombinasi strobilurin + triazol untuk efikasi maksimal", + "Aplikasi preventif lebih efektif daripada kuratif", + ], + imageUrl: + "https://images.unsplash.com/photo-1651029826601-9d3fae8926d2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&q=80&w=600", + riskLevel: "high", + accentColor: "#DC2626", displayOrder: 1, }, { - slug: 'hawar-daun', - label: 'Hawar Daun', - commonName: 'Northern/Southern Leaf Blight', - summary: 'Penyakit jamur yang menyebabkan hawar pada daun jagung dengan gejala bercak memanjang.', + slug: "hawar-daun", + label: "Hawar Daun", + commonName: "Northern/Southern Leaf Blight", + summary: + "Penyakit jamur yang menyebabkan hawar pada daun jagung dengan gejala bercak memanjang.", description: - 'Hawar Daun adalah penyakit jamur yang disebabkan oleh Exserohilum turcicum (Northern Leaf Blight) atau Bipolaris maydis (Southern Leaf Blight). Penyakit ini ditandai dengan munculnya bercak memanjang berwarna coklat atau abu-abu pada daun jagung. Penyakit ini dapat menyebabkan kerusakan daun yang parah dan mengurangi hasil panen.', + "Hawar Daun adalah penyakit jamur yang disebabkan oleh Exserohilum turcicum (Northern Leaf Blight) atau Bipolaris maydis (Southern Leaf Blight). Penyakit ini ditandai dengan munculnya bercak memanjang berwarna coklat atau abu-abu pada daun jagung. Penyakit ini dapat menyebabkan kerusakan daun yang parah dan mengurangi hasil panen.", symptoms: [ - 'Bercak memanjang berwarna coklat atau abu-abu', - 'Bercak dapat mencapai panjang 10-15 cm', - 'Tepi bercak sering berwarna lebih gelap', - 'Dalam kondisi lembab, bercak dapat berkembang dengan cepat', - 'Daun dapat mati jika terinfeksi parah', + "Bercak memanjang berwarna coklat atau abu-abu", + "Bercak dapat mencapai panjang 10-15 cm", + "Tepi bercak sering berwarna lebih gelap", + "Dalam kondisi lembab, bercak dapat berkembang dengan cepat", + "Daun dapat mati jika terinfeksi parah", ], recommendations: [ - 'Gunakan varietas jagung yang tahan terhadap penyakit ini', - 'Terapkan rotasi tanaman dengan tanaman non-inang', - 'Kurangi kelembaban dengan meningkatkan jarak tanam', - 'Aplikasikan fungisida jika diperlukan', - 'Buang sisa tanaman yang terinfeksi setelah panen', + "Gunakan varietas jagung yang tahan terhadap penyakit ini", + "Terapkan rotasi tanaman dengan tanaman non-inang", + "Kurangi kelembaban dengan meningkatkan jarak tanam", + "Aplikasikan fungisida jika diperlukan", + "Buang sisa tanaman yang terinfeksi setelah panen", ], - riskLevel: 'high', - accentColor: '#8B4513', + medicineRecommendations: [ + "Mancozeb 80 WP: 2 g/L air, semprotkan 7–10 hari sekali", + "Propineb 70 WP: 2 g/L air, dimulai saat gejala awal", + "Azoksistrobin + Difenokonazol (Amistar Top 325 SC)", + "Klorotalonil 75 WP sebagai fungisida protektif", + ], + riskLevel: "high", + accentColor: "#DC2626", displayOrder: 2, + imageUrl: + "https://images.unsplash.com/photo-1671559457949-5ac52323e19d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&q=80&w=600", }, { - slug: 'karat-daun', - label: 'Karat Daun', - commonName: 'Common Rust', - summary: 'Penyakit jamur yang menyebabkan pustula berwarna coklat kemerahan pada daun jagung.', + slug: "karat-daun", + label: "Karat Daun", + commonName: "Common Rust", + summary: + "Penyakit jamur yang menyebabkan pustula berwarna coklat kemerahan pada daun jagung.", description: - 'Karat Daun adalah penyakit jamur yang disebabkan oleh Puccinia sorghi. Penyakit ini ditandai dengan munculnya pustula kecil berwarna coklat kemerahan pada permukaan daun jagung. Penyakit ini berkembang dalam kondisi lembab dan dapat mengurangi hasil panen jika tidak dikendalikan.', + "Karat Daun adalah penyakit jamur yang disebabkan oleh Puccinia sorghi. Penyakit ini ditandai dengan munculnya pustula kecil berwarna coklat kemerahan pada permukaan daun jagung. Penyakit ini berkembang dalam kondisi lembab dan dapat mengurangi hasil panen jika tidak dikendalikan.", symptoms: [ - 'Pustula kecil berwarna coklat kemerahan pada permukaan daun', - 'Pustula biasanya muncul pada daun bagian bawah terlebih dahulu', - 'Dalam kondisi lembab, pustula dapat berkembang dengan cepat', - 'Daun dapat menjadi kuning dan mati jika terinfeksi parah', + "Pustula kecil berwarna coklat kemerahan pada permukaan daun", + "Pustula biasanya muncul pada daun bagian bawah terlebih dahulu", + "Dalam kondisi lembab, pustula dapat berkembang dengan cepat", + "Daun dapat menjadi kuning dan mati jika terinfeksi parah", ], recommendations: [ - 'Gunakan varietas jagung yang tahan terhadap penyakit ini', - 'Terapkan rotasi tanaman dengan tanaman non-inang', - 'Kurangi kelembaban dengan meningkatkan jarak tanam', - 'Aplikasikan fungisida jika diperlukan', - 'Buang sisa tanaman yang terinfeksi setelah panen', + "Gunakan varietas jagung yang tahan terhadap penyakit ini", + "Terapkan rotasi tanaman dengan tanaman non-inang", + "Kurangi kelembaban dengan meningkatkan jarak tanam", + "Aplikasikan fungisida jika diperlukan", + "Buang sisa tanaman yang terinfeksi setelah panen", ], - riskLevel: 'medium', - accentColor: '#DC2626', + medicineRecommendations: [ + "Propikonazol 250 EC: 0.5 mL/L air, 2 minggu sekali", + "Tebukonazol 250 EC: fungisida sistemik triazol", + "Trifloksistrobin + Tebukonazol (Nativo 75 WG)", + "Aplikasikan saat ≥ 5% permukaan daun terinfeksi", + ], + imageUrl: + "https://images.unsplash.com/photo-1660904900487-3c6fbcb3b387?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&q=80&w=600", + riskLevel: "medium", + accentColor: "#8B4513", displayOrder: 3, }, { - slug: 'daun-sehat', - label: 'Daun Sehat', - commonName: 'Healthy Leaf', - summary: 'Daun jagung yang sehat tanpa tanda-tanda penyakit atau kerusakan.', + slug: "daun-sehat", + label: "Daun Sehat", + commonName: "Healthy Leaf", + summary: + "Daun jagung yang sehat tanpa tanda-tanda penyakit atau kerusakan.", description: - 'Daun Sehat menunjukkan kondisi daun jagung yang optimal tanpa adanya gejala penyakit jamur atau kerusakan lainnya. Daun yang sehat memiliki warna hijau cerah, tekstur normal, dan tidak menunjukkan bercak, pustula, atau tanda-tanda kerusakan lainnya.', + "Daun Sehat menunjukkan kondisi daun jagung yang optimal tanpa adanya gejala penyakit jamur atau kerusakan lainnya. Daun yang sehat memiliki warna hijau cerah, tekstur normal, dan tidak menunjukkan bercak, pustula, atau tanda-tanda kerusakan lainnya.", + imageUrl: "https://cdn.iespa.or.id/image/manfaat-daun-jagung/public", symptoms: [ - 'Warna daun hijau cerah dan seragam', - 'Tekstur daun normal dan tidak ada bercak', - 'Tidak ada pustula atau tanda-tanda penyakit lainnya', - 'Daun terlihat kuat dan tidak layu', + "Warna daun hijau cerah dan seragam", + "Tekstur daun normal dan tidak ada bercak", + "Tidak ada pustula atau tanda-tanda penyakit lainnya", + "Daun terlihat kuat dan tidak layu", ], recommendations: [ - 'Pertahankan praktik budidaya yang baik', - 'Lakukan monitoring rutin untuk mendeteksi penyakit sejak dini', - 'Terapkan rotasi tanaman untuk menjaga kesehatan tanah', - 'Berikan nutrisi yang cukup untuk pertumbuhan optimal', - 'Jaga kelembaban tanah yang sesuai', + "Pertahankan praktik budidaya yang baik", + "Lakukan monitoring rutin untuk mendeteksi penyakit sejak dini", + "Terapkan rotasi tanaman untuk menjaga kesehatan tanah", + "Berikan nutrisi yang cukup untuk pertumbuhan optimal", + "Jaga kelembaban tanah yang sesuai", ], - riskLevel: 'low', - accentColor: '#22C55E', + medicineRecommendations: [ + "Tidak diperlukan aplikasi fungisida saat ini", + "Pupuk foliar mikro (Fe, Mn, Zn) dapat memperkuat ketahanan", + "Pupuk organik/biostimulant untuk memperbaiki kondisi tanah", + ], + riskLevel: "low", + accentColor: "#22C55E", displayOrder: 4, }, ];