summaryrefslogtreecommitdiff
path: root/app/routes/band-auto-register.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'app/routes/band-auto-register.tsx')
-rw-r--r--app/routes/band-auto-register.tsx88
1 files changed, 88 insertions, 0 deletions
diff --git a/app/routes/band-auto-register.tsx b/app/routes/band-auto-register.tsx
new file mode 100644
index 0000000..227908d
--- /dev/null
+++ b/app/routes/band-auto-register.tsx
@@ -0,0 +1,88 @@
+import { Form, Link, redirect, useLoaderData, useNavigation } from "react-router";
+import type { ActionFunctionArgs } from "react-router";
+import { createParseJob, getIpAddress, listRecentParseJobs } from "~/lib/db.server";
+
+export function loader() {
+ return { jobs: listRecentParseJobs(10) };
+}
+
+export async function action({ request }: ActionFunctionArgs) {
+ const fd = await request.formData();
+ const liveText = (fd.get("liveText") as string | null)?.trim() ?? "";
+ if (!liveText) return { error: "テキストを入力してください" };
+ const job = createParseJob(liveText);
+ void getIpAddress(request); // unused but kept for symmetry
+ return redirect(`/bands/auto-register/jobs/${job.id}`);
+}
+
+const STATUS_LABEL: Record<string, string> = {
+ pending: "待機中",
+ processing: "解析中",
+ done: "完了",
+ error: "エラー",
+};
+
+const STATUS_COLOR: Record<string, string> = {
+ pending: "#6b7280",
+ processing: "#fbbf24",
+ done: "#34d399",
+ error: "#f87171",
+};
+
+export default function BandAutoRegister() {
+ const { jobs } = useLoaderData<typeof loader>();
+ const nav = useNavigation();
+ const busy = nav.state !== "idle";
+
+ return (
+ <main>
+ <div className="page-header">
+ <Link to="/bands" className="back">←</Link>
+ <h1>ライブ情報から自動登録</h1>
+ </div>
+
+ <Form method="post">
+ <div>
+ <label>ライブ情報テキスト <span className="req">*</span></label>
+ <textarea
+ name="liveText"
+ rows={10}
+ placeholder={"出演バンド・アーティストの情報をペーストしてください。\n\n例:\n2024.08.10 @ 渋谷CLUB QUATTRO\nopen 17:30 / start 18:00\n\nband1 / Band Two / バンド三"}
+ />
+ </div>
+ <div className="actions">
+ <button type="submit" disabled={busy}>
+ {busy ? "送信中..." : "キューに追加する"}
+ </button>
+ </div>
+ </Form>
+
+ {jobs.length > 0 && (
+ <section style={{ marginTop: "2rem" }}>
+ <h2>最近のジョブ</h2>
+ <div className="job-list">
+ {jobs.map((job) => (
+ <Link
+ key={job.id}
+ to={`/bands/auto-register/jobs/${job.id}`}
+ className="job-row"
+ >
+ <span
+ className="job-status"
+ style={{ color: STATUS_COLOR[job.status] ?? "#6b7280" }}
+ >
+ {STATUS_LABEL[job.status] ?? job.status}
+ </span>
+ <span className="job-preview">
+ {job.input_text.slice(0, 60).replace(/\n/g, " ")}
+ {job.input_text.length > 60 ? "…" : ""}
+ </span>
+ <span className="job-time">{job.created_at.slice(0, 16).replace("T", " ")}</span>
+ </Link>
+ ))}
+ </div>
+ </section>
+ )}
+ </main>
+ );
+}