'use client'; import { useEffect, useRef, useState } from 'react'; import IntroStep from './components/IntroStep'; import Q1Step from './components/Q1Step'; import Q2Step from './components/Q2Step'; import Q3Step from './components/Q3Step'; import Q4Step from './components/Q4Step'; import Q5Step from './components/Q5Step'; import Q6Step from './components/Q6Step'; import Q7Step from './components/Q7Step'; import ThanksStep from './components/ThanksStep'; import type { SurveyResponse, SurveyStep } from '@/lib/survey/types'; import { loadProgress, saveProgress, clearProgress } from '@/lib/survey/storage'; export default function GyeolPage() { const [step, setStep] = useState('intro'); const [response, setResponse] = useState>({}); const [submitting, setSubmitting] = useState(false); const [submitError, setSubmitError] = useState(null); const startedAtRef = useRef(null); // 진입 시 localStorage 복구 useEffect(() => { const saved = loadProgress(); if (saved) { setStep(saved.step); setResponse(saved.response); startedAtRef.current = saved.startedAt; } }, []); // step 변경 시 진행 상태 저장 (질문 step만) useEffect(() => { if (step !== 'intro' && step !== 'thanks' && startedAtRef.current) { saveProgress({ step, response, startedAt: startedAtRef.current, }); } }, [step, response]); function handleStart() { if (!startedAtRef.current) { startedAtRef.current = Date.now(); } setStep('q1'); } function applyPartialAndAdvance(partial: Partial, nextStep: SurveyStep) { setResponse((prev) => ({ ...prev, ...partial })); setStep(nextStep); } function goBack(prevStep: SurveyStep) { setStep(prevStep); } async function handleFinalSubmit(partial: Partial) { const finalResponse: SurveyResponse = { ...response, ...partial, completion_seconds: startedAtRef.current ? Math.floor((Date.now() - startedAtRef.current) / 1000) : undefined, user_agent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined, referrer: typeof document !== 'undefined' ? (document.referrer || undefined) : undefined, utm_source: typeof window !== 'undefined' ? (new URLSearchParams(window.location.search).get('utm_source') ?? undefined) : undefined, utm_medium: typeof window !== 'undefined' ? (new URLSearchParams(window.location.search).get('utm_medium') ?? undefined) : undefined, utm_campaign: typeof window !== 'undefined' ? (new URLSearchParams(window.location.search).get('utm_campaign') ?? undefined) : undefined, }; setSubmitting(true); setSubmitError(null); try { const res = await fetch('/api/survey', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(finalResponse), }); if (!res.ok) { const err = await res.json().catch(() => ({})); throw new Error(err.error ?? '제출 실패'); } clearProgress(); setResponse(finalResponse); setStep('thanks'); } catch (e) { setSubmitError(e instanceof Error ? e.message : '제출 실패'); } finally { setSubmitting(false); } } return ( <> {step === 'intro' && } {step === 'q1' && ( setStep('intro')} onNext={(p) => applyPartialAndAdvance(p, 'q2')} /> )} {step === 'q2' && ( goBack('q1')} onNext={(p) => applyPartialAndAdvance(p, 'q3')} /> )} {step === 'q3' && ( goBack('q2')} onNext={(p) => applyPartialAndAdvance(p, 'q4')} /> )} {step === 'q4' && ( goBack('q3')} onNext={(p) => applyPartialAndAdvance(p, 'q5')} /> )} {step === 'q5' && ( goBack('q4')} onNext={(p) => applyPartialAndAdvance(p, 'q6')} /> )} {step === 'q6' && ( goBack('q5')} onNext={(p) => applyPartialAndAdvance(p, 'q7')} /> )} {step === 'q7' && ( goBack('q6')} onSubmit={handleFinalSubmit} submitting={submitting} /> )} {step === 'thanks' && } {submitError && (
{submitError}
)} ); }