From: Radek Czajka Date: Thu, 5 Dec 2024 21:03:46 +0000 (+0100) Subject: Crisis banners X-Git-Url: https://git.mdrn.pl/wolnelektury.git/commitdiff_plain/298a2c3414d84d57ec9e691cfbc6d084530af278?ds=inline Crisis banners --- diff --git a/src/annoy/apps.py b/src/annoy/apps.py index 213a4e98e..b2b7eff82 100644 --- a/src/annoy/apps.py +++ b/src/annoy/apps.py @@ -3,3 +3,6 @@ from django.apps import AppConfig class AnnoyConfig(AppConfig): name = 'annoy' + + def ready(self): + from . import signals diff --git a/src/annoy/migrations/0017_banner_progress_banner_target_alter_banner_place.py b/src/annoy/migrations/0017_banner_progress_banner_target_alter_banner_place.py new file mode 100644 index 000000000..62246bf2d --- /dev/null +++ b/src/annoy/migrations/0017_banner_progress_banner_target_alter_banner_place.py @@ -0,0 +1,28 @@ +# Generated by Django 4.0.8 on 2024-12-04 11:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('annoy', '0016_alter_mediainsertset_file_format'), + ] + + operations = [ + migrations.AddField( + model_name='banner', + name='progress', + field=models.IntegerField(blank=True, null=True, verbose_name='postęp'), + ), + migrations.AddField( + model_name='banner', + name='target', + field=models.IntegerField(blank=True, null=True, verbose_name='cel'), + ), + migrations.AlterField( + model_name='banner', + name='place', + field=models.SlugField(choices=[('top', 'U góry wszystkich stron'), ('book-page', 'Strona książki'), ('book-text-intermission', 'Przerwa w treści książki'), ('book-fragment-list', 'Obok listy fragmentów książki'), ('blackout', 'Blackout'), ('crisis', 'Kryzysowa')], verbose_name='miejsce'), + ), + ] diff --git a/src/annoy/models.py b/src/annoy/models.py index e60e3c024..92b8184dd 100644 --- a/src/annoy/models.py +++ b/src/annoy/models.py @@ -33,6 +33,8 @@ class Banner(models.Model): help_text='Bannery z wyższym priorytetem mają pierwszeństwo.') since = models.DateTimeField('od', null=True, blank=True) until = models.DateTimeField('do', null=True, blank=True) + target = models.IntegerField('cel', null=True, blank=True) + progress = models.IntegerField('postęp', null=True, blank=True) show_members = models.BooleanField('widoczny dla członków klubu', default=False) staff_preview = models.BooleanField('podgląd tylko dla zespołu', default=False) only_authenticated = models.BooleanField('tylko dla zalogowanych', default=False) @@ -49,10 +51,10 @@ class Banner(models.Model): return Template(self.text).render(Context()) @classmethod - def choice(cls, place, request): + def choice(cls, place, request, exemptions=True): Membership = apps.get_model('club', 'Membership') - if hasattr(request, 'annoy_banner_exempt'): + if exemptions and hasattr(request, 'annoy_banner_exempt'): return cls.objects.none() if settings.DEBUG: @@ -78,6 +80,29 @@ class Banner(models.Model): return banners + @property + def progress_percent(self): + if not self.target: + return 0 + return (self.progress or 0) / self.target * 100 + + def update_progress(self): + # Total of new payments during the action. + # This definition will need to change for longer timespans. + if not self.since or not self.until or not self.target: + return + Schedule = apps.get_model('club', 'Schedule') + self.progress = Schedule.objects.filter( + payed_at__gte=self.since, + payed_at__lte=self.until, + ).aggregate(c=models.Sum('amount'))['c'] + self.save(update_fields=['progress']) + + @classmethod + def update_all_progress(cls): + for obj in cls.objects.exclude(target=None): + obj.update_progress() + class DynamicTextInsert(models.Model): paragraphs = models.IntegerField('akapity') @@ -146,12 +171,3 @@ class MediaInsertText(models.Model): class Meta: ordering = ('ordering',) - - -from django.db.models.signals import post_save, post_delete -from django.dispatch import receiver - -@receiver(post_delete, sender=MediaInsertText) -@receiver(post_save, sender=MediaInsertText) -def update_etag(sender, instance, **kwargs): - instance.media_insert_set.update_etag() diff --git a/src/annoy/places.py b/src/annoy/places.py index c9f8031af..ca3324223 100644 --- a/src/annoy/places.py +++ b/src/annoy/places.py @@ -8,6 +8,7 @@ PLACE_DEFINITIONS = [ # ('centre', 'Środek ekranu'), ('upper', 'Górna połowa ekranu'), )), + ('crisis', 'Kryzysowa', False), ] PLACE_CHOICES = [p[:2] for p in PLACE_DEFINITIONS] diff --git a/src/annoy/signals.py b/src/annoy/signals.py new file mode 100644 index 000000000..c98528247 --- /dev/null +++ b/src/annoy/signals.py @@ -0,0 +1,18 @@ +from django.db.models.signals import post_save, post_delete +from django.dispatch import receiver +import club.models +from . import models + + +@receiver(post_delete, sender=models.MediaInsertText) +@receiver(post_save, sender=models.MediaInsertText) +def update_etag(sender, instance, **kwargs): + instance.media_insert_set.update_etag() + + +@receiver(post_save, sender=club.models.Schedule) +def update_progress(sender, instance, **kwargs): + try: + models.Banner.update_all_progress() + except: + pass diff --git a/src/annoy/templates/annoy/banner_crisis.html b/src/annoy/templates/annoy/banner_crisis.html new file mode 100644 index 000000000..cd39469fb --- /dev/null +++ b/src/annoy/templates/annoy/banner_crisis.html @@ -0,0 +1,60 @@ +{% load l10n %} +{% load time_tags %} + +{% if banner %} +
+
+
+ +
+ {% if banner.image %} + + {% endif %} +
+ +
+
+ {{ banner.get_text|safe|linebreaks }} +
+ +
+
+
+
+ +
+
+
+
+ +
+
+ {% if banner.action_label %} + + {{ banner.action_label }} + + {% endif %} +
+
+
+ + + +
+
+
+ +{% endif %} + diff --git a/src/annoy/templatetags/annoy.py b/src/annoy/templatetags/annoy.py index 2bc93143c..40f7511a3 100644 --- a/src/annoy/templatetags/annoy.py +++ b/src/annoy/templatetags/annoy.py @@ -29,3 +29,12 @@ def annoy_banners(context, place): 'banners': Banner.choice(place, request=context['request']), 'closable': PLACES.get(place, False), } + + +@register.inclusion_tag('annoy/banner_crisis.html', takes_context=True) +def annoy_banner_crisis(context): + banners = Banner.choice('crisis', request=context['request'], exemptions=False) + return { + 'banner': banners.first(), + 'closable': True, + } diff --git a/src/club/templates/club/donation_step_base.html b/src/club/templates/club/donation_step_base.html index 52256fecd..cede1b4ca 100644 --- a/src/club/templates/club/donation_step_base.html +++ b/src/club/templates/club/donation_step_base.html @@ -14,6 +14,8 @@
+ {% comment %} +
@@ -23,6 +25,7 @@

