feat: wire order and chat state flow
This commit is contained in:
+102
@@ -0,0 +1,102 @@
|
||||
import { create } from "zustand"
|
||||
import { mockChatMessages, mockChatSessions, mockUsers } from "@/lib/mock"
|
||||
import type { ChatMessage, ChatSession, Order } from "@/lib/types"
|
||||
|
||||
interface Sender {
|
||||
id: string
|
||||
name: string
|
||||
avatar: string
|
||||
}
|
||||
|
||||
interface ChatState {
|
||||
sessions: ChatSession[]
|
||||
messages: ChatMessage[]
|
||||
ensureOrderSession: (order: Order) => ChatSession
|
||||
sendTextMessage: (sessionId: string, sender: Sender, content: string) => void
|
||||
}
|
||||
|
||||
function resolveAvatar(userId: string) {
|
||||
return mockUsers.find((user) => user.id === userId)?.avatar ?? ""
|
||||
}
|
||||
|
||||
function shouldReadonly(status: Order["status"]) {
|
||||
return status === "pending_review" || status === "completed" || status === "cancelled"
|
||||
}
|
||||
|
||||
export const useChatStore = create<ChatState>((set, get) => ({
|
||||
sessions: mockChatSessions,
|
||||
messages: mockChatMessages,
|
||||
ensureOrderSession: (order) => {
|
||||
const existing = get().sessions.find(
|
||||
(session) => session.type === "order" && session.orderId === order.id,
|
||||
)
|
||||
|
||||
const readonly = shouldReadonly(order.status)
|
||||
|
||||
if (existing) {
|
||||
if (existing.readonly !== readonly) {
|
||||
set((state) => ({
|
||||
sessions: state.sessions.map((session) =>
|
||||
session.id === existing.id ? { ...session, readonly } : session,
|
||||
),
|
||||
}))
|
||||
}
|
||||
return get().sessions.find((session) => session.id === existing.id) ?? existing
|
||||
}
|
||||
|
||||
const session: ChatSession = {
|
||||
id: `chat-${order.id}`,
|
||||
type: "order",
|
||||
orderId: order.id,
|
||||
participants: [
|
||||
{
|
||||
id: order.consumerId,
|
||||
name: order.consumerName,
|
||||
avatar: resolveAvatar(order.consumerId),
|
||||
},
|
||||
{
|
||||
id: order.playerId,
|
||||
name: order.playerName,
|
||||
avatar: resolveAvatar(order.playerId),
|
||||
},
|
||||
],
|
||||
unreadCount: 0,
|
||||
readonly,
|
||||
}
|
||||
|
||||
set((state) => ({
|
||||
sessions: [session, ...state.sessions],
|
||||
}))
|
||||
|
||||
return session
|
||||
},
|
||||
sendTextMessage: (sessionId, sender, content) => {
|
||||
const text = content.trim()
|
||||
if (!text) return
|
||||
|
||||
const now = new Date().toISOString()
|
||||
const message: ChatMessage = {
|
||||
id: `msg-${Date.now()}`,
|
||||
sessionId,
|
||||
senderId: sender.id,
|
||||
senderName: sender.name,
|
||||
senderAvatar: sender.avatar,
|
||||
type: "text",
|
||||
content: text,
|
||||
createdAt: now,
|
||||
}
|
||||
|
||||
set((state) => ({
|
||||
messages: [...state.messages, message],
|
||||
sessions: state.sessions.map((session) =>
|
||||
session.id === sessionId
|
||||
? {
|
||||
...session,
|
||||
lastMessage: text,
|
||||
lastMessageAt: now,
|
||||
}
|
||||
: session,
|
||||
),
|
||||
}))
|
||||
},
|
||||
}))
|
||||
@@ -0,0 +1,83 @@
|
||||
import { create } from "zustand"
|
||||
import { mockOrders } from "@/lib/mock"
|
||||
import type { Order, OrderStatus, PlayerService } from "@/lib/types"
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
export const useOrderStore = create<OrderState>((set) => ({
|
||||
orders: mockOrders,
|
||||
createOrder: (input) => {
|
||||
const order: Order = {
|
||||
id: `ord${Date.now()}`,
|
||||
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],
|
||||
}))
|
||||
|
||||
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_review":
|
||||
return {
|
||||
...order,
|
||||
status,
|
||||
closedAt: order.closedAt ?? now,
|
||||
}
|
||||
case "completed":
|
||||
return {
|
||||
...order,
|
||||
status,
|
||||
closedAt: order.closedAt ?? now,
|
||||
completedAt: order.completedAt ?? now,
|
||||
}
|
||||
default:
|
||||
return {
|
||||
...order,
|
||||
status,
|
||||
}
|
||||
}
|
||||
}),
|
||||
})),
|
||||
}))
|
||||
Reference in New Issue
Block a user