Files
juwan-frontend/app/(order)/order/new/page.tsx
T

219 lines
7.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client"
import { ArrowLeft, CheckCircle, CreditCard, ShieldCheck } from "lucide-react"
import Link from "next/link"
import { useRouter, useSearchParams } from "next/navigation"
import { useState } from "react"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Separator } from "@/components/ui/separator"
import { Textarea } from "@/components/ui/textarea"
import { mockPlayers, mockServices, walletBalance } from "@/lib/mock"
import { notifySuccess } from "@/lib/toast"
import { useRequireAuth } from "@/lib/use-require-auth"
import { useAuthStore } from "@/store/auth"
import { useChatStore } from "@/store/chat"
import { useOrderStore } from "@/store/orders"
export default function NewOrderPage() {
const router = useRouter()
const searchParams = useSearchParams()
const { requireAuth } = useRequireAuth()
const createOrder = useOrderStore((state) => state.createOrder)
const ensureOrderSession = useChatStore((state) => state.ensureOrderSession)
const serviceId = searchParams.get("serviceId")
const service = mockServices.find((s) => s.id === serviceId)
const player = service ? mockPlayers.find((p) => p.id === service.playerId) : null
const [quantity, setQuantity] = useState(1)
const [note, setNote] = useState("")
const [submitted, setSubmitted] = useState(false)
if (!service || !player) {
return (
<div className="container mx-auto py-8 px-4 text-center text-muted-foreground">
</div>
)
}
const totalPrice = service.price * quantity
if (submitted) {
return (
<div className="container mx-auto py-8 px-4 max-w-lg text-center space-y-4">
<CheckCircle className="h-12 w-12 mx-auto text-green-500" />
<h2 className="text-xl font-bold"></h2>
<p className="text-sm text-muted-foreground">
</p>
<div className="flex gap-2 justify-center">
<Button asChild>
<Link href="/orders"></Link>
</Button>
<Button variant="outline" asChild>
<Link href={`/player/${player.id}`}></Link>
</Button>
</div>
</div>
)
}
return (
<div className="container mx-auto py-8 px-4 max-w-2xl">
<Link
href={`/player/${player.id}`}
className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground mb-4"
>
<ArrowLeft className="h-4 w-4" />
</Link>
<h1 className="text-2xl font-bold mb-6"></h1>
<div className="space-y-6">
<Card>
<CardHeader>
<CardTitle className="text-base"></CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center gap-3">
<Avatar className="h-10 w-10">
<AvatarImage src={player.user.avatar} />
<AvatarFallback>{player.user.nickname[0]}</AvatarFallback>
</Avatar>
<div>
<p className="font-medium">{player.user.nickname}</p>
<p className="text-xs text-muted-foreground">
{player.shopName ? `${player.shopName} · ` : ""}
{service.gameName}
</p>
</div>
</div>
<Separator />
<div className="space-y-2 text-sm">
<div className="flex justify-between">
<span className="text-muted-foreground"></span>
<span>{service.title}</span>
</div>
<div className="flex justify-between">
<span className="text-muted-foreground"></span>
<span>
¥{service.price}/{service.unit}
</span>
</div>
{service.rankRange && (
<div className="flex justify-between">
<span className="text-muted-foreground"></span>
<span>{service.rankRange}</span>
</div>
)}
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="text-base"></CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<Label htmlFor="quantity">{service.unit}</Label>
<Input
id="quantity"
type="number"
min={1}
max={99}
value={quantity}
onChange={(e) => setQuantity(Math.max(1, Number.parseInt(e.target.value, 10) || 1))}
/>
</div>
<div className="space-y-2">
<Label htmlFor="note"></Label>
<Textarea
id="note"
placeholder="例如:希望晚上8点后开始"
value={note}
onChange={(e) => setNote(e.target.value)}
rows={3}
/>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="text-base"></CardTitle>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex justify-between text-sm">
<span className="text-muted-foreground">
{service.title} × {quantity}
</span>
<span>¥{totalPrice}</span>
</div>
<Separator />
<div className="flex justify-between font-medium">
<span></span>
<span className="text-lg text-primary">¥{totalPrice}</span>
</div>
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<CreditCard className="h-4 w-4" />
<span>: ¥{walletBalance}</span>
{walletBalance < totalPrice && <span className="text-destructive"></span>}
{walletBalance < totalPrice && (
<Button variant="outline" size="sm" asChild>
<Link href="/wallet"></Link>
</Button>
)}
</div>
<div className="flex items-center gap-2 text-xs text-muted-foreground">
<ShieldCheck className="h-3.5 w-3.5" />
<span></span>
</div>
</CardContent>
</Card>
<Button
className="w-full"
size="lg"
disabled={walletBalance < totalPrice}
onClick={() =>
requireAuth(async () => {
await new Promise((resolve) => setTimeout(resolve, 500))
const authUser = useAuthStore.getState().user
if (!authUser) return
const order = createOrder({
consumerId: authUser.id,
consumerName: authUser.nickname,
playerId: player.id,
playerName: player.user.nickname,
shopId: player.shopId,
shopName: player.shopName,
service,
totalPrice,
note,
status: "pending_accept",
})
ensureOrderSession(order)
setSubmitted(true)
notifySuccess("下单成功")
setTimeout(() => {
router.push(`/order/${order.id}`)
}, 800)
})
}
>
¥{totalPrice}
</Button>
</div>
</div>
)
}