o2o-infinith-web/src/pages/AnalysisStartPage.tsx

161 lines
4.7 KiB
TypeScript

import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useAnalysis } from '@/hooks/useAnalysis'
/**
* AnalysisStartPage — MVP 핵심 페이지.
*
* 사용자가 병원 URL + 유튜브/IG/FB/네이버블로그/강남언니 핸들을 직접 입력.
* 원본 프로토타입은 URL만 받고 자동 발견했지만, MVP는 핸들 수동 입력.
*
* TODO (D2 frontend):
* - 각 입력 필드에 `POST /api/channels/verify` 실시간 검증 (debounce 500ms)
* - 핸들 정규화 UI (사용자가 URL 전체 붙여넣어도 @handle 추출)
* - 최소 1개 채널 필수 검증
*/
export default function AnalysisStartPage() {
const navigate = useNavigate()
const { start, error } = useAnalysis()
const [isSubmitting, setIsSubmitting] = useState(false)
const [form, setForm] = useState({
url: '',
name: '',
youtube: '',
instagram: '',
facebook: '',
naver_blog: '',
gangnam_unni: '',
})
async function handleSubmit(e: React.FormEvent) {
e.preventDefault()
setIsSubmitting(true)
try {
const runId = await start({
url: form.url,
channels: {
youtube: form.youtube || undefined,
instagram: form.instagram ? [form.instagram] : [],
facebook: form.facebook || undefined,
naver_blog: form.naver_blog || undefined,
gangnam_unni: form.gangnam_unni || undefined,
},
})
navigate(`/analysis/${runId}/loading`)
} catch {
setIsSubmitting(false)
}
}
return (
<div className="min-h-screen px-6 py-16 flex justify-center">
<form onSubmit={handleSubmit} className="w-full max-w-2xl glass-card p-10">
<h1 className="font-serif text-3xl font-bold mb-8"> </h1>
<Field label="병원 홈페이지 URL *" required>
<input
required
type="url"
placeholder="https://www.example.com"
value={form.url}
onChange={(e) => setForm({ ...form, url: e.target.value })}
className="input"
/>
</Field>
<h2 className="text-lg font-semibold mt-8 mb-4 text-white/80"> ( 1)</h2>
<Field label="YouTube 핸들">
<input
placeholder="@viewclinic"
value={form.youtube}
onChange={(e) => setForm({ ...form, youtube: e.target.value })}
className="input"
/>
</Field>
<Field label="Instagram 핸들">
<input
placeholder="@clinic_official"
value={form.instagram}
onChange={(e) => setForm({ ...form, instagram: e.target.value })}
className="input"
/>
</Field>
<Field label="Facebook 페이지">
<input
placeholder="clinicofficial"
value={form.facebook}
onChange={(e) => setForm({ ...form, facebook: e.target.value })}
className="input"
/>
</Field>
<Field label="네이버 블로그 URL">
<input
type="url"
placeholder="https://blog.naver.com/clinic"
value={form.naver_blog}
onChange={(e) => setForm({ ...form, naver_blog: e.target.value })}
className="input"
/>
</Field>
<Field label="강남언니 URL">
<input
type="url"
placeholder="https://www.gangnamunni.com/hospital/..."
value={form.gangnam_unni}
onChange={(e) => setForm({ ...form, gangnam_unni: e.target.value })}
className="input"
/>
</Field>
{error && <p className="text-status-critical mt-4 text-sm">{error.message}</p>}
<button
type="submit"
disabled={isSubmitting}
className="w-full mt-8 bg-accent hover:bg-accent-dark disabled:opacity-50 text-white font-semibold py-4 rounded-xl transition"
>
{isSubmitting ? '분석 요청 중…' : '분석 시작'}
</button>
</form>
<style>{`
.input {
width: 100%;
padding: 12px 16px;
background: rgba(255,255,255,0.05);
border: 1px solid rgba(255,255,255,0.1);
border-radius: 12px;
color: white;
outline: none;
}
.input:focus { border-color: var(--color-accent); }
`}</style>
</div>
)
}
function Field({
label,
required,
children,
}: {
label: string
required?: boolean
children: React.ReactNode
}) {
return (
<label className="block mb-4">
<span className="block text-sm text-white/70 mb-2">
{label}
{required && <span className="text-status-critical ml-1">*</span>}
</span>
{children}
</label>
)
}