feat(dev): /test 라우트 — URL prefill 픽스처로 분석 플로우 빠르게 검증
- TestPrefillPage: 자주 쓰는 병원 URL 묶음을 버튼 한 번에 채널 입력으로 prefill - /dev/* 와 동일하게 DevOnly 가드 적용 (로컬에서만 접근)main
parent
47fed51efc
commit
a805afa39d
|
|
@ -0,0 +1,144 @@
|
||||||
|
/**
|
||||||
|
* /test 페이지 + 향후 E2E·부하 테스트용 목업 병원 URL 데이터.
|
||||||
|
*
|
||||||
|
* 7개 채널: homepage, youtube, instagram, facebook, naverPlace, naverBlog, gangnamUnni
|
||||||
|
* 빈 채널은 분석에서 제외됨. naverPlace는 수동 확인 필요(숫자 ID 기반).
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface ChannelUrls {
|
||||||
|
homepage?: string
|
||||||
|
youtube?: string
|
||||||
|
instagram?: string
|
||||||
|
facebook?: string
|
||||||
|
naverPlace?: string
|
||||||
|
naverBlog?: string
|
||||||
|
gangnamUnni?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClinicFixture {
|
||||||
|
label: string
|
||||||
|
urls: ChannelUrls
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CLINICS: ClinicFixture[] = [
|
||||||
|
{
|
||||||
|
label: '뷰성형외과',
|
||||||
|
urls: {
|
||||||
|
homepage: 'viewclinic.com',
|
||||||
|
youtube: 'youtube.com/channel/UCQqqH3Klj2HQSHNNSVug-CQ',
|
||||||
|
instagram: 'instagram.com/viewplastic',
|
||||||
|
facebook: 'facebook.com/viewps1',
|
||||||
|
naverPlace: 'https://naver.me/x9BxGXkK',
|
||||||
|
naverBlog: 'blog.naver.com/viewclinicps',
|
||||||
|
gangnamUnni: 'gangnamunni.com/hospitals/189',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '바노바기 성형외과',
|
||||||
|
urls: {
|
||||||
|
homepage: 'banobagi.com',
|
||||||
|
youtube: 'youtube.com/c/banobagips',
|
||||||
|
instagram: 'instagram.com/banobagi_ps',
|
||||||
|
facebook: 'facebook.com/BanobagiPlasticSurgery',
|
||||||
|
naverPlace: 'https://naver.me/xxY2yLr5',
|
||||||
|
naverBlog: 'blog.naver.com/banobagiprs',
|
||||||
|
gangnamUnni: 'gangnamunni.com/hospitals/23',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'ID 성형외과',
|
||||||
|
urls: {
|
||||||
|
homepage: 'idhospital.com',
|
||||||
|
youtube: 'youtube.com/user/IDhospital',
|
||||||
|
instagram: 'instagram.com/idhospital',
|
||||||
|
facebook: 'facebook.com/idhospital0050',
|
||||||
|
naverPlace: 'https://naver.me/GtURpCEn',
|
||||||
|
naverBlog: '',
|
||||||
|
gangnamUnni: 'gangnamunni.com/hospitals/257',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'JK 성형외과',
|
||||||
|
urls: {
|
||||||
|
homepage: 'jkplastic.com',
|
||||||
|
youtube: 'youtube.com/channel/UC5F8dEt32hdp3cTeFyls4qg',
|
||||||
|
instagram: 'instagram.com/jkplasticsurgery_kr',
|
||||||
|
facebook: 'facebook.com/jkmedicalgroup',
|
||||||
|
naverPlace: 'https://naver.me/x67y6cAc',
|
||||||
|
naverBlog: 'blog.naver.com/jkstory1',
|
||||||
|
gangnamUnni: 'gangnamunni.com/hospitals/858',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '그랜드 성형외과',
|
||||||
|
urls: {
|
||||||
|
homepage: 'grandsurgery.com',
|
||||||
|
youtube: 'youtube.com/channel/UCU2o_aHqsNFuqwtdzVM3xbQ',
|
||||||
|
instagram: 'instagram.com/grand_korea',
|
||||||
|
facebook: 'facebook.com/grandps.korea',
|
||||||
|
naverPlace: 'https://naver.me/Fw7MYKWK',
|
||||||
|
naverBlog: 'blog.naver.com/grandprs',
|
||||||
|
gangnamUnni: 'gangnamunni.com/hospitals/62',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'BK 성형외과',
|
||||||
|
urls: {
|
||||||
|
homepage: 'bkhospital.com',
|
||||||
|
youtube: 'youtube.com/channel/UChJONft3hemy5DGbXUveTFg',
|
||||||
|
instagram: 'instagram.com/bkhospital_korea',
|
||||||
|
facebook: '',
|
||||||
|
naverPlace: 'https://naver.me/517CTH3W',
|
||||||
|
naverBlog: '',
|
||||||
|
gangnamUnni: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '톡스앤필',
|
||||||
|
urls: {
|
||||||
|
homepage: 'toxnfill.com',
|
||||||
|
youtube: 'youtube.com/channel/UCFpFZkm7mclD-z_-j7FTUag',
|
||||||
|
instagram: 'instagram.com/toxnfill_official',
|
||||||
|
facebook: 'facebook.com/toxnfill.official',
|
||||||
|
naverPlace: 'https://naver.me/FvEmJIHA',
|
||||||
|
naverBlog: 'blog.naver.com/toxnfill',
|
||||||
|
gangnamUnni: 'gangnamunni.com/hospitals/3702',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '더 압구정 성형외과',
|
||||||
|
urls: {
|
||||||
|
homepage: 'theclinic.co.kr',
|
||||||
|
youtube: 'youtube.com/user/theplasticsurgery1',
|
||||||
|
instagram: 'instagram.com/the_plasticsurgery',
|
||||||
|
facebook: 'facebook.com/THEPS16445998',
|
||||||
|
naverPlace: '',
|
||||||
|
naverBlog: 'blog.naver.com/with_theps',
|
||||||
|
gangnamUnni: 'gangnamunni.com/hospitals/30',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '라마르 성형외과',
|
||||||
|
urls: {
|
||||||
|
homepage: 'lamarps.com',
|
||||||
|
youtube: '',
|
||||||
|
instagram: '',
|
||||||
|
facebook: '',
|
||||||
|
naverPlace: '',
|
||||||
|
naverBlog: '',
|
||||||
|
gangnamUnni: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '오라클 성형외과',
|
||||||
|
urls: {
|
||||||
|
homepage: 'oracleclinic.com',
|
||||||
|
youtube: 'youtube.com/@oracle_medical_group',
|
||||||
|
instagram: 'instagram.com/oraclemedicalgroup',
|
||||||
|
facebook: 'facebook.com/oracleclinickr',
|
||||||
|
naverPlace: 'https://naver.me/GhbU3VtK',
|
||||||
|
naverBlog: '',
|
||||||
|
gangnamUnni: 'gangnamunni.com/hospitals/125',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
/**
|
||||||
|
* /test — 랜덤 병원 fixture를 디폴트로 채워 분석 플로우를 빠르게 검증하는 dev 페이지.
|
||||||
|
*
|
||||||
|
* - 진입 시 CLINICS 중 1개를 랜덤 선택해 form prefill
|
||||||
|
* - "다른 병원 랜덤" 버튼으로 재선택 가능
|
||||||
|
* - DevOnly 가드 아래 등록되어 localhost에서만 접근
|
||||||
|
*/
|
||||||
|
import { useMemo, useState } from 'react'
|
||||||
|
import { useNavigate } from 'react-router'
|
||||||
|
import MultiChannelInput, { type AnalyzePayload } from '@/features/channels/components/MultiChannelInput'
|
||||||
|
import { CLINICS } from '../fixtures/mockUrls'
|
||||||
|
|
||||||
|
function pickRandomIndex(): number {
|
||||||
|
return Math.floor(Math.random() * CLINICS.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function TestPrefillPage() {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const [seed, setSeed] = useState(0)
|
||||||
|
const index = useMemo(() => pickRandomIndex(), [seed])
|
||||||
|
const clinic = CLINICS[index]
|
||||||
|
|
||||||
|
const handleAnalyze = (payload: AnalyzePayload) => {
|
||||||
|
navigate('/report/loading', {
|
||||||
|
state: {
|
||||||
|
url: payload.primaryUrl,
|
||||||
|
manualChannels: payload.manualChannels,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="min-h-screen pt-28 pb-12 px-6 bg-gradient-to-br from-indigo-50 via-purple-50 to-pink-50">
|
||||||
|
<div className="max-w-4xl mx-auto">
|
||||||
|
<div className="mb-8 flex items-center justify-between gap-4">
|
||||||
|
<div>
|
||||||
|
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-amber-100 text-amber-800 text-xs font-medium mb-3">
|
||||||
|
DEV · /test
|
||||||
|
</div>
|
||||||
|
<h1 className="text-3xl font-bold text-primary-900">
|
||||||
|
랜덤 병원 분석 테스트
|
||||||
|
</h1>
|
||||||
|
<p className="mt-2 text-sm text-slate-600">
|
||||||
|
선택된 병원: <span className="font-semibold text-primary-900">{clinic.label}</span>
|
||||||
|
{' '}<span className="text-slate-400">({index + 1} / {CLINICS.length})</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setSeed((s) => s + 1)}
|
||||||
|
className="px-4 py-2 rounded-lg bg-white border border-slate-200 text-sm font-medium text-slate-700 hover:bg-slate-50 shadow-sm"
|
||||||
|
>
|
||||||
|
다른 병원 랜덤
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* key={seed} 로 강제 remount — initialUrls는 mount 시점 1회만 반영되기 때문 */}
|
||||||
|
<MultiChannelInput
|
||||||
|
key={seed}
|
||||||
|
variant="hero"
|
||||||
|
initialUrls={clinic.urls}
|
||||||
|
onAnalyze={handleAnalyze}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -3,14 +3,16 @@ import DevOnly from './components/DevOnly'
|
||||||
|
|
||||||
const ComponentsPage = lazy(() => import('./pages/ComponentsPage'))
|
const ComponentsPage = lazy(() => import('./pages/ComponentsPage'))
|
||||||
const ClinicsPage = lazy(() => import('./pages/ClinicsPage'))
|
const ClinicsPage = lazy(() => import('./pages/ClinicsPage'))
|
||||||
|
const TestPrefillPage = lazy(() => import('./pages/TestPrefillPage'))
|
||||||
|
|
||||||
// `/dev/*` 는 DevOnly 가드를 거쳐 로컬호스트에서만 접근 가능.
|
// `/dev/*` 와 `/test` 는 DevOnly 가드를 거쳐 로컬호스트에서만 접근 가능.
|
||||||
export const devRoutes = [
|
export const devRoutes = [
|
||||||
{
|
{
|
||||||
element: <DevOnly />,
|
element: <DevOnly />,
|
||||||
children: [
|
children: [
|
||||||
{ path: 'dev/components', element: <ComponentsPage /> },
|
{ path: 'dev/components', element: <ComponentsPage /> },
|
||||||
{ path: 'dev/clinics', element: <ClinicsPage /> },
|
{ path: 'dev/clinics', element: <ClinicsPage /> },
|
||||||
|
{ path: 'test', element: <TestPrefillPage /> },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue