fix(shop): persist settings through backend

This commit is contained in:
zetaloop
2026-04-25 14:49:36 +08:00
parent 358bfc7ac9
commit fc0b754056
4 changed files with 226 additions and 89 deletions
+81 -42
View File
@@ -7,50 +7,99 @@ 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 { addShopAnnouncement, deleteShopAnnouncement, updateShop } from "@/lib/api"
import { toApiError } from "@/lib/errors"
import { useMyShop } from "@/lib/hooks/use-my-shop"
import { notifyInfo, notifySuccess } from "@/lib/toast"
import type { Shop } from "@/lib/types"
import { useAuthStore } from "@/store/auth"
import { useShopStore } from "@/store/shops"
import { DollarSign, Edit, ExternalLink, ListOrdered, Star, Users } from "lucide-react"
import Link from "next/link"
import { useState } from "react"
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)
const { shop, setShop, loading, error, refreshShop } = useMyShop()
if (loading) {
return <div className="text-sm text-muted-foreground">...</div>
}
if (error) {
return <div className="text-sm text-muted-foreground">{error}</div>
}
if (!shop) {
return <div className="text-sm text-muted-foreground"></div>
}
return (
<ShopManagementContent
key={shop.id}
shop={shop}
updateShop={updateShop}
updateAnnouncement={updateAnnouncement}
addAnnouncement={addAnnouncement}
/>
<ShopManagementContent key={shop.id} shop={shop} setShop={setShop} refreshShop={refreshShop} />
)
}
function ShopManagementContent({
shop,
updateShop,
updateAnnouncement,
addAnnouncement,
setShop,
refreshShop,
}: {
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
setShop: (shop: Shop | null) => void
refreshShop: () => Promise<Shop | null>
}) {
const [name, setName] = useState(shop.name)
const [description, setDescription] = useState(shop.description)
const [saving, setSaving] = useState(false)
const handleSave = async () => {
setSaving(true)
try {
const nextShop = await updateShop(shop.id, {
name,
description,
commissionType: shop.commissionType,
commissionValue: shop.commissionValue,
allowMultiShop: shop.allowMultiShop,
allowIndependentOrders: shop.allowIndependentOrders,
dispatchMode: shop.dispatchMode,
})
setShop(nextShop)
notifySuccess("店铺信息已保存")
} catch (error) {
notifyInfo(toApiError(error).msg)
} finally {
setSaving(false)
}
}
const handleAddAnnouncement = async () => {
const next = window.prompt("", "")
if (next === null) return
const value = next.trim()
if (!value) return
setSaving(true)
try {
await addShopAnnouncement(shop.id, value)
await refreshShop()
notifySuccess("公告已添加")
} catch (error) {
notifyInfo(toApiError(error).msg)
} finally {
setSaving(false)
}
}
const handleDeleteAnnouncement = async (index: number) => {
setSaving(true)
try {
await deleteShopAnnouncement(shop.id, index)
await refreshShop()
notifySuccess("公告已删除")
} catch (error) {
notifyInfo(toApiError(error).msg)
} finally {
setSaving(false)
}
}
return (
<div className="container mx-auto max-w-6xl px-4 py-8 space-y-8">
@@ -126,12 +175,10 @@ function ShopManagementContent({
/>
</div>
<Button
onClick={() =>
updateShop(shop.id, {
name,
description,
})
}
onClick={() => {
void handleSave()
}}
disabled={saving}
>
<Edit className="mr-1 h-4 w-4" />
@@ -144,7 +191,7 @@ function ShopManagementContent({
<CardTitle className="text-base"></CardTitle>
</CardHeader>
<CardContent className="space-y-3">
{shop.announcements.map((announcement) => (
{shop.announcements.map((announcement, index) => (
<div
key={announcement}
className="flex items-center justify-between rounded-md border p-3"
@@ -154,16 +201,11 @@ function ShopManagementContent({
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)
void handleDeleteAnnouncement(index)
}}
disabled={saving}
>
</Button>
</div>
))}
@@ -172,12 +214,9 @@ function ShopManagementContent({
variant="outline"
size="sm"
onClick={() => {
const next = window.prompt("", "")
if (next === null) return
const value = next.trim()
if (!value) return
addAnnouncement(shop.id, value)
void handleAddAnnouncement()
}}
disabled={saving}
>
</Button>