{% blocktrans with c=500 %}Potrzebujemy {{ c }} regularnych darczyńców, by Wolne Lektury mogły działać!{% endblocktrans %}

+ {% endcomment %}
diff --git a/src/wolnelektury/static/2022/styles/layout/_annoy.scss b/src/wolnelektury/static/2022/styles/layout/_annoy.scss index f0f06360a..24152507e 100644 --- a/src/wolnelektury/static/2022/styles/layout/_annoy.scss +++ b/src/wolnelektury/static/2022/styles/layout/_annoy.scss @@ -73,3 +73,117 @@ } } } + + +.annoy-banner_crisis-container { + position: sticky; + top: 0; + height: 160px; + z-index: 10; + box-shadow: 0 0 10px black; + display: flex; + background: #c32721; + color: black; + align-items:center; + cursor: pointer; + + @media screen and (min-height: 480px) { + height: 33vh; + top: calc(-33vh + 160px); + } + + @media screen and (max-width: 940px) { + padding: 10px 0; + height: auto; + top: 0; + } + + .annoy-banner_crisis { + position: sticky; + top: 0; + width: 100%; + + .annoy-banner-inner { + max-width: 1172px; + margin: auto; + padding-right: 16px; + padding-left: 16px; + + display: flex; + gap: 20px; + align-items: flex-start; + + .image-box { + position: relative; + img { + height: 160px; + display: block; + + @media screen and (max-width: 700px) { + height: 120px; + } + } + } + + .text-box { + flex-grow: 1; + display: flex; + flex-direction: column; + gap: 10px; + + @media screen and (max-width: 700px) { + p { + font-size: .9em; + } + } + + .text { + background: #edc016; + padding: 1em; + border: 3px solid black; + } + a { + color: #c32721; + } + .state-box { + display: flex; + gap: 10px; + align-items: center; + @media screen and (max-width: 700px) { + flex-direction: column; + align-items: stretch; + text-align: center; + } + .progress-box { + flex-grow: 1; + + .l-checkout__support__bar span::after { + right: auto; + left: 5px; + color: black; + } + } + } + } + + p { + margin: 0; + } + + a.action { + background: #edc016; + color: black; + padding: .8em 1em; + border: 3px solid black; + border-radius: 10px; + display: block; + transition: background-color .2s; + + &:hover { + background: #ffd430; + text-decoration: none; + } + } + } + } +} diff --git a/src/wolnelektury/static/js/main.js b/src/wolnelektury/static/js/main.js index acc38a933..efa442e12 100644 --- a/src/wolnelektury/static/js/main.js +++ b/src/wolnelektury/static/js/main.js @@ -543,4 +543,10 @@ $(".c-media__settings").toggleClass('active'); }); + const crisis = document.querySelector(".annoy-banner_crisis-container"); + const crisisLink = document.querySelector('.annoy-banner_crisis-container a.action'); + crisis.addEventListener("click", function() { + crisisLink.click(); + }); + })(); diff --git a/src/wolnelektury/templates/header.html b/src/wolnelektury/templates/header.html index e7a29b807..17e237948 100644 --- a/src/wolnelektury/templates/header.html +++ b/src/wolnelektury/templates/header.html @@ -6,6 +6,8 @@ {% load latest_blog_posts from blog %} {% load preview_ad from catalogue_tags %} +{% annoy_banner_crisis %} + {% annoy_banner_blackout %}