From 81d083a2b8991901e3b86ccafdaead1ae0c9fa97 Mon Sep 17 00:00:00 2001 From: Asep Haryana Saputra <90584806+MythEclipse@users.noreply.github.com> Date: Tue, 2 Jun 2026 07:47:59 +0000 Subject: [PATCH] fix(frontend): wrap catalog, disease detail, and expert reviews with MainLayout - Add MainLayout wrapper to /catalog, /catalog/:slug, and /expert/reviews routes in app.tsx so they share the same navbar and footer as dashboard - Remove duplicate header/layout/spacing from CatalogPage, DiseaseDetailPage, and ExpertReviewsPage - Update ExpertReviewsPage to use consistent space-y layout pattern matching other pages - Update CatalogPage to remove outer main wrapper since MainLayout provides the container Co-Authored-By: Claude Opus 4.7 --- apps/web/src/app.tsx | 22 +- apps/web/src/pages/catalog-page.tsx | 31 +- apps/web/src/pages/disease-detail-page.tsx | 192 +++++---- apps/web/src/pages/expert-reviews-page.tsx | 456 ++++++++++----------- 4 files changed, 344 insertions(+), 357 deletions(-) diff --git a/apps/web/src/app.tsx b/apps/web/src/app.tsx index d6e50ec..4a4f7b3 100644 --- a/apps/web/src/app.tsx +++ b/apps/web/src/app.tsx @@ -78,12 +78,28 @@ const router = createBrowserRouter([ path: "/expert/reviews", element: ( - + + + ), }, - { path: "/catalog", element: }, - { path: "/catalog/:slug", element: }, + { + path: "/catalog", + element: ( + + + + ), + }, + { + path: "/catalog/:slug", + element: ( + + + + ), + }, ]); export function App() { diff --git a/apps/web/src/pages/catalog-page.tsx b/apps/web/src/pages/catalog-page.tsx index aff925c..0093a07 100644 --- a/apps/web/src/pages/catalog-page.tsx +++ b/apps/web/src/pages/catalog-page.tsx @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react'; import { useQuery } from '@tanstack/react-query'; import { Link, useSearchParams } from 'react-router-dom'; -import { ArrowLeft, Shield, AlertCircle } from 'lucide-react'; +import { AlertCircle } from 'lucide-react'; import type { RiskLevel } from '@zeavis/shared'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; @@ -42,25 +42,15 @@ export function CatalogPage() { }); return ( -
-
-
-
-
- -
-

Edukasi Penyakit

-

Katalog Penyakit

-
-
-
-
+
+
+
+

Edukasi Penyakit

+

Katalog Penyakit

+
+
- {/* Filters */} + {/* Filters */}
)} -
-
+ ); } diff --git a/apps/web/src/pages/disease-detail-page.tsx b/apps/web/src/pages/disease-detail-page.tsx index 3bae73f..c0407eb 100644 --- a/apps/web/src/pages/disease-detail-page.tsx +++ b/apps/web/src/pages/disease-detail-page.tsx @@ -1,7 +1,7 @@ import { useParams, Link } from 'react-router-dom'; import { useQuery } from '@tanstack/react-query'; import { isDiseaseSlug } from '@zeavis/shared'; -import { ArrowLeft, BookOpen, AlertCircle } from 'lucide-react'; +import { ArrowLeft, AlertCircle, BookOpen } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { RiskBadge } from '@/components/risk-badge'; @@ -20,37 +20,37 @@ export function DiseaseDetailPage() { if (!validatedSlug || error || (!isLoading && !disease)) { return ( -
-
- - -

Materi tidak ditemukan

-
-
+ +

Materi tidak ditemukan

+
+ ); } if (isLoading) { return ( -
-
- - -

Memuat materi...

-
-
+ +

Memuat materi...

+
+ ); } @@ -59,88 +59,86 @@ export function DiseaseDetailPage() { } return ( -
-
-
- - -
- -
-
-
-

{disease.commonName}

-

{disease.label}

-
- -
-

{disease.summary}

-
- - - - Deskripsi - - -

{disease.description}

-
-
- - - - Gejala - Tanda-tanda yang perlu diperhatikan - - -
    - {disease.symptoms.map((symptom, index) => ( -
  • - - {symptom} -
  • - ))} -
-
-
- - - - Rekomendasi Penanganan - Langkah-langkah untuk mengendalikan penyakit - - -
    - {disease.recommendations.map((recommendation, index) => ( -
  1. - - {index + 1} - - {recommendation} -
  2. - ))} -
-
-
- -
- - -
+
+
+ +
-
+ +
+
+
+

{disease.commonName}

+

{disease.label}

+
+ +
+

{disease.summary}

+
+ + + + Deskripsi + + +

{disease.description}

+
+
+ + + + Gejala + Tanda-tanda yang perlu diperhatikan + + +
    + {disease.symptoms.map((symptom, index) => ( +
  • + + {symptom} +
  • + ))} +
+
+
+ + + + Rekomendasi Penanganan + Langkah-langkah untuk mengendalikan penyakit + + +
    + {disease.recommendations.map((recommendation, index) => ( +
  1. + + {index + 1} + + {recommendation} +
  2. + ))} +
+
+
+ +
+ + +
+ ); } diff --git a/apps/web/src/pages/expert-reviews-page.tsx b/apps/web/src/pages/expert-reviews-page.tsx index 48ae300..a2f8117 100644 --- a/apps/web/src/pages/expert-reviews-page.tsx +++ b/apps/web/src/pages/expert-reviews-page.tsx @@ -1,7 +1,7 @@ import { FormEvent, useMemo, useState } from 'react'; -import { Link, useSearchParams } from 'react-router-dom'; +import { useSearchParams } from 'react-router-dom'; import { useMutation, useQueries, useQueryClient } from '@tanstack/react-query'; -import type { DiseaseSlug, DiagnosisStatus } from '@zeavis/shared'; +import type { DiseaseSlug } from '@zeavis/shared'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { DiagnosisStatusBadge } from '@/components/diagnosis-status-badge'; @@ -24,14 +24,18 @@ export function ExpertReviewsPage() { const reviews = reviewsQuery.data || []; const diseases = diseasesQuery.data || []; - const selected = useMemo(() => reviews.find((item) => item.id === selectedId) ?? reviews[0] ?? null, [reviews, selectedId]); + const selected = useMemo( + () => reviews.find((item) => item.id === selectedId) ?? reviews[0] ?? null, + [reviews, selectedId], + ); const mutation = useMutation({ - mutationFn: () => apiClient.reviewDiagnosis(selected!.id, { - verdict, - correctedDiseaseSlug: verdict === 'corrected' ? correctedDiseaseSlug || undefined : undefined, - notes, - }), + mutationFn: () => + apiClient.reviewDiagnosis(selected!.id, { + verdict, + correctedDiseaseSlug: verdict === 'corrected' ? correctedDiseaseSlug || undefined : undefined, + notes, + }), onSuccess: () => { setNotes(''); setVerdict('verified'); @@ -47,244 +51,224 @@ export function ExpertReviewsPage() { await mutation.mutateAsync(); } - const statusLabel = (status: DiagnosisStatus) => { - switch (status) { - case 'ai_verified': return 'Terverifikasi AI'; - case 'needs_review': return 'Menunggu Review'; - case 'expert_verified': return 'Diverifikasi Pakar'; - case 'expert_corrected': return 'Dikoreksi Pakar'; - case 'failed': return 'Gagal'; - } - }; + const isLoading = reviewsQuery.isPending || diseasesQuery.isPending; return ( -
-
-
-
-

Review Pakar

-

Diagnosis Menunggu Review

-
- - - +
+
+
+

Review Pakar

+

Diagnosis Menunggu Review

-
+ -
-
- {/* Left: List of reviews */} -
-
-

Daftar Diagnosis

- {reviews.length} -
- -
- {reviewsQuery.isPending || diseasesQuery.isPending ? ( -

Memuat diagnosis...

- ) : reviews.length === 0 ? ( -

Tidak ada diagnosis yang menunggu review

- ) : ( - reviews.map((review) => ( - - )) - )} -
+
+ {/* Left: List of reviews */} +
+
+

Daftar Diagnosis

+ {reviews.length}
- {/* Right: Detail and form */} -
- {reviewsQuery.isPending || diseasesQuery.isPending ? ( - - - Memuat diagnosis... - - - ) : selected ? ( - <> - {/* Detail card */} - - - {selected.disease?.commonName ?? 'Diagnosis gagal'} - - {new Date(selected.createdAt).toLocaleString('id-ID')} - - - - {`Gambar - -
-
- Status - -
-
- Confidence - - {selected.confidence === null ? 'N/A' : `${(selected.confidence * 100).toFixed(1)}%`} - -
-
- - {/* Top predictions */} - {selected.predictions.length > 0 && ( -
-

Prediksi Teratas

-
- {selected.predictions.map((pred) => ( -
- {pred.modelLabel} - {(pred.confidence * 100).toFixed(1)}% -
- ))} -
-
- )} -
-
- - {/* Review form */} - - - Review Pakar - - -
- {/* Verdict selection */} -
- -
- - -
-
- - {/* Disease selection (only if corrected) */} - {verdict === 'corrected' && ( -
- - -
- )} - - {/* Notes */} -
- -