Files
juwan-frontend/store/orders.ts
T

153 lines
4.0 KiB
TypeScript

import { create } from "zustand"
import { ORDER_ACCEPT_TIMEOUT_MS, ORDER_CLOSE_TIMEOUT_MS } from "@/lib/config/demo-timers"
import { generateId } from "@/lib/id"
import { mockOrders } from "@/lib/mock"
import type { Order, OrderStatus, PlayerService } from "@/lib/types"
import { useWalletStore } from "@/store/wallet"
interface CreateOrderInput {
consumerId: string
consumerName: string
playerId: string
playerName: string
shopId?: string
shopName?: string
service: PlayerService
totalPrice: number
note?: string
status?: OrderStatus
}
interface OrderState {
orders: Order[]
createOrder: (input: CreateOrderInput) => Order
updateOrderStatus: (orderId: string, status: OrderStatus) => void
}
const orderTimeouts = new Map<string, ReturnType<typeof setTimeout>>()
function clearOrderTimeout(orderId: string) {
const timer = orderTimeouts.get(orderId)
if (!timer) return
clearTimeout(timer)
orderTimeouts.delete(orderId)
}
function scheduleOrderTimeout(orderId: string, status: OrderStatus) {
clearOrderTimeout(orderId)
if (status !== "pending_accept" && status !== "pending_close") {
return
}
const timeoutMs = status === "pending_accept" ? ORDER_ACCEPT_TIMEOUT_MS : ORDER_CLOSE_TIMEOUT_MS
const timer = setTimeout(() => {
const state = useOrderStore.getState()
const order = state.orders.find((item) => item.id === orderId)
if (!order || order.status !== status) {
orderTimeouts.delete(orderId)
return
}
if (status === "pending_accept") {
state.updateOrderStatus(orderId, "cancelled")
}
if (status === "pending_close") {
state.updateOrderStatus(orderId, "pending_review")
}
orderTimeouts.delete(orderId)
}, timeoutMs)
orderTimeouts.set(orderId, timer)
}
export const useOrderStore = create<OrderState>((set) => ({
orders: mockOrders,
createOrder: (input) => {
const order: Order = {
id: generateId("ord"),
consumerId: input.consumerId,
consumerName: input.consumerName,
playerId: input.playerId,
playerName: input.playerName,
shopId: input.shopId,
shopName: input.shopName,
service: input.service,
status: input.status ?? "pending_payment",
totalPrice: input.totalPrice,
note: input.note?.trim() ? input.note.trim() : undefined,
createdAt: new Date().toISOString(),
}
set((state) => ({
orders: [order, ...state.orders],
}))
scheduleOrderTimeout(order.id, order.status)
return order
},
updateOrderStatus: (orderId, status) =>
set((state) => ({
orders: state.orders.map((order) => {
if (order.id !== orderId) return order
const now = new Date().toISOString()
switch (status) {
case "in_progress":
return {
...order,
status,
acceptedAt: order.acceptedAt ?? now,
}
case "pending_close":
return {
...order,
status,
closedAt: order.closedAt ?? now,
}
case "pending_review":
return {
...order,
status,
closedAt: order.closedAt ?? now,
}
case "completed":
if (order.status !== "completed") {
useWalletStore.getState().addIncome(order.id, order.totalPrice)
}
return {
...order,
status,
closedAt: order.closedAt ?? now,
completedAt: order.completedAt ?? now,
}
default:
return {
...order,
status,
}
}
}),
})),
}))
useOrderStore.subscribe((state, prevState) => {
state.orders.forEach((order) => {
const prevOrder = prevState.orders.find((item) => item.id === order.id)
if (!prevOrder || prevOrder.status !== order.status) {
scheduleOrderTimeout(order.id, order.status)
}
})
prevState.orders.forEach((order) => {
if (!state.orders.some((item) => item.id === order.id)) {
clearOrderTimeout(order.id)
}
})
})