From 094d6b17e41aaf5e560a6255d9a0b906eaa378c6 Mon Sep 17 00:00:00 2001 From: Clas Wen Date: Fri, 10 Oct 2025 20:14:52 +0800 Subject: [PATCH] add error handling --- src/pages/repair/TicketForm.tsx | 139 ++++++++++++++++++++++++- src/pages/repair/UserRepairHistory.tsx | 4 +- 2 files changed, 136 insertions(+), 7 deletions(-) diff --git a/src/pages/repair/TicketForm.tsx b/src/pages/repair/TicketForm.tsx index d4020bb..9e0f4a7 100644 --- a/src/pages/repair/TicketForm.tsx +++ b/src/pages/repair/TicketForm.tsx @@ -11,6 +11,14 @@ type TicketFormData = { description?: string } +type FormError = { + field?: string + message: string + type: "validation" | "network" | "server" | "auth" +} + +type SubmissionState = "idle" | "submitting" | "success" | "error" | "retrying" + function LoginHintAlert(props: { onLogin: () => void }) { @@ -36,13 +44,86 @@ function TicketForm(props: { userInfo?: UserInfoResponse onSubmit: (form: TicketFormData) => Promise }) { - const [loading, setLoading] = useState() + const [submissionState, setSubmissionState] = useState("idle") const [formData, setFormData] = useState({}) + const [errors, setErrors] = useState([]) + + // Form persistence + useEffect(() => { + const savedData = localStorage.getItem("ticket-form-draft") + if (savedData) { + try { + const parsed = JSON.parse(savedData) + setFormData(parsed) + } + catch (error) { + console.warn("Failed to parse saved form data:", error) + } + } + }, []) + + useEffect(() => { + if (Object.keys(formData).length > 0) { + localStorage.setItem("ticket-form-draft", JSON.stringify(formData)) + } + }, [formData]) + + const clearFormData = () => { + localStorage.removeItem("ticket-form-draft") + setFormData({}) + } + const onSubmit = async (e: React.FormEvent) => { e.preventDefault() - setLoading(true) - await props.onSubmit(formData) - setLoading(false) + setErrors([]) + + setSubmissionState("submitting") + + try { + await props.onSubmit(formData) + setSubmissionState("success") + clearFormData() + + // Show success message briefly before redirect + setTimeout(() => { + // The redirect will be handled by the parent component + }, 1500) + } + catch (error) { + setSubmissionState("error") + + // Handle different types of errors + if (error instanceof Error) { + if (error.message.includes("auth") || error.message.includes("token")) { + setErrors([{ message: "登录状态已过期,请重新登录", type: "auth" }]) + } + else if (error.message.includes("network") || error.message.includes("fetch")) { + setErrors([{ message: "网络连接失败,请检查网络后重试", type: "network" }]) + } + else { + setErrors([{ message: "提交失败,请稍后重试", type: "server" }]) + } + } + else { + setErrors([{ message: "提交失败,请稍后重试", type: "server" }]) + } + } + } + + const handleRetry = async () => { + setSubmissionState("retrying") + setErrors([]) + + try { + await props.onSubmit(formData) + setSubmissionState("success") + clearFormData() + } + catch (error) { + setSubmissionState("error") + setErrors([{ message: "重试失败,请稍后再试", type: "server" }]) + console.error("Retry submission error:", error) + } } const onLogin = async () => { @@ -66,6 +147,54 @@ function TicketForm(props: {
+ {/* Error Messages */} + {errors.length > 0 && ( +
+ {errors.map((error, index) => ( + + 重试 + + ) + : error.type === "auth" + ? ( + + ) + : null + } + > + {error.message} + + ))} +
+ )} + + {/* Success Message */} + {submissionState === "success" && ( + + 提交成功!正在跳转到详情页面... + + )} +
-
diff --git a/src/pages/repair/UserRepairHistory.tsx b/src/pages/repair/UserRepairHistory.tsx index 0bc9ddc..bb1426b 100644 --- a/src/pages/repair/UserRepairHistory.tsx +++ b/src/pages/repair/UserRepairHistory.tsx @@ -4,7 +4,7 @@ import { saturdayClient } from "../../utils/client" import { makeLogtoClient } from "../../utils/auth" import RepairHistoryCard from "./RepairHistoryCard" import type { components } from "../../types/saturday" -import { LogtoError } from "@logto/browser" +import { LogtoRequestError } from "@logto/browser" type PublicEvent = components["schemas"]["PublicEvent"] @@ -53,7 +53,7 @@ export default function UserRepairHistory({ onCreateNew, onLogin }: UserRepairHi setTotalPages(Math.ceil(totalItems / itemsPerPage)) } catch (err) { - if (err instanceof LogtoError) { + if (err instanceof LogtoRequestError) { onLogin() } console.error("Error fetching user events:", err)