Compare commits
20 Commits
894316d3ff
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
356d916e26 | ||
|
|
a28424c07c | ||
|
|
37ceb37b82 | ||
|
|
0c9b8d6aa2 | ||
|
|
123f752946 | ||
|
|
a420bfa7f0 | ||
|
|
42f4a8b68f | ||
|
|
e653acb921 | ||
|
|
7eb66fbf24 | ||
|
|
3cc5730377 | ||
|
|
f63a9ec0a7 | ||
|
|
56e32585b7 | ||
|
|
fa9ffa98e5 | ||
|
|
193014a4d8 | ||
|
|
125c9bd64a | ||
|
|
7ba0f349ec | ||
|
|
a1e11c10d4 | ||
|
|
39803578af | ||
|
|
be9563f0d3 | ||
|
|
e19b6c6ce1 |
74
alembic/versions/a1b2c3d4e5f6_add_page_configs_table.py
Normal file
74
alembic/versions/a1b2c3d4e5f6_add_page_configs_table.py
Normal file
@@ -0,0 +1,74 @@
|
||||
"""add page_configs table
|
||||
|
||||
Revision ID: a1b2c3d4e5f6
|
||||
Revises: f6d4a1b2c3e7
|
||||
Create Date: 2026-02-10
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import text
|
||||
|
||||
revision = 'a1b2c3d4e5f6'
|
||||
down_revision = 'f6d4a1b2c3e7'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.create_table(
|
||||
'page_configs',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('post_id', sa.Integer(), nullable=False),
|
||||
sa.Column('features', sa.JSON(), server_default='{}', nullable=False),
|
||||
sa.Column('sumup_merchant_code', sa.String(64), nullable=True),
|
||||
sa.Column('sumup_api_key', sa.Text(), nullable=True),
|
||||
sa.Column('sumup_checkout_prefix', sa.String(64), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
|
||||
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.ForeignKeyConstraint(['post_id'], ['posts.id'], ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('post_id'),
|
||||
)
|
||||
|
||||
# Backfill: create PageConfig for every existing page
|
||||
conn = op.get_bind()
|
||||
|
||||
# 1. Pages with calendars -> features={"calendar": true}
|
||||
conn.execute(text("""
|
||||
INSERT INTO page_configs (post_id, features, created_at, updated_at)
|
||||
SELECT p.id, '{"calendar": true}'::jsonb, now(), now()
|
||||
FROM posts p
|
||||
WHERE p.is_page = true
|
||||
AND p.deleted_at IS NULL
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM calendars c
|
||||
WHERE c.post_id = p.id AND c.deleted_at IS NULL
|
||||
)
|
||||
"""))
|
||||
|
||||
# 2. Market page (slug='market', is_page=true) -> features={"market": true}
|
||||
# Only if not already inserted above
|
||||
conn.execute(text("""
|
||||
INSERT INTO page_configs (post_id, features, created_at, updated_at)
|
||||
SELECT p.id, '{"market": true}'::jsonb, now(), now()
|
||||
FROM posts p
|
||||
WHERE p.slug = 'market'
|
||||
AND p.is_page = true
|
||||
AND p.deleted_at IS NULL
|
||||
AND p.id NOT IN (SELECT post_id FROM page_configs)
|
||||
"""))
|
||||
|
||||
# 3. All other pages -> features={}
|
||||
conn.execute(text("""
|
||||
INSERT INTO page_configs (post_id, features, created_at, updated_at)
|
||||
SELECT p.id, '{}'::jsonb, now(), now()
|
||||
FROM posts p
|
||||
WHERE p.is_page = true
|
||||
AND p.deleted_at IS NULL
|
||||
AND p.id NOT IN (SELECT post_id FROM page_configs)
|
||||
"""))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_table('page_configs')
|
||||
97
alembic/versions/b2c3d4e5f6a7_add_market_places_table.py
Normal file
97
alembic/versions/b2c3d4e5f6a7_add_market_places_table.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""add market_places table and nav_tops.market_id
|
||||
|
||||
Revision ID: b2c3d4e5f6a7
|
||||
Revises: a1b2c3d4e5f6
|
||||
Create Date: 2026-02-10
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import text
|
||||
|
||||
revision = 'b2c3d4e5f6a7'
|
||||
down_revision = 'a1b2c3d4e5f6'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# 1. Create market_places table
|
||||
op.create_table(
|
||||
'market_places',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('post_id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(255), nullable=False),
|
||||
sa.Column('slug', sa.String(255), nullable=False),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
|
||||
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.ForeignKeyConstraint(['post_id'], ['posts.id'], ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
)
|
||||
op.create_index('ix_market_places_post_id', 'market_places', ['post_id'])
|
||||
op.create_index(
|
||||
'ux_market_places_slug_active',
|
||||
'market_places',
|
||||
[sa.text('lower(slug)')],
|
||||
unique=True,
|
||||
postgresql_where=sa.text('deleted_at IS NULL'),
|
||||
)
|
||||
|
||||
# 2. Add market_id column to nav_tops
|
||||
op.add_column(
|
||||
'nav_tops',
|
||||
sa.Column('market_id', sa.Integer(), nullable=True),
|
||||
)
|
||||
op.create_foreign_key(
|
||||
'fk_nav_tops_market_id',
|
||||
'nav_tops',
|
||||
'market_places',
|
||||
['market_id'],
|
||||
['id'],
|
||||
ondelete='SET NULL',
|
||||
)
|
||||
op.create_index('ix_nav_tops_market_id', 'nav_tops', ['market_id'])
|
||||
|
||||
# 3. Backfill: create default MarketPlace for the 'market' page
|
||||
conn = op.get_bind()
|
||||
|
||||
# Find the market page
|
||||
result = conn.execute(text("""
|
||||
SELECT id FROM posts
|
||||
WHERE slug = 'market' AND is_page = true AND deleted_at IS NULL
|
||||
LIMIT 1
|
||||
"""))
|
||||
row = result.fetchone()
|
||||
if row:
|
||||
post_id = row[0]
|
||||
|
||||
# Insert the default market
|
||||
conn.execute(text("""
|
||||
INSERT INTO market_places (post_id, name, slug, created_at, updated_at)
|
||||
VALUES (:post_id, 'Suma Market', 'suma-market', now(), now())
|
||||
"""), {"post_id": post_id})
|
||||
|
||||
# Get the new market_places id
|
||||
market_row = conn.execute(text("""
|
||||
SELECT id FROM market_places
|
||||
WHERE slug = 'suma-market' AND deleted_at IS NULL
|
||||
LIMIT 1
|
||||
""")).fetchone()
|
||||
|
||||
if market_row:
|
||||
market_id = market_row[0]
|
||||
# Assign all active nav_tops to this market
|
||||
conn.execute(text("""
|
||||
UPDATE nav_tops SET market_id = :market_id
|
||||
WHERE deleted_at IS NULL
|
||||
"""), {"market_id": market_id})
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index('ix_nav_tops_market_id', table_name='nav_tops')
|
||||
op.drop_constraint('fk_nav_tops_market_id', 'nav_tops', type_='foreignkey')
|
||||
op.drop_column('nav_tops', 'market_id')
|
||||
op.drop_index('ux_market_places_slug_active', table_name='market_places')
|
||||
op.drop_index('ix_market_places_post_id', table_name='market_places')
|
||||
op.drop_table('market_places')
|
||||
55
alembic/versions/c3d4e5f6a7b8_add_page_tracking_to_orders.py
Normal file
55
alembic/versions/c3d4e5f6a7b8_add_page_tracking_to_orders.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""add page_config_id to orders, market_place_id to cart_items
|
||||
|
||||
Revision ID: c3d4e5f6a7b8
|
||||
Revises: b2c3d4e5f6a7
|
||||
Create Date: 2026-02-10
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = 'c3d4e5f6a7b8'
|
||||
down_revision = 'b2c3d4e5f6a7'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# 1. Add market_place_id to cart_items
|
||||
op.add_column(
|
||||
'cart_items',
|
||||
sa.Column('market_place_id', sa.Integer(), nullable=True),
|
||||
)
|
||||
op.create_foreign_key(
|
||||
'fk_cart_items_market_place_id',
|
||||
'cart_items',
|
||||
'market_places',
|
||||
['market_place_id'],
|
||||
['id'],
|
||||
ondelete='SET NULL',
|
||||
)
|
||||
op.create_index('ix_cart_items_market_place_id', 'cart_items', ['market_place_id'])
|
||||
|
||||
# 2. Add page_config_id to orders
|
||||
op.add_column(
|
||||
'orders',
|
||||
sa.Column('page_config_id', sa.Integer(), nullable=True),
|
||||
)
|
||||
op.create_foreign_key(
|
||||
'fk_orders_page_config_id',
|
||||
'orders',
|
||||
'page_configs',
|
||||
['page_config_id'],
|
||||
['id'],
|
||||
ondelete='SET NULL',
|
||||
)
|
||||
op.create_index('ix_orders_page_config_id', 'orders', ['page_config_id'])
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index('ix_orders_page_config_id', table_name='orders')
|
||||
op.drop_constraint('fk_orders_page_config_id', 'orders', type_='foreignkey')
|
||||
op.drop_column('orders', 'page_config_id')
|
||||
|
||||
op.drop_index('ix_cart_items_market_place_id', table_name='cart_items')
|
||||
op.drop_constraint('fk_cart_items_market_place_id', 'cart_items', type_='foreignkey')
|
||||
op.drop_column('cart_items', 'market_place_id')
|
||||
@@ -13,6 +13,8 @@ from .ghost_membership_entities import (
|
||||
)
|
||||
|
||||
from .calendars import Calendar, CalendarEntry, Ticket
|
||||
from .page_config import PageConfig
|
||||
from .market_place import MarketPlace
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Integer, String, DateTime, ForeignKey, func, Index
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from db.base import Base # you already import Base in app.py
|
||||
# from .user import User # only if you normally import it here
|
||||
# from .coop import Product # if not already in this module
|
||||
|
||||
from .market import Product
|
||||
|
||||
from .user import User
|
||||
|
||||
class CartItem(Base):
|
||||
__tablename__ = "cart_items"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
|
||||
# Either a logged-in user OR an anonymous session
|
||||
user_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("users.id", ondelete="CASCADE"),
|
||||
nullable=True,
|
||||
)
|
||||
session_id: Mapped[str | None] = mapped_column(
|
||||
String(128),
|
||||
nullable=True,
|
||||
)
|
||||
|
||||
# IMPORTANT: link to product *id*, not slug
|
||||
product_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("products.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
quantity: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
nullable=False,
|
||||
default=1,
|
||||
server_default="1",
|
||||
)
|
||||
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
)
|
||||
deleted_at: Mapped[datetime | None] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
)
|
||||
|
||||
# Relationships
|
||||
|
||||
product: Mapped["Product"] = relationship(
|
||||
"Product",
|
||||
back_populates="cart_items",
|
||||
)
|
||||
user: Mapped["User | None"] = relationship("User", back_populates="cart_items")
|
||||
|
||||
__table_args__ = (
|
||||
Index("ix_cart_items_user_product", "user_id", "product_id"),
|
||||
Index("ix_cart_items_session_product", "session_id", "product_id"),
|
||||
)
|
||||
@@ -164,6 +164,22 @@ class Post(Base):
|
||||
order_by="MenuItem.sort_order",
|
||||
)
|
||||
|
||||
page_config: Mapped[Optional["PageConfig"]] = relationship(
|
||||
"PageConfig",
|
||||
back_populates="post",
|
||||
uselist=False,
|
||||
cascade="all, delete-orphan",
|
||||
passive_deletes=True,
|
||||
)
|
||||
|
||||
markets: Mapped[List["MarketPlace"]] = relationship(
|
||||
"MarketPlace",
|
||||
back_populates="post",
|
||||
cascade="all, delete-orphan",
|
||||
passive_deletes=True,
|
||||
order_by="MarketPlace.name",
|
||||
)
|
||||
|
||||
class Author(Base):
|
||||
__tablename__ = "authors"
|
||||
|
||||
|
||||
@@ -186,11 +186,18 @@ class NavTop(Base):
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
label: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
slug: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
|
||||
market_id: Mapped[Optional[int]] = mapped_column(
|
||||
Integer,
|
||||
ForeignKey("market_places.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
|
||||
deleted_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True))
|
||||
|
||||
|
||||
listings: Mapped[List["Listing"]] = relationship(back_populates="top", cascade="all, delete-orphan")
|
||||
market = relationship("MarketPlace", back_populates="nav_tops")
|
||||
|
||||
__table_args__ = (UniqueConstraint("label", "slug", name="uq_nav_tops_label_slug"),)
|
||||
|
||||
@@ -406,13 +413,23 @@ class CartItem(Base):
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
)
|
||||
market_place_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("market_places.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
|
||||
deleted_at: Mapped[datetime | None] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
)
|
||||
|
||||
# Relationships
|
||||
|
||||
|
||||
market_place: Mapped["MarketPlace | None"] = relationship(
|
||||
"MarketPlace",
|
||||
foreign_keys=[market_place_id],
|
||||
)
|
||||
product: Mapped["Product"] = relationship(
|
||||
"Product",
|
||||
back_populates="cart_items",
|
||||
|
||||
54
models/market_place.py
Normal file
54
models/market_place.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Optional, List
|
||||
|
||||
from sqlalchemy import (
|
||||
Integer, String, Text, DateTime, ForeignKey, Index, func, text,
|
||||
)
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from db.base import Base
|
||||
|
||||
|
||||
def utcnow() -> datetime:
|
||||
return datetime.now(timezone.utc)
|
||||
|
||||
|
||||
class MarketPlace(Base):
|
||||
__tablename__ = "market_places"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||
post_id: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
ForeignKey("posts.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
)
|
||||
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
slug: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
description: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||||
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now(),
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now(),
|
||||
)
|
||||
deleted_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
DateTime(timezone=True), nullable=True,
|
||||
)
|
||||
|
||||
post = relationship("Post", back_populates="markets")
|
||||
nav_tops: Mapped[List["NavTop"]] = relationship(
|
||||
"NavTop", back_populates="market",
|
||||
)
|
||||
|
||||
__table_args__ = (
|
||||
Index("ix_market_places_post_id", "post_id"),
|
||||
Index(
|
||||
"ux_market_places_slug_active",
|
||||
func.lower(slug),
|
||||
unique=True,
|
||||
postgresql_where=text("deleted_at IS NULL"),
|
||||
),
|
||||
)
|
||||
@@ -17,6 +17,12 @@ class Order(Base):
|
||||
user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("users.id"), nullable=True)
|
||||
session_id: Mapped[Optional[str]] = mapped_column(String(64), index=True, nullable=True)
|
||||
|
||||
page_config_id: Mapped[Optional[int]] = mapped_column(
|
||||
ForeignKey("page_configs.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
|
||||
status: Mapped[str] = mapped_column(
|
||||
String(32),
|
||||
nullable=False,
|
||||
@@ -68,6 +74,11 @@ class Order(Base):
|
||||
back_populates="order",
|
||||
lazy="selectin",
|
||||
)
|
||||
page_config: Mapped[Optional["PageConfig"]] = relationship(
|
||||
"PageConfig",
|
||||
foreign_keys=[page_config_id],
|
||||
lazy="selectin",
|
||||
)
|
||||
|
||||
|
||||
class OrderItem(Base):
|
||||
|
||||
45
models/page_config.py
Normal file
45
models/page_config.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import Integer, String, Text, DateTime, ForeignKey, func, JSON
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from db.base import Base
|
||||
|
||||
|
||||
class PageConfig(Base):
|
||||
__tablename__ = "page_configs"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
|
||||
post_id: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
ForeignKey("posts.id", ondelete="CASCADE"),
|
||||
unique=True,
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
features: Mapped[dict] = mapped_column(
|
||||
JSON, nullable=False, server_default="{}"
|
||||
)
|
||||
|
||||
# Phase 3: per-page SumUp credentials (NULL until configured)
|
||||
sumup_merchant_code: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
||||
sumup_api_key: Mapped[Optional[str]] = mapped_column(Text(), nullable=True)
|
||||
sumup_checkout_prefix: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
||||
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
deleted_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
DateTime(timezone=True), nullable=True
|
||||
)
|
||||
|
||||
post: Mapped["Post"] = relationship(
|
||||
"Post", back_populates="page_config", foreign_keys=[post_id]
|
||||
)
|
||||
@@ -13,7 +13,7 @@ from suma_browser.app.csrf import generate_csrf_token
|
||||
from suma_browser.app.authz import has_access
|
||||
from suma_browser.app.filters import register as register_filters
|
||||
|
||||
from .urls import coop_url, market_url, cart_url, events_url, login_url
|
||||
from .urls import coop_url, market_url, cart_url, events_url, login_url, page_cart_url
|
||||
|
||||
|
||||
def setup_jinja(app: Quart) -> None:
|
||||
@@ -93,6 +93,7 @@ def setup_jinja(app: Quart) -> None:
|
||||
app.jinja_env.globals["cart_url"] = cart_url
|
||||
app.jinja_env.globals["events_url"] = events_url
|
||||
app.jinja_env.globals["login_url"] = login_url
|
||||
app.jinja_env.globals["page_cart_url"] = page_cart_url
|
||||
|
||||
# register jinja filters
|
||||
register_filters(app)
|
||||
|
||||
@@ -37,6 +37,12 @@ def events_url(path: str = "/") -> str:
|
||||
return app_url("events", path)
|
||||
|
||||
|
||||
def page_cart_url(page_slug: str, path: str = "/") -> str:
|
||||
if not path.startswith("/"):
|
||||
path = "/" + path
|
||||
return cart_url(f"/{page_slug}{path}")
|
||||
|
||||
|
||||
def login_url(next_url: str = "") -> str:
|
||||
if next_url:
|
||||
return coop_url(f"/auth/login/?next={quote(next_url, safe='')}")
|
||||
|
||||
@@ -681,13 +681,9 @@ document.body.addEventListener("htmx:responseError", function (event) {
|
||||
|
||||
document.addEventListener('toggle', function (event) {
|
||||
const details = event.target;
|
||||
console.log('toggle fired on', details.tagName, 'open=', details.open);
|
||||
|
||||
// Only act on <details> elements that were just opened
|
||||
if (details.tagName !== 'DETAILS' || !details.open) return;
|
||||
|
||||
console.log('details opened – closing children');
|
||||
|
||||
// Close any child <details> that are open
|
||||
details.querySelectorAll('details[open]').forEach(function (child) {
|
||||
if (child !== details) {
|
||||
@@ -824,19 +820,3 @@ document.body.addEventListener('htmx:beforeSwap', function (event) {
|
||||
});
|
||||
|
||||
|
||||
document.body.addEventListener('htmx:beforeSwap', function(evt) {
|
||||
console.log('HTMX beforeSwap:', {
|
||||
hasSearch: !!document.getElementById('search-desktop'),
|
||||
target: evt.detail.target,
|
||||
requestURL: evt.detail.xhr?.responseURL,
|
||||
swapStyle: evt.detail.swapStyle,
|
||||
serverResponse: evt.detail.serverResponse.substring(0, 200) + '...'
|
||||
});
|
||||
});
|
||||
|
||||
document.body.addEventListener('htmx:afterSwap', function(evt) {
|
||||
console.log('HTMX afterSwap:', {
|
||||
target: evt.detail.target,
|
||||
hasSearch: !!document.getElementById('search-desktop')
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,8 @@
|
||||
{% call links.link(url_for('auth.newsletters'), hx_select_search, select_colours, True, aclass=styles.nav_button) %}
|
||||
newsletters
|
||||
{% endcall %}
|
||||
{% call links.link(cart_url('/orders/'), hx_select_search, select_colours, True, aclass=styles.nav_button) %}
|
||||
orders
|
||||
{% endcall %}
|
||||
<div class="relative nav-group">
|
||||
<a href="{{ cart_url('/orders/') }}" class="{{styles.nav_button}}">
|
||||
orders
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<div class="overflow-x-auto scrollbar-hide" style="scroll-behavior: smooth;">
|
||||
<div class="flex gap-2 px-2">
|
||||
{% for entry in post.associated_entries %}
|
||||
{% set _entry_path = '/calendars/' + entry.calendar.slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
|
||||
{% set _entry_path = '/' + post.slug + '/calendars/' + entry.calendar.slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
|
||||
<a
|
||||
href="{{ events_url(_entry_path) }}"
|
||||
class="flex flex-col gap-1 px-3 py-2 bg-stone-50 hover:bg-stone-100 rounded border border-stone-200 transition text-sm whitespace-nowrap flex-shrink-0 min-w-[180px]">
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
{# Outer left: -1 year #}
|
||||
<a
|
||||
class="{{styles.pill}} text-xl"
|
||||
href="{{ url_for('blog.post.calendars.calendar.get',
|
||||
href="{{ url_for('calendars.calendar.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=prev_year,
|
||||
month=month) }}"
|
||||
hx-get="{{ url_for('blog.post.calendars.calendar.get',
|
||||
hx-get="{{ url_for('calendars.calendar.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=prev_year,
|
||||
@@ -27,12 +27,12 @@
|
||||
{# Inner left: -1 month #}
|
||||
<a
|
||||
class="{{styles.pill}} text-xl"
|
||||
href="{{ url_for('blog.post.calendars.calendar.get',
|
||||
href="{{ url_for('calendars.calendar.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=prev_month_year,
|
||||
month=prev_month) }}"
|
||||
hx-get="{{ url_for('blog.post.calendars.calendar.get',
|
||||
hx-get="{{ url_for('calendars.calendar.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=prev_month_year,
|
||||
@@ -52,12 +52,12 @@
|
||||
{# Inner right: +1 month #}
|
||||
<a
|
||||
class="{{styles.pill}} text-xl"
|
||||
href="{{ url_for('blog.post.calendars.calendar.get',
|
||||
href="{{ url_for('calendars.calendar.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=next_month_year,
|
||||
month=next_month) }}"
|
||||
hx-get="{{ url_for('blog.post.calendars.calendar.get',
|
||||
hx-get="{{ url_for('calendars.calendar.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=next_month_year,
|
||||
@@ -73,12 +73,12 @@
|
||||
{# Outer right: +1 year #}
|
||||
<a
|
||||
class="{{styles.pill}} text-xl"
|
||||
href="{{ url_for('blog.post.calendars.calendar.get',
|
||||
href="{{ url_for('calendars.calendar.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=next_year,
|
||||
month=month) }}"
|
||||
hx-get="{{ url_for('blog.post.calendars.calendar.get',
|
||||
hx-get="{{ url_for('calendars.calendar.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=next_year,
|
||||
@@ -118,13 +118,13 @@
|
||||
{# Clickable day number: goes to day detail view #}
|
||||
<a
|
||||
class="{{styles.pill}}"
|
||||
href="{{ url_for('blog.post.calendars.calendar.day.show_day',
|
||||
href="{{ url_for('calendars.calendar.day.show_day',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=day.date.year,
|
||||
month=day.date.month,
|
||||
day=day.date.day) }}"
|
||||
hx-get="{{ url_for('blog.post.calendars.calendar.day.show_day',
|
||||
hx-get="{{ url_for('calendars.calendar.day.show_day',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=day.date.year,
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
<!-- Desktop nav -->
|
||||
{% import 'macros/links.html' as links %}
|
||||
{% call links.link(
|
||||
url_for('blog.post.calendars.calendar.slots.get', slug=post.slug, calendar_slug=calendar.slug),
|
||||
hx_select_search,
|
||||
select_colours,
|
||||
aclass=styles.nav_button
|
||||
) %}
|
||||
<a href="{{ events_url('/' + post.slug + '/calendars/' + calendar.slug + '/slots/') }}" class="{{styles.nav_button}}">
|
||||
<i class="fa fa-clock" aria-hidden="true"></i>
|
||||
<div>
|
||||
Slots
|
||||
</div>
|
||||
{% endcall %}
|
||||
<div>Slots</div>
|
||||
</a>
|
||||
{% if g.rights.admin %}
|
||||
{% from 'macros/admin_nav.html' import admin_nav_item %}
|
||||
{{admin_nav_item(url_for('blog.post.calendars.calendar.admin.admin', slug=post.slug, calendar_slug=calendar.slug))}}
|
||||
<a href="{{ events_url('/' + post.slug + '/calendars/' + calendar.slug + '/admin/') }}" class="{{styles.nav_button}}">
|
||||
<i class="fa fa-cog" aria-hidden="true"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
@@ -13,7 +13,7 @@
|
||||
type="button"
|
||||
class="mt-2 text-xs underline"
|
||||
hx-get="{{ url_for(
|
||||
'blog.post.calendars.calendar.admin.calendar_description_edit',
|
||||
'calendars.calendar.admin.calendar_description_edit',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
) }}"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div id="calendar-description">
|
||||
<form
|
||||
hx-post="{{ url_for(
|
||||
'blog.post.calendars.calendar.admin.calendar_description_save',
|
||||
'calendars.calendar.admin.calendar_description_save',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
) }}"
|
||||
@@ -29,7 +29,7 @@
|
||||
type="button"
|
||||
class="px-3 py-1 rounded border"
|
||||
hx-get="{{ url_for(
|
||||
'blog.post.calendars.calendar.admin.calendar_description_view',
|
||||
'calendars.calendar.admin.calendar_description_view',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
) }}"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<form
|
||||
id="calendar-form"
|
||||
method="post"
|
||||
hx-put="{{ url_for('blog.post.calendars.calendar.put', slug=post.slug, calendar_slug=calendar.slug ) }}"
|
||||
hx-put="{{ url_for('calendars.calendar.put', slug=post.slug, calendar_slug=calendar.slug ) }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{ hx_select_search }}"
|
||||
hx-on::before-request="document.querySelector('#cal-put-errors').textContent='';"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% macro header_row(oob=False) %}
|
||||
{% call links.menu_row(id='calendar-admin-row', oob=oob) %}
|
||||
{% call links.link(
|
||||
url_for('blog.post.calendars.calendar.admin.admin', slug=post.slug, calendar_slug=calendar.slug),
|
||||
url_for('calendars.calendar.admin.admin', slug=post.slug, calendar_slug=calendar.slug),
|
||||
hx_select_search
|
||||
) %}
|
||||
{{ links.admin() }}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% import 'macros/links.html' as links %}
|
||||
{% macro header_row(oob=False) %}
|
||||
{% call links.menu_row(id='calendar-row', oob=oob) %}
|
||||
{% call links.link(url_for('blog.post.calendars.calendar.get', slug=post.slug, calendar_slug= calendar.slug), hx_select_search) %}
|
||||
<a href="{{ events_url('/' + post.slug + '/calendars/' + calendar.slug + '/') }}" class="flex items-center gap-2 px-3 py-2 rounded whitespace-normal text-center break-words leading-snug">
|
||||
<div class="flex flex-col md:flex-row md:gap-2 items-center min-w-0">
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<i class="fa fa-calendar"></i>
|
||||
@@ -12,7 +12,7 @@
|
||||
{% from '_types/calendar/_description.html' import description %}
|
||||
{{description(calendar)}}
|
||||
</div>
|
||||
{% endcall %}
|
||||
</a>
|
||||
{% call links.desktop_nav() %}
|
||||
{% include '_types/calendar/_nav.html' %}
|
||||
{% endcall %}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="mt-6 border rounded-lg p-4">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
|
||||
{% set calendar_href = url_for('blog.post.calendars.calendar.get', slug=post.slug, calendar_slug=cal.slug)|host%}
|
||||
{% set calendar_href = url_for('calendars.calendar.get', slug=post.slug, calendar_slug=cal.slug)|host%}
|
||||
<a
|
||||
class="flex items-baseline gap-3"
|
||||
href="{{ calendar_href }}"
|
||||
@@ -27,7 +27,7 @@
|
||||
data-confirm-confirm-text="Yes, delete it"
|
||||
data-confirm-cancel-text="Cancel"
|
||||
data-confirm-event="confirmed"
|
||||
hx-delete="{{ url_for('blog.post.calendars.calendar.delete', slug=post.slug, calendar_slug=cal.slug) }}"
|
||||
hx-delete="{{ url_for('calendars.calendar.delete', slug=post.slug, calendar_slug=cal.slug) }}"
|
||||
hx-trigger="confirmed"
|
||||
hx-target="#calendars-list"
|
||||
hx-select="#calendars-list"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<section class="p-4">
|
||||
{% if has_access('blog.post.calendars.create_calendar') %}
|
||||
{% if has_access('calendars.create_calendar') %}
|
||||
<!-- error container under the inputs -->
|
||||
<div id="cal-create-errors" class="mt-2 text-sm text-red-600"></div>
|
||||
|
||||
<form
|
||||
class="mt-4 flex gap-2 items-end"
|
||||
hx-post="{{ url_for('blog.post.calendars.create_calendar', slug=post.slug) }}"
|
||||
hx-post="{{ url_for('calendars.create_calendar', slug=post.slug) }}"
|
||||
hx-target="#calendars-list"
|
||||
hx-select="#calendars-list"
|
||||
hx-swap="outerHTML"
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
{% import 'macros/links.html' as links %}
|
||||
{% macro header_row(oob=False) %}
|
||||
{% call links.menu_row(id='calendars-row', oob=oob) %}
|
||||
{% call links.link(events_url('/calendars/'), hx_select_search) %}
|
||||
<a href="{{ events_url('/' + post.slug + '/calendars/') }}" class="flex gap-2 px-3 py-2 rounded whitespace-normal text-center break-words leading-snug">
|
||||
<i class="fa fa-calendar" aria-hidden="true"></i>
|
||||
<div>
|
||||
Calendars
|
||||
</div>
|
||||
{% endcall %}
|
||||
<div>Calendars</div>
|
||||
</a>
|
||||
{% call links.desktop_nav() %}
|
||||
{% include '_types/calendars/_nav.html' %}
|
||||
{% endcall %}
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
{% if g.user %}
|
||||
<form
|
||||
method="post"
|
||||
action="{{ url_for('cart.checkout')|host }}"
|
||||
action="{{ url_for('page_cart.page_checkout')|host if page_post is defined and page_post else url_for('cart_global.checkout')|host }}"
|
||||
class="w-full"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<div>
|
||||
<a
|
||||
href="{{ url_for('cart.view_cart')|host }}"
|
||||
href="{{ cart_url('/') }}"
|
||||
class="inline-flex items-center px-3 py-2 text-xs sm:text-sm rounded-full border border-stone-300 bg-white hover:bg-stone-50 transition"
|
||||
>
|
||||
<i class="fa fa-shopping-cart mr-2" aria-hidden="true"></i>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% import 'macros/links.html' as links %}
|
||||
{% macro header_row(oob=False) %}
|
||||
{% call links.menu_row(id='cart-row', oob=oob) %}
|
||||
{% call links.link(url_for('cart.view_cart'), hx_select_search ) %}
|
||||
{% call links.link(cart_url('/'), hx_select_search ) %}
|
||||
<i class="fa fa-shopping-cart"></i>
|
||||
<h2 class="text-xl font-bold">cart</h2>
|
||||
{% endcall %}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<form
|
||||
class="mt-4 grid grid-cols-1 md:grid-cols-4 gap-2"
|
||||
hx-post="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.add_entry',
|
||||
'calendars.calendar.day.calendar_entries.add_entry',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
@@ -124,7 +124,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.cancel_button}}"
|
||||
hx-get="{{ url_for('blog.post.calendars.calendar.day.calendar_entries.add_button',
|
||||
hx-get="{{ url_for('calendars.calendar.day.calendar_entries.add_button',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
type="button"
|
||||
class="{{styles.pre_action_button}}"
|
||||
hx-get="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.add_form',
|
||||
'calendars.calendar.day.calendar_entries.add_form',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
||||
{% call(entry) scrolling_menu('day-entries-container', confirmed_entries) %}
|
||||
<a
|
||||
href="{{ url_for('blog.post.calendars.calendar.day.calendar_entries.calendar_entry.get',
|
||||
href="{{ url_for('calendars.calendar.day.calendar_entries.calendar_entry.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=day_date.year,
|
||||
@@ -30,7 +30,7 @@
|
||||
{% from 'macros/admin_nav.html' import admin_nav_item %}
|
||||
{{admin_nav_item(
|
||||
url_for(
|
||||
'blog.post.calendars.calendar.day.admin.admin',
|
||||
'calendars.calendar.day.admin.admin',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=day_date.year,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="font-medium">
|
||||
{% call links.link(
|
||||
url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.get',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
@@ -24,7 +24,7 @@
|
||||
<div class="text-xs font-medium">
|
||||
{% call links.link(
|
||||
url_for(
|
||||
'blog.post.calendars.calendar.slots.slot.get',
|
||||
'calendars.calendar.slots.slot.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
slot_id=entry.slot.id
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
||||
{% call(entry) scrolling_menu('day-entries-container', confirmed_entries) %}
|
||||
<a
|
||||
href="{{ url_for('blog.post.calendars.calendar.day.calendar_entries.calendar_entry.get',
|
||||
href="{{ url_for('calendars.calendar.day.calendar_entries.calendar_entry.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=day_date.year,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{% call links.menu_row(id='day-admin-row', oob=oob) %}
|
||||
{% call links.link(
|
||||
url_for(
|
||||
'blog.post.calendars.calendar.day.admin.admin',
|
||||
'calendars.calendar.day.admin.admin',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=day_date.year,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{% call links.menu_row(id='day-row', oob=oob) %}
|
||||
{% call links.link(
|
||||
url_for(
|
||||
'blog.post.calendars.calendar.day.show_day',
|
||||
'calendars.calendar.day.show_day',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=day_date.year,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<form
|
||||
class="space-y-3 mt-4"
|
||||
hx-put="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.put',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.put',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day, month=month, year=year,
|
||||
@@ -163,7 +163,7 @@
|
||||
type="button"
|
||||
class="{{ styles.cancel_button }}"
|
||||
hx-get="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.get',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day, month=month, year=year,
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
type="button"
|
||||
class="{{styles.pre_action_button}}"
|
||||
hx-get="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.get_edit',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.get_edit',
|
||||
entry_id=entry.id,
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
||||
{% call(entry_post) scrolling_menu('entry-posts-container', entry_posts) %}
|
||||
<a
|
||||
href="{{ url_for('blog.post.post_detail', slug=entry_post.slug) }}"
|
||||
href="{{ coop_url('/' + entry_post.slug + '/') }}"
|
||||
class="flex items-center gap-2 px-3 py-2 hover:bg-stone-100 rounded transition text-sm border sm:whitespace-nowrap sm:flex-shrink-0">
|
||||
{% if entry_post.feature_image %}
|
||||
<img src="{{ entry_post.feature_image }}"
|
||||
@@ -28,7 +28,7 @@
|
||||
{% from 'macros/admin_nav.html' import admin_nav_item %}
|
||||
{{admin_nav_item(
|
||||
url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.admin.admin',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.admin.admin',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% if entry.state == 'provisional' %}
|
||||
<form
|
||||
hx-post="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.confirm_entry',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.confirm_entry',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
@@ -32,7 +32,7 @@
|
||||
</form>
|
||||
<form
|
||||
hx-post="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.decline_entry',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.decline_entry',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
@@ -64,7 +64,7 @@
|
||||
{% if entry.state == 'confirmed' %}
|
||||
<form
|
||||
hx-post="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.provisional_entry',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.provisional_entry',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% for search_post in search_posts %}
|
||||
<form
|
||||
hx-post="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.add_post',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.add_post',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
@@ -42,7 +42,7 @@
|
||||
<div
|
||||
id="post-search-sentinel-{{ page }}"
|
||||
hx-get="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.search_posts',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.search_posts',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
data-confirm-cancel-text="Cancel"
|
||||
data-confirm-event="confirmed"
|
||||
hx-delete="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.remove_post',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.remove_post',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
@@ -56,7 +56,7 @@
|
||||
placeholder="Search posts..."
|
||||
class="w-full px-3 py-2 border rounded text-sm"
|
||||
hx-get="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.search_posts',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.search_posts',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
id="ticket-form-{{entry.id}}"
|
||||
class="{% if entry.ticket_price is not none %}hidden{% endif %} space-y-3 mt-2 p-3 border rounded bg-stone-50"
|
||||
hx-post="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.update_tickets',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.update_tickets',
|
||||
entry_id=entry.id,
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% import 'macros/links.html' as links %}
|
||||
{% call links.link(
|
||||
url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.get',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
entry_id=entry.id,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
||||
{% call(entry_post) scrolling_menu('entry-posts-container', entry_posts) %}
|
||||
<a
|
||||
href="{{ url_for('blog.post.post_detail', slug=entry_post.slug) }}"
|
||||
href="{{ coop_url('/' + entry_post.slug + '/') }}"
|
||||
class="{{styles.nav_button}}"
|
||||
>
|
||||
{% if entry_post.feature_image %}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{% call links.menu_row(id='entry-admin-row', oob=oob) %}
|
||||
{% call links.link(
|
||||
url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.admin.admin',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.admin.admin',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{% call links.menu_row(id='entry-row', oob=oob) %}
|
||||
{% call links.link(
|
||||
url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.get',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
{% set has_more_entries = has_more if has_more is defined else (associated_entries.has_more if associated_entries is defined else False) %}
|
||||
|
||||
{% for entry in entry_list %}
|
||||
{% set _entry_path = '/calendars/' + entry.calendar.slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
|
||||
{% set _entry_path = '/' + post.slug + '/calendars/' + entry.calendar.slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
|
||||
<a
|
||||
href="{{ events_url(_entry_path) }}"
|
||||
class="{{styles.nav_button_less_pad}}"
|
||||
|
||||
@@ -6,11 +6,3 @@
|
||||
{% include '_types/post/admin/_nav_entries.html' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Admin link #}
|
||||
{% if post and has_access('blog.post.admin.admin') %}
|
||||
{% import 'macros/links.html' as links %}
|
||||
{% call links.link(url_for('blog.post.admin.admin', slug=post.slug), hx_select_search, select_colours, True, aclass=styles.nav_button) %}
|
||||
<i class="fa fa-cog" aria-hidden="true"></i>
|
||||
{% endcall %}
|
||||
{% endif %}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
{% import 'macros/links.html' as links %}
|
||||
{% call links.link(events_url('/calendars/'), hx_select_search, select_colours, True, aclass=styles.nav_button) %}
|
||||
calendars
|
||||
{% endcall %}
|
||||
<div class="relative nav-group">
|
||||
<a href="{{ events_url('/' + post.slug + '/calendars/') }}" class="{{styles.nav_button}}">
|
||||
calendars
|
||||
</a>
|
||||
</div>
|
||||
{% call links.link(url_for('blog.post.admin.entries', slug=post.slug), hx_select_search, select_colours, True, aclass=styles.nav_button) %}
|
||||
entries
|
||||
{% endcall %}
|
||||
|
||||
@@ -29,19 +29,24 @@
|
||||
|
||||
{# Calendars #}
|
||||
{% for calendar in calendars %}
|
||||
{% set local_href=events_url('/calendars/' + calendar.slug + '/') %}
|
||||
{% set local_href=events_url('/' + post.slug + '/calendars/' + calendar.slug + '/') %}
|
||||
<a
|
||||
href="{{ local_href }}"
|
||||
hx-get="{{ local_href }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{ hx_select_search }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
class="{{styles.nav_button_less_pad}}">
|
||||
<i class="fa fa-calendar" aria-hidden="true"></i>
|
||||
<div>{{calendar.name}}</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
|
||||
{# Markets #}
|
||||
{% for m in markets %}
|
||||
<a
|
||||
href="{{ market_url('/' + post.slug + '/' + m.slug + '/') }}"
|
||||
class="{{styles.nav_button_less_pad}}">
|
||||
<i class="fa fa-shopping-bag" aria-hidden="true"></i>
|
||||
<div>{{m.name}}</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% import 'macros/links.html' as links %}
|
||||
{% macro header_row(oob=False) %}
|
||||
{% call links.menu_row(id='post-row', oob=oob) %}
|
||||
{% call links.link(url_for('blog.post.post_detail', slug=post.slug), hx_select_search ) %}
|
||||
<a href="{{ coop_url('/' + post.slug + '/') }}" class="flex items-center gap-2 px-3 py-2 rounded whitespace-normal text-center break-words leading-snug">
|
||||
{% if post.feature_image %}
|
||||
<img
|
||||
src="{{ post.feature_image }}"
|
||||
@@ -11,8 +11,8 @@
|
||||
<span>
|
||||
{{ post.title | truncate(160, True, '…') }}
|
||||
</span>
|
||||
{% endcall %}
|
||||
{% call links.desktop_nav() %}
|
||||
</a>
|
||||
{% call links.desktop_nav() %}
|
||||
{% include '_types/post/_nav.html' %}
|
||||
{% endcall %}
|
||||
{% endcall %}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
{% import 'macros/links.html' as links %}
|
||||
{% macro header_row(oob=False) %}
|
||||
{% call links.menu_row(id='post_data-row', oob=oob) %}
|
||||
{% call links.link(events_url('/calendars/'), hx_select_search) %}
|
||||
<i class="fa fa-database" aria-hidden="true"></i>
|
||||
<div>
|
||||
data
|
||||
</div>
|
||||
{% endcall %}
|
||||
<a href="{{ events_url('/' + post.slug + '/calendars/') }}" class="flex gap-2 px-3 py-2 rounded whitespace-normal text-center break-words leading-snug">
|
||||
<i class="fa fa-database" aria-hidden="true"></i>
|
||||
<div>data</div>
|
||||
</a>
|
||||
{% call links.desktop_nav() %}
|
||||
{#% include '_types/post_data/_nav.html' %#}
|
||||
{% endcall %}
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
{% if not quantity %}
|
||||
<form
|
||||
action="{{ market_url('/product/' + slug + '/cart') }}"
|
||||
action="{{ url_for('market.browse.product.cart', slug=slug) }}"
|
||||
method="post"
|
||||
hx-post="{{ market_url('/product/' + slug + '/cart') }}"
|
||||
hx-post="{{ url_for('market.browse.product.cart', slug=slug) }}"
|
||||
hx-target="#cart-mini"
|
||||
hx-swap="outerHTML"
|
||||
class="rounded flex items-center"
|
||||
@@ -38,9 +38,9 @@
|
||||
<div class="rounded flex items-center gap-2">
|
||||
<!-- minus -->
|
||||
<form
|
||||
action="{{ market_url('/product/' + slug + '/cart') }}"
|
||||
action="{{ url_for('market.browse.product.cart', slug=slug) }}"
|
||||
method="post"
|
||||
hx-post="{{ market_url('/product/' + slug + '/cart') }}"
|
||||
hx-post="{{ url_for('market.browse.product.cart', slug=slug) }}"
|
||||
hx-target="#cart-mini"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
@@ -80,9 +80,9 @@
|
||||
|
||||
<!-- plus -->
|
||||
<form
|
||||
action="{{ market_url('/product/' + slug + '/cart') }}"
|
||||
action="{{ url_for('market.browse.product.cart', slug=slug) }}"
|
||||
method="post"
|
||||
hx-post="{{ market_url('/product/' + slug + '/cart') }}"
|
||||
hx-post="{{ url_for('market.browse.product.cart', slug=slug) }}"
|
||||
hx-target="#cart-mini"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
@@ -139,7 +139,7 @@
|
||||
<div class="flex flex-col sm:flex-row sm:items-start justify-between gap-2 sm:gap-3">
|
||||
<div class="min-w-0">
|
||||
<h2 class="text-sm sm:text-base md:text-lg font-semibold text-stone-900">
|
||||
{% set href=market_url('/product/' + p.slug + '/') %}
|
||||
{% set href=url_for('market.browse.product.product_detail', slug=p.slug) %}
|
||||
<a
|
||||
href="{{ href }}"
|
||||
hx_get="{{href}}"
|
||||
@@ -189,9 +189,9 @@
|
||||
<div class="flex items-center gap-2 text-xs sm:text-sm text-stone-700">
|
||||
<span class="text-[0.65rem] sm:text-xs uppercase tracking-wide text-stone-500">Quantity</span>
|
||||
<form
|
||||
action="{{ market_url('/product/' + p.slug + '/cart') }}"
|
||||
action="{{ url_for('market.browse.product.cart', slug=p.slug) }}"
|
||||
method="post"
|
||||
hx-post="{{ market_url('/product/' + p.slug + '/cart') }}"
|
||||
hx-post="{{ url_for('market.browse.product.cart', slug=p.slug) }}"
|
||||
hx-target="#cart-mini"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
@@ -212,9 +212,9 @@
|
||||
{{ item.quantity }}
|
||||
</span>
|
||||
<form
|
||||
action="{{ market_url('/product/' + p.slug + '/cart') }}"
|
||||
action="{{ url_for('market.browse.product.cart', slug=p.slug) }}"
|
||||
method="post"
|
||||
hx-post="{{ market_url('/product/' + p.slug + '/cart') }}"
|
||||
hx-post="{{ url_for('market.browse.product.cart', slug=p.slug) }}"
|
||||
hx-target="#cart-mini"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% set _app_slugs = {'market': market_url('/'), 'cart': cart_url('/')} %}
|
||||
{% set _app_slugs = {'cart': cart_url('/')} %}
|
||||
<div class="flex flex-col sm:flex-row sm:items-center gap-2 border-r border-stone-200 mr-2 sm:max-w-2xl"
|
||||
id="menu-items-nav-wrapper">
|
||||
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% import 'macros/links.html' as links %}
|
||||
{% if has_access('settings.home') %}
|
||||
{% if g.rights.admin %}
|
||||
<a href="{{ coop_url('/settings/') }}" class="{{styles.nav_button}}">
|
||||
<i class="fa fa-cog" aria-hidden="true"></i>
|
||||
</a>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div id="slot-errors" class="mt-2 text-sm text-red-600"></div>
|
||||
<form
|
||||
class="space-y-3 mt-4"
|
||||
hx-put="{{ url_for('blog.post.calendars.calendar.slots.slot.put',
|
||||
hx-put="{{ url_for('calendars.calendar.slots.slot.put',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
slot_id=slot.id) }}"
|
||||
@@ -154,7 +154,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.cancel_button}}"
|
||||
hx-get="{{ url_for('blog.post.calendars.calendar.slots.slot.get_view',
|
||||
hx-get="{{ url_for('calendars.calendar.slots.slot.get_view',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
slot_id=slot.id) }}"
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
type="button"
|
||||
class="{{styles.pre_action_button}}"
|
||||
hx-get="{{ url_for(
|
||||
'blog.post.calendars.calendar.slots.slot.get_edit',
|
||||
'calendars.calendar.slots.slot.get_edit',
|
||||
slot_id=slot.id,
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% macro header_row(oob=False) %}
|
||||
{% call links.menu_row(id='slot-row', oob=oob) %}
|
||||
{% call links.link(
|
||||
url_for('blog.post.calendars.calendar.slots.slot.get', slug=post.slug, calendar_slug=calendar.slug, slot_id=slot.id),
|
||||
url_for('calendars.calendar.slots.slot.get', slug=post.slug, calendar_slug=calendar.slug, slot_id=slot.id),
|
||||
hx_select_search,
|
||||
) %}
|
||||
<div class="flex flex-col md:flex-row md:gap-2 items-center">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<form
|
||||
hx-post="{{ url_for('blog.post.calendars.calendar.slots.post',
|
||||
hx-post="{{ url_for('calendars.calendar.slots.post',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug) }}"
|
||||
hx-target="#slots-table"
|
||||
@@ -99,7 +99,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.cancel_button}}"
|
||||
hx-get="{{ url_for('blog.post.calendars.calendar.slots.add_button',
|
||||
hx-get="{{ url_for('calendars.calendar.slots.add_button',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug) }}"
|
||||
hx-target="#slot-add-container"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.pre_action_button}}"
|
||||
hx-get="{{ url_for('blog.post.calendars.calendar.slots.add_form',
|
||||
hx-get="{{ url_for('calendars.calendar.slots.add_form',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug) }}"
|
||||
hx-target="#slot-add-container"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<td class="p-2 align-top w-1/6">
|
||||
<div class="font-medium">
|
||||
{% call links.link(
|
||||
url_for('blog.post.calendars.calendar.slots.slot.get', slug=post.slug, calendar_slug=calendar.slug, slot_id=s.id),
|
||||
url_for('calendars.calendar.slots.slot.get', slug=post.slug, calendar_slug=calendar.slug, slot_id=s.id),
|
||||
hx_select_search,
|
||||
aclass=styles.pill
|
||||
) %}
|
||||
@@ -46,7 +46,7 @@
|
||||
data-confirm-confirm-text="Yes, delete it"
|
||||
data-confirm-cancel-text="Cancel"
|
||||
data-confirm-event="confirmed"
|
||||
hx-delete="{{ url_for('blog.post.calendars.calendar.slots.slot.slot_delete',
|
||||
hx-delete="{{ url_for('calendars.calendar.slots.slot.slot_delete',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
slot_id=s.id) }}"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% macro header_row(oob=False) %}
|
||||
{% call links.menu_row(id='slots-row', oob=oob) %}
|
||||
{% call links.link(
|
||||
url_for('blog.post.calendars.calendar.slots.get', slug=post.slug, calendar_slug= calendar.slug),
|
||||
url_for('calendars.calendar.slots.get', slug=post.slug, calendar_slug= calendar.slug),
|
||||
hx_select_search,
|
||||
) %}
|
||||
<i class="fa fa-clock"></i>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div id="ticket-errors" class="mt-2 text-sm text-red-600"></div>
|
||||
<form
|
||||
class="space-y-3 mt-4"
|
||||
hx-put="{{ url_for('blog.post.calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.put',
|
||||
hx-put="{{ url_for('calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.put',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=year,
|
||||
@@ -71,7 +71,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.cancel_button}}"
|
||||
hx-get="{{ url_for('blog.post.calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get_view',
|
||||
hx-get="{{ url_for('calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get_view',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
entry_id=entry.id,
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
type="button"
|
||||
class="{{styles.pre_action_button}}"
|
||||
hx-get="{{ url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get_edit',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get_edit',
|
||||
ticket_type_id=ticket_type.id,
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{% call links.menu_row(id='ticket_type-row', oob=oob) %}
|
||||
{% call links.link(
|
||||
url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=year,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<form
|
||||
hx-post="{{ url_for('blog.post.calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.post',
|
||||
hx-post="{{ url_for('calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.post',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
entry_id=entry.id,
|
||||
@@ -56,7 +56,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.cancel_button}}"
|
||||
hx-get="{{ url_for('blog.post.calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.add_button',
|
||||
hx-get="{{ url_for('calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.add_button',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
entry_id=entry.id,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<button
|
||||
class="{{styles.action_button}}"
|
||||
hx-get="{{ url_for('blog.post.calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.add_form',
|
||||
hx-get="{{ url_for('calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.add_form',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
entry_id=entry.id,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="font-medium">
|
||||
{% call links.link(
|
||||
url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=year,
|
||||
@@ -36,7 +36,7 @@
|
||||
data-confirm-confirm-text="Yes, delete it"
|
||||
data-confirm-cancel-text="Cancel"
|
||||
data-confirm-event="confirmed"
|
||||
hx-delete="{{ url_for('blog.post.calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.delete',
|
||||
hx-delete="{{ url_for('calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.delete',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
year=year,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% macro header_row(oob=False) %}
|
||||
{% call links.menu_row(id='ticket_types-row', oob=oob) %}
|
||||
{% call links.link(url_for(
|
||||
'blog.post.calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.get',
|
||||
'calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.get',
|
||||
slug=post.slug,
|
||||
calendar_slug=calendar.slug,
|
||||
entry_id=entry.id,
|
||||
|
||||
Reference in New Issue
Block a user