diff --git a/donate/forms.py b/donate/forms.py index 970724776f3a014fb335cdcdc6ef23040abec413..05fe9cceab424c3c361c4f1dc9c5d86cd5f9f58f 100644 --- a/donate/forms.py +++ b/donate/forms.py @@ -12,6 +12,7 @@ class DonateForm(forms.Form): amount = forms.IntegerField() custom_amount = forms.IntegerField(required=False) periodicity = forms.IntegerField() + portal_project_id = forms.IntegerField() def clean_periodicity(self): value = self.cleaned_data["periodicity"] @@ -27,9 +28,10 @@ class DonateForm(forms.Form): ) return amount - def get_redirect_url(self, portal_project_id): + def get_redirect_url(self): amount = self.get_amount() periodicity = self.cleaned_data["periodicity"] + portal_project_id = self.cleaned_data["portal_project_id"] query = urllib.parse.urlencode( { "amount": amount, diff --git a/donate/migrations/0005_auto_20200715_1415.py b/donate/migrations/0005_auto_20200715_1415.py new file mode 100644 index 0000000000000000000000000000000000000000..b806953e2a6cec0d788719046e75b1c12c3ff917 --- /dev/null +++ b/donate/migrations/0005_auto_20200715_1415.py @@ -0,0 +1,91 @@ +# Generated by Django 3.0.8 on 2020-07-15 12:15 + +import django.db.models.deletion +import wagtail.core.blocks +import wagtail.core.fields +import wagtailmetadata.models +from django.db import migrations, models + +import donate.models + + +class Migration(migrations.Migration): + + dependencies = [ + ("wagtailcore", "0045_assign_unlock_grouppagepermission"), + ("wagtailimages", "0022_uploadedimage"), + ("donate", "0004_auto_20200621_2349"), + ] + + operations = [ + migrations.RemoveField(model_name="donateregionpage", name="perex",), + migrations.CreateModel( + name="DonateTargetedDonationsPage", + fields=[ + ( + "page_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="wagtailcore.Page", + ), + ), + ( + "targeted_donations", + wagtail.core.fields.StreamField( + [ + ( + "item", + wagtail.core.blocks.StructBlock( + [ + ( + "title", + wagtail.core.blocks.CharBlock( + label="název" + ), + ), + ( + "description", + wagtail.core.blocks.CharBlock( + label="popis", required=False + ), + ), + ( + "portal_project_id", + wagtail.core.blocks.IntegerBlock( + label="ID projektu v darovacím portálu", + required=False, + ), + ), + ] + ), + ) + ], + blank=True, + verbose_name="adresné dary", + ), + ), + ( + "search_image", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailimages.Image", + verbose_name="Search image", + ), + ), + ], + options={"abstract": False,}, + bases=( + "wagtailcore.page", + donate.models.SubpageMixin, + wagtailmetadata.models.MetadataMixin, + models.Model, + ), + ), + ] diff --git a/donate/models.py b/donate/models.py index 288cbfe6351bdc9969b30abb143aa60139b6bef3..d464ace11b8f8f270c6cd53f5b7504625b0acab6 100644 --- a/donate/models.py +++ b/donate/models.py @@ -7,6 +7,7 @@ from wagtail.admin.edit_handlers import ( MultiFieldPanel, StreamFieldPanel, ) +from wagtail.core import blocks from wagtail.core.fields import RichTextField, StreamField from wagtail.core.models import Page from wagtail.images.blocks import ImageChooserBlock @@ -21,10 +22,13 @@ from .forms import DonateForm class SubpageMixin: """Must be used in class definition before MetadataPageMixin!""" + # flag for rendering anchor links in menu + is_home = False + @property def root_page(self): if not hasattr(self, "_root_page"): - self._root_page = self.get_parent().specific + self._root_page = self.get_ancestors().type(DonateHomePage).specific().get() return self._root_page def get_meta_image(self): @@ -45,7 +49,7 @@ class DonateFormMixin(models.Model): if request.method == "POST": form = DonateForm(request.POST) if form.is_valid(): - url = form.get_redirect_url(self.portal_project_id) + url = form.get_redirect_url() return redirect(url) return super().serve(request) @@ -62,6 +66,8 @@ def get_url(page, dest_page_type): class DonateHomePage(DonateFormMixin, Page, MetadataPageMixin): + ### FIELDS + # lead section lead_title = models.CharField("hlavní nadpis", max_length=250, blank=True) lead_body = models.TextField("hlavní popis", blank=True) @@ -93,6 +99,8 @@ class DonateHomePage(DonateFormMixin, Page, MetadataPageMixin): "Matomo ID pro sledování návštěvnosti", blank=True, null=True ) + ### PANELS + content_panels = Page.content_panels + [ MultiFieldPanel( [ @@ -140,6 +148,8 @@ class DonateHomePage(DonateFormMixin, Page, MetadataPageMixin): FieldPanel("portal_project_id"), ] + ### RELATIONS + subpage_types = [ "donate.DonateRegionIndexPage", "donate.DonateProjectIndexPage", @@ -147,6 +157,8 @@ class DonateHomePage(DonateFormMixin, Page, MetadataPageMixin): "donate.DonateCookiesPage", ] + ### OTHERS + # flag for rendering anchor links in menu is_home = True @@ -196,6 +208,8 @@ class DonateHomePage(DonateFormMixin, Page, MetadataPageMixin): class DonateRegionIndexPage(Page, SubpageMixin, MetadataPageMixin): + ### PANELS + promote_panels = [ MultiFieldPanel( [ @@ -211,11 +225,12 @@ class DonateRegionIndexPage(Page, SubpageMixin, MetadataPageMixin): settings_panels = [] + ### RELATIONS + parent_page_types = ["donate.DonateHomePage"] subpage_types = ["donate.DonateRegionPage"] - # flag for rendering anchor links in menu - is_home = False + ### OTHERS class Meta: verbose_name = "Přehled krajů" @@ -227,11 +242,13 @@ class DonateRegionIndexPage(Page, SubpageMixin, MetadataPageMixin): class DonateRegionPage(DonateFormMixin, Page, SubpageMixin, MetadataPageMixin): - # TODO remove if not needed anymore - perex = models.TextField("krátký popis do přehledu krajů") + ### FIELDS + main_title = models.CharField("hlavní nadpis na stránce", max_length=250) body = RichTextField("obsah") + ### PANELS + content_panels = Page.content_panels + [ FieldPanel("main_title"), FieldPanel("body", classname="full"), @@ -258,31 +275,31 @@ class DonateRegionPage(DonateFormMixin, Page, SubpageMixin, MetadataPageMixin): settings_panels = [FieldPanel("portal_project_id")] + ### RELATIONS + parent_page_types = ["donate.DonateRegionIndexPage"] - subpage_types = [] + subpage_types = ["donate.DonateTargetedDonationsPage"] - # flag for rendering anchor links in menu - is_home = False + ### OTHERS class Meta: verbose_name = "Kraj" - @property - def root_page(self): - if not hasattr(self, "_root_page"): - self._root_page = self.get_ancestors().type(DonateHomePage).specific().get() - return self._root_page - def get_meta_title(self): return self.seo_title or self.main_title - def get_context(self, request): - context = super().get_context(request) - context["other_regions"] = self.get_siblings(inclusive=False).live() - return context + @property + def targeted_donations_page_url(self): + return get_url(self, DonateTargetedDonationsPage) + + @property + def has_targeted_donations(self): + return self.get_descendants().type(DonateTargetedDonationsPage).live().exists() class DonateProjectIndexPage(Page, SubpageMixin, MetadataPageMixin): + ### PANELS + promote_panels = [ MultiFieldPanel( [ @@ -298,11 +315,12 @@ class DonateProjectIndexPage(Page, SubpageMixin, MetadataPageMixin): settings_panels = [] + ### RELATIONS + parent_page_types = ["donate.DonateHomePage"] subpage_types = ["donate.DonateProjectPage"] - # flag for rendering anchor links in menu - is_home = False + ### OTHERS class Meta: verbose_name = "Přehled projektů" @@ -316,6 +334,8 @@ class DonateProjectIndexPage(Page, SubpageMixin, MetadataPageMixin): class DonateProjectPage(DonateFormMixin, Page, SubpageMixin, MetadataPageMixin): + ### FIELDS + date = models.DateField("běží od") perex = models.TextField("krátký popis") body = RichTextField("obsah") @@ -335,6 +355,8 @@ class DonateProjectPage(DonateFormMixin, Page, SubpageMixin, MetadataPageMixin): # we will use photo as search image search_image = None + ### PANELS + content_panels = Page.content_panels + [ MultiFieldPanel( [FieldPanel("is_new"), FieldPanel("perex"), ImageChooserPanel("photo")], @@ -366,21 +388,16 @@ class DonateProjectPage(DonateFormMixin, Page, SubpageMixin, MetadataPageMixin): settings_panels = Page.settings_panels + [FieldPanel("portal_project_id")] + ### RELATIONS + parent_page_types = ["donate.DonateProjectIndexPage"] subpage_types = [] - # flag for rendering anchor links in menu - is_home = False + ### OTHERS class Meta: verbose_name = "Projekt" - @property - def root_page(self): - if not hasattr(self, "_root_page"): - self._root_page = self.get_ancestors().type(DonateHomePage).specific().get() - return self._root_page - def get_meta_image(self): return self.photo @@ -406,8 +423,12 @@ class DonateProjectPage(DonateFormMixin, Page, SubpageMixin, MetadataPageMixin): class DonateCookiesPage(Page, SubpageMixin, MetadataPageMixin): + ### FIELDS + body = RichTextField("obsah", blank=True) + ### PANELS + content_panels = Page.content_panels + [ FieldPanel("body", classname="full"), ] @@ -427,19 +448,24 @@ class DonateCookiesPage(Page, SubpageMixin, MetadataPageMixin): settings_panels = [] + ### RELATIONS + parent_page_types = ["donate.DonateHomePage"] subpage_types = [] - # flag for rendering anchor links in menu - is_home = False + ### OTHERS class Meta: verbose_name = "Cookies" class DonateInfoPage(DonateFormMixin, Page, SubpageMixin, MetadataPageMixin): + ### FIELDS + body = RichTextField("obsah", blank=True) + ### PANELS + content_panels = Page.content_panels + [ FieldPanel("body", classname="full"), ] @@ -459,11 +485,12 @@ class DonateInfoPage(DonateFormMixin, Page, SubpageMixin, MetadataPageMixin): settings_panels = [] + ### RELATIONS + parent_page_types = ["donate.DonateHomePage"] subpage_types = [] - # flag for rendering anchor links in menu - is_home = False + ### OTHERS class Meta: verbose_name = "Info" @@ -472,3 +499,64 @@ class DonateInfoPage(DonateFormMixin, Page, SubpageMixin, MetadataPageMixin): @property def portal_project_id(self): return self.get_parent().specific.portal_project_id + + +class TargetedDonationBlock(blocks.StructBlock): + title = blocks.CharBlock(label="název") + description = blocks.CharBlock(label="popis", required=False) + portal_project_id = blocks.IntegerBlock( + label="ID projektu v darovacím portálu", + required=False, + help_text="Pokud není zadáno ID projektu, tak se adresný dar nezobrazí.", + ) + + class Meta: + label = "adresný dar" + + +class DonateTargetedDonationsPage( + DonateFormMixin, Page, SubpageMixin, MetadataPageMixin +): + ### FIELDS + + targeted_donations = StreamField( + [("item", TargetedDonationBlock())], verbose_name="adresné dary", blank=True + ) + + # page does not have specific portal_project_id + portal_project_id = None + + ### PANELS + + content_panels = Page.content_panels + [ + StreamFieldPanel("targeted_donations"), + ] + + promote_panels = [ + MultiFieldPanel( + [ + FieldPanel("slug"), + FieldPanel("seo_title"), + FieldPanel("search_description"), + ImageChooserPanel("search_image"), + HelpPanel(help.build(help.NO_SEO_TITLE, help.NO_SEARCH_IMAGE)), + ], + gettext_lazy("Common page configuration"), + ), + ] + + settings_panels = [] + + ### RELATIONS + + parent_page_types = ["donate.DonateRegionPage"] + subpage_types = [] + + ### OTHERS + + class Meta: + verbose_name = "Adresné dary" + + @property + def show_donate_form(self): + return bool(self.targeted_donations) diff --git a/donate/static/donate/assets/css/style.css b/donate/static/donate/assets/css/style.css index 70de6b7d640380dcf51e724947de9145dae7bb3d..927b17fc83f97c2697f6e2f50b2b7c165333adb9 100644 --- a/donate/static/donate/assets/css/style.css +++ b/donate/static/donate/assets/css/style.css @@ -227,6 +227,10 @@ section { padding-bottom: 0rem; } +.section--form { + padding-top: 2rem; +} + @media screen and (max-width: 991px) { section { padding: 3.5rem 0rem; @@ -729,6 +733,11 @@ footer h1, footer h2, footer h3, footer h4, footer h5, footer h6 { box-shadow: 0 0 0 .2rem rgba(0, 255, 147, 0.25); } +.custom-control-label { + line-height: 1.2; + padding-top: .7rem; +} + .custom-control-label::after { top: .5rem; left: -2.5rem; diff --git a/donate/templates/donate/donate_home_page.html b/donate/templates/donate/donate_home_page.html index 15db0cc163bed98df6b5d9a25cb51044a9ac8bed..fa767f27c14c5252a7b74d7a37fb708bf325b6db 100644 --- a/donate/templates/donate/donate_home_page.html +++ b/donate/templates/donate/donate_home_page.html @@ -48,6 +48,7 @@ <div class="donate-form__right"> <form id="js-donate-form" method="post"> {% csrf_token %} + <input type="hidden" name="portal_project_id" value="{{ page.portal_project_id }}"> <div class="form-group row mb-4 align-items-center"> <legend class="col-form-label col-md-4 col-form-label-lg">Částka</legend> <div class="col-md-8"> diff --git a/donate/templates/donate/donate_info_page.html b/donate/templates/donate/donate_info_page.html index 7effd2043dd4bdadb43f73250d1054b4f56b3c33..40cbefa019f857daaef4fd642c0a2c68f07d1081 100644 --- a/donate/templates/donate/donate_info_page.html +++ b/donate/templates/donate/donate_info_page.html @@ -33,6 +33,7 @@ {% if page.show_donate_form %} <form id="js-donate-form" method="post"> {% csrf_token %} + <input type="hidden" name="portal_project_id" value="{{ page.portal_project_id }}"> <div class="form-group row mb-2 align-items-center"> <legend class="col-form-label col-md-12 col-form-label-lg">Částka</legend> <div class="col-md-12"> diff --git a/donate/templates/donate/donate_project_page.html b/donate/templates/donate/donate_project_page.html index 45031ced0c8bb5070da867747a42ced973910b80..2338358b708d6bd834de751e75b73c73471295a6 100644 --- a/donate/templates/donate/donate_project_page.html +++ b/donate/templates/donate/donate_project_page.html @@ -71,6 +71,7 @@ {% if page.show_donate_form %} <form id="js-donate-form" method="post"> {% csrf_token %} + <input type="hidden" name="portal_project_id" value="{{ page.portal_project_id }}"> <div class="form-group row mb-2 align-items-center"> <legend class="col-form-label col-md-12 col-form-label-lg">Částka</legend> <div class="col-md-12"> diff --git a/donate/templates/donate/donate_region_page.html b/donate/templates/donate/donate_region_page.html index f8db40a93f0d65056addaaddd70b412e360948ee..f542f0379d5e440ed2a937b6760a772556807215 100644 --- a/donate/templates/donate/donate_region_page.html +++ b/donate/templates/donate/donate_region_page.html @@ -17,7 +17,14 @@ <div class="row"> <div class="col-12 col-lg-7 mb-5 mb-lg-0 richtext"> - {{ page.body|richtext }} + <div class="row"> + {{ page.body|richtext }} + </div> + {% if page.has_targeted_donations %} + <div class="row my-4"> + <a href="{{ page.targeted_donations_page_url }}" class="btn btn-dark btn-lg my-2">Adresné dary pro kraj <i class="icon-chevron-right ml-2"></i></a> + </div> + {% endif %} </div><!-- /column --> <div class="col-12 col-lg-5 col-xl-4 offset-xl-1"><!-- /column --> @@ -33,6 +40,7 @@ {% if page.show_donate_form %} <form id="js-donate-form" method="post"> {% csrf_token %} + <input type="hidden" name="portal_project_id" value="{{ page.portal_project_id }}"> <div class="form-group row mb-2 align-items-center"> <legend class="col-form-label col-md-12 col-form-label-lg">Částka</legend> <div class="col-md-12"> diff --git a/donate/templates/donate/donate_targeted_donations_page.html b/donate/templates/donate/donate_targeted_donations_page.html new file mode 100644 index 0000000000000000000000000000000000000000..2c4a7b6bd3da215eb6c36ffdf642d49cb859193c --- /dev/null +++ b/donate/templates/donate/donate_targeted_donations_page.html @@ -0,0 +1,97 @@ +{% extends "donate/base.html" %} +{% load wagtailcore_tags %} + +{% block content %} + +<!-- CONTENT --> +<main role="main"> + + <section class="section--alternate region__header"> + <div class="container"> + <h1 class="lead heading">{{ page.title }}</h1> + </div> <!-- /container --> + </section> + + <section class="section--primary section--form"> + <div class="container"> + + {% if page.show_donate_form %} + <form id="js-donate-form" method="post"> + {% csrf_token %} + + <div class="form-group row mb-4 align-items-center"> + <div class="col-12"> + {% for target in page.targeted_donations %} + {% if target.value.portal_project_id %} + <div class="custom-control custom-radio my-3"> + <input type="radio" id="target{{ forloop.counter }}" name="portal_project_id" value="{{ target.value.portal_project_id }}" class="custom-control-input"{% if forloop.first %} checked required{% endif %}> + <label class="custom-control-label col-form-label-lg" for="target{{ forloop.counter }}">{{ target.value.title }}<br> <span class="small">{{ target.value.description }}</span></label> + </div> + {% endif %} + {% endfor %} + </div> + </div> + + <div class="form-group row mb-4 align-items-center"> + <legend class="col-form-label col-md-3 col-form-label-lg">Částka</legend> + <div class="col-md-9"> + <div class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="amount1" name="amount" value="100" class="custom-control-input" checked required> + <label class="custom-control-label col-form-label-lg" for="amount1">100 Kč</label> + </div> + <div class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="amount2" name="amount" value="200" class="custom-control-input"> + <label class="custom-control-label col-form-label-lg" for="amount2">200 Kč</label> + </div> + <div class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="amount3" name="amount" value="500" class="custom-control-input"> + <label class="custom-control-label col-form-label-lg" for="amount3">500 Kč</label> + </div> + <div class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="amount4" name="amount" value="-1" class="custom-control-input"> + <label class="custom-control-label col-form-label-lg" for="amount4">Jiná částka</label> + </div> + </div> + </div> + <div class="form-group row mb-4 align-items-center" id="js-custom-amount-input" style="display: none;"> + <div class="offset-md-3 col-md-9"> + <div class="input-group input-group-lg mb-3 custom-amount"> + <input type="number" class="form-control" id="customamount" name="custom_amount" placeholder="1000" aria-describedby="customamount-currency"> + <div class="input-group-append"> + <span class="input-group-text" id="customamount-currency">Kč</span> + </div> + </div> + </div> + </div> + <div class="form-group row mb-4 align-items-center"> + <legend class="col-form-label col-md-3 col-form-label-lg">Typ příspěvku</legend> + <div class="col-md-9"> + <div class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="periodicity1" name="periodicity" value="730" class="custom-control-input" checked required> + <label class="custom-control-label col-form-label-lg" for="periodicity1">Měsíční</label> + </div> + <div class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="periodicity2" name="periodicity" value="99999" class="custom-control-input"> + <label class="custom-control-label col-form-label-lg" for="periodicity2">Jednorázový</label> + </div> + </div> + </div> + <div class="form-group row mb-0"> + <div class="col-12"> + <button type="submit" class="btn btn-danger btn-lg">Darovat</button> + </div> + </div> + </form> + {% else %} + <div class="row mb-4 donate-form"> + <p>Krajské sdružení momentálně nepřijímá adresné dary. Místo toho <a href="{% pageurl page.get_parent %}">podpořte celý kraj!</a></p> + </div> + {% endif %} + + </div> <!-- /container --> + </section> + +</main> +<!-- /CONTENT --> + +{% endblock %}