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>;
|
|||
|
|
}
|