o2o-infinith-demo/src/components/discovery/DiscoveryHero.tsx
Haewon Kam 3ba8fc839d feat: /discovery CTA 'URL 입력으로 시작하기' — URL 입력 진단 신청 모달 + discovery_leads 저장
- 히어로·하단 CTA 버튼명 변경(무료 AEO/GEO 진단 받기 → URL 입력으로 시작하기), mailto 직행 제거
- DiscoveryLeadModal: URL(필수)·연락처(필수)·상호(선택) → Supabase discovery_leads insert
- RLS anon insert 전용(조회 불가), 저장 실패 시 o2oteam@o2o.kr mailto 폴백 (정직성 규약)
- 마이그레이션 20260831_discovery_leads.sql (적용은 supabase login 후 db push 필요)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgWoJZAvvzMxTpWeenZSia
2026-08-31 16:58:38 +09:00

111 lines
4.5 KiB
TypeScript

/**
* AI Discovery 랜딩 히어로.
* Hero.tsx의 배경·배지·헤드라인 구조를 따르고, 하단에 ABMR 루프 + AI 답변 목업 2열 그리드.
* 시안: docs/reports/ai_discovery_landing.html (픽셀 기준)
*/
import { Link } from 'react-router';
import { motion } from 'motion/react';
import { ArrowRight } from 'lucide-react';
import type { OverallScore } from '../../types/discovery';
import AbmrLoop from './AbmrLoop';
import AiAnswerMock from './AiAnswerMock';
interface DiscoveryHeroProps {
overall: OverallScore;
target: { score: number; grade: OverallScore['grade'] } | null;
clinicName: string;
sampleReportPath: string;
criteriaCount: number;
/** CTA 클릭 → URL 입력 신청 모달 열기 */
onStart: () => void;
}
export default function DiscoveryHero({
overall,
target,
clinicName,
sampleReportPath,
criteriaCount,
onStart,
}: DiscoveryHeroProps) {
return (
<section className="relative overflow-hidden bg-[radial-gradient(ellipse_at_top,#e0e7ff_0%,#faf5ff_45%,#fdf2f8_100%)]">
{/* Decorative blobs */}
<div className="absolute top-[120px] left-[60px] w-64 h-64 bg-purple-300 rounded-full blur-3xl opacity-30 pointer-events-none" />
<div className="absolute top-[180px] right-[60px] w-64 h-64 bg-pink-300 rounded-full blur-3xl opacity-30 pointer-events-none" />
<div className="relative flex flex-col items-center text-center px-6 pt-32 md:pt-46 pb-16 md:pb-22">
{/* Badge */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-white/60 backdrop-blur-sm border border-white/40 shadow-sm mb-8"
>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path
d="M4.5 8c0-1.4 1-2.5 2.2-2.5 1.6 0 2.6 5 4.2 5 1.2 0 2.2-1.1 2.2-2.5s-1-2.5-2.2-2.5c-1.6 0-2.6 5-4.2 5C5.5 10.5 4.5 9.4 4.5 8Z"
stroke="#6C5CE7"
strokeWidth="1.4"
/>
</svg>
<span className="text-sm font-medium text-slate-700">AI DISCOVERY · AEO / GEO for Clinics</span>
</motion.div>
{/* Headline */}
<motion.h1
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.1 }}
className="font-serif text-5xl md:text-7xl font-bold text-primary-900 leading-[1.1] tracking-[-0.02em] mb-6 break-keep"
>
AI가 추천하는 병원은
<br />
<span className="text-gradient">따로 있습니다.</span>
</motion.h1>
{/* Sub copy */}
<motion.p
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.2 }}
className="text-lg md:text-xl text-slate-600 leading-relaxed max-w-3xl mb-10 break-keep"
>
고객은 이제 ChatGPT와 Perplexity에게 병원을 묻습니다.
<br className="hidden md:block" /> 답변에 인용될 근거를 {criteriaCount}개 항목으로 실측
진단하고, 8주 안에 구축합니다.
</motion.p>
{/* CTAs */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.3 }}
className="flex flex-col sm:flex-row items-center gap-4 mb-18"
>
<button
type="button"
onClick={onStart}
className="inline-flex items-center justify-center gap-2 px-10 py-4 text-lg font-medium text-white rounded-full shadow-xl bg-gradient-to-r from-[#4F1DA1] to-[#021341] hover:opacity-90 transition-opacity"
>
URL 입력으로 시작하기
<ArrowRight className="w-5 h-5" />
</button>
<Link
to={sampleReportPath}
className="inline-flex items-center justify-center px-10 py-4 text-lg font-medium text-primary-900 bg-white/80 border border-slate-200 rounded-full hover:bg-white transition-colors"
>
샘플 리포트 보기
</Link>
</motion.div>
{/* ABMR loop + AI answer mock */}
<div className="w-full max-w-7xl grid md:grid-cols-2 gap-6">
<AbmrLoop overall={overall} target={target} />
<AiAnswerMock clinicName={clinicName} criteriaCount={criteriaCount} />
</div>
</div>
</section>
);
}