Add pagination for past events

This commit is contained in:
2026-07-03 14:59:07 +02:00
parent 0571b9fdd9
commit 2e5ac73bf2
3 changed files with 62 additions and 11 deletions

View File

@@ -12,7 +12,7 @@ from fastapi.responses import FileResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from pydantic import BaseModel, BeforeValidator, validator from pydantic import BaseModel, BeforeValidator, validator
from sqlalchemy import create_engine, select from sqlalchemy import create_engine, func, select
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from meal_manager.grist import sync_with_grist from meal_manager.grist import sync_with_grist
@@ -93,12 +93,13 @@ SessionDep = Annotated[Session, Depends(get_session)]
UserDep = Annotated[dict, Depends(get_user)] UserDep = Annotated[dict, Depends(get_user)]
StrictUserDep = Annotated[dict, Depends(partial(get_user, allow_none=False))] StrictUserDep = Annotated[dict, Depends(partial(get_user, allow_none=False))]
PAGE_SIZE = 18
@app.get("/") @app.get("/")
async def index(request: Request, session: SessionDep, user: UserDep): async def index(request: Request, session: SessionDep, user: UserDep):
"""Displays coming events and a button to register new ones""" """Displays coming events and a button to register new ones"""
now = datetime.now() now = datetime.now()
# TODO: Once we refactored to use SQLAlchemy directly, we can probably do a nicer filtering on the date alone
statement = ( statement = (
select(Event) select(Event)
.order_by(Event.event_time) .order_by(Event.event_time)
@@ -108,7 +109,14 @@ async def index(request: Request, session: SessionDep, user: UserDep):
return templates.TemplateResponse( return templates.TemplateResponse(
request=request, request=request,
name="index.html", name="index.html",
context={"events": events, "current_page": "home", "now": now, "user": user}, context={
"now": now,
"total_pages": 1,
"page": {
"page_number": 1,
"events": events,
},
},
) )
@@ -117,20 +125,39 @@ async def robots_txt():
return FileResponse("src/meal_manager/static/robots.txt", media_type="text/plain") return FileResponse("src/meal_manager/static/robots.txt", media_type="text/plain")
@app.get("/past_events") @app.get("/past_events/{page_number}")
async def past_events(request: Request, session: SessionDep): async def past_events(request: Request, session: SessionDep, page_number: int):
now = datetime.now() now = datetime.now()
# TODO: Once we refactored to use SQLAlchemy directly, we can probably do a nicer filtering on the date alone
statement = ( statement = (
select(Event) select(Event)
.order_by(Event.event_time)
.where(Event.event_time < now - timedelta(days=1)) .where(Event.event_time < now - timedelta(days=1))
.order_by(Event.event_time.desc())
.offset((page_number - 1) * PAGE_SIZE)
.limit(PAGE_SIZE)
) )
events = session.scalars(statement) events = session.scalars(statement)
num_past_events = (
session.query(func.count(Event.id))
.where(Event.event_time < func.datetime("now", "-1 day"))
.scalar()
)
assert num_past_events is not None, "num_past_events should not be None"
total_pages = num_past_events // PAGE_SIZE + 1
return templates.TemplateResponse( return templates.TemplateResponse(
request=request, request=request,
name="index.html", name="index.html",
context={"events": events, "current_page": "past", "now": now}, context={
"now": now,
"total_pages": total_pages,
"page": {
"page_number": page_number,
"events": events,
},
},
) )

View File

@@ -25,7 +25,7 @@
<a class="nav-link {% if current_page == 'home' %}active{% endif %}" {% if current_page == 'home' %}aria-current="page"{% endif %} href="/">Kommende</a> <a class="nav-link {% if current_page == 'home' %}active{% endif %}" {% if current_page == 'home' %}aria-current="page"{% endif %} href="/">Kommende</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link {% if current_page == 'past' %}active{% endif %}" {% if current_page == 'past' %}aria-current="page"{% endif %} href="/past_events">Vergangene</a> <a class="nav-link {% if current_page == 'past' %}active{% endif %}" {% if current_page == 'past' %}aria-current="page"{% endif %} href="/past_events/1/">Vergangene</a>
</li> </li>
<!-- <li class="nav-item">--> <!-- <li class="nav-item">-->
<!-- <a class="nav-link {% if current_page == 'preise' %}active{% endif %}" {% if current_page == 'preise' %}aria-current="page"{% endif %} href="/preise">Preise</a>--> <!-- <a class="nav-link {% if current_page == 'preise' %}active{% endif %}" {% if current_page == 'preise' %}aria-current="page"{% endif %} href="/preise">Preise</a>-->

View File

@@ -32,7 +32,7 @@
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4"> <div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
{% for event in events %} {% for event in page.events %}
<div class="col"> <div class="col">
<div class="card h-100 shadow-sm"> <div class="card h-100 shadow-sm">
<div class="card-body"> <div class="card-body">
@@ -49,13 +49,37 @@
</div> </div>
<p class="text-muted mb-3"><i class="bi bi-calendar"></i> {{ event.event_time.strftime('%A, %d.%m.%Y') }}</p> <p class="text-muted mb-3"><i class="bi bi-calendar"></i> {{ event.event_time.strftime('%A, %d.%m.%Y') }}</p>
<p class="card-text">{{ event.description }}</p> <p class="card-text">{{ event.description }}</p>
<a href="event/{{ event.id }}" class="btn btn-sm {% if event.registration_deadline > now %}btn-primary{% else %}btn-secondary{% endif %}">{% if event.registration_deadline > now %}Zur Anmeldung{% else %}Details ansehen{% endif %}</a> <a href="/event/{{ event.id }}" class="btn btn-sm {% if event.registration_deadline > now %}btn-primary{% else %}btn-secondary{% endif %}">{% if event.registration_deadline > now %}Zur Anmeldung{% else %}Details ansehen{% endif %}</a>
</div> </div>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
{% if total_pages and total_pages > 1 %}
<nav aria-label="Event pagination">
<ul class="pagination justify-content-center my-4">
<li class="page-item {% if page.page_number <= 1 %}disabled{% endif %}">
<a class="page-link" href="{% if page.page_number == 'home' %}/?page={{ page.page_number - 1 }}{% else %}/past_events/{{ page.page_number - 1 }}/{% endif %}" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
<span class="visually-hidden">Zurück</span>
</a>
</li>
{% for p in range(1, total_pages + 1) %}
<li class="page-item {% if page.page_number == p %}active{% endif %}">
<a class="page-link" href="{% if page.page_number == 'home' %}/?page={{ p }}{% else %}/past_events/{{ p }}/{% endif %}">{{ p }}</a>
</li>
{% endfor %}
<li class="page-item {% if page.page_number >= total_pages %}disabled{% endif %}">
<a class="page-link" href="{% if page.page_number == 'home' %}/?page={{ page.page_number + 1 }}{% else %}/past_events/{{ page.page_number + 1 }}/{% endif %}" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
<span class="visually-hidden">Weiter</span>
</a>
</li>
</ul>
</nav>
{% endif %}
<!-- Modal --> <!-- Modal -->
{{ macros.login_info_modal() }} {{ macros.login_info_modal() }}
{% endblock %} {% endblock %}