fix(services): resolve owner shop from backend
This commit is contained in:
@@ -20,13 +20,12 @@ import {
|
|||||||
listPlayers,
|
listPlayers,
|
||||||
updatePlayerService,
|
updatePlayerService,
|
||||||
} from "@/lib/api"
|
} from "@/lib/api"
|
||||||
import { resolveOwnerShop } from "@/lib/domain/resolve-current-shop"
|
|
||||||
import { toApiError } from "@/lib/errors"
|
import { toApiError } from "@/lib/errors"
|
||||||
import { GameIcon } from "@/lib/game-icons"
|
import { GameIcon } from "@/lib/game-icons"
|
||||||
|
import { useMyShop } from "@/lib/hooks/use-my-shop"
|
||||||
import { notifyInfo, notifySuccess } from "@/lib/toast"
|
import { notifyInfo, notifySuccess } from "@/lib/toast"
|
||||||
import type { Game, PlayerService } from "@/lib/types"
|
import type { Game, PlayerService } from "@/lib/types"
|
||||||
import { useAuthStore } from "@/store/auth"
|
import { useAuthStore } from "@/store/auth"
|
||||||
import { useShopStore } from "@/store/shops"
|
|
||||||
import { standardSchemaResolver } from "@hookform/resolvers/standard-schema"
|
import { standardSchemaResolver } from "@hookform/resolvers/standard-schema"
|
||||||
import { ArrowLeft } from "lucide-react"
|
import { ArrowLeft } from "lucide-react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
@@ -51,11 +50,14 @@ export default function NewServicePage() {
|
|||||||
const serviceId = searchParams.get("serviceId")
|
const serviceId = searchParams.get("serviceId")
|
||||||
const userId = useAuthStore((state) => state.user?.id)
|
const userId = useAuthStore((state) => state.user?.id)
|
||||||
const currentRole = useAuthStore((state) => state.currentRole)
|
const currentRole = useAuthStore((state) => state.currentRole)
|
||||||
const shops = useShopStore((state) => state.shops)
|
const {
|
||||||
|
shop: ownerShop,
|
||||||
|
loading: shopLoading,
|
||||||
|
error: shopError,
|
||||||
|
} = useMyShop(currentRole === "owner")
|
||||||
const [players, setPlayers] = useState<Awaited<ReturnType<typeof listPlayers>>>([])
|
const [players, setPlayers] = useState<Awaited<ReturnType<typeof listPlayers>>>([])
|
||||||
const [editingService, setEditingService] = useState<PlayerService | undefined>(undefined)
|
const [editingService, setEditingService] = useState<PlayerService | undefined>(undefined)
|
||||||
const [loadingService, setLoadingService] = useState(Boolean(serviceId))
|
const [loadingService, setLoadingService] = useState(Boolean(serviceId))
|
||||||
const ownerShop = resolveOwnerShop(userId, shops)
|
|
||||||
const scopedPlayerIds =
|
const scopedPlayerIds =
|
||||||
currentRole === "player"
|
currentRole === "player"
|
||||||
? userId
|
? userId
|
||||||
@@ -156,10 +158,14 @@ export default function NewServicePage() {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
if (loadingService) {
|
if (loadingService || (currentRole === "owner" && shopLoading)) {
|
||||||
return <div className="text-sm text-muted-foreground">加载中...</div>
|
return <div className="text-sm text-muted-foreground">加载中...</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentRole === "owner" && shopError) {
|
||||||
|
return <div className="text-sm text-muted-foreground">{shopError}</div>
|
||||||
|
}
|
||||||
|
|
||||||
if (serviceId && (!editingService || !scopedPlayerIdSet.has(editingService.playerId))) {
|
if (serviceId && (!editingService || !scopedPlayerIdSet.has(editingService.playerId))) {
|
||||||
return <div className="text-sm text-muted-foreground">服务不存在或当前身份不可编辑</div>
|
return <div className="text-sm text-muted-foreground">服务不存在或当前身份不可编辑</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,11 @@ import {
|
|||||||
TableRow,
|
TableRow,
|
||||||
} from "@/components/ui/table"
|
} from "@/components/ui/table"
|
||||||
import { deletePlayerService, listPlayers, listServices } from "@/lib/api"
|
import { deletePlayerService, listPlayers, listServices } from "@/lib/api"
|
||||||
import { resolveOwnerShop } from "@/lib/domain/resolve-current-shop"
|
|
||||||
import { toApiError } from "@/lib/errors"
|
import { toApiError } from "@/lib/errors"
|
||||||
|
import { useMyShop } from "@/lib/hooks/use-my-shop"
|
||||||
import { notifyInfo, notifySuccess } from "@/lib/toast"
|
import { notifyInfo, notifySuccess } from "@/lib/toast"
|
||||||
import type { Player, PlayerService } from "@/lib/types"
|
import type { Player, PlayerService } from "@/lib/types"
|
||||||
import { useAuthStore } from "@/store/auth"
|
import { useAuthStore } from "@/store/auth"
|
||||||
import { useShopStore } from "@/store/shops"
|
|
||||||
import { Edit, Plus, Trash2 } from "lucide-react"
|
import { Edit, Plus, Trash2 } from "lucide-react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react"
|
import { useCallback, useEffect, useMemo, useState } from "react"
|
||||||
@@ -25,11 +24,14 @@ import { useCallback, useEffect, useMemo, useState } from "react"
|
|||||||
export default function ServicesPage() {
|
export default function ServicesPage() {
|
||||||
const userId = useAuthStore((state) => state.user?.id)
|
const userId = useAuthStore((state) => state.user?.id)
|
||||||
const currentRole = useAuthStore((state) => state.currentRole)
|
const currentRole = useAuthStore((state) => state.currentRole)
|
||||||
const shops = useShopStore((state) => state.shops)
|
const {
|
||||||
|
shop: ownerShop,
|
||||||
|
loading: shopLoading,
|
||||||
|
error: shopError,
|
||||||
|
} = useMyShop(currentRole === "owner")
|
||||||
const [players, setPlayers] = useState<Player[]>([])
|
const [players, setPlayers] = useState<Player[]>([])
|
||||||
const [services, setServices] = useState<PlayerService[]>([])
|
const [services, setServices] = useState<PlayerService[]>([])
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const ownerShop = resolveOwnerShop(userId, shops)
|
|
||||||
|
|
||||||
const loadData = useCallback(async () => {
|
const loadData = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -124,12 +126,18 @@ export default function ServicesPage() {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{loading ? (
|
{loading || (currentRole === "owner" && shopLoading) ? (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={6} className="text-center text-sm text-muted-foreground">
|
<TableCell colSpan={6} className="text-center text-sm text-muted-foreground">
|
||||||
加载中...
|
加载中...
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
) : currentRole === "owner" && shopError ? (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={6} className="text-center text-sm text-muted-foreground">
|
||||||
|
{shopError}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
) : scopedServices.length === 0 ? (
|
) : scopedServices.length === 0 ? (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={6} className="text-center text-sm text-muted-foreground">
|
<TableCell colSpan={6} className="text-center text-sm text-muted-foreground">
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ import { toApiError } from "@/lib/errors"
|
|||||||
import type { Shop } from "@/lib/types"
|
import type { Shop } from "@/lib/types"
|
||||||
import { useCallback, useEffect, useState } from "react"
|
import { useCallback, useEffect, useState } from "react"
|
||||||
|
|
||||||
export function useMyShop() {
|
export function useMyShop(enabled = true) {
|
||||||
const [shop, setShop] = useState<Shop | null>(null)
|
const [shop, setShop] = useState<Shop | null>(null)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(enabled)
|
||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
|
|
||||||
const refreshShop = useCallback(async () => {
|
const refreshShop = useCallback(async () => {
|
||||||
|
if (!enabled) return null
|
||||||
|
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
setError(null)
|
setError(null)
|
||||||
|
|
||||||
@@ -29,12 +31,20 @@ export function useMyShop() {
|
|||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}, [])
|
}, [enabled])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!enabled) return
|
||||||
|
|
||||||
let cancelled = false
|
let cancelled = false
|
||||||
|
|
||||||
getMyShop()
|
Promise.resolve()
|
||||||
|
.then(() => {
|
||||||
|
if (cancelled) return undefined
|
||||||
|
setLoading(true)
|
||||||
|
setError(null)
|
||||||
|
return getMyShop()
|
||||||
|
})
|
||||||
.then((nextShop) => {
|
.then((nextShop) => {
|
||||||
if (cancelled) return
|
if (cancelled) return
|
||||||
setShop(nextShop ?? null)
|
setShop(nextShop ?? null)
|
||||||
@@ -56,7 +66,7 @@ export function useMyShop() {
|
|||||||
return () => {
|
return () => {
|
||||||
cancelled = true
|
cancelled = true
|
||||||
}
|
}
|
||||||
}, [])
|
}, [enabled])
|
||||||
|
|
||||||
return { shop, setShop, loading, error, refreshShop }
|
return { shop, setShop, loading, error, refreshShop }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user