fix: reduce paid proposal intake friction
All checks were successful
CI and Production Smoke / smoke (push) Successful in 7s

This commit is contained in:
OG T
2026-06-11 22:27:24 +08:00
parent 3ba60c41e0
commit ec7ac29cd1
2 changed files with 113 additions and 112 deletions

View File

@@ -94,8 +94,8 @@ export async function createDemandProposal(formData: FormData) {
if (!title || title.length < 6) {
throw new Error("請提供至少 6 個字元的需求標題。");
}
if (!description || description.length < 30) {
throw new Error("請提供至少 30 個字元的需求述,讓 AI Agent 可以判斷範圍。");
if (!description || description.length < 12) {
throw new Error("請提供至少 12 個字元的需求述,讓平台可以建立付款與 scoping 紀錄。");
}
if (!proposerEmail || !proposerEmail.includes("@")) {
throw new Error("請提供有效 email方便後續 scope review 聯繫。");

View File

@@ -173,114 +173,8 @@ export default async function ProposePage({ searchParams }: { searchParams?: Sea
<input type="hidden" name="campaign" value={campaign} />
<input type="hidden" name="source" value={source} />
<div className="grid gap-4 md:grid-cols-2">
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<input
name="proposerName"
autoComplete="name"
defaultValue={prefill.proposerName}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
placeholder="你的姓名"
/>
</label>
<label className="grid gap-2 text-sm font-medium text-zinc-200">
Email
<input
required
name="proposerEmail"
type="email"
autoComplete="email"
defaultValue={prefill.proposerEmail}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
placeholder="name@company.com"
/>
</label>
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<input
name="company"
autoComplete="organization"
defaultValue={prefill.company}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
placeholder="可留空"
/>
</label>
<label className="grid gap-2 text-sm font-medium text-zinc-200">
USD
<input
required
name="budgetUsd"
inputMode="decimal"
defaultValue={prefill.budgetUsd}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
/>
</label>
</div>
<div className="mt-4 grid gap-4">
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<input
required
name="title"
minLength={6}
defaultValue={prefill.title}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
placeholder="例如:自動整理客戶表單並生成報價草稿"
/>
</label>
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<textarea
required
name="description"
minLength={30}
rows={6}
defaultValue={prefill.description}
className="resize-y rounded-md border border-zinc-700 bg-zinc-950 px-3 py-3 text-white outline-none focus:border-sky-400"
placeholder="描述目前流程、需要自動化的輸入輸出、系統限制、交付期待。請不要貼密碼或私鑰。"
/>
</label>
<div className="grid gap-4 md:grid-cols-2">
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<input
name="desiredOutcome"
defaultValue={prefill.desiredOutcome}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
placeholder="可驗收的結果"
/>
</label>
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<input
name="requiredStack"
defaultValue={prefill.requiredStack}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
placeholder="Next.js, Python, Zapier"
/>
</label>
</div>
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<select
name="urgency"
defaultValue={prefill.urgency}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
>
<option value="normal"></option>
<option value="this_week"></option>
<option value="urgent"></option>
</select>
</label>
</div>
<fieldset className="mt-6">
<legend className="mb-3 text-sm font-semibold text-zinc-100"></legend>
<fieldset>
<legend className="mb-3 text-sm font-semibold text-zinc-100">1. </legend>
<div className="grid gap-2">
{PROPOSAL_PACKAGES.map((item) => (
<label
@@ -308,7 +202,7 @@ export default async function ProposePage({ searchParams }: { searchParams?: Sea
</fieldset>
<fieldset className="mt-6">
<legend className="mb-3 text-sm font-semibold text-zinc-100"></legend>
<legend className="mb-3 text-sm font-semibold text-zinc-100">2. </legend>
<div className="grid gap-3 md:grid-cols-2">
<label className="flex cursor-pointer items-center gap-3 rounded-md border border-zinc-700 bg-zinc-950 p-4 hover:border-emerald-400">
<input type="radio" name="paymentMethod" value="wallet" defaultChecked={walletPaymentAvailable} className="h-4 w-4 accent-emerald-400" />
@@ -329,11 +223,118 @@ export default async function ProposePage({ searchParams }: { searchParams?: Sea
</div>
</fieldset>
<div className="mt-6 grid gap-4">
<div className="grid gap-4 md:grid-cols-2">
<label className="grid gap-2 text-sm font-medium text-zinc-200">
Email
<input
required
name="proposerEmail"
type="email"
autoComplete="email"
defaultValue={prefill.proposerEmail}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
placeholder="name@company.com"
/>
</label>
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<input
required
name="title"
minLength={6}
defaultValue={prefill.title}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
placeholder="例如:客戶表單自動報價"
/>
</label>
</div>
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<textarea
required
name="description"
minLength={12}
rows={4}
defaultValue={prefill.description}
className="resize-y rounded-md border border-zinc-700 bg-zinc-950 px-3 py-3 text-white outline-none focus:border-sky-400"
placeholder="一句話描述要自動化、分析、修復或整合的工作。"
/>
</label>
<details className="rounded-md border border-zinc-800 bg-zinc-950/70 p-4">
<summary className="cursor-pointer text-sm font-semibold text-sky-200"></summary>
<div className="mt-4 grid gap-4 md:grid-cols-2">
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<input
name="proposerName"
autoComplete="name"
defaultValue={prefill.proposerName}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
placeholder="你的姓名"
/>
</label>
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<input
name="company"
autoComplete="organization"
defaultValue={prefill.company}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
placeholder="可留空"
/>
</label>
<label className="grid gap-2 text-sm font-medium text-zinc-200">
USD
<input
required
name="budgetUsd"
inputMode="decimal"
defaultValue={prefill.budgetUsd}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
/>
</label>
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<select
name="urgency"
defaultValue={prefill.urgency}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
>
<option value="normal"></option>
<option value="this_week"></option>
<option value="urgent"></option>
</select>
</label>
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<input
name="desiredOutcome"
defaultValue={prefill.desiredOutcome}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
placeholder="可驗收的結果"
/>
</label>
<label className="grid gap-2 text-sm font-medium text-zinc-200">
<input
name="requiredStack"
defaultValue={prefill.requiredStack}
className="h-11 rounded-md border border-zinc-700 bg-zinc-950 px-3 text-white outline-none focus:border-sky-400"
placeholder="Next.js, Python, Zapier"
/>
</label>
</div>
</details>
</div>
<button
type="submit"
className="mt-6 inline-flex h-12 w-full items-center justify-center gap-2 rounded-md bg-sky-400 px-5 text-sm font-semibold text-zinc-950 transition hover:bg-sky-300 md:w-auto"
>
<ArrowRight className="h-4 w-4" />
</button>
</form>