Merge pull request #39 from ATLAS-PJK-GM007/selly/frontend

Selly/frontend
This commit is contained in:
Selly Supriyatin
2026-06-15 21:07:56 +07:00
committed by GitHub
2 changed files with 68 additions and 33 deletions
@@ -15,7 +15,7 @@ import { RiskBadge } from "@/components/risk-badge";
type Props = { type Props = {
imageUrl: string; imageUrl: string;
confidence: number; // contoh: 0.95 confidence: number;
diseaseName: string; diseaseName: string;
scientificName: string; scientificName: string;
riskLevel: string; riskLevel: string;
@@ -42,8 +42,8 @@ export function DiagnosisResultView({
const getRiskLevelKey = (level: string): "low" | "medium" | "high" => { const getRiskLevelKey = (level: string): "low" | "medium" | "high" => {
const normalized = level.toLowerCase(); const normalized = level.toLowerCase();
if (normalized.includes("rendah")) return "low"; if (normalized.includes("rendah") || normalized === "low") return "low";
if (normalized.includes("tinggi")) return "high"; if (normalized.includes("tinggi") || normalized === "high") return "high";
return "medium"; return "medium";
}; };
@@ -85,18 +85,35 @@ export function DiagnosisResultView({
<div className="space-y-2 mb-4"> <div className="space-y-2 mb-4">
<div className="flex justify-between text-sm font-bold text-slate-700"> <div className="flex justify-between text-sm font-bold text-slate-700">
<span>Tingkat Keyakinan AI</span> <span>Tingkat Keyakinan AI</span>
<span className="text-emerald-600">{confidencePercent}%</span> <span
className={
confidencePercent >= 75
? "text-emerald-600"
: "text-amber-500"
}
>
{confidencePercent}%
</span>
</div> </div>
<div className="w-full bg-slate-200 rounded-full h-2.5 overflow-hidden"> <div className="w-full bg-slate-200 rounded-full h-2.5 overflow-hidden">
<div <div
className="bg-emerald-500 h-2.5 rounded-full transition-all duration-1000" className={`h-2.5 rounded-full transition-all duration-1000 ${
confidencePercent >= 75 ? "bg-emerald-500" : "bg-amber-500"
}`}
style={{ width: `${confidencePercent}%` }} style={{ width: `${confidencePercent}%` }}
></div> ></div>
</div> </div>
<p className="text-[11px] text-emerald-600 flex items-center gap-1 font-medium"> {confidencePercent >= 75 ? (
<CheckCircle2 className="w-3 h-3" /> Di atas ambang batas minimum <p className="text-[11px] text-emerald-600 flex items-center gap-1 font-medium">
(75%) <CheckCircle2 className="w-3 h-3" /> Di atas ambang batas
</p> minimum (75%)
</p>
) : (
<p className="text-[11px] text-amber-600 flex items-center gap-1 font-medium">
<AlertTriangle className="w-3 h-3" /> Di bawah ambang batas
minimum (75%)
</p>
)}
</div> </div>
<div className="flex items-center gap-3 pt-4 border-t border-amber-200/50"> <div className="flex items-center gap-3 pt-4 border-t border-amber-200/50">
+42 -24
View File
@@ -16,6 +16,7 @@ import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { Modal } from "@/components/ui/modal"; import { Modal } from "@/components/ui/modal";
import type { DiagnosisRecord } from "@zeavis/shared"; import type { DiagnosisRecord } from "@zeavis/shared";
import { diseaseCatalogSeed } from "@zeavis/shared"; // Import data seed lokal ditambahkan
import { apiClient } from "@/lib/api-client"; import { apiClient } from "@/lib/api-client";
import { trackScan, trackDiagnosisResult } from "@/lib/telemetry"; import { trackScan, trackDiagnosisResult } from "@/lib/telemetry";
import { DiagnosisResultView } from "../components/diagnose-result-view"; import { DiagnosisResultView } from "../components/diagnose-result-view";
@@ -95,7 +96,7 @@ export function ScanPage() {
const [diagnosisPreview, setDiagnosisPreview] = const [diagnosisPreview, setDiagnosisPreview] =
useState<DiagnosisRecord | null>(null); useState<DiagnosisRecord | null>(null);
const diagnosesQuery = useQuery({ useQuery({
queryKey: ["diagnoses"], queryKey: ["diagnoses"],
queryFn: () => apiClient.getDiagnoses(), queryFn: () => apiClient.getDiagnoses(),
enabled: previewOpen, enabled: previewOpen,
@@ -429,29 +430,46 @@ export function ScanPage() {
</div> </div>
)} )}
<DiagnosisResultView {/* Render DiagnosisResultView dengan Fallback Obat */}
imageUrl={ {(() => {
previewUrl || // Fallback logic for scientific name and medicine recommendations
diagnosisPreview.imageUrl || const seedData = diagnosisPreview.disease
"https://placehold.co/600x400?text=Foto+Daun" ? diseaseCatalogSeed.find(
} (seed) =>
confidence={diagnosisPreview.confidence ?? 0} seed.commonName === diagnosisPreview.disease?.commonName,
diseaseName={ )
diagnosisPreview.disease?.commonName ?? "Tidak Diketahui" : null;
}
scientificName={diagnosisPreview.disease?.label ?? ""} // If the API doesn't return medicine recommendations, use the seed data as a fallback
riskLevel={diagnosisPreview.disease?.riskLevel ?? "Sedang"} const finalMedicines =
description={ (diagnosisPreview.disease as any)?.medicineRecommendations ||
diagnosisPreview.disease?.description ?? seedData?.medicineRecommendations ||
diagnosisPreview.disease?.summary ?? [];
"Deskripsi tidak tersedia."
} return (
symptoms={diagnosisPreview.disease?.symptoms ?? []} <DiagnosisResultView
preventions={diagnosisPreview.disease?.recommendations ?? []} imageUrl={
medicines={ previewUrl ||
(diagnosisPreview.disease as any)?.medicineRecommendations ?? [] diagnosisPreview.imageUrl ||
} "https://placehold.co/600x400?text=Foto+Daun"
/> }
confidence={diagnosisPreview.confidence ?? 0}
diseaseName={
diagnosisPreview.disease?.commonName ?? "Tidak Diketahui"
}
scientificName={diagnosisPreview.disease?.label ?? ""}
riskLevel={diagnosisPreview.disease?.riskLevel ?? "Sedang"}
description={
diagnosisPreview.disease?.description ??
diagnosisPreview.disease?.summary ??
"Deskripsi tidak tersedia."
}
symptoms={diagnosisPreview.disease?.symptoms ?? []}
preventions={diagnosisPreview.disease?.recommendations ?? []}
medicines={finalMedicines} // Datanya terhubung ke sini!
/>
);
})()}
{/* All Model Predictions */} {/* All Model Predictions */}
{diagnosisPreview.predictions && {diagnosisPreview.predictions &&