mirror of
https://github.com/pretix/pretix.git
synced 2026-08-12 11:07:02 +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.")
|
||||
)
|
||||
},
|
||||
'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': {
|
||||
'default': '',
|
||||
'type': LazyI18nString,
|
||||
|
||||
@@ -600,6 +600,7 @@ class EventSettingsForm(EventSettingsValidationMixin, FormPlaceholderMixin, Sett
|
||||
'imprint_url',
|
||||
'checkout_email_helptext',
|
||||
'presale_has_ended_text',
|
||||
'event_list_empty_text',
|
||||
'voucher_explanation_text',
|
||||
'checkout_success_text',
|
||||
'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_filters']
|
||||
del self.fields['event_calendar_future_only']
|
||||
del self.fields['event_list_empty_text']
|
||||
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()
|
||||
], key=lambda a: a[0])
|
||||
|
||||
@@ -275,6 +275,9 @@
|
||||
{% bootstrap_field sform.event_calendar_future_only layout="control" %}
|
||||
{% endif %}
|
||||
{% 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>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
{% load eventurl %}
|
||||
{% load icon %}
|
||||
{% load urlreplace %}
|
||||
{% load rich_text %}
|
||||
<nav aria-label="{% trans "calendar navigation" %}">
|
||||
<ul class="row calendar-nav">
|
||||
<li class="text-left flip">
|
||||
@@ -50,4 +51,12 @@
|
||||
</li>
|
||||
</ul>
|
||||
</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 icon %}
|
||||
{% load urlreplace %}
|
||||
{% load rich_text %}
|
||||
<nav aria-label="{% trans "calendar navigation" %}">
|
||||
<ul class="row calendar-nav">
|
||||
<li class="text-left flip">
|
||||
@@ -59,7 +60,15 @@
|
||||
</li>
|
||||
</ul>
|
||||
</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="col-xs-6 text-left flip">
|
||||
<a href="?{% url_replace request "date" subevent_list.before|date:"o-\WW" %}"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
{% load icon %}
|
||||
{% load eventurl %}
|
||||
{% load date_fast %}
|
||||
{% load rich_text %}
|
||||
|
||||
<div class="event-list full-width-list alternating-rows">
|
||||
{% for subev in subevent_list.subevent_list %}
|
||||
@@ -43,5 +44,10 @@
|
||||
</a>
|
||||
</p>
|
||||
</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 %}
|
||||
</div>
|
||||
|
||||
@@ -356,6 +356,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
after,
|
||||
future_only=self.request.event.settings.event_calendar_future_only
|
||||
)
|
||||
context['any_events'] = any(ebd)
|
||||
elif context['list_type'] == "week":
|
||||
self._set_week_year()
|
||||
tz = self.request.event.timezone
|
||||
@@ -430,6 +431,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
after,
|
||||
future_only=self.request.event.settings.event_calendar_future_only
|
||||
)
|
||||
context['any_events'] = any(ebd)
|
||||
else:
|
||||
subevents = self.request.event.subevents_sorted(
|
||||
filter_qs_by_attr(
|
||||
|
||||
@@ -642,6 +642,8 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
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)
|
||||
for w in data['weeks']:
|
||||
for d in w:
|
||||
@@ -700,6 +702,8 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
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)
|
||||
for d in data['days']:
|
||||
d['events'] = self._serialize_events(d['events'] or [])
|
||||
@@ -770,6 +774,8 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
'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)
|
||||
# These pages are cached for a really short duration – this should make them pretty accurate, while still
|
||||
# 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 {
|
||||
td, th {
|
||||
width: 14.29%;
|
||||
|
||||
@@ -513,7 +513,7 @@ h2 .label {
|
||||
}
|
||||
|
||||
.event-list.full-width-list {
|
||||
h3, h4, p {
|
||||
h3, h4, article p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@@ -748,6 +748,13 @@ $table-bg-accent: rgba(128, 128, 128, 0.05);
|
||||
display: block;
|
||||
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[]
|
||||
has_more_events?: boolean
|
||||
meta_filter_fields?: MetaFilterField[]
|
||||
empty_text?: string
|
||||
weeks?: DayEntry[][]
|
||||
date?: string
|
||||
days?: DayEntry[]
|
||||
|
||||
@@ -92,7 +92,9 @@ function nextmonth () {
|
||||
| {{ STRINGS.next_month }} »
|
||||
|
||||
//- Calendar
|
||||
.pretix-widget-event-calendar-empty(v-if="!!store.emptyText", v-html="store.emptyText")
|
||||
table.pretix-widget-event-calendar-table(
|
||||
v-else
|
||||
:id="id",
|
||||
tabindex="0",
|
||||
:aria-labelledby="ariaLabelledby"
|
||||
|
||||
@@ -62,6 +62,8 @@ console.log(store)
|
||||
: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")
|
||||
button(@click.prevent.stop="loadMore") {{ STRINGS.load_more }}
|
||||
</template>
|
||||
|
||||
@@ -88,7 +88,8 @@ function nextweek () {
|
||||
| {{ STRINGS.next_week }} »
|
||||
|
||||
//- 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 || ''")
|
||||
EventWeekCell(:day="d", :mobile="mobile")
|
||||
</template>
|
||||
|
||||
@@ -95,6 +95,7 @@ export function createWidgetStore (config: {
|
||||
offset: 0,
|
||||
appendEvents: false,
|
||||
metaFilterFields: [] as MetaFilterField[],
|
||||
emptyText: null as string | null,
|
||||
|
||||
// UI state
|
||||
mobile: false,
|
||||
@@ -270,6 +271,7 @@ export function createWidgetStore (config: {
|
||||
this.name = data.name ?? null
|
||||
this.frontpageText = data.frontpage_text ?? null
|
||||
this.metaFilterFields = data.meta_filter_fields ?? []
|
||||
this.emptyText = data.empty_text ?? null
|
||||
} else if (data.days !== undefined) {
|
||||
this.days = data.days
|
||||
this.date = null
|
||||
@@ -279,6 +281,7 @@ export function createWidgetStore (config: {
|
||||
this.name = data.name ?? null
|
||||
this.frontpageText = data.frontpage_text ?? null
|
||||
this.metaFilterFields = data.meta_filter_fields ?? []
|
||||
this.emptyText = data.empty_text ?? null
|
||||
} else if (data.events !== undefined) {
|
||||
this.events = this.appendEvents && this.events
|
||||
? this.events.concat(data.events)
|
||||
@@ -290,6 +293,7 @@ export function createWidgetStore (config: {
|
||||
this.frontpageText = data.frontpage_text ?? null
|
||||
this.hasMoreEvents = data.has_more_events ?? false
|
||||
this.metaFilterFields = data.meta_filter_fields ?? []
|
||||
this.emptyText = data.empty_text ?? null
|
||||
} else {
|
||||
this.view = 'event'
|
||||
this.targetUrl = data.target_url ?? this.targetUrl
|
||||
|
||||
Reference in New Issue
Block a user