Seed: healthcare template (18 files)

This commit is contained in:
2026-07-23 22:12:05 +00:00
parent 3c1105cacb
commit a77a1429d9
+169
View File
@@ -0,0 +1,169 @@
import { useParams, Link } from "react-router-dom";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { ArrowLeft, Star, GraduationCap, Clock, Quote } from "lucide-react";
import { toast } from "sonner";
import { useSaasMutation } from "@/hooks/use-tygarun";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
const doctorData: Record<string, any> = {
chen: {
name: "Dr. Sarah Chen", specialty: "Cardiology", credentials: "MD, FACC",
gradient: "from-sky-400 to-teal-400",
bio: "Dr. Sarah Chen is a board-certified cardiologist with over 15 years of experience in interventional cardiology and preventive heart care. She completed her fellowship at Stanford University Medical Center and is passionate about using the latest evidence-based approaches to help patients achieve optimal cardiovascular health. Dr. Chen has published extensively in peer-reviewed journals and is recognized as a leading voice in womens heart health.",
education: [
{ school: "Johns Hopkins School of Medicine", degree: "Doctor of Medicine" },
{ school: "Stanford University Medical Center", degree: "Cardiology Fellowship" },
{ school: "American Board of Cardiology", degree: "Board Certification" },
],
expertise: ["Interventional Cardiology", "Heart Failure", "Preventive Cardiology", "Echocardiography", "Cardiac Rehab"],
hours: { Mon: "9:00 AM - 5:00 PM", Tue: "9:00 AM - 5:00 PM", Wed: "9:00 AM - 12:00 PM", Thu: "9:00 AM - 5:00 PM", Fri: "9:00 AM - 3:00 PM" },
reviews: [
{ name: "Margaret S.", rating: 5, text: "Dr. Chen is incredibly thorough and caring. She explained my condition in terms I could understand." },
{ name: "David R.", rating: 5, text: "After my cardiac event, Dr. Chen's expertise and compassion made all the difference in my recovery." },
],
},
okafor: {
name: "Dr. James Okafor", specialty: "Neurology", credentials: "MD, PhD, FAAN",
gradient: "from-teal-400 to-emerald-400",
bio: "Dr. James Okafor is a distinguished neurologist with dual expertise in clinical neurology and neuroscience research. With a PhD from MIT and over 20 years of clinical experience, he brings a unique research-informed perspective to patient care. Dr. Okafor specializes in stroke prevention, epilepsy management, and neurodegenerative conditions, and has been instrumental in advancing treatment protocols at leading medical institutions.",
education: [
{ school: "Harvard Medical School", degree: "Doctor of Medicine" },
{ school: "MIT", degree: "PhD in Neuroscience" },
{ school: "Massachusetts General Hospital", degree: "Neurology Residency" },
],
expertise: ["Stroke Treatment", "Epilepsy", "Neurodegenerative Diseases", "Brain Mapping", "Clinical Trials"],
hours: { Mon: "8:00 AM - 4:00 PM", Tue: "8:00 AM - 4:00 PM", Wed: "8:00 AM - 4:00 PM", Thu: "10:00 AM - 6:00 PM", Fri: "8:00 AM - 2:00 PM" },
reviews: [
{ name: "Thomas K.", rating: 5, text: "Dr. Okafor is brilliant and deeply empathetic. His approach to my neurological condition was life-changing." },
{ name: "Lisa M.", rating: 5, text: "The best neurologist I have ever seen. Takes time to listen and creates personalized treatment plans." },
],
},
};
const fallback = doctorData.chen;
export default function DoctorDetailPage() {
const { id } = useParams();
const doc = doctorData[id || ""] || fallback;
const { mutate: bookDoctor, loading: booking } = useSaasMutation("scheduling", "/bookings");
const handleBook = async () => {
try {
await bookDoctor({ doctor: doc.name, specialty: doc.specialty });
toast.success(`Appointment request sent for \${doc.name}`, {
description: "Our scheduling team will contact you within 24 hours to confirm.",
});
} catch {
toast.error("Could not submit request. Please call us or try again.");
}
};
return (
<div className="min-h-screen bg-background text-foreground antialiased">
<Header />
<section className="pt-28 pb-20">
<div className="mx-auto max-w-4xl px-6">
<Link to="/doctors" className="inline-flex items-center text-sm text-sky-600 dark:text-sky-400 hover:text-sky-700 mb-8 animate-fade-up">
<ArrowLeft className="mr-2 h-4 w-4" /> Back to All Doctors
</Link>
{/* ── PROFILE HEADER ── */}
<div className="flex flex-col sm:flex-row items-center sm:items-start gap-6 mb-12 animate-fade-up">
<div className={`w-28 h-28 rounded-full bg-gradient-to-br \${doc.gradient} flex items-center justify-center text-white text-3xl font-bold ring-4 ring-sky-200/30 dark:ring-sky-800/30`}>
{doc.name.split(" ").slice(-2).map((n: string) => n[0]).join("")}
</div>
<div className="text-center sm:text-left">
<h1 className="text-3xl font-bold">{doc.name}</h1>
<Badge className="mt-2 bg-sky-100 text-sky-700 dark:bg-sky-900/40 dark:text-sky-300 border-0 text-sm">{doc.specialty}</Badge>
<p className="text-sm text-muted-foreground mt-1 font-medium">{doc.credentials}</p>
</div>
</div>
{/* ── BIO ── */}
<div className="prose dark:prose-invert max-w-none mb-12 animate-fade-up">
<p className="text-muted-foreground leading-relaxed">{doc.bio}</p>
</div>
{/* ── EDUCATION ── */}
<div className="mb-12 animate-fade-up">
<h2 className="text-xl font-semibold mb-4 flex items-center gap-2"><GraduationCap className="h-5 w-5 text-sky-500" /> Education & Training</h2>
<div className="space-y-3">
{doc.education.map((e: any, i: number) => (
<div key={i} className="flex items-start gap-3 p-4 rounded-xl bg-slate-50 dark:bg-slate-900/50 border border-slate-200/60 dark:border-slate-800/60">
<div className="w-2 h-2 rounded-full bg-sky-500 mt-2 flex-shrink-0" />
<div>
<div className="font-medium text-sm">{e.school}</div>
<div className="text-xs text-muted-foreground">{e.degree}</div>
</div>
</div>
))}
</div>
</div>
{/* ── EXPERTISE ── */}
<div className="mb-12 animate-fade-up">
<h2 className="text-xl font-semibold mb-4">Areas of Expertise</h2>
<div className="flex flex-wrap gap-2">
{doc.expertise.map((e: string, i: number) => (
<Badge key={i} variant="secondary" className="px-4 py-1.5 bg-sky-50 text-sky-700 dark:bg-sky-900/30 dark:text-sky-300 border border-sky-200 dark:border-sky-800">{e}</Badge>
))}
</div>
</div>
{/* ── OFFICE HOURS ── */}
<div className="mb-12 animate-fade-up">
<h2 className="text-xl font-semibold mb-4 flex items-center gap-2"><Clock className="h-5 w-5 text-sky-500" /> Office Hours</h2>
<Card className="bg-white/60 dark:bg-slate-900/60 backdrop-blur-sm border-slate-200/60 dark:border-slate-800/60">
<CardContent className="p-0">
<table className="w-full text-sm">
<tbody>
{Object.entries(doc.hours).map(([day, time]) => (
<tr key={day} className="border-b border-slate-100 dark:border-slate-800 last:border-0">
<td className="px-6 py-3 font-medium w-32">{day}</td>
<td className="px-6 py-3 text-muted-foreground">{time as string}</td>
</tr>
))}
</tbody>
</table>
</CardContent>
</Card>
</div>
{/* ── BOOK CTA ── */}
<div className="text-center mb-16 animate-fade-up">
<Button size="lg" disabled={booking} className="rounded-full px-12 bg-sky-500 hover:bg-sky-600 text-white shadow-lg shadow-sky-500/20 active:scale-[0.97] transition-all" onClick={handleBook}>
{booking ? "Sending..." : `Book with \${doc.name}`}
</Button>
</div>
{/* ── PATIENT REVIEWS ── */}
<div className="animate-fade-up">
<h2 className="text-xl font-semibold mb-6">Patient Reviews</h2>
<div className="grid md:grid-cols-2 gap-6 stagger">
{doc.reviews.map((r: any, i: number) => (
<Card key={i} className="bg-white/60 dark:bg-slate-900/60 backdrop-blur-sm border-slate-200/60 dark:border-slate-800/60">
<CardContent className="p-6">
<div className="flex items-center gap-1 mb-3">
{Array.from({ length: r.rating }).map((_, si) => (
<Star key={si} className="h-4 w-4 fill-amber-400 text-amber-400" />
))}
</div>
<Quote className="h-6 w-6 text-sky-200 dark:text-sky-800 mb-2" />
<p className="text-sm text-muted-foreground italic mb-3">{r.text}</p>
<span className="text-sm font-medium">{r.name}</span>
</CardContent>
</Card>
))}
</div>
</div>
</div>
</section>
<Footer />
</div>
);
}