refactor(orders): replace local state machine with minimal cache
Strip store/orders.ts to a thin local cache with setOrders and updateOrder only. Remove all client-side state transition logic, actor validation, chat sync, notification generation, and wallet integration — these are now handled by the backend API. Fix components/order-actions.tsx and stores that depended on the removed order store methods (markDisputed, autoTimeout*).
This commit is contained in:
@@ -5,9 +5,10 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { EmptyState } from "@/components/ui/empty-state"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { StatusBadge } from "@/components/ui/status-badge"
|
||||
import { getOrderById, listChatSessions, listReviewsByOrder } from "@/lib/api"
|
||||
import { getOrderById, getPlayerById, getUserById, listReviewsByOrder } from "@/lib/api"
|
||||
import { statusLabels } from "@/lib/constants"
|
||||
import type { OrderStatus } from "@/lib/types"
|
||||
import type { OrderStatus, Player, User } from "@/lib/types"
|
||||
import { useAuthStore } from "@/store/auth"
|
||||
import { ArrowLeft, CheckCircle, Clock, Star } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
import { use, useEffect, useState } from "react"
|
||||
@@ -46,32 +47,15 @@ const statusVariants: Record<OrderStatus, OrderStatusBadgeVariant> = {
|
||||
|
||||
export default function OrderDetailPage({ params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = use(params)
|
||||
const [sessions, setSessions] = useState<Awaited<ReturnType<typeof listChatSessions>>>([])
|
||||
const currentUserId = useAuthStore((state) => state.user?.id)
|
||||
const [reviews, setReviews] = useState<Awaited<ReturnType<typeof listReviewsByOrder>>>([])
|
||||
const [chatTarget, setChatTarget] = useState<User | null>(null)
|
||||
const [player, setPlayer] = useState<Player | null>(null)
|
||||
const [order, setOrder] = useState<Awaited<ReturnType<typeof getOrderById>> | undefined>(
|
||||
undefined,
|
||||
)
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
|
||||
void (async () => {
|
||||
try {
|
||||
const sessions = await Promise.resolve(listChatSessions())
|
||||
if (cancelled) return
|
||||
setSessions(sessions)
|
||||
} catch {
|
||||
if (cancelled) return
|
||||
setSessions([])
|
||||
}
|
||||
})()
|
||||
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
|
||||
@@ -94,6 +78,42 @@ export default function OrderDetailPage({ params }: { params: Promise<{ id: stri
|
||||
}
|
||||
}, [id])
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
|
||||
void (async () => {
|
||||
if (!order || !currentUserId) {
|
||||
setPlayer(null)
|
||||
setChatTarget(null)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
setPlayer(null)
|
||||
setChatTarget(null)
|
||||
const player = await getPlayerById(String(order.playerId))
|
||||
if (!cancelled) setPlayer(player ?? null)
|
||||
|
||||
if (String(order.consumerId) === currentUserId) {
|
||||
if (!cancelled) setChatTarget(player?.user ?? null)
|
||||
return
|
||||
}
|
||||
|
||||
if (player?.user.id === currentUserId) {
|
||||
const consumer = await getUserById(String(order.consumerId))
|
||||
if (!cancelled) setChatTarget(consumer ?? null)
|
||||
}
|
||||
} catch {
|
||||
if (!cancelled) setPlayer(null)
|
||||
if (!cancelled) setChatTarget(null)
|
||||
}
|
||||
})()
|
||||
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}, [currentUserId, order])
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
|
||||
@@ -129,7 +149,6 @@ export default function OrderDetailPage({ params }: { params: Promise<{ id: stri
|
||||
)
|
||||
}
|
||||
|
||||
const chatSession = sessions.find((session) => session.type === "order" && session.orderId === id)
|
||||
const statusSteps =
|
||||
order.status === "disputed"
|
||||
? disputedStatusSteps
|
||||
@@ -137,6 +156,7 @@ export default function OrderDetailPage({ params }: { params: Promise<{ id: stri
|
||||
? cancelledStatusSteps
|
||||
: normalStatusSteps
|
||||
const currentStepIndex = statusSteps.indexOf(order.status)
|
||||
const isPlayerParticipant = player?.user.id === currentUserId
|
||||
|
||||
return (
|
||||
<div className="container mx-auto py-8 px-4 max-w-2xl">
|
||||
@@ -291,7 +311,8 @@ export default function OrderDetailPage({ params }: { params: Promise<{ id: stri
|
||||
order={order}
|
||||
onOrderChange={(next) => setOrder(next)}
|
||||
initialStatus={order.status}
|
||||
chatSessionId={chatSession?.id}
|
||||
chatTargetId={chatTarget?.id}
|
||||
isPlayerParticipant={isPlayerParticipant}
|
||||
serviceId={order.service.id}
|
||||
/>
|
||||
</div>
|
||||
|
||||
+26
-14
@@ -6,7 +6,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { EmptyState } from "@/components/ui/empty-state"
|
||||
import { StatusBadge } from "@/components/ui/status-badge"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { listChatSessions, listOrders } from "@/lib/api"
|
||||
import { getPlayerById, listOrders } from "@/lib/api"
|
||||
import { statusLabels } from "@/lib/constants"
|
||||
import {
|
||||
isActiveOrder,
|
||||
@@ -111,7 +111,7 @@ function OrderListContent({
|
||||
const orderRole = getOrderRole(currentRole)
|
||||
const [tab, setTab] = useState<TabFilter | "pending">("all")
|
||||
const [orders, setOrders] = useState<Awaited<ReturnType<typeof listOrders>>>([])
|
||||
const [sessions, setSessions] = useState<Awaited<ReturnType<typeof listChatSessions>>>([])
|
||||
const [chatTargets, setChatTargets] = useState<Record<string, string>>({})
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
@@ -143,27 +143,41 @@ function OrderListContent({
|
||||
|
||||
void (async () => {
|
||||
try {
|
||||
const items = await Promise.resolve(listChatSessions())
|
||||
const entries = await Promise.all(
|
||||
orders.map(async (order) => {
|
||||
if (currentRole === "consumer") {
|
||||
const player = await getPlayerById(String(order.playerId))
|
||||
return [String(order.id), player?.user.id] as const
|
||||
}
|
||||
if (currentRole === "player")
|
||||
return [String(order.id), String(order.consumerId)] as const
|
||||
return [String(order.id), undefined] as const
|
||||
}),
|
||||
)
|
||||
if (cancelled) return
|
||||
setSessions(items)
|
||||
setChatTargets(
|
||||
Object.fromEntries(
|
||||
entries.filter((entry): entry is readonly [string, string] => Boolean(entry[1])),
|
||||
),
|
||||
)
|
||||
} catch {
|
||||
if (cancelled) return
|
||||
setSessions([])
|
||||
setChatTargets({})
|
||||
}
|
||||
})()
|
||||
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}, [])
|
||||
}, [currentRole, orders])
|
||||
|
||||
const tabs =
|
||||
currentRole === "consumer" ? consumerTabs : currentRole === "player" ? playerTabs : ownerTabs
|
||||
|
||||
const roleFiltered = orders.filter((order) => {
|
||||
if (currentRole === "consumer") return userId ? order.consumerId === userId : false
|
||||
if (currentRole === "player") return userId ? order.playerId === userId : false
|
||||
return ownerShopId ? order.shopId === ownerShopId : false
|
||||
if (currentRole === "consumer") return userId ? String(order.consumerId) === userId : false
|
||||
if (currentRole === "player") return true
|
||||
return ownerShopId ? String(order.shopId) === ownerShopId : false
|
||||
})
|
||||
|
||||
const filtered = roleFiltered.filter((order) => {
|
||||
@@ -241,13 +255,11 @@ function OrderListContent({
|
||||
if (order.status !== "in_progress" && order.status !== "pending_close") {
|
||||
return null
|
||||
}
|
||||
const session = sessions.find(
|
||||
(item) => item.type === "order" && item.orderId === order.id,
|
||||
)
|
||||
if (!session) return null
|
||||
const chatTargetId = chatTargets[String(order.id)]
|
||||
if (!chatTargetId) return null
|
||||
return (
|
||||
<Button variant="outline" size="sm" asChild>
|
||||
<Link href={`/chat/${session.id}`}>
|
||||
<Link href={`/chat/${chatTargetId}?orderId=${order.id}`}>
|
||||
<MessageSquare className="mr-1 h-3.5 w-3.5" />
|
||||
聊天
|
||||
</Link>
|
||||
|
||||
Reference in New Issue
Block a user