mirror of
https://github.com/pretix/pretix.git
synced 2026-08-22 12:42:00 +00:00
Event calendar: Allow to show a message if no events are found
This commit is contained in:
@@ -933,6 +933,23 @@ DEFAULTS = {
|
|||||||
"is over. You can use it to describe other options to get a ticket, such as a box office.")
|
"is over. You can use it to describe other options to get a ticket, such as a box office.")
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
'event_list_empty_text': {
|
||||||
|
'default': LazyI18nString.from_gettext(
|
||||||
|
gettext_noop('No dates are currently available for sale that match your criteria.'),
|
||||||
|
),
|
||||||
|
'type': LazyI18nString,
|
||||||
|
'form_class': I18nFormField,
|
||||||
|
'serializer_class': I18nField,
|
||||||
|
'form_kwargs': dict(
|
||||||
|
label=pgettext_lazy("subevents", "Text for empty date results"),
|
||||||
|
widget=I18nMarkdownTextarea,
|
||||||
|
widget_kwargs={'attrs': {'rows': '2'}},
|
||||||
|
help_text=pgettext_lazy("subevents", "This text will be shown if the calendar or list of dates is empty, "
|
||||||
|
"e.g. because a month does not contain any dates or a filter chosen by the user does "
|
||||||
|
"find any results. You can use this to advertise ways to get in touch with you to "
|
||||||
|
"arrange further dates. We do not recommend more than one or two sentences.")
|
||||||
|
)
|
||||||
|
},
|
||||||
'payment_explanation': {
|
'payment_explanation': {
|
||||||
'default': '',
|
'default': '',
|
||||||
'type': LazyI18nString,
|
'type': LazyI18nString,
|
||||||
|
|||||||
@@ -600,6 +600,7 @@ class EventSettingsForm(EventSettingsValidationMixin, FormPlaceholderMixin, Sett
|
|||||||
'imprint_url',
|
'imprint_url',
|
||||||
'checkout_email_helptext',
|
'checkout_email_helptext',
|
||||||
'presale_has_ended_text',
|
'presale_has_ended_text',
|
||||||
|
'event_list_empty_text',
|
||||||
'voucher_explanation_text',
|
'voucher_explanation_text',
|
||||||
'checkout_success_text',
|
'checkout_success_text',
|
||||||
'show_dates_on_frontpage',
|
'show_dates_on_frontpage',
|
||||||
@@ -734,6 +735,7 @@ class EventSettingsForm(EventSettingsValidationMixin, FormPlaceholderMixin, Sett
|
|||||||
del self.fields['event_list_available_only']
|
del self.fields['event_list_available_only']
|
||||||
del self.fields['event_list_filters']
|
del self.fields['event_list_filters']
|
||||||
del self.fields['event_calendar_future_only']
|
del self.fields['event_calendar_future_only']
|
||||||
|
del self.fields['event_list_empty_text']
|
||||||
self.fields['primary_font'].choices = [('Open Sans', 'Open Sans')] + sorted([
|
self.fields['primary_font'].choices = [('Open Sans', 'Open Sans')] + sorted([
|
||||||
(a, FontSelect.FontOption(title=a, data=v)) for a, v in get_fonts(self.event, pdf_support_required=False).items()
|
(a, FontSelect.FontOption(title=a, data=v)) for a, v in get_fonts(self.event, pdf_support_required=False).items()
|
||||||
], key=lambda a: a[0])
|
], key=lambda a: a[0])
|
||||||
|
|||||||
@@ -275,6 +275,9 @@
|
|||||||
{% bootstrap_field sform.event_calendar_future_only layout="control" %}
|
{% bootstrap_field sform.event_calendar_future_only layout="control" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% bootstrap_field sform.low_availability_percentage layout="control" addon_after="%" %}
|
{% bootstrap_field sform.low_availability_percentage layout="control" addon_after="%" %}
|
||||||
|
{% if sform.event_list_empty_text %}
|
||||||
|
{% bootstrap_field sform.event_list_empty_text layout="control" addon_after="%" %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
<h4>{% trans "Order details" %}</h4>
|
<h4>{% trans "Order details" %}</h4>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
{% load eventurl %}
|
{% load eventurl %}
|
||||||
{% load icon %}
|
{% load icon %}
|
||||||
{% load urlreplace %}
|
{% load urlreplace %}
|
||||||
|
{% load rich_text %}
|
||||||
<nav aria-label="{% trans "calendar navigation" %}">
|
<nav aria-label="{% trans "calendar navigation" %}">
|
||||||
<ul class="row calendar-nav">
|
<ul class="row calendar-nav">
|
||||||
<li class="text-left flip">
|
<li class="text-left flip">
|
||||||
@@ -50,4 +51,12 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
{% include "pretixpresale/fragment_calendar.html" with show_avail=event.settings.event_list_availability weeks=subevent_list.weeks show_names=subevent_list.show_names %}
|
<div class="calendar-container">
|
||||||
|
{% include "pretixpresale/fragment_calendar.html" with show_avail=event.settings.event_list_availability weeks=subevent_list.weeks show_names=subevent_list.show_names %}
|
||||||
|
{% if subevent_list.any_events is False %}
|
||||||
|
<div class="calendar-empty">
|
||||||
|
<span class="fa fa-calendar-times-o fa-4x text-muted"></span>
|
||||||
|
{{ event.settings.event_list_empty_text|rich_text }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|||||||
+10
-1
@@ -2,6 +2,7 @@
|
|||||||
{% load eventurl %}
|
{% load eventurl %}
|
||||||
{% load icon %}
|
{% load icon %}
|
||||||
{% load urlreplace %}
|
{% load urlreplace %}
|
||||||
|
{% load rich_text %}
|
||||||
<nav aria-label="{% trans "calendar navigation" %}">
|
<nav aria-label="{% trans "calendar navigation" %}">
|
||||||
<ul class="row calendar-nav">
|
<ul class="row calendar-nav">
|
||||||
<li class="text-left flip">
|
<li class="text-left flip">
|
||||||
@@ -59,7 +60,15 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
{% include "pretixpresale/fragment_week_calendar.html" with show_avail=event.settings.event_list_availability days=subevent_list.days show_names=subevent_list.show_names %}
|
<div class="calendar-container">
|
||||||
|
{% include "pretixpresale/fragment_week_calendar.html" with show_avail=event.settings.event_list_availability days=subevent_list.days show_names=subevent_list.show_names %}
|
||||||
|
{% if subevent_list.any_events is False %}
|
||||||
|
<div class="calendar-empty">
|
||||||
|
<span class="fa fa-calendar-times-o fa-4x text-muted"></span>
|
||||||
|
{{ event.settings.event_list_empty_text|rich_text }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
<div class="row visible-xs">
|
<div class="row visible-xs">
|
||||||
<div class="col-xs-6 text-left flip">
|
<div class="col-xs-6 text-left flip">
|
||||||
<a href="?{% url_replace request "date" subevent_list.before|date:"o-\WW" %}"
|
<a href="?{% url_replace request "date" subevent_list.before|date:"o-\WW" %}"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
{% load icon %}
|
{% load icon %}
|
||||||
{% load eventurl %}
|
{% load eventurl %}
|
||||||
{% load date_fast %}
|
{% load date_fast %}
|
||||||
|
{% load rich_text %}
|
||||||
|
|
||||||
<div class="event-list full-width-list alternating-rows">
|
<div class="event-list full-width-list alternating-rows">
|
||||||
{% for subev in subevent_list.subevent_list %}
|
{% for subev in subevent_list.subevent_list %}
|
||||||
@@ -43,5 +44,10 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</article>
|
</article>
|
||||||
|
{% empty %}
|
||||||
|
<div class="calendar-empty">
|
||||||
|
<span class="fa fa-calendar-times-o fa-4x text-muted"></span>
|
||||||
|
{{ event.settings.event_list_empty_text|rich_text }}
|
||||||
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -356,6 +356,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
after,
|
after,
|
||||||
future_only=self.request.event.settings.event_calendar_future_only
|
future_only=self.request.event.settings.event_calendar_future_only
|
||||||
)
|
)
|
||||||
|
context['any_events'] = any(ebd)
|
||||||
elif context['list_type'] == "week":
|
elif context['list_type'] == "week":
|
||||||
self._set_week_year()
|
self._set_week_year()
|
||||||
tz = self.request.event.timezone
|
tz = self.request.event.timezone
|
||||||
@@ -430,6 +431,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
after,
|
after,
|
||||||
future_only=self.request.event.settings.event_calendar_future_only
|
future_only=self.request.event.settings.event_calendar_future_only
|
||||||
)
|
)
|
||||||
|
context['any_events'] = any(ebd)
|
||||||
else:
|
else:
|
||||||
subevents = self.request.event.subevents_sorted(
|
subevents = self.request.event.subevents_sorted(
|
||||||
filter_qs_by_attr(
|
filter_qs_by_attr(
|
||||||
|
|||||||
@@ -642,6 +642,8 @@ class WidgetAPIProductList(EventListMixin, View):
|
|||||||
sales_channel=self.request.sales_channel,
|
sales_channel=self.request.sales_channel,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not any(ebd):
|
||||||
|
data['empty_text'] = str(rich_text(request.event.settings.event_list_empty_text, safelinks=False))
|
||||||
data['weeks'] = weeks_for_template(ebd, self.year, self.month)
|
data['weeks'] = weeks_for_template(ebd, self.year, self.month)
|
||||||
for w in data['weeks']:
|
for w in data['weeks']:
|
||||||
for d in w:
|
for d in w:
|
||||||
@@ -700,6 +702,8 @@ class WidgetAPIProductList(EventListMixin, View):
|
|||||||
sales_channel=self.request.sales_channel,
|
sales_channel=self.request.sales_channel,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not any(ebd):
|
||||||
|
data['empty_text'] = str(rich_text(request.event.settings.event_list_empty_text, safelinks=False))
|
||||||
data['days'] = days_for_template(ebd, week)
|
data['days'] = days_for_template(ebd, week)
|
||||||
for d in data['days']:
|
for d in data['days']:
|
||||||
d['events'] = self._serialize_events(d['events'] or [])
|
d['events'] = self._serialize_events(d['events'] or [])
|
||||||
@@ -770,6 +774,8 @@ class WidgetAPIProductList(EventListMixin, View):
|
|||||||
'event_url': eventreverse_absolute(event, 'presale:event.index'),
|
'event_url': eventreverse_absolute(event, 'presale:event.index'),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if not data['events']:
|
||||||
|
data['empty_text'] = str(rich_text(request.event.settings.event_list_empty_text, safelinks=False))
|
||||||
cache.set(cache_key, data, 30)
|
cache.set(cache_key, data, 30)
|
||||||
# These pages are cached for a really short duration – this should make them pretty accurate, while still
|
# These pages are cached for a really short duration – this should make them pretty accurate, while still
|
||||||
# providing some protection against burst traffic.
|
# providing some protection against burst traffic.
|
||||||
|
|||||||
@@ -1,3 +1,35 @@
|
|||||||
|
.calendar-container:has(.calendar-empty), .event-list:has(.calendar-empty) {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.table-responsive, .week-calendar {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-empty {
|
||||||
|
position: relative;
|
||||||
|
z-index: 100;
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
text-align: center;
|
||||||
|
font-size: $font-size-large;
|
||||||
|
padding: 30px 0;
|
||||||
|
|
||||||
|
.fa {
|
||||||
|
margin-block: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
.table-calendar, .week-calendar, .day-calendar {
|
.table-calendar, .week-calendar, .day-calendar {
|
||||||
td, th {
|
td, th {
|
||||||
width: 14.29%;
|
width: 14.29%;
|
||||||
|
|||||||
@@ -513,7 +513,7 @@ h2 .label {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.event-list.full-width-list {
|
.event-list.full-width-list {
|
||||||
h3, h4, p {
|
h3, h4, article p {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -748,6 +748,13 @@ $table-bg-accent: rgba(128, 128, 128, 0.05);
|
|||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pretix-widget-event-list-empty,
|
||||||
|
.pretix-widget-event-week-empty,
|
||||||
|
.pretix-widget-event-calendar-empty {
|
||||||
|
padding: 10px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export interface ProductListResponse {
|
|||||||
events?: EventEntry[]
|
events?: EventEntry[]
|
||||||
has_more_events?: boolean
|
has_more_events?: boolean
|
||||||
meta_filter_fields?: MetaFilterField[]
|
meta_filter_fields?: MetaFilterField[]
|
||||||
|
empty_text?: string
|
||||||
weeks?: DayEntry[][]
|
weeks?: DayEntry[][]
|
||||||
date?: string
|
date?: string
|
||||||
days?: DayEntry[]
|
days?: DayEntry[]
|
||||||
|
|||||||
@@ -92,7 +92,9 @@ function nextmonth () {
|
|||||||
| {{ STRINGS.next_month }} »
|
| {{ STRINGS.next_month }} »
|
||||||
|
|
||||||
//- Calendar
|
//- Calendar
|
||||||
|
.pretix-widget-event-calendar-empty(v-if="!!store.emptyText", v-html="store.emptyText")
|
||||||
table.pretix-widget-event-calendar-table(
|
table.pretix-widget-event-calendar-table(
|
||||||
|
v-else
|
||||||
:id="id",
|
:id="id",
|
||||||
tabindex="0",
|
tabindex="0",
|
||||||
:aria-labelledby="ariaLabelledby"
|
:aria-labelledby="ariaLabelledby"
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ console.log(store)
|
|||||||
:event="event"
|
:event="event"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
.pretix-widget-event-list-empty(v-if="!store.events.length && store.emptyText", v-html="store.emptyText")
|
||||||
|
|
||||||
p.pretix-widget-event-list-load-more(v-if="store.hasMoreEvents")
|
p.pretix-widget-event-list-load-more(v-if="store.hasMoreEvents")
|
||||||
button(@click.prevent.stop="loadMore") {{ STRINGS.load_more }}
|
button(@click.prevent.stop="loadMore") {{ STRINGS.load_more }}
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -88,7 +88,8 @@ function nextweek () {
|
|||||||
| {{ STRINGS.next_week }} »
|
| {{ STRINGS.next_week }} »
|
||||||
|
|
||||||
//- Actual calendar
|
//- Actual calendar
|
||||||
.pretix-widget-event-week-table(:id="id", tabindex="0", :aria-label="weekname")
|
.pretix-widget-event-week-empty(v-if="store.emptyText", v-html="store.emptyText")
|
||||||
|
.pretix-widget-event-week-table(v-else, :id="id", tabindex="0", :aria-label="weekname")
|
||||||
.pretix-widget-event-week-col(v-for="d in store.days", :key="d?.date || ''")
|
.pretix-widget-event-week-col(v-for="d in store.days", :key="d?.date || ''")
|
||||||
EventWeekCell(:day="d", :mobile="mobile")
|
EventWeekCell(:day="d", :mobile="mobile")
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ export function createWidgetStore (config: {
|
|||||||
offset: 0,
|
offset: 0,
|
||||||
appendEvents: false,
|
appendEvents: false,
|
||||||
metaFilterFields: [] as MetaFilterField[],
|
metaFilterFields: [] as MetaFilterField[],
|
||||||
|
emptyText: null as string | null,
|
||||||
|
|
||||||
// UI state
|
// UI state
|
||||||
mobile: false,
|
mobile: false,
|
||||||
@@ -270,6 +271,7 @@ export function createWidgetStore (config: {
|
|||||||
this.name = data.name ?? null
|
this.name = data.name ?? null
|
||||||
this.frontpageText = data.frontpage_text ?? null
|
this.frontpageText = data.frontpage_text ?? null
|
||||||
this.metaFilterFields = data.meta_filter_fields ?? []
|
this.metaFilterFields = data.meta_filter_fields ?? []
|
||||||
|
this.emptyText = data.empty_text ?? null
|
||||||
} else if (data.days !== undefined) {
|
} else if (data.days !== undefined) {
|
||||||
this.days = data.days
|
this.days = data.days
|
||||||
this.date = null
|
this.date = null
|
||||||
@@ -279,6 +281,7 @@ export function createWidgetStore (config: {
|
|||||||
this.name = data.name ?? null
|
this.name = data.name ?? null
|
||||||
this.frontpageText = data.frontpage_text ?? null
|
this.frontpageText = data.frontpage_text ?? null
|
||||||
this.metaFilterFields = data.meta_filter_fields ?? []
|
this.metaFilterFields = data.meta_filter_fields ?? []
|
||||||
|
this.emptyText = data.empty_text ?? null
|
||||||
} else if (data.events !== undefined) {
|
} else if (data.events !== undefined) {
|
||||||
this.events = this.appendEvents && this.events
|
this.events = this.appendEvents && this.events
|
||||||
? this.events.concat(data.events)
|
? this.events.concat(data.events)
|
||||||
@@ -290,6 +293,7 @@ export function createWidgetStore (config: {
|
|||||||
this.frontpageText = data.frontpage_text ?? null
|
this.frontpageText = data.frontpage_text ?? null
|
||||||
this.hasMoreEvents = data.has_more_events ?? false
|
this.hasMoreEvents = data.has_more_events ?? false
|
||||||
this.metaFilterFields = data.meta_filter_fields ?? []
|
this.metaFilterFields = data.meta_filter_fields ?? []
|
||||||
|
this.emptyText = data.empty_text ?? null
|
||||||
} else {
|
} else {
|
||||||
this.view = 'event'
|
this.view = 'event'
|
||||||
this.targetUrl = data.target_url ?? this.targetUrl
|
this.targetUrl = data.target_url ?? this.targetUrl
|
||||||
|
|||||||
Reference in New Issue
Block a user