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
@@ -3,10 +3,12 @@
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Switch } from "@/components/ui/switch"
import { resolveOwnerShop } from "@/lib/domain/resolve-current-shop"
import { updateShopTemplate } from "@/lib/api"
import { getShopSections } from "@/lib/domain/shop-template"
import { toApiError } from "@/lib/errors"
import { useMyShop } from "@/lib/hooks/use-my-shop"
import { notifyInfo } from "@/lib/toast"
import type { Shop, ShopSection } from "@/lib/types"
import { useAuthStore } from "@/store/auth"
import { useShopStore } from "@/store/shops"
import { Eye, EyeOff, GripVertical } from "lucide-react"
import Link from "next/link"
import { type DragEvent, useEffect, useState } from "react"
@@ -30,37 +32,35 @@ const sectionDescriptions: Record<ShopSection["type"], string> = {
}
export default function ShopTemplatesPage() {
const userId = useAuthStore((state) => state.user?.id)
const shops = useShopStore((state) => state.shops)
const shop = resolveOwnerShop(userId, shops)
const updateTemplateSections = useShopStore((state) => state.updateTemplateSections)
const { shop, setShop, loading, error } = 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 (
<ShopTemplatesEditor
key={shop.id}
shop={shop}
updateTemplateSections={updateTemplateSections}
/>
)
return <ShopTemplatesEditor key={shop.id} shop={shop} setShop={setShop} />
}
function ShopTemplatesEditor({
shop,
updateTemplateSections,
setShop,
}: {
shop: Shop
updateTemplateSections: (shopId: string, sections: ShopSection[]) => void
setShop: (shop: Shop | null) => void
}) {
const [sections, setSections] = useState<ShopSection[]>(
[...shop.templateConfig.sections].sort((a, b) => a.order - b.order),
)
const [sections, setSections] = useState<ShopSection[]>(getShopSections(shop))
const [dragIndex, setDragIndex] = useState<number | null>(null)
const [dropIndex, setDropIndex] = useState<number | null>(null)
const [showSavedToast, setShowSavedToast] = useState(false)
const [saving, setSaving] = useState(false)
useEffect(() => {
if (!showSavedToast) {
@@ -116,9 +116,21 @@ function ShopTemplatesEditor({
setDropIndex(null)
}
const handleSaveTemplate = () => {
updateTemplateSections(shop.id, sections)
setShowSavedToast(true)
const handleSaveTemplate = async () => {
setSaving(true)
try {
const templateConfig = {
...shop.templateConfig,
sections,
}
await updateShopTemplate(shop.id, templateConfig)
setShop({ ...shop, templateConfig })
setShowSavedToast(true)
} catch (error) {
notifyInfo(toApiError(error).msg)
} finally {
setSaving(false)
}
}
return (
@@ -137,7 +149,14 @@ function ShopTemplatesEditor({
<Button variant="outline" asChild>
<Link href={`/shop/${shop.id}`}></Link>
</Button>
<Button onClick={handleSaveTemplate}></Button>
<Button
onClick={() => {
void handleSaveTemplate()
}}
disabled={saving}
>
</Button>
</div>
</div>