증거(진단)와 처방(할 일)을 한 페이지에 두면 스크롤이 너무 길어져
둘 다 읽기 힘들다는 지적에 따라 단계를 나눴다.
- /actions/:id 신규: Action Plan(P0~P2) + What We Don't Sell + 빌드 제안
(ActionPlanSection·IntegritySection 신규 컴포넌트, Tag는 두 페이지가
같이 써서 공용 컴포넌트로 뺌)
- /discovery/🆔 위 섹션 제거, 진단(점수·근거·Scorecard·Rubric)만 남김.
페이지 맨 아래 중복으로 박혀 있던 확인 항목 패널(ClinicInputsPanel)도
제거 — /supporters/:id 전용 단계가 이미 있어 두 번 보여줄 필요가 없었다
- 진단 데이터가 없는 병원이 /actions/:id 로 오면 /discovery/:id 로 되돌림
- ClinicNav: 5단계로 확장(진단 리포트→개선 제안→사이트 빌드→사진 확인→
확인 항목), 다음 단계 플로팅 버튼 추가(기존엔 이전 단계만 있었다)
- App.tsx: 라우트 전환 시 스크롤을 맨 위로 되돌림. 스크롤을 내린 채
다음 단계를 누르면 새 페이지가 같은 위치(짧으면 빈 하단)에서 시작하던
문제 수정. 인앱 해시 앵커(#breakdown)가 있으면 건드리지 않음
- 사이트 빌드/확인 항목 화면의 미리보기 버튼을 "초안 사이트 열기"로
통일(공개 후에는 "공개본 사이트 열기")
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
81 lines
3.7 KiB
TypeScript
81 lines
3.7 KiB
TypeScript
/**
|
|
* /actions/:id — 개선 제안 (Action Plan). 진단 리포트(/discovery/:id)에서 분리된 처방 단계.
|
|
*
|
|
* 진단은 "지금 무엇이 문제인가"(증거), 여기는 "그래서 무엇을 하는가"(처방)다.
|
|
* 읽는 목적이 다르고, 둘을 한 페이지에 두면 스크롤이 길어져 둘 다 읽기 힘들어진다.
|
|
* 진단 데이터가 없으면 처방도 쓸 수 없으므로 진단 리포트로 돌려보낸다.
|
|
*/
|
|
import { useMemo } from 'react';
|
|
import { useParams, Navigate } from 'react-router';
|
|
import { AEO_GEO_RUBRIC } from '../data/aeoGeoRubric';
|
|
import { AEO_GEO_RUBRIC_V2 } from '../data/aeoGeoRubricV2';
|
|
import { DISCOVERY_RESULTS } from '../data/discoveryResults';
|
|
import { scoreDiscovery } from '../lib/discoveryScore';
|
|
import { scoreDiscoveryV2 } from '../lib/discoveryScoreV2';
|
|
import { ActionPlanSection } from '../components/discovery/ActionPlanSection';
|
|
import { IntegritySection } from '../components/discovery/IntegritySection';
|
|
import { BuildPlanSection } from '../components/discovery/BuildPlanSection';
|
|
import { PrismFilled } from '../components/icons/FilledIcons';
|
|
|
|
export default function ActionPlanPage() {
|
|
const { id } = useParams<{ id: string }>();
|
|
const result = id ? DISCOVERY_RESULTS[id] : undefined;
|
|
const overall = useMemo(
|
|
() => (result ? scoreDiscovery(AEO_GEO_RUBRIC, result) : null),
|
|
[result],
|
|
);
|
|
const overallV2 = useMemo(
|
|
() => (result ? scoreDiscoveryV2(AEO_GEO_RUBRIC_V2, result) : null),
|
|
[result],
|
|
);
|
|
|
|
if (!id) return null;
|
|
if (!result || !overall) {
|
|
// 개선 제안은 진단 항목 위에 세운다. 진단이 없으면 여기서 보여줄 근거가 없으니
|
|
// 진단 리포트로 보낸다. 그 페이지가 "아직 진단 전" 안내와 다음 링크를 갖고 있다.
|
|
return <Navigate to={`/discovery/${id}`} replace />;
|
|
}
|
|
|
|
return (
|
|
<div data-report-content className="[word-break:keep-all]">
|
|
<section className="on-dark bg-[#0A1128] text-white relative overflow-hidden pt-28 pb-16 md:pt-36 md:pb-20 px-6">
|
|
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,rgba(108,92,231,0.18),transparent_60%)]" />
|
|
<div className="relative max-w-7xl mx-auto">
|
|
<div className="inline-flex items-center gap-2 rounded-full bg-white/10 border border-white/10 px-4 py-1.5 mb-6">
|
|
<PrismFilled size={16} className="text-purple-300" />
|
|
<span className="text-sm font-semibold tracking-wide text-purple-200">
|
|
INFINITH AI Discovery · Action Plan
|
|
</span>
|
|
</div>
|
|
<h1 className="font-serif text-4xl md:text-6xl font-bold tracking-[-0.02em] mb-4">
|
|
<span className="bg-gradient-to-r from-purple-300 to-blue-300 bg-clip-text text-transparent">
|
|
개선 제안
|
|
</span>
|
|
</h1>
|
|
<p className="text-3xl font-bold mb-2">{result.clinicName}</p>
|
|
<p className="ui-body text-white/70 max-w-2xl">
|
|
진단(v{result.rubricVersion} · {overall.score}/{overall.grade})에서 확인된 항목을 근거로,
|
|
무엇을 언제까지 할지와 저희가 하지 않을 것을 정리했습니다.
|
|
</p>
|
|
</div>
|
|
</section>
|
|
|
|
<ActionPlanSection result={result} />
|
|
<IntegritySection result={result} />
|
|
<BuildPlanSection
|
|
result={result}
|
|
overall={overall}
|
|
summary={{
|
|
rubricVersion: result.rubricVersion,
|
|
grade: overall.grade,
|
|
score: overall.score,
|
|
aeo: overallV2?.aeo.score,
|
|
geo: overallV2?.geo.score,
|
|
verified: overall.categories.reduce((n, c) => n + c.verifiedCount, 0),
|
|
total: AEO_GEO_RUBRIC.criteria.length,
|
|
}}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|