Files
juwan-frontend/app/(dashboard)/dashboard/shop/page.tsx
T

215 lines
7.6 KiB
TypeScript

"use client"
import { DollarSign, Edit, ExternalLink, ListOrdered, Star, Users } from "lucide-react"
import Link from "next/link"
import { useState } from "react"
import { Badge } from "@/components/ui/badge"
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 { resolveOwnerShop } from "@/lib/domain/resolve-current-shop"
import type { Shop } from "@/lib/types"
import { useAuthStore } from "@/store/auth"
import { useShopStore } from "@/store/shops"
export default function ShopManagementPage() {
const userId = useAuthStore((state) => state.user?.id)
const shops = useShopStore((state) => state.shops)
const shop = resolveOwnerShop(userId, shops)
const updateShop = useShopStore((state) => state.updateShop)
const updateAnnouncement = useShopStore((state) => state.updateAnnouncement)
const addAnnouncement = useShopStore((state) => state.addAnnouncement)
if (!shop) {
return <div className="text-sm text-muted-foreground"></div>
}
return (
<ShopManagementContent
key={shop.id}
shop={shop}
updateShop={updateShop}
updateAnnouncement={updateAnnouncement}
addAnnouncement={addAnnouncement}
/>
)
}
function ShopManagementContent({
shop,
updateShop,
updateAnnouncement,
addAnnouncement,
}: {
shop: Shop
updateShop: (shopId: string, patch: Partial<Omit<Shop, "id" | "owner">>) => void
updateAnnouncement: (shopId: string, index: number, announcement: string) => void
addAnnouncement: (shopId: string, announcement: string) => void
}) {
const [name, setName] = useState(shop.name)
const [description, setDescription] = useState(shop.description)
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<h1 className="text-2xl font-bold"></h1>
<Button variant="outline" size="sm" asChild>
<Link href={`/shop/${shop.id}`}>
<ExternalLink className="mr-1 h-4 w-4" />
</Link>
</Button>
</div>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium"></CardTitle>
<ListOrdered className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{shop.totalOrders}</div>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium"></CardTitle>
<Star className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{shop.rating}</div>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium"></CardTitle>
<Users className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{shop.playerCount}</div>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium"></CardTitle>
<DollarSign className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">
{shop.commissionType === "percentage"
? `${shop.commissionValue}%`
: `¥${shop.commissionValue}`}
</div>
</CardContent>
</Card>
</div>
<Card>
<CardHeader>
<CardTitle className="text-base"></CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<Label htmlFor="shop-name"></Label>
<Input id="shop-name" value={name} onChange={(event) => setName(event.target.value)} />
</div>
<div className="space-y-2">
<Label htmlFor="shop-desc"></Label>
<Textarea
id="shop-desc"
value={description}
onChange={(event) => setDescription(event.target.value)}
rows={3}
/>
</div>
<Button
onClick={() =>
updateShop(shop.id, {
name,
description,
})
}
>
<Edit className="mr-1 h-4 w-4" />
</Button>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="text-base"></CardTitle>
</CardHeader>
<CardContent className="space-y-3">
{shop.announcements.map((announcement) => (
<div
key={announcement}
className="flex items-center justify-between rounded-md border p-3"
>
<span className="text-sm">{announcement}</span>
<Button
variant="ghost"
size="sm"
onClick={() => {
const next = window.prompt("", announcement)
if (next === null) return
const value = next.trim()
if (!value) return
const index = shop.announcements.indexOf(announcement)
if (index < 0) return
updateAnnouncement(shop.id, index, value)
}}
>
</Button>
</div>
))}
<Separator />
<Button
variant="outline"
size="sm"
onClick={() => {
const next = window.prompt("", "")
if (next === null) return
const value = next.trim()
if (!value) return
addAnnouncement(shop.id, value)
}}
>
</Button>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="text-base"></CardTitle>
</CardHeader>
<CardContent className="space-y-3 text-sm">
<div className="flex items-center justify-between">
<span className="text-muted-foreground"></span>
<Badge variant="outline">
{shop.dispatchMode === "manual" ? "手动派单" : "自动派单"}
</Badge>
</div>
<div className="flex items-center justify-between">
<span className="text-muted-foreground"></span>
<Badge variant={shop.allowMultiShop ? "default" : "secondary"}>
{shop.allowMultiShop ? "是" : "否"}
</Badge>
</div>
<div className="flex items-center justify-between">
<span className="text-muted-foreground"></span>
<Badge variant={shop.allowIndependentOrders ? "default" : "secondary"}>
{shop.allowIndependentOrders ? "是" : "否"}
</Badge>
</div>
</CardContent>
</Card>
</div>
)
}