35 lines
1.7 KiB
TypeScript
35 lines
1.7 KiB
TypeScript
"use client";
|
||
|
||
import { FormEvent, useState } from "react";
|
||
|
||
type Source = { id: number; name: string };
|
||
|
||
export function PublishForm({ sources }: { sources: Source[] }) {
|
||
const [error, setError] = useState("");
|
||
const [submitting, setSubmitting] = useState(false);
|
||
|
||
async function submit(event: FormEvent<HTMLFormElement>) {
|
||
event.preventDefault();
|
||
setSubmitting(true); setError("");
|
||
try {
|
||
const response = await fetch("/api/posts", { method: "POST", body: new FormData(event.currentTarget), headers: { Accept: "application/json" } });
|
||
const result = await response.json();
|
||
if (!response.ok) throw new Error(result.error || "發佈失敗");
|
||
window.location.assign(`/posts/${result.id}`);
|
||
} catch (reason) {
|
||
setError(reason instanceof Error ? reason.message : "發佈失敗");
|
||
setSubmitting(false);
|
||
}
|
||
}
|
||
|
||
return <form onSubmit={submit} encType="multipart/form-data">
|
||
<label>內容(Markdown)<textarea name="content" required /></label>
|
||
<label>標籤(逗號分隔)<input name="tags" placeholder="旅行, 想法" /></label>
|
||
<label>可見性<select name="visibility" defaultValue="PUBLIC"><option value="PUBLIC">公開</option><option value="PROTECTED">受保護</option><option value="PRIVATE">私人</option></select></label>
|
||
<label>發佈來源<select name="sourceId" required>{sources.map((source) => <option key={source.id} value={source.id}>{source.name}</option>)}</select></label>
|
||
<label>圖片或附件(每檔最多 10 MB)<input name="attachments" type="file" multiple /></label>
|
||
{error && <p className="error">{error}</p>}
|
||
<button disabled={submitting}>{submitting ? "發佈中…" : "發佈並同步"}</button>
|
||
</form>;
|
||
}
|