wip: fixed pagination

This commit is contained in:
2026-10-20 10:53:42 +02:00
parent 1f5db3b5db
commit b38bfa4e45
7 changed files with 125 additions and 22 deletions
+6 -3
View File
@@ -4,7 +4,7 @@ name: Deployment (Staging)
on:
# Runs on pushes targeting the default branch
push:
branches: ['main']
branches: ["main"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
@@ -20,8 +20,8 @@ jobs:
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version: 'lts/*'
cache: 'npm'
node-version: "lts/*"
cache: "npm"
- name: Set environment variables
run: |
@@ -44,6 +44,9 @@ jobs:
if [[ -n "${{ secrets.VITE_BC_EMAIL }}" ]]; then
echo "VITE_BC_EMAIL=${{ secrets.VITE_BC_EMAIL }}" >> .env
fi
if [[ -n "${{ secrets.VITE_EV_CARTO_KEY }}" ]]; then
echo "VITE_EV_CARTO_KEY=${{ secrets.VITE_EV_CARTO_KEY }}" >> .env
fi
- name: Install dependencies
run: npm ci --omit=dev
@@ -63,8 +63,8 @@ const EventDialog: React.FC<EventDialogProps> = ({ event, onClose }) => {
</>
)}
</DialogContent>
<DialogActions sx={{ px: 3, pb: 2, justifyContent: 'space-between' }}>
<Stack direction="row" spacing={1}>
<DialogActions sx={{ px: 3, pb: 2, justifyContent: 'space-between', gap: 1, flexWrap: 'wrap' }}>
<Stack direction="row" spacing={1} useFlexGap flexWrap="wrap" sx={{ minWidth: 0 }}>
{event.link && (
<Chip
component={Link}
@@ -0,0 +1,58 @@
import { fireEvent, render, screen, within } from '@testing-library/react'
import ListView from './ListView.js'
import type { Event } from './types.js'
const makeEvent = (id: string, title: string, date: string, city = 'Ferrara'): Event => ({
id,
title,
date: new Date(date),
location: { name: 'Piazza', city, lat: 44, lng: 11 },
})
describe('Events list', () => {
beforeEach(() => {
vi.useFakeTimers()
vi.setSystemTime(new Date('2026-10-19T12:00:00'))
})
afterEach(() => vi.useRealTimers())
it('separates events and sorts upcoming ascending and past descending', () => {
render(
<ListView
events={[
makeEvent('past-old', 'Past old', '2026-01-01'),
makeEvent('future-late', 'Future late', '2026-12-01'),
makeEvent('past-new', 'Past new', '2026-10-01'),
makeEvent('future-soon', 'Future soon', '2026-11-01'),
]}
onSelect={vi.fn()}
/>
)
const upcoming = within(screen.getByRole('region', { name: 'prossimi eventi' }))
const past = within(screen.getByRole('region', { name: 'eventi passati' }))
expect(upcoming.getAllByRole('heading', { level: 2 }).map(node => node.textContent)).toEqual(['Future soon', 'Future late'])
expect(past.getAllByRole('heading', { level: 2 }).map(node => node.textContent)).toEqual(['Past new', 'Past old'])
})
it('renders date ranges and invokes onSelect for the clicked card', () => {
const onSelect = vi.fn()
const event = { ...makeEvent('range', 'Long medieval event', '2026-11-01', 'San Martino'), endDate: new Date('2026-11-03') }
render(<ListView events={[event]} onSelect={onSelect} />)
expect(screen.getByText(/1-3 novembre 2026/)).toBeInTheDocument()
expect(screen.getByText('San Martino')).toBeInTheDocument()
fireEvent.click(screen.getByRole('heading', { name: 'Long medieval event' }))
expect(onSelect).toHaveBeenCalledWith(event)
})
it('uses a single fluid column on small screens', () => {
render(<ListView events={[makeEvent('one', 'A very long event title that must wrap', '2026-11-01')]} onSelect={vi.fn()} />)
const card = screen.getByRole('heading', { name: /very long event/ }).closest('.MuiCard-root')
expect(card).toHaveStyle({ width: '100%', minWidth: '0', boxSizing: 'border-box' })
expect(screen.getByRole('region', { name: 'prossimi eventi' })).toHaveStyle({ width: '100%', minWidth: '0' })
})
})
+33 -11
View File
@@ -31,7 +31,11 @@ const EventCard: React.FC<{ event: Event; onSelect: (event: Event) => void }> =
display: 'flex',
flexDirection: 'column',
opacity: isUpcoming(event.date) ? 1 : 0.6,
width: theme => theme.breakpoints.values.lg * 0.3,
// Cards must be allowed to shrink on phones. The previous fixed
// width (30% of the `lg` breakpoint) was wider than small screens.
width: '100%',
minWidth: 0,
boxSizing: 'border-box',
}}>
<CardActionArea
onClick={() => onSelect(event)}
@@ -39,27 +43,27 @@ const EventCard: React.FC<{ event: Event; onSelect: (event: Event) => void }> =
{event.image && <CardMedia component="img" height={160} image={event.image} alt={event.title} />}
<CardContent>
<Stack direction="row" justifyContent="space-between" alignItems="flex-start" mb={1}>
<Typography variant="h6" component="h2" sx={{ flexGrow: 1, mr: 1 }}>
<Typography variant="h6" component="h2" sx={{ flexGrow: 1, minWidth: 0, mr: 1, overflowWrap: 'anywhere' }}>
{event.title}
</Typography>
{!isUpcoming(event.date) && <Chip label="Passato" size="small" color="default" />}
</Stack>
<Stack direction="row" alignItems="center" justifyContent="space-between">
<div>
<Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ minWidth: 0 }}>
<Box sx={{ minWidth: 0 }}>
<Stack direction="row" alignItems="center" spacing={0.5} mb={0.5}>
<CalendarMonthIcon fontSize="small" color="primary" />
<Typography variant="body2" color="text.secondary">
<Typography variant="body2" color="text.secondary" sx={{ overflowWrap: 'anywhere' }}>
{formatDateRange(event.date, event.endDate)}
</Typography>
</Stack>
<Stack direction="row" alignItems="center" spacing={0.5}>
<LocationOnIcon fontSize="small" color="primary" />
<Typography variant="body2" color="text.secondary">
<Typography variant="body2" color="text.secondary" sx={{ overflowWrap: 'anywhere' }}>
{event.location.city}
</Typography>
</Stack>
</div>
<InfoOutline sx={{ color: 'text.secondary' }} />
</Box>
<InfoOutline sx={{ color: 'text.secondary', flexShrink: 0, ml: 1 }} />
</Stack>
</CardContent>
</CardActionArea>
@@ -85,13 +89,22 @@ const ListView: React.FC<ListViewProps> = ({ events, onSelect }) => {
return groups
}, [events])
return (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'flex-start', pb: 4 }}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 4, width: '100%', minWidth: 0, pb: 4 }}>
{eventGroups.upcoming.length > 0 && (
<>
<Typography variant="h5" component="h2" textAlign="center" mt={4} mb={2}>
Prossimi eventi
</Typography>
<Box sx={{ display: 'flex', gap: 3, flexWrap: 'wrap' }}>
<Box
role="region"
aria-label="prossimi eventi"
sx={{
display: 'grid',
width: '100%',
minWidth: 0,
gridTemplateColumns: { xs: 'minmax(0, 1fr)', sm: 'repeat(2, minmax(0, 1fr))', lg: 'repeat(3, minmax(0, 1fr))' },
gap: 3,
}}>
{eventGroups.upcoming.map(event => (
<EventCard key={event.id} event={event} onSelect={onSelect} />
))}
@@ -103,7 +116,16 @@ const ListView: React.FC<ListViewProps> = ({ events, onSelect }) => {
<Typography variant="h5" component="h3" textAlign="center" mt={4} mb={2}>
Eventi passati
</Typography>
<Box sx={{ display: 'flex', gap: 3, flexWrap: 'wrap' }}>
<Box
role="region"
aria-label="eventi passati"
sx={{
display: 'grid',
width: '100%',
minWidth: 0,
gridTemplateColumns: { xs: 'minmax(0, 1fr)', sm: 'repeat(2, minmax(0, 1fr))', lg: 'repeat(3, minmax(0, 1fr))' },
gap: 3,
}}>
{eventGroups.past.map(event => (
<EventCard key={event.id} event={event} onSelect={onSelect} />
))}
+1 -1
View File
@@ -68,7 +68,7 @@ const MapView: React.FC<MapViewProps> = ({ events, onSelect }) => {
<MapContainer center={CENTER} zoom={6} scrollWheelZoom style={{ height: 560, width: '100%' }}>
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> &copy; <a href="https://carto.com/">CARTO</a>'
url="https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png"
url={`https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png?key=${import.meta.env.VITE_EV_CARTO_KEY}`}
/>
{sorted.map((event, idx) => (
<Marker
+21 -3
View File
@@ -105,7 +105,26 @@ export const events: Event[] = [
'https://scontent-fco2-1.xx.fbcdn.net/v/t39.30808-6/475772202_928196622760603_187755049466880515_n.jpg?_nc_cat=108&ccb=1-7&_nc_sid=2a1932&_nc_ohc=GFNIVf-3cKoQ7kNvwHWpMoA&_nc_oc=AdqCNjkyT6mYI9D8sIsmAgfQdXtrVMNOthjth3dfcGCvVgxVSJSG_SVWroEcBPbyI7k&_nc_zt=23&_nc_ht=scontent-fco2-1.xx&_nc_gid=nD82EIE8zEzhzr8oQIF78A&_nc_ss=7b2a8&oh=00_Af6Jg9HJBlMy--pZ0eQp_QZ18k1b-hSmMDp-zUC6ID5Yrw&oe=69FFE2CC',
},
{
id: '5',
id: 'Autunno Ducale nelle Terre Estensi',
title: 'Autunno Ducale nelle Terre Estensi',
date: new Date('2026-10-24'),
endDate: new Date('2026-10-25'),
location: {
name: 'Ferrara',
city: 'Ferrara',
lat: 44.5,
lng: 11.37,
link: 'https://maps.app.goo.gl/TYLWP51PvjCjsxdw6',
},
link: 'https://www.prolocoferrara.org/category/eventi/autunno-ducale/',
image: 'https://www.prolocoferrara.org/wp-content/uploads/2026/07/locandina-AUTUNNO-DUCALE-2026.jpg',
details: {
description:
"La Compagnia d'Arme del Santo Luca partecipa al tradizionale Palio di Ferrara con uno spettacolo di combattimento storico e una mostra della vita civile medievale.",
},
},
{
id: 'Usi & Costumi',
title: 'Usi & Costumi',
date: new Date('2026-11-07'),
endDate: new Date('2026-11-08'),
@@ -117,8 +136,7 @@ export const events: Event[] = [
link: 'https://maps.app.goo.gl/q6MgoYrjm1uGxrrD8',
},
link: 'https://www.usiecostumi.org/',
image:
'https://scontent-fco2-1.xx.fbcdn.net/v/t39.30808-6/688923196_1294084136264066_3431102776522875652_n.jpg?_nc_cat=111&ccb=1-7&_nc_sid=2a1932&_nc_ohc=8DTyQeSJaEUQ7kNvwHpXmkS&_nc_oc=AdoKtRJlPuSnY0LgIEkrFSznA6aOekLn9cj09sScE7fPJEQz4YU7GSHIxHTZ0oOcJSw&_nc_zt=23&_nc_ht=scontent-fco2-1.xx&_nc_gid=6_24uMOlLU5IMhQptMgtsg&_nc_ss=7b2a8&oh=00_Af4WsF0pOUJT70MBLbOaRro0wJ1kct7-4dh_dto93ObmWw&oe=69FFD8CE',
image: 'https://www.usiecostumi.org/wp-content/uploads/2024/04/usi-e-costumi-box.jpg',
details: {
description: 'La prima grande fiera internazionale, dedicata alla tradizione come strumento al servizio del turismo sostenibile.',
},
+4 -2
View File
@@ -22,8 +22,10 @@ const EventsPage = () => {
<Page
title="Eventi"
sx={{
width: theme => theme.breakpoints.values.lg,
px: 'auto',
width: '100%',
maxWidth: theme => theme.breakpoints.values.lg,
boxSizing: 'border-box',
px: { xs: 2, sm: 3, md: 4 },
mx: 'auto',
}}>
<Typography>