|
|
import React, { useState } from "react"; |
|
|
import Field from "./Field"; |
|
|
import { generateEmail, lintText, GenerateReq } from "@/lib/api"; |
|
|
|
|
|
type Props = { |
|
|
onResult: (r: any) => void; |
|
|
}; |
|
|
|
|
|
export default function GeneratorForm({ onResult }: Props) { |
|
|
const [loading, setLoading] = useState(false); |
|
|
const [form, setForm] = useState<GenerateReq>({ |
|
|
language: "ja", |
|
|
industry: "ITサービス", |
|
|
target_company: "株式会社○○", |
|
|
target_persona: "情報システム部の部長", |
|
|
pain_points: "SaaS乱立によるコスト・運用負荷増大", |
|
|
value_prop: "運用統合と可視化によりTCOを30%削減", |
|
|
product_name: "Aroundabout Suite", |
|
|
cta: "15分のオンライン面談をご提案", |
|
|
tone: "フォーマルで簡潔", |
|
|
variables: { company: "株式会社○○", person: "山田様" }, |
|
|
length_hint: "中", |
|
|
extra_instr: "" |
|
|
}); |
|
|
|
|
|
const update = (k: keyof GenerateReq) => (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => |
|
|
setForm(f => ({ ...f, [k]: e.target.value })); |
|
|
|
|
|
async function onSubmit(e: React.FormEvent) { |
|
|
e.preventDefault(); |
|
|
setLoading(true); |
|
|
try { |
|
|
const res = await generateEmail({ ...form, variables: form.variables }); |
|
|
|
|
|
const lint = await lintText(res.body); |
|
|
onResult({ ...res, lint }); |
|
|
} catch (err) { |
|
|
onResult({ error: String(err) }); |
|
|
} finally { |
|
|
setLoading(false); |
|
|
} |
|
|
} |
|
|
|
|
|
return ( |
|
|
<form onSubmit={onSubmit} style={{ display: "grid", gap: 12 }}> |
|
|
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}> |
|
|
<Field label="言語"> |
|
|
<select value={form.language} onChange={update("language")}> |
|
|
<option value="ja">日本語</option> |
|
|
<option value="en">English</option> |
|
|
</select> |
|
|
</Field> |
|
|
<Field label="トーン"> |
|
|
<input value={form.tone} onChange={update("tone")} /> |
|
|
</Field> |
|
|
<Field label="業界"> |
|
|
<input value={form.industry} onChange={update("industry")} /> |
|
|
</Field> |
|
|
<Field label="相手企業"> |
|
|
<input value={form.target_company} onChange={update("target_company")} /> |
|
|
</Field> |
|
|
<Field label="担当者ペルソナ"> |
|
|
<input value={form.target_persona} onChange={update("target_persona")} /> |
|
|
</Field> |
|
|
<Field label="文章ボリューム"> |
|
|
<select value={form.length_hint} onChange={update("length_hint")}> |
|
|
<option>短</option><option>中</option><option>長</option> |
|
|
</select> |
|
|
</Field> |
|
|
</div> |
|
|
|
|
|
<Field label="相手の課題"> |
|
|
<textarea value={form.pain_points} onChange={update("pain_points")} rows={3} /> |
|
|
</Field> |
|
|
<Field label="提供価値(成果/差別化)"> |
|
|
<textarea value={form.value_prop} onChange={update("value_prop")} rows={3} /> |
|
|
</Field> |
|
|
<Field label="製品/サービス名"> |
|
|
<input value={form.product_name} onChange={update("product_name")} /> |
|
|
</Field> |
|
|
<Field label="CTA(次アクション)"> |
|
|
<input value={form.cta} onChange={update("cta")} /> |
|
|
</Field> |
|
|
<Field label="追加指示(禁止表現など)"> |
|
|
<input value={form.extra_instr ?? ""} onChange={update("extra_instr")} /> |
|
|
</Field> |
|
|
|
|
|
<button |
|
|
type="submit" |
|
|
disabled={loading} |
|
|
style={{ |
|
|
padding: "10px 14px", |
|
|
borderRadius: 12, |
|
|
border: "1px solid #ddd", |
|
|
cursor: "pointer", |
|
|
background: loading ? "#f3f3f3" : "white" |
|
|
}} |
|
|
> |
|
|
{loading ? "生成中..." : "生成する"} |
|
|
</button> |
|
|
</form> |
|
|
); |
|
|
} |
|
|
|