From 452004b19424ba00dce3a2b7c3d565c5f4e1c029 Mon Sep 17 00:00:00 2001 From: zetaloop Date: Fri, 1 May 2026 04:10:03 +0800 Subject: [PATCH] refactor: remove demo timers and client-side timeout simulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove lib/config/demo-timers.ts and all usages across stores and pages. Order timeout scheduling, dispute auto-progression, and hardcoded countdown displays are removed — timeouts are now handled server-side by the backend. --- app/(order)/dispute/[id]/page.tsx | 88 ++++++++++++++++++++----------- app/(order)/order/[id]/page.tsx | 34 ------------ lib/config/demo-timers.ts | 6 --- store/disputes.ts | 79 +-------------------------- store/orders.ts | 64 ---------------------- 5 files changed, 58 insertions(+), 213 deletions(-) delete mode 100644 lib/config/demo-timers.ts diff --git a/app/(order)/dispute/[id]/page.tsx b/app/(order)/dispute/[id]/page.tsx index d3dcbca..76d306f 100644 --- a/app/(order)/dispute/[id]/page.tsx +++ b/app/(order)/dispute/[id]/page.tsx @@ -7,14 +7,13 @@ import { Label } from "@/components/ui/label" import { Separator } from "@/components/ui/separator" import { StatusBadge, type StatusBadgeProps } from "@/components/ui/status-badge" import { Textarea } from "@/components/ui/textarea" -import { getOrderById } from "@/lib/api" +import { getOrderById, getPlayerById, uploadFile } from "@/lib/api" import { getDisputeByOrderId, submitDispute, submitDisputeAppeal, submitDisputeResponse, } from "@/lib/api/disputes" -import { DISPUTE_TO_RESOLVED_MS } from "@/lib/config/demo-timers" import { notifyInfo } from "@/lib/toast" import { useAuthStore } from "@/store/auth" import { AlertTriangle, ArrowLeft, Clock, FileText, Upload, X } from "lucide-react" @@ -81,12 +80,14 @@ export default function DisputePage({ params }: { params: Promise<{ id: string } const [existingDispute, setExistingDispute] = useState > | null>(null) + const [playerUserId, setPlayerUserId] = useState(null) const [reason, setReason] = useState("") const [files, setFiles] = useState([]) const [responseReason, setResponseReason] = useState("") const [responseFiles, setResponseFiles] = useState([]) const [appealReason, setAppealReason] = useState("") + const [uploading, setUploading] = useState(false) const fileInputRef = useRef(null) const responseFileInputRef = useRef(null) @@ -100,6 +101,7 @@ export default function DisputePage({ params }: { params: Promise<{ id: string } setLoading(true) setOrder(null) setExistingDispute(null) + setPlayerUserId(null) } const load = async () => { @@ -113,6 +115,13 @@ export default function DisputePage({ params }: { params: Promise<{ id: string } if (cancelled) return setOrder(nextOrder ?? null) setExistingDispute(nextDispute ?? null) + + if (nextOrder) { + const player = await getPlayerById(String(nextOrder.playerId)) + if (cancelled) return + setPlayerUserId(player?.user.id ?? null) + } + setLoading(false) } @@ -133,34 +142,36 @@ export default function DisputePage({ params }: { params: Promise<{ id: string } useEffect( () => () => { - filesRef.current.forEach((url) => { - URL.revokeObjectURL(url) - }) - responseFilesRef.current.forEach((url) => { - URL.revokeObjectURL(url) - }) + filesRef.current = [] + responseFilesRef.current = [] }, [], ) - const handleFileSelect = ( + const handleFileSelect = async ( event: ChangeEvent, setter: Dispatch>, + currentFiles: string[], ) => { const selectedFiles = event.target.files if (!selectedFiles?.length) return - setter((prev) => { - const remaining = 5 - prev.length - if (remaining <= 0) return prev - - const nextUrls = Array.from(selectedFiles) - .slice(0, remaining) - .map((file) => URL.createObjectURL(file)) - return [...prev, ...nextUrls] - }) - - event.target.value = "" + setUploading(true) + try { + const remaining = 5 - currentFiles.length + if (remaining <= 0) return + const nextUrls = await Promise.all( + Array.from(selectedFiles) + .slice(0, remaining) + .map((file) => uploadFile(file, "dispute")), + ) + setter((prev) => [...prev, ...nextUrls]) + } catch { + notifyInfo("证据上传失败") + } finally { + setUploading(false) + event.target.value = "" + } } const removeFile = ( @@ -168,13 +179,14 @@ export default function DisputePage({ params }: { params: Promise<{ id: string } filesState: string[], setter: Dispatch>, ) => { - const removed = filesState[index] - if (removed) { - URL.revokeObjectURL(removed) - } setter((prev) => prev.filter((_, currentIndex) => currentIndex !== index)) } + const reloadDispute = async () => { + const nextDispute = await getDisputeByOrderId(id) + setExistingDispute(nextDispute ?? null) + } + const handleSubmit = () => { if (!userId || !reason.trim()) return @@ -212,7 +224,7 @@ export default function DisputePage({ params }: { params: Promise<{ id: string } } const isParticipant = Boolean( - userId && (order.consumerId === userId || order.playerId === userId), + userId && (String(order.consumerId) === userId || playerUserId === userId), ) if (!isParticipant) { return ( @@ -337,12 +349,15 @@ export default function DisputePage({ params }: { params: Promise<{ id: string } accept="image/*" multiple className="hidden" - onChange={(event) => handleFileSelect(event, setResponseFiles)} + onChange={(event) => { + void handleFileSelect(event, setResponseFiles, responseFiles) + }} />