// modal.jsx — inquiry form (2 steps: 入力 → 確認 → 完了) function ConsultModal({ isOpen, onClose, initialTheme }) { const [step, setStep] = React.useState(0); const [submitting, setSubmitting] = React.useState(false); const [submitError, setSubmitError] = React.useState(''); const openedAtRef = React.useRef(0); const [data, setData] = React.useState({ theme: '', company: '', name: '', email: '', role: '', phone: '', detail: '' }); React.useEffect(() => { if (isOpen) { setStep(0); setSubmitting(false); setSubmitError(''); openedAtRef.current = Date.now(); // ボット対策(時間トラップ)の基準時刻 setData(d => ({ ...d, theme: initialTheme || '' })); } }, [isOpen, initialTheme]); React.useEffect(() => { if (isOpen) document.body.style.overflow = 'hidden'; else document.body.style.overflow = ''; return () => { document.body.style.overflow = ''; }; }, [isOpen]); const update = (k, v) => setData(d => ({ ...d, [k]: v })); const steps = ['お客様情報', '確認']; const SUCCESS = steps.length; // 2 const themeMap = { ai: { ttl: 'DX / AX 推進' }, sec: { ttl: '情報セキュリティ' }, bcp: { ttl: 'BCP対策' }, other: { ttl: '横断 / その他' } }; const themeLabel = themeMap[data.theme] ? themeMap[data.theme].ttl : ''; const canNext = (step === 0 && data.company && data.name && data.email && data.detail) || step >= 1; // 当社サーバーの contact.php 経由で info@skyidea.co.jp へ送信。 // 同一ドメインのため CORS の問題がなく、送信結果(JSON)を確実に判定できる。 const submit = async () => { if (submitting) return; setSubmitting(true); setSubmitError(''); try { const fd = new FormData(); fd.append('company', data.company); fd.append('role', data.role); fd.append('name', data.name); fd.append('email', data.email); fd.append('phone', data.phone); fd.append('detail', data.detail); if (themeLabel) fd.append('theme', themeLabel); fd.append('_gotcha', ''); // ハニーポット(人間は空のまま) // フォーム表示から送信までの経過ミリ秒(極端に速い=ボットの判定に使用) fd.append('_elapsed', String(Date.now() - (openedAtRef.current || Date.now()))); const res = await fetch('contact.php', { method: 'POST', body: fd }); const json = await res.json().catch(() => null); if (res.ok && json && json.success) { setStep(SUCCESS); } else { throw new Error((json && json.message) || ('サーバー応答エラー (HTTP ' + res.status + ')')); } } catch (e) { const detail = (e && e.message && e.message !== 'Failed to fetch') ? '(詳細:' + e.message + ')' : ''; setSubmitError('送信に失敗しました。' + detail + ' お手数ですが info@skyidea.co.jp 宛に直接メールでご連絡ください。'); } finally { setSubmitting(false); } }; return (
e.stopPropagation()}>

{step === SUCCESS ? 'ありがとうございます' : 'お問い合わせ'}

CONTACT — {step < SUCCESS ? `STEP ${step + 1} / ${steps.length}` : 'COMPLETED'}
{step < SUCCESS && (
{steps.map((_, i) => (
))}
)} {step === 0 && (
ご相談内容と連絡先をご記入ください。初回のご相談は無料です。無理な営業は一切いたしません。
update('company', e.target.value)} placeholder="株式会社..." />
update('role', e.target.value)} placeholder="情報システム部長 等" />
update('name', e.target.value)} placeholder="山田 太郎" />
update('email', e.target.value)} placeholder="name@example.com" />
update('phone', e.target.value)} placeholder="03-1234-5678" />
)} {step === 1 && (

ご入力内容のご確認

{themeLabel && (
ご関心テーマ
{themeLabel}
)}
会社
{data.company}{data.role ? ` / ${data.role}` : ''}
お名前
{data.name}
メール
{data.email}
{data.phone && (
電話番号
{data.phone}
)}
内容
{data.detail}
送信後、内容を確認のうえ、1営業日以内にメールにてご連絡いたします。
ご記入いただいた情報は、ご返信の目的にのみ使用いたします。
{submitError && (
{submitError}
)}
)} {step === SUCCESS && (

送信いたしました。

お問い合わせありがとうございます。
1営業日以内に、ご担当より {data.email} 宛にご連絡いたします。

)} {step < SUCCESS && (
{`STEP ${step + 1} OF ${steps.length} — ${steps[step]}`}
{step > 0 && ( )}
)}
); } window.ConsultModal = ConsultModal;