refactor(api): standardize venues endpoint
Some checks failed
Deploy Fediversion / deploy (push) Failing after 1s
Some checks failed
Deploy Fediversion / deploy (push) Failing after 1s
- Backend: /api/venues returns PaginatedResponse envelope - Frontend: Updated VenuesPage, AdminVenuesPage, VerticalVenuesPage to consume envelope
This commit is contained in:
parent
c0e3e2a7e2
commit
3aaf35d43b
4 changed files with 34 additions and 27 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
from typing import List
|
from typing import List
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||||
from sqlmodel import Session, select
|
from sqlmodel import Session, select, func
|
||||||
from database import get_session
|
from database import get_session
|
||||||
from models import Venue
|
from models import Venue
|
||||||
from schemas import VenueCreate, VenueRead, VenueUpdate
|
from schemas import VenueCreate, VenueRead, VenueUpdate, PaginatedResponse, PaginationMeta
|
||||||
from auth import get_current_user
|
from auth import get_current_user
|
||||||
|
|
||||||
router = APIRouter(prefix="/venues", tags=["venues"])
|
router = APIRouter(prefix="/venues", tags=["venues"])
|
||||||
|
|
@ -16,10 +16,14 @@ def create_venue(venue: VenueCreate, session: Session = Depends(get_session), cu
|
||||||
session.refresh(db_venue)
|
session.refresh(db_venue)
|
||||||
return db_venue
|
return db_venue
|
||||||
|
|
||||||
@router.get("/", response_model=List[VenueRead])
|
@router.get("/", response_model=PaginatedResponse[VenueRead])
|
||||||
def read_venues(offset: int = 0, limit: int = Query(default=1000, le=1000), session: Session = Depends(get_session)):
|
def read_venues(offset: int = 0, limit: int = Query(default=1000, le=1000), session: Session = Depends(get_session)):
|
||||||
|
total = session.exec(select(func.count()).select_from(Venue)).one()
|
||||||
venues = session.exec(select(Venue).offset(offset).limit(limit)).all()
|
venues = session.exec(select(Venue).offset(offset).limit(limit)).all()
|
||||||
return venues
|
return PaginatedResponse(
|
||||||
|
data=venues,
|
||||||
|
meta=PaginationMeta(total=total, limit=limit, offset=offset)
|
||||||
|
)
|
||||||
|
|
||||||
@router.get("/{slug}", response_model=VenueRead)
|
@router.get("/{slug}", response_model=VenueRead)
|
||||||
def read_venue(slug: str, session: Session = Depends(get_session)):
|
def read_venue(slug: str, session: Session = Depends(get_session)):
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ async function getVenues(verticalSlug: string) {
|
||||||
next: { revalidate: 60 }
|
next: { revalidate: 60 }
|
||||||
})
|
})
|
||||||
if (!res.ok) return []
|
if (!res.ok) return []
|
||||||
return res.json()
|
const data = await res.json()
|
||||||
|
return data.data || []
|
||||||
} catch {
|
} catch {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState, useCallback } from "react"
|
||||||
import { useAuth } from "@/contexts/auth-context"
|
import { useAuth } from "@/contexts/auth-context"
|
||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
import { Card, CardContent } from "@/components/ui/card"
|
import { Card, CardContent } from "@/components/ui/card"
|
||||||
|
|
@ -38,6 +38,24 @@ export default function AdminVenuesPage() {
|
||||||
const [editingVenue, setEditingVenue] = useState<Venue | null>(null)
|
const [editingVenue, setEditingVenue] = useState<Venue | null>(null)
|
||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
|
|
||||||
|
const fetchVenues = useCallback(async () => {
|
||||||
|
if (!token) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${getApiUrl()}/venues?limit=200`, {
|
||||||
|
headers: { Authorization: `Bearer ${token}` }
|
||||||
|
})
|
||||||
|
if (res.ok) {
|
||||||
|
const data = await res.json()
|
||||||
|
setVenues(data.data || [])
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to fetch venues", e)
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}, [token])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (authLoading) return
|
if (authLoading) return
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
|
@ -49,25 +67,7 @@ export default function AdminVenuesPage() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fetchVenues()
|
fetchVenues()
|
||||||
}, [user, router, authLoading])
|
}, [user, router, authLoading, fetchVenues])
|
||||||
|
|
||||||
const fetchVenues = async () => {
|
|
||||||
if (!token) return
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await fetch(`${getApiUrl()}/venues?limit=200`, {
|
|
||||||
headers: { Authorization: `Bearer ${token}` }
|
|
||||||
})
|
|
||||||
if (res.ok) {
|
|
||||||
const data = await res.json()
|
|
||||||
setVenues(data.venues || data)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Failed to fetch venues", e)
|
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateVenue = async () => {
|
const updateVenue = async () => {
|
||||||
if (!token || !editingVenue) return
|
if (!token || !editingVenue) return
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,13 @@ export default function VenuesPage() {
|
||||||
setError(null)
|
setError(null)
|
||||||
// Fetch venues
|
// Fetch venues
|
||||||
const venuesRes = await fetch(`${getApiUrl()}/venues/`)
|
const venuesRes = await fetch(`${getApiUrl()}/venues/`)
|
||||||
const venuesData: Venue[] = await venuesRes.json()
|
const venuesEnvelope = await venuesRes.json()
|
||||||
|
const venuesData: Venue[] = venuesEnvelope.data || []
|
||||||
|
|
||||||
// Fetch show counts for each venue (batch approach)
|
// Fetch show counts for each venue (batch approach)
|
||||||
const showsRes = await fetch(`${getApiUrl()}/shows/?limit=1000`)
|
const showsRes = await fetch(`${getApiUrl()}/shows/?limit=1000`)
|
||||||
const showsData = await showsRes.json()
|
const showsEnvelope = await showsRes.json()
|
||||||
|
const showsData = showsEnvelope.data || []
|
||||||
|
|
||||||
// Count shows per venue
|
// Count shows per venue
|
||||||
const showCounts: Record<number, number> = {}
|
const showCounts: Record<number, number> = {}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue