Started with area page

This commit is contained in:
2025-10-29 10:31:09 +01:00
parent bd2f7b286e
commit b3166811e5
7 changed files with 78 additions and 3 deletions

View File

@@ -18,3 +18,13 @@ async def get_shop(request: Request, session: SessionDep):
"shop.html.jinja",
context={"request": request, "areas": areas},
)
@shop_router.get("/shop/area/{area_id}")
async def get_shop(request: Request, session: SessionDep, area_id: int):
query = select(Area).where(Area.id == area_id)
area = session.scalars(query).one()
return templates.TemplateResponse(
"area.html.jinja",
context={"request": request, "area": area},
)

View File

@@ -1,3 +1,5 @@
import locale
from fastapi import Depends, FastAPI
from fastapi.staticfiles import StaticFiles
@@ -5,6 +7,7 @@ from allmende_payment_system.api import root_router
from allmende_payment_system.api.dependencies import get_user
from allmende_payment_system.api.shop import shop_router
locale.setlocale(locale.LC_ALL, "de_DE.UTF-8")
app = FastAPI(dependencies=[Depends(get_user)])

View File

@@ -55,6 +55,15 @@ class Area(Base):
description: Mapped[str] = mapped_column(nullable=True)
image_path: Mapped[str] = mapped_column(nullable=True)
products: Mapped[list["Product"]] = relationship("Product")
UnitsOfMeasure = typing.Literal[
"g",
"kg",
"piece",
]
class Product(Base):
__tablename__ = TABLE_PREFIX + "product"
@@ -62,11 +71,14 @@ class Product(Base):
name: Mapped[str] = mapped_column(nullable=False, unique=True)
price: Mapped[decimal.Decimal] = mapped_column(Numeric(10, 2))
unit_of_measure: Mapped[UnitsOfMeasure] = mapped_column(nullable=False)
# TODO: limit this to actually used vat rates?
vat_rate: Mapped[decimal.Decimal] = mapped_column(Numeric(10, 2))
area_id: Mapped[int] = mapped_column(ForeignKey(TABLE_PREFIX + "area.id"))
area: Mapped["Area"] = relationship("Area")
area: Mapped["Area"] = relationship("Area", back_populates="products")
image_path: Mapped[str] = mapped_column(nullable=True)
TransactionTypes = typing.Literal[

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -0,0 +1,36 @@
{% extends "base.html.jinja" %}
{% block content %}
<!-- Area Header -->
<div class="mb-4">
<h2 class="h4 mb-3">{{ area.name }}</h2>
<p class="text-muted">{{ area.description or ''}} </p>
</div>
<!-- Products Grid -->
<div class="row g-3">
{% for product in area.products %}
<div class="col-md-6 col-lg-4">
<div class="card h-100 border-0 shadow-sm">
<a href="#" class="text-decoration-none text-dark">
<!-- Product Image -->
<img
src="/static/img/{{ product.image_path if product.image_path else 'placeholder.jpg' }}"
alt="{{ product.name }}"
class="card-img-top img-fluid rounded-top"
style="height: 100px; object-fit: cover;"
>
<!-- Product Details -->
<div class="card-body">
<h5 class="card-title mb-2">{{ product.name }}</h5>
<p class="card-text text-muted small mb-3">{{ product.description }}</p>
<div class="d-flex justify-content-between align-items-center">
<span class="fw-bold">{{ product.price|format_number }} € pro {{ product.unit_of_measure|units_of_measure_de }}</span>
<button class="btn btn-sm btn-outline-primary">Add to Cart</button>
</div>
</div>
</a>
</div>
</div>
{% endfor %}
</div>
{% endblock %}

View File

@@ -9,13 +9,13 @@
<div class="row g-3">
{% for area in areas %}
<div class="col-md-6 col-lg-4">
<a href="#" class="text-decoration-none">
<a href="/shop/area/{{ area.id }}" class="text-decoration-none">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body d-flex align-items-center p-3">
<!-- Image on the left -->
<div class="me-3" style="width: 120px; flex-shrink: 0;">
<img
src="/static/img/{{ area.image_path }}"
src="/static/img/{{ area.image_path if area.image_path !='' else 'placeholder.png'}}" }}"
alt="{{ area.name }}"
class="img-fluid rounded"
style="max-height: 100px; width: 100%; object-fit: contain;"

View File

@@ -1,3 +1,6 @@
import locale
import numbers
from starlette.templating import Jinja2Templates
TRANSACTION_TYPE_DE = {
@@ -7,8 +10,19 @@ TRANSACTION_TYPE_DE = {
"product": "Einkauf",
}
UNITS_OF_MEASURE = {"piece": "Stück"}
def format_number(value: float):
try:
return f"{value:n}"
except TypeError:
return value
def get_jinja_renderer() -> Jinja2Templates:
renderer = Jinja2Templates(directory="src/allmende_payment_system/templates")
renderer.env.filters["transaction_type_de"] = lambda x: TRANSACTION_TYPE_DE[x]
renderer.env.filters["units_of_measure_de"] = lambda x: UNITS_OF_MEASURE.get(x, x)
renderer.env.filters["format_number"] = format_number
return renderer