115 lines
4.7 KiB
TypeScript
115 lines
4.7 KiB
TypeScript
import { motion } from 'motion/react';
|
|
import { Calendar, Users, MapPin, Phone, Award, Star, Globe } from 'lucide-react';
|
|
import { SectionWrapper } from './ui/SectionWrapper';
|
|
import type { ClinicSnapshot as ClinicSnapshotType } from '../../types/report';
|
|
|
|
interface ClinicSnapshotProps {
|
|
data: ClinicSnapshotType;
|
|
}
|
|
|
|
function formatNumber(n: number): string {
|
|
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(2)}M`;
|
|
if (n >= 1_000) return `${(n / 1_000).toFixed(0)}K`;
|
|
return n.toLocaleString();
|
|
}
|
|
|
|
const infoFields = (data: ClinicSnapshotType) => [
|
|
{ label: '개원', value: `${data.established} (${data.yearsInBusiness}년)`, icon: Calendar },
|
|
{ label: '의료진', value: `${data.staffCount}명`, icon: Users },
|
|
{ label: '강남언니 평점', value: `${data.overallRating} / 5.0`, icon: Star },
|
|
{ label: '리뷰 수', value: formatNumber(data.totalReviews), icon: Star },
|
|
{ label: '시술 가격대', value: `${data.priceRange.min} ~ ${data.priceRange.max}`, icon: Globe },
|
|
{ label: '위치', value: `${data.location} (${data.nearestStation})`, icon: MapPin },
|
|
{ label: '전화', value: data.phone, icon: Phone },
|
|
{ label: '도메인', value: data.domain, icon: Globe },
|
|
];
|
|
|
|
export default function ClinicSnapshot({ data }: ClinicSnapshotProps) {
|
|
const fields = infoFields(data);
|
|
|
|
return (
|
|
<SectionWrapper id="clinic-snapshot" title="Clinic Overview" subtitle="병원 기본 정보">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-8">
|
|
{fields.map((field, i) => {
|
|
const Icon = field.icon;
|
|
return (
|
|
<motion.div
|
|
key={field.label}
|
|
className="rounded-2xl bg-white border border-slate-100 shadow-sm p-5"
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.5, delay: i * 0.05 }}
|
|
>
|
|
<div className="flex items-start gap-3">
|
|
<div className="shrink-0 w-8 h-8 rounded-lg bg-slate-50 flex items-center justify-center">
|
|
<Icon size={16} className="text-slate-400" />
|
|
</div>
|
|
<div className="min-w-0">
|
|
<p className="text-xs text-slate-500 uppercase tracking-wide">{field.label}</p>
|
|
<p className="text-lg font-semibold text-[#0A1128] mt-1">{field.value}</p>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{/* Lead Doctor Highlight */}
|
|
<motion.div
|
|
className="rounded-2xl bg-gradient-to-r from-[#4F1DA1]/5 to-[#021341]/5 border border-purple-100 p-6 mb-8"
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.5, delay: 0.3 }}
|
|
>
|
|
<div className="flex items-center gap-2 mb-3">
|
|
<Award size={20} className="text-[#6C5CE7]" />
|
|
<h3 className="font-serif font-bold text-2xl text-[#0A1128]">대표 원장</h3>
|
|
</div>
|
|
<p className="text-xl font-bold text-[#0A1128] mb-1">{data.leadDoctor.name}</p>
|
|
<p className="text-sm text-slate-600 mb-3">{data.leadDoctor.credentials}</p>
|
|
<div className="flex items-center gap-4">
|
|
<div className="flex items-center gap-1">
|
|
{Array.from({ length: 5 }).map((_, i) => (
|
|
<Star
|
|
key={i}
|
|
size={16}
|
|
className={i < Math.round(data.leadDoctor.rating) ? 'text-[#6B2D8B] fill-[#6B2D8B]' : 'text-slate-200'}
|
|
/>
|
|
))}
|
|
<span className="text-sm font-semibold text-[#0A1128] ml-1">
|
|
{data.leadDoctor.rating}
|
|
</span>
|
|
</div>
|
|
<span className="text-sm text-slate-500">
|
|
리뷰 {formatNumber(data.leadDoctor.reviewCount)}건
|
|
</span>
|
|
</div>
|
|
</motion.div>
|
|
|
|
{/* Certifications */}
|
|
{data.certifications.length > 0 && (
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.5, delay: 0.4 }}
|
|
>
|
|
<p className="text-sm font-semibold text-slate-700 mb-3">인증 및 자격</p>
|
|
<div className="flex flex-wrap gap-2">
|
|
{data.certifications.map((cert) => (
|
|
<span
|
|
key={cert}
|
|
className="rounded-full bg-white/60 backdrop-blur-sm border border-white/40 px-3 py-1 text-sm font-medium text-slate-700"
|
|
>
|
|
{cert}
|
|
</span>
|
|
))}
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</SectionWrapper>
|
|
);
|
|
}
|