import { useState } from 'react' import { useParams, useNavigate, Link } from 'react-router-dom' import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors, type DragEndEvent, } from '@dnd-kit/core' import { SortableContext, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy, } from '@dnd-kit/sortable' import { CSS } from '@dnd-kit/utilities' import { RouteFormModal } from '../../components/admin/RouteFormModal' import { DeleteConfirmModal } from '../../components/admin/DeleteConfirmModal' import { useGame } from '../../hooks/useGames' import { useCreateRoute, useUpdateRoute, useDeleteRoute, useReorderRoutes, } from '../../hooks/useAdmin' import type { Route as GameRoute, CreateRouteInput, UpdateRouteInput } from '../../types' function SortableRouteRow({ route, onEdit, onDelete, onClick, }: { route: GameRoute onEdit: (r: GameRoute) => void onDelete: (r: GameRoute) => void onClick: (r: GameRoute) => void }) { const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: route.id }) const style = { transform: CSS.Transform.toString(transform), transition, } return ( onClick(route)} > {route.order} {route.name}
e.stopPropagation()}>
) } export function AdminGameDetail() { const { gameId } = useParams<{ gameId: string }>() const navigate = useNavigate() const id = Number(gameId) const { data: game, isLoading } = useGame(id) const createRoute = useCreateRoute(id) const updateRoute = useUpdateRoute(id) const deleteRoute = useDeleteRoute(id) const reorderRoutes = useReorderRoutes(id) const [showCreate, setShowCreate] = useState(false) const [editing, setEditing] = useState(null) const [deleting, setDeleting] = useState(null) const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 5 } }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }), ) if (isLoading) return
Loading...
if (!game) return
Game not found
const routes = game.routes ?? [] const handleDragEnd = (event: DragEndEvent) => { const { active, over } = event if (!over || active.id === over.id) return const oldIndex = routes.findIndex((r) => r.id === active.id) const newIndex = routes.findIndex((r) => r.id === over.id) if (oldIndex === -1 || newIndex === -1) return // Build new order assignments based on rearranged positions const reordered = [...routes] const [moved] = reordered.splice(oldIndex, 1) reordered.splice(newIndex, 0, moved) const newOrders = reordered.map((r, i) => ({ id: r.id, order: i + 1, })) reorderRoutes.mutate(newOrders) } return (

{game.name}

{game.region} · Gen {game.generation} {game.releaseYear ? ` \u00b7 ${game.releaseYear}` : ''}

Routes ({routes.length})

{routes.length === 0 ? (
No routes yet. Add one to get started.
) : (
r.id)} strategy={verticalListSortingStrategy} > {routes.map((route) => ( navigate(`/admin/games/${id}/routes/${r.id}`)} /> ))}
Order Name Actions
)} {showCreate && ( 0 ? Math.max(...routes.map((r) => r.order)) + 1 : 1} onSubmit={(data) => createRoute.mutate(data as CreateRouteInput, { onSuccess: () => setShowCreate(false), }) } onClose={() => setShowCreate(false)} isSubmitting={createRoute.isPending} /> )} {editing && ( updateRoute.mutate( { routeId: editing.id, data: data as UpdateRouteInput }, { onSuccess: () => setEditing(null) }, ) } onClose={() => setEditing(null)} isSubmitting={updateRoute.isPending} /> )} {deleting && ( deleteRoute.mutate(deleting.id, { onSuccess: () => setDeleting(null), }) } onCancel={() => setDeleting(null)} isDeleting={deleteRoute.isPending} /> )}
) }