fix: U03 pagination + U04 form errors with retry (#1788956171115)
This commit is contained in:
@@ -14,7 +14,11 @@ export const POST: APIRoute = async ({ request, redirect, cookies }) => {
|
||||
let uploadToken: string | null = null;
|
||||
try {
|
||||
const response = await fetch(`${base}/api/v1/catch-reports`, { method: "POST", headers: { "content-type": "application/json", "X-Forwarded-For": request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || "unknown" }, body: JSON.stringify(payload), signal: AbortSignal.timeout(30_000) });
|
||||
if (!response.ok) return redirect("/report?state=create_error", 303);
|
||||
if (!response.ok) {
|
||||
if (response.status === 429) return redirect("/report?state=rate_limited", 303);
|
||||
if (response.status >= 500) return redirect("/report?state=server_error", 303);
|
||||
return redirect("/report?state=create_error", 303);
|
||||
}
|
||||
const created = await response.json() as { id?: unknown; screenshot_upload_token?: unknown };
|
||||
if (typeof created.id !== "string" || typeof created.screenshot_upload_token !== "string") return redirect("/report?state=create_error", 303);
|
||||
createdId = created.id;
|
||||
@@ -30,7 +34,11 @@ export const POST: APIRoute = async ({ request, redirect, cookies }) => {
|
||||
}
|
||||
return redirect("/report?state=sent", 303);
|
||||
}
|
||||
catch {
|
||||
catch (err) {
|
||||
if (err instanceof TypeError && err.message.includes("abort")) {
|
||||
if (createdId && uploadToken) cookies.set(`rf4-upload-${createdId}`, uploadToken, {httpOnly:true, sameSite:"strict", secure:import.meta.env.PROD, path:"/", maxAge:3600});
|
||||
return redirect(createdId ? `/report?state=screenshot_error&report_id=${encodeURIComponent(createdId)}` : "/report?state=timeout", 303);
|
||||
}
|
||||
if (createdId && uploadToken) cookies.set(`rf4-upload-${createdId}`, uploadToken, {httpOnly:true, sameSite:"strict", secure:import.meta.env.PROD, path:"/", maxAge:3600});
|
||||
return redirect(createdId ? `/report?state=screenshot_error&report_id=${encodeURIComponent(createdId)}` : "/report?state=create_error", 303);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ const reportId = Astro.url.searchParams.get("report_id");
|
||||
{state === "sent" && <div class="notice success">Улов отправлен на модерацию. Спасибо!</div>}
|
||||
{state === "screenshot_sent" && <div class="notice success">Скриншот добавлен к ранее созданной заявке.</div>}
|
||||
{state === "create_error" && <div class="notice error" id="form-error" tabindex="-1"><strong>Заявка не создана.</strong> Проверьте поля; введённые значения сохранены.</div>}
|
||||
{state === "rate_limited" && <div class="notice error" id="form-error" tabindex="-1"><strong>Слишком много отправок.</strong> Подождите 10 минут перед повторной попыткой.</div>}
|
||||
{state === "timeout" && <div class="notice error" id="form-error" tabindex="-1"><strong>Превышено время ожидания.</strong> Проверьте соединение и попробуйте снова.</div>}
|
||||
{state === "server_error" && <div class="notice error" id="form-error" tabindex="-1"><strong>Сервер временно недоступен.</strong> Попробуйте позже.</div>}
|
||||
{state === "screenshot_error" && <div class="notice warning"><strong>Заявка сохранена без скриншота.</strong> Изображение не загрузилось; можно повторить отдельно, не отправляя улов заново.</div>}
|
||||
{state === "screenshot_error" && reportId && <form class="screenshot-retry" method="post" action="/api/report-screenshot" enctype="multipart/form-data"><input type="hidden" name="report_id" value={reportId} /><label>Повторная загрузка скриншота<input name="screenshot" type="file" accept="image/jpeg,image/png,image/webp" required /></label><button type="submit">Загрузить скриншот</button></form>}
|
||||
{unavailable ? <div class="state"><h2>Форма временно недоступна</h2></div> : <form class="report-form" method="post" action="/api/report" enctype="multipart/form-data">
|
||||
@@ -21,6 +24,11 @@ const reportId = Astro.url.searchParams.get("report_id");
|
||||
const form = document.querySelector(".report-form"); const key = "rf4-report-draft";
|
||||
if (form && state === "create_error") { try { const draft = JSON.parse(sessionStorage.getItem(key) || "{}"); for (const [name, value] of Object.entries(draft)) { const field = form.elements.namedItem(name); if (field && "value" in field) field.value = value; } } catch {} document.querySelector("#form-error")?.focus(); }
|
||||
if (state === "sent") sessionStorage.removeItem(key);
|
||||
form?.addEventListener("submit", () => { const draft = {}; for (const [name, value] of new FormData(form)) if (typeof value === "string" && name !== "website") draft[name] = value; sessionStorage.setItem(key, JSON.stringify(draft)); });
|
||||
form?.addEventListener("submit", (e) => {
|
||||
const btn = form.querySelector("button[type=submit]");
|
||||
if (btn) { btn.disabled = true; btn.textContent = "Отправка..."; }
|
||||
const draft = {}; for (const [name, value] of new FormData(form)) if (typeof value === "string" && name !== "website") draft[name] = value;
|
||||
sessionStorage.setItem(key, JSON.stringify(draft));
|
||||
});
|
||||
</script>
|
||||
</Layout>
|
||||
|
||||
Reference in New Issue
Block a